Using the spaceship operator to compare nil?

Hey folks,

I have a test helper in a Rails app called assert_ordered_by

def assert_ordered_by(attribute, collection, direction)
collection = collection.to_s
return true if assigns[“#{collection}”].length < 2
option_one = assigns[“#{collection}”][0].send(attribute)
option_two = assigns[“#{collection}”][1].send(attribute)
assert option_one.send(direction, option_two), “#{option_one} is not
#{direction} #{option_two}”
end

It works well in all the cases I’ve tried thus far except when dealing
with nil. I want to teach the method to treat nil the same way SQL
treats NULL because the collections will often contain ActiveRecord
objects.

I have the idea in my head that I need to use the spaceship operator
(<=>) to do this, but am unsure about how…

Any ideas?

Thanks,
Dan C.

I forgot to mention that this is called, for example, with:

assert_ordered_by :last_name, :users, “<=”

I’m also moving away from using the spaceship operator into
conditional logic land because I was having difficulty dealing
(mentally) with comparing nil to various types (dates, strings,
integers, etc.). Here’s the latest non-working code… :confused:

def assert_ordered_by(attribute, collection, direction)
collection = assigns["#{collection.to_s}"]
return true if collection.length < 2
collection.sort do |a, b|
if a.nil? && !b.nil?
return false if direction.include?(">") # nil cannot be
greater than anything except another nil
elsif b.nil? && !a.nil?
return false if direction.include?("<") # nil cannot be
greater than anything except another nil
elsif !a.nil? && !b.nil?
assert a.send(attribute).send(direction, b.send(attribute))
elsif a.nil? && b.nil?
return true
end
end
end

On 8/9/07, Dan C. [email protected] wrote:

I forgot to mention that this is called, for example, with:

assert_ordered_by :last_name, :users, “<=”

I’m also moving away from using the spaceship operator into
conditional logic land because I was having difficulty dealing
(mentally) with comparing nil to various types (dates, strings,
integers, etc.). Here’s the latest non-working code… :confused:

Try this:

has_nil, doesnt = collection.partition { |r| r.send(attribute).nil? }

you can then sort only the ones that have a meaningful sort value and
then rejoin as needed based on the direction, e.g. for one directed
you want:

doesnt.sort + has_nil

and for another you want

has_nil + doesn’t.sort

hope that helps. Excuse the incomplete code :slight_smile:

On Aug 9, 5:39 pm, “Gregory B.” [email protected] wrote:

and for another you want

has_nil + doesn’t.sort

hope that helps. Excuse the incomplete code :slight_smile:

Thanks, Gregory. This is what I ended up with (works well) ~

def assert_ordered_by(attribute, collection, direction)
collection = assigns[“#{collection.to_s}”]
return true if collection.length < 2
has_nil, has_no_nil = collection.partition { |r|
r.send(attribute).nil? }
has_no_nil = has_no_nil.sort_by(&:“#{attribute}”)
expected = has_nil + has_no_nil
expected.reverse! if direction.include?(“>”)
assert_equal expected.map(&:“#{attribute}”),
collection.map(&:“#{attribute}”)
end