Improved ‘try()’
I recently discovered the nice ‘try()’ hack that chris@ozmm.org created.
It has some resemblance to my Array#to_proc - so I though that I would try to create an extended ‘try()’
It works with “nested methods” and supports a default return value.
Here we go:
class Object
def try(*args)
options = {:default => nil}.merge(args.last.is_a?(Hash) ? args.pop : {})
target = self # Initial target is self.
while target && mtd = args.shift
target = target.send(mtd) if target.respond_to?(mtd)
end
return target || options[:default]
end
end
class Person
attr_accessor :name
attr_accessor :address
end
class Address
attr_accessor :street
end
def print_info(person, default = nil)
puts <<-END
==============================================================
Name: #{person.try(:name, :default => default)}
Street: #{person.try(:address, :street, :default => default)}
END
end
@person = Person.new
@person.name = "Frank Black"
@person.address = Address.new
@person.address.street = "xyz"
print_info(@person)
@person.address = nil
print_info(@person)
print_info(@person, "No Info Registered")
Array#to_proc - Nested properties for to_proc hack.
Ruby is really elegant when it come to extending core libraries with custom behavior.
I needed a way to apply the standard to_proc hack to nested method calls. Normally the to_proc implementation in Symbol allows you to replace
['abc', 'defg'].map{|x| x.size} #=> [3, 4]
with
['abc, 'defg'].map(&:size) #=> [3, 4]
But this only applies to “first level” methods on the target reference. The following extension of the Array class allows specifying a ‘call chain’ of methods:
class Array
def to_proc
proc{|target|
inject(target){|memo, arg|
break unless memo
memo.send(arg)
}
}
end
end
So, in order to extract the regnr of an optional default_trailer:
class Car < ActiveRecord::Base
has_one :default_trailer, :class_name => 'Trailer'
end
class Trailer < ActiveRecord::Base
belongs_to :car
end
you can do:
[car1, car2, car3].map(&[:default_trailer, :regnr])
#=> ['GH3456', nil, 'FF1234']