Skip to content
This repository
Browse code

Added Object#try. ( Taken from http://ozmm.org/posts/try.html ) [Chri…

…s Wanstrath]
commit 51730792ca930a896361eb92354a42bc56903de1 1 parent 51a19ae
Pratik authored November 19, 2008
2  activesupport/CHANGELOG
... ...
@@ -1,5 +1,7 @@
1 1
 *2.3.0 [Edge]*
2 2
 
  3
+* Added Object#try. ( Taken from http://ozmm.org/posts/try.html ) [Chris Wanstrath]
  4
+
3 5
 * Added Enumerable#none? to check that none of the elements match the block #1408 [Damian Janowski]
4 6
 
5 7
 * TimeZone offset tests: use current_period, to ensure TimeZone#utc_offset is up-to-date [Geoff Buesing]
13  activesupport/lib/active_support/core_ext/object/misc.rb
@@ -71,4 +71,17 @@ def with_options(options)
71 71
   def acts_like?(duck)
72 72
     respond_to? "acts_like_#{duck}?"
73 73
   end
  74
+
  75
+  # Tries to send the method only if object responds to it. Return +nil+ otherwise.
  76
+  # 
  77
+  # ==== Example :
  78
+  # 
  79
+  # # Without try
  80
+  # @person ? @person.name : nil
  81
+  # 
  82
+  # With try
  83
+  # @person.try(:name)
  84
+  def try(method)
  85
+    send(method) if respond_to?(method, true)
  86
+  end
74 87
 end
25  activesupport/test/core_ext/object_and_class_ext_test.rb
@@ -247,3 +247,28 @@ def test_instance_exec_nested
247 247
       [arg] + instance_exec('bar') { |v| [reverse, v] } }
248 248
   end
249 249
 end
  250
+
  251
+class ObjectTryTest < Test::Unit::TestCase
  252
+  def setup
  253
+    @string = "Hello"
  254
+  end
  255
+
  256
+  def test_nonexisting_method
  257
+    method = :undefined_method
  258
+    assert !@string.respond_to?(method)
  259
+    assert_nil @string.try(method)
  260
+  end
  261
+  
  262
+  def test_valid_method
  263
+    assert_equal 5, @string.try(:size)
  264
+  end
  265
+
  266
+  def test_valid_private_method
  267
+    class << @string
  268
+      private :size
  269
+    end
  270
+
  271
+    assert_equal 5, @string.try(:size)
  272
+  end
  273
+
  274
+end

27 notes on commit 5173079

Xavier Noria
Owner

I like the functionality, but the name doesn’t quite “click” to me either.

Bang methods have different semantics… what about “send?”. Oh, the signature could accept args as well.

Eloy Durán

Nice!

Simon Menke

‘send?’ would be nice.

Roger Pack

take a look at .andand http://weblog.raganwald.com/2008/01/objectandand-objectme-in-ruby.html though renaming it ._? might be nicer # almost equivalent to groovy’s object.?.method

Roman Le Négrate

+1 for send?

Pete Nicholls

How about `attempt?`? Try reminds me of `try… catch`

`person.attempt?(:name)`

Henrik Nyh

+1 for “send?”.

Pat Nakajima

I like the name try, though I prefer a version that allows arguments and/or a block: http://gist.github.com/26751

Eloy Durán

Try is fine by me, but +1 for nakajima’s patch.

Matthew Rudy Jacobs

I particularly like the use of the symbol :wee in his examples.

Michael Niessner

why not use a proxy so you could just do string.try.size ?

josegit

-5 for send?. Foo? methods, by convention, return boolean values. Try does not.

Grant Hutchins

+1 nakajima

Henrik Nyh

josegit: That’s usually the case, but not always. To quote matz from a recent ruby-talk thread:

By convention, they are predicates, which means the return value can be considered as boolean value. But at the same time, the values are not limited to true and false. For example, defined? returns the string to describe the kind of expression defined, and nil otherwise.

There’s another convention that when a predicate returns non-true value for represent true, it should return nil for false.

Then again, whether this is a predicate can be discussed. I think I’ll retract my +1 for a ±0.

Henrik Nyh

Mangled by textile. First and last paragraphs are mine, middle two are quoted from matz.

Henrik Nyh

A better example may be Ruby’s Numeric#nonzero? which returns the number if it’s not zero and returns nil otherwise. send? would be pretty analogous.

Peter Wagenet

I’ll let others hash out the appropriate method name, but I agree that it should at least support arguments like #send.

Pratik
Owner

Please submit patches at Lighthouse and assign to me.

Thanks!

Amos King

this is nice sugar.

Eloy Durán

Sumitted patch with Nakajima’s suggestion: http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1425-allow-optional-arguments-andor-block-for-objecttry

Luciano Panaro

Submitted a patch based on alloy’s, adding the option of doing person.try_name(arg1, arg2, …) { … }

http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1425-allow-optional-arguments-andor-block-for-objecttry

Alexander Lomakin

Thank you very-very much. I think it will be very useful!

Rob Anderton

Surely with nakajima’s version it should be called do_or_do_not – remember “there is no try”…

Vitaly Kushner

The problem is nil.respond_to?(:id) is true. and so you can’t use it as for @object.try.id

Pat Nakajima

vitaly: That’s an instance in which you’d probably want to rethink using #try anyway, and instead perhaps structure your interface in such a way that doesn’t return nil objects.

I know it’s ridiculous for me to say this, since I was the one who recommended an “improved” version, but I actually think that nine times out of ten, using #try is a code smell.

Matthew Rudy Jacobs

noticed a problem.

>> “some string”.try(:gsub, “some”, “this”) => “this string”

>> nil.try(:gsub, “some”, “this”) => TypeError: $_ value need to be String (nil given) from (irb):18:in `gsub’ from (irb):18:in `send’ from (irb):18 from :0

This is because nil defines a private method “gsub”. Is there really a need for “try” to “try” private methods? It seems like a less useful case than someone using gsub against an accidental nil.

Carlos Brando

+1 nakajima

José Valim
Owner

nakajima suggestion is already into core:

http://github.com/rails/rails/commit/823b623fe2de8846c37aa13250010809ac940b57

Please sign in to comment.
Something went wrong with that request. Please try again.