3Feb/100
Ruby Objective-C like Null Pattern
So, I think the objective c null(nil) pattern is pretty cool. I know that lots of people talk about doing it in different ways. Here is my implementation. I'm not keen on having nil catch method missing, because I'm not sure what havoc that may cause in one of the 10million gems I use. I also like the last link above (which I just found when writing this article) except that I dont want to type "try" a million times.
This is my preferred method when dealing with deeply nested messages. Stick this in your lib.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class Object def rcall(*method_names) _result = self method_names.collect.each { |mname| if _result.respond_to?(mname) _result = _result.send(mname) else _result = nil break end } _result end end |
Wanna use it?
1 2 3 4 5 6 7 8 9 10 | # In this example, if an of the messages return nil, i'll get a MethodMissing error and I'll be scorned. my_object.first_message.second_message.the_message_whos_value_i_want # The problem is, I dont care if its nil, I have a default, the method is still missing. value = my_object.first_message.second_message.the_message_whos_value_i_want || "Im ok with this being nil" # If chain_message encounters a nil, it just returns nil and you can use standard language logic to default that value # You dont have to do a million if-checks. value = my_object.rcall( :first_message, :second_message, :the_message_whos_value_i_want ) || "Im ok with this being nil" |
Another Example:
1 2 3 4 5 6 7 8 9 10 11 | # Some cool way of finding purchases, be it AR, Datamapper, or whatever, just get an object already purchases = Purchase.all( arbitrary_finder_logic ) # I need to output the name of who added the product on some arbitrary report no one will read # yeah, I know. My validators should have made sure the values were there, I'm just making this up. purchases.each do |purchase| buyer = purchase.rcall(:purchaser, :name) || "John Doe" seller = purchase.rcall(:product, :listor, :name) || "Jack Sales" puts "Buyer: #{buyer}, Seller: #{seller}" end |
Yay, Drying up if-else nil checking statements. High Five.