public
Description: Ruby on Rails
Homepage: http://rubyonrails.org
Clone URL: git://github.com/rails/rails.git
Allow optional arguments and/or block for Object#try like Object#send does. 
[#1425 state:resolved]

Original suggestion by Pat Nakajima.

Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
alloy (author)
Fri Nov 21 00:47:55 -0800 2008
lifo (committer)
Mon Nov 24 09:53:48 -0800 2008
commit  823b623fe2de8846c37aa13250010809ac940b57
tree    7bf0e7e557bdedb57226cd35fef12f7e9fbbea4b
parent  fffb1da3f22852c722dbc4436ec7c924435d29a5
...
73
74
75
 
76
77
78
...
81
82
83
84
85
 
 
 
 
 
 
86
87
...
73
74
75
76
77
78
79
...
82
83
84
 
 
85
86
87
88
89
90
91
92
0
@@ -73,6 +73,7 @@ class Object
0
   end
0
 
0
   # Tries to send the method only if object responds to it. Return +nil+ otherwise.
0
+  # It will also forward any arguments and/or block like Object#send does.
0
   # 
0
   # ==== Example :
0
   # 
0
@@ -81,7 +82,11 @@ class Object
0
   # 
0
   # With try
0
   # @person.try(:name)
0
-  def try(method)
0
-    send(method) if respond_to?(method, true)
0
+  #
0
+  # # try also accepts arguments/blocks for the method it is trying
0
+  # Person.try(:find, 1)
0
+  # @people.try(:map) {|p| p.name}
0
+  def try(method, *args, &block)
0
+    send(method, *args, &block) if respond_to?(method, true)
0
   end
0
 end
...
271
272
273
 
 
 
 
 
 
 
274
...
271
272
273
274
275
276
277
278
279
280
281
0
@@ -271,4 +271,11 @@ class ObjectTryTest < Test::Unit::TestCase
0
     assert_equal 5, @string.try(:size)
0
   end
0
 
0
+  def test_argument_forwarding
0
+    assert_equal 'Hey', @string.try(:sub, 'llo', 'y')
0
+  end
0
+
0
+  def test_block_forwarding
0
+    assert_equal 'Hey', @string.try(:sub, 'llo') { |match| 'y' }
0
+  end
0
 end

Comments

rogerdpack Sat Feb 21 06:41:35 -0800 2009

This definition of try would seriously benefit from being implemented like andand, at least from my side of the fence. Cheers! -=r

bitti Tue Mar 03 13:18:07 -0800 2009

rogerdpack is right. The current semantic has many problems.

Firstly the major usecase for try is to catch the case when the receiver is nil, not so much if the method is defined on the receiver. There are also lots of methods on nil, so e.g. object.try(:id) will not archive anything besides subtle errors.

Secondly, because catching the first missing method is not enough, one often sees cascades of two ore more tries:

User.admins.first.try(:address).try(:reset)

but (apart from the hard to read syntax) it can hide many problems, because if address is defined one expects to have a reset method on it and otherwise get an exception. So like in andand it would be better to have something like

User.admin.try { |u| u.address.reset }

I guess this form can even be implemented without breaking compatibility with the old form (because the current implementation expects a “method” parameter)

bitti Tue Mar 03 14:15:07 -0800 2009

Sorry it should’ve read

User.admins.first.try { |u| u.address.reset }