Keep Trying
One part of Objective-C that I like is being able to send messages to nil objects safely and more so their KVC and KVO patterns. In Ruby I often use the #try
method to safely send messages to objects that may be nil at runtime. But one thing I always wanted was a nice way to send a key path, basically a string of methods signatures, to an object in the same way. I give you my simple #try_keypath
method :)
class Object
def try_keypath(methods, *args, &block)
methods.to_s.split('.').inject(self) { |result, method| result.try(method) }
end
end
class NilClass
def try_keypath(*args)
nil
end
end
Yup, it is that simple. Let's see how this would work. Here are a few basic classes that randomly return nested objects. So staring with the Foo
object, we have the possibility to get to some deeply nested info.
class Foo
def bar
rand(2) == 1 ? Bar.new : nil
end
end
class Bar
def batz
'wohoo'
end
def deep
Deep.new
end
end
class Deep
def info
{:winning => true}
end
end
Finally, here is how it would look and return different results. Man I love Ruby!
Foo.new.try :bar # => #<Bar:0x108d7dfd0>
Foo.new.try :bar # => #<Bar:0x108d7ddf0>
Foo.new.try :bar # => nil
Foo.new.try :bar # => nil
Foo.new.try :bar # => #<Bar:0x108d7d4b8>
Foo.new.try :bar # => nil
Foo.new.try_keypath 'bar.batz' # => "wohoo"
Foo.new.try_keypath 'bar.batz' # => "wohoo"
Foo.new.try_keypath 'bar.batz' # => nil
Foo.new.try_keypath 'bar.batz' # => nil
Foo.new.try_keypath 'bar.batz' # => nil
Foo.new.try_keypath 'bar.batz' # => "wohoo"
Foo.new.try_keypath 'bar.deep.info' # => nil
Foo.new.try_keypath 'bar.deep.info' # => {:winning=>true}
Foo.new.try_keypath 'bar.deep.info' # => nil
Foo.new.try_keypath 'bar.deep.info' # => nil
Foo.new.try_keypath 'bar.deep.info' # => {:winning=>true}
Foo.new.try_keypath 'bar.deep.info' # => nil