Ruby, JavaScript, Sass, iOS. Stinky Cheese & Beer Advocate. Working at CustomInk and loving it!

Keep Trying

Ruby Is Evil! 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