[LRUG] Comparable Null Objects

Frederick Cheung frederick.cheung at gmail.com
Wed Jul 15 08:07:28 PDT 2015




On 15 July 2015 at 15:58:53, Duncan Stuart (dgmstuart at gmail.com) wrote:

Thanks Frederick and Rob

Defining to_date doesn't suffice: the <=> method on Date doesn't try and coerce the argument into a date, which is why Date.today > Time.now fails, even though Time responds to to_date.

If I were to define a coercion method, I think it would have to be on Date, which feels wrong.


As a quick hack:

class NoExpectedDate
  def to_s(format=:default)
    "Unknown"
  end
  def coerce(other)
    [other, 10000000] # a date long in the future
  end
end

Date.today <=> NoExpectedDate.new
=> -1


Fred



On 15 July 2015 at 13:21, Rob Isenberg <robisenberg at me.com> wrote:
Hi Duncan, if you want your class to be comparable with other built-in objects, I think you need to implement any #to_* methods that make sense.

I think you need to write a #to_date method which with then automatically be coerced when the comparison is done starting with a Date object. 

Sent from my iPhone

On 15 Jul 2015, at 13:04, Duncan Stuart <dgmstuart at gmail.com> wrote:

Sorry that last code snippet should be:
def sort_by_expected_date
  sort do |a, b| 
    if b.class = NoExpectedDate 
      1
    else
      a <=> b
    end
  end
end


On 15 July 2015 at 13:03, Duncan Stuart <dgmstuart at gmail.com> wrote:
Hi LRUG - hopefully an interesting little problem:

I have an Event class which has an "expected_date" attribute.
Some events don't have an expected date, so like a good little OO programmer i've created a Null object:

class NoExpectedDate
  def to_s(format=:default)
    "Unknown"
  end
end

This works great for printing the values, but when it comes to sorting the list I of course get:
   ArgumentError: comparison of Date with NoExpectedDate failed 

If I include Comparable and define <=> then one comparison works, but the other doesn't :

class NoExpectedDate
  include Comparable
  def to_s(format=:default)
    "Unknown"
  end
  def <=>(other_date)
    1 # Treat it as after every other date
  end
end
$ NoExpectedDate.new > Date.today
=> true

$ Date.today > NoExpectedDate.new
ArgumentError: comparison of Date with NoExpectedDate failed

I think this is because Date's <=> method expects it's argument to be a Date object or a number ("a numeric value as an astronomical Julian day number"). I've tried defining to_i and to_r on NoExpectedDate, but no dice.

Can I get NoExpectedDate to pretend to be a Date (like SimpleDelegator lies about it's class)? Is that evil?

I suppose I could always just define a method on Event to do this particular sort, but that seems nasty for all sorts of reasons:


def sort_by_expected_date sort do |a, b| 

    if b.class = NoExpectedDate 

      1

    else

      a <=> b

    end

  end

end




_______________________________________________
Chat mailing list
Chat at lists.lrug.org
Archives: http://lists.lrug.org/pipermail/chat-lrug.org
Manage your subscription: http://lists.lrug.org/options.cgi/chat-lrug.org
List info: http://lists.lrug.org/listinfo.cgi/chat-lrug.org

_______________________________________________
Chat mailing list
Chat at lists.lrug.org
Archives: http://lists.lrug.org/pipermail/chat-lrug.org
Manage your subscription: http://lists.lrug.org/options.cgi/chat-lrug.org
List info: http://lists.lrug.org/listinfo.cgi/chat-lrug.org


_______________________________________________  
Chat mailing list  
Chat at lists.lrug.org  
Archives: http://lists.lrug.org/pipermail/chat-lrug.org  
Manage your subscription: http://lists.lrug.org/options.cgi/chat-lrug.org  
List info: http://lists.lrug.org/listinfo.cgi/chat-lrug.org  
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lrug.org/pipermail/chat-lrug.org/attachments/20150715/b3a25682/attachment-0003.html>


More information about the Chat mailing list