A better “try()” for Ruby, why not do the Groovy way?
The new method in Ruby 1.9 is making some people happy and creative too.
The only problem with that in my opinion is that every one is fixed about using method chaining with the name “try” with a symbol as a parameter to escape from the:
@person.name unless @person.nil?
or
@person ? @person.name : nil
and for some strange reason they think it is natural to write:
@person.try(:name)
when I see the sentence above, the first thing I want to “try” is:
@person.try(:to_swim)
Ok, the last comment was not cool, but I thought it would be funny
So, what is this post about?
In Groovy there is a built’in language construct to solve this situation in a very cool way:
person?.nameThe method call after the “?” is only called if the previous expression was not nil.
I could not think in a way to implement any thing like that in ruby, but I think I came out with a satisfactory solution.
What do you think about flagging your method calls with “I know this can be null, but ignore it, it is a normal situation”?
No, I’m not telling you to write all this sentence in your code ![]()
the flag I’m using now is the “_” character.
I’m monkey patching ruby like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class NilClass alias :old_method_missing :method_missing def method_missing(methodname,*args) old_method_missing methodname, *args unless methodname.to_s =~ /.*_$/ end end class Object alias :old_method_missing :method_missing def method_missing(methodname,*args) methodname = (methodname.to_s.gsub(/(.*)_$/,'\1')).to_sym if respond_to? methodname send methodname,*args else old_method_missing methodname, *args end end end |
and you can use it like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #test classes class Named attr_accessor :name def initialize(name) @name = name end end class Person < Named attr_accessor :name, :company def initialize(name,company=nil) super(name) @company = company end end #Testing starts here def run_test puts @person.name_ puts @person.company_.name_ end @person = Person.new('Urubatan',Named.new('The Best')) run_test @person = nil run_test |
With this little method missing hack, we just put an “_” in the end of the method name we want to call and if the target object is nil the method will not be called and we will not get a NoMethodError.
Better yet, we can even pass arguments to the method we want to call
This way, we can use this solution only in situations we know it is safe.
What do you think about this?
I prefer the groovy solution, but I kine this one better than the “try” method
<updated>
Added one more link to the list in the beggining of the post (thanks coderr)
</updated>
If you enjoyed this post, make sure you subscribe to my RSS feed!





[…] Bom, desta vez não vou traduzir o meu post, então deem uma olhadinha no meu blog em ingles: A better “try()” for Ruby, why not do the Groovy way? […]
you have seen this solution, no?
http://coderrr.wordpress.com/2007/09/15/the-ternary-destroyer/
it’s probly the most similar to the groovy way.
and I agree the .try() method is pretty ugly.
“The method call after the “?” is only called if the previous expression was not nil. I could not think in a way to implement any thing like that in ruby, but I think I came out with a satisfactory solution.”
I don’t see the “try(:method)” as a “clean” solution, too. But, unfortunately, “:?” isn’t a valid ruby symbol. So, I guess, we can’t define a “?” method. What about this solution?
class MyProxy
def initialize(object)
@object = object
end
def method_missing(methodname, *args)
if @object.respond_to? methodname
@object.send(methodname,*args)
end
end
end
class Object
def e?
return MyProxy.new(self)
end
end
x = nil
x.e?.name
x = Struct.new(:name)
x.e?.name
–
(Yeah, I know, there are better ways to implement a proxy object in ruby. And there are more methods that need to be overwritten, like “object_id” and “class”. And that “e?” isn’t the better method name of all times. But this is a simple proof of concept =D)
coderrr and bruno, I have seen this solution before, and I think it is safer than mine (because it does not play much with method_missing)
I just think that @person.e?.company.e?.manager.e?.name
is a little stranger to write than just placing a suffix in the method names …
but I agree that the implementation is a lot more elegant than mine
[…] A better “try()” for Ruby, why not do the Groovy way? (tags: ruby programming) […]
This is the ugliest version I’ve seen yet.
Interesting approach, but it removes the readability that we rubyists love. The underscore character has no meaning to the reader and to someone who is reading someone else’s code, there would either have to be comments for each use of it or ask the original programmer to figure out why there is an underscore.
Maybe a more readable solution but very similar to what you did is to have it be “try_method_name” but that uses the “try” word that you don’t like.
Anyway, good work, I think it can potentially be better and usable.
Urubatan, off-topic:
what do you use(plugin) to put code(jsp, ruby, java) in your blog ?
Thank you!
Could just see if methodname[0..-2] exists, effectively allowing:
person?.name
The test could be written:
respond_to? :”#{methodname[0..-2]}” if methodname.split(”).last == ‘?’
Something like that… Come now, we can use the ‘?’ in our method names! Makes much more sense than ‘_’.
By the by, your captcha image isn’t showing up…
I’ve been doing…
@person && @person.name
It’s a little bit less typing than
@person.name unless @person.nil?
It gets really useful when you want to go deeper into an object..
e.g. id = @person && @person.friend && @person.friend.youngest && @person.friend.youngest.user && @person.friend.youngest.user.id
( Careful now.. http://en.wikipedia.org/wiki/Law_of_Demeter )
Cheers,
Rajesh Duggal
I think the captcha is already working

but if SK2 is working you’ll not see it again
Matt, I agree that the “?” termination would be more clear, but there is already a convention in ruby programming saying that methods terminated in “?” return a boolean value …
Renan, I use the WP-Syntax plugin
Arya, try_method_name is a good approach too, and it looks like calling a method (different of try(:method_name) ), the “_” having no meaning is a matter of convention, line the “?” at the end of boolean methods
Mark, I agree this is ugly, but I think try(:method_name) is uglier because it is not clear that you are calling a method (IMHO)
[…] 루비에서도 이 문법을 차용해오자는 의견도 있다. 구현은 method_missing을 이용해 처리해줄 수 있을 것 같다. 재미있는 […]
Me parece uma cópia do operador ? do Io …
http://www.iolanguage.com/scm/git/checkout/Io/docs/IoGuide.html
[…] Monkey-patching proposals have abounded in the Ruby community recently - including, but not limited to Object#andand, Object#_? and SafeNil and Object#method_. […]
http://andand.rubyforge.org/
whats about a ? in as the first letter?
puts @person.?company.?name
Arno, thinking about the other comments in this thread, I change my position, and I agree that playing with method_missing is not a good solution …
Even because Rails applications, and Ruby applications in general do not have a very complex object hierarchy.
By complex I mean, usually you do not go very deep in the object model to show an information.
I think this post was inspired by the java programmer inside my head