diff options
author | Nate Smith <nate.smith@thescore.com> | 2015-05-14 11:21:24 -0400 |
---|---|---|
committer | Godfrey Chan <godfreykfc@gmail.com> | 2015-05-19 13:29:02 -0700 |
commit | af53280a4b5b3323ac87dc60deb2b1b781197b2b (patch) | |
tree | 654673a761ee89c5123173127f5750517fc19562 /activesupport/lib/active_support | |
parent | 0e12300c5e685ddc1b26c99fdb790e54a93153d5 (diff) | |
download | rails-af53280a4b5b3323ac87dc60deb2b1b781197b2b.tar.gz rails-af53280a4b5b3323ac87dc60deb2b1b781197b2b.tar.bz2 rails-af53280a4b5b3323ac87dc60deb2b1b781197b2b.zip |
Patch `Delegator` to work with `#try`
`Delegator` inherits from `BasicObject`, which means that it will not
have `Object#try` defined. It will then delegate the call to the
underlying object, which will not (necessarily) respond to the method
defined in the enclosing `Delegator`.
This patches `Delegator` with the `#try` method to work around the
surprising behaviour.
Fixes #5790
Diffstat (limited to 'activesupport/lib/active_support')
-rw-r--r-- | activesupport/lib/active_support/core_ext/object/try.rb | 74 |
1 files changed, 57 insertions, 17 deletions
diff --git a/activesupport/lib/active_support/core_ext/object/try.rb b/activesupport/lib/active_support/core_ext/object/try.rb index e0f70b9caa..6605771d90 100644 --- a/activesupport/lib/active_support/core_ext/object/try.rb +++ b/activesupport/lib/active_support/core_ext/object/try.rb @@ -1,4 +1,36 @@ +require 'delegate' + +module ActiveSupport + module Try #:nodoc: + def try(*a, &b) + try!(*a, &b) if a.empty? || respond_to?(a.first) + end + + def try!(*a, &b) + if a.empty? && block_given? + if b.arity.zero? + instance_eval(&b) + else + yield self + end + else + public_send(*a, &b) + end + end + end +end + +[Object, Delegator].each do |klass| + klass.include(ActiveSupport::Try) +end + class Object + ## + # :method: try + # + # :call-seq: + # try(*a, &b) + # # Invokes the public method whose name goes as first argument just like # +public_send+ does, except that if the receiver does not respond to it the # call returns +nil+ rather than raising an exception. @@ -56,30 +88,38 @@ class Object # # Please also note that +try+ is defined on +Object+. Therefore, it won't work # with instances of classes that do not have +Object+ among their ancestors, - # like direct subclasses of +BasicObject+. For example, using +try+ with - # +SimpleDelegator+ will delegate +try+ to the target instead of calling it on - # the delegator itself. - def try(*a, &b) - try!(*a, &b) if a.empty? || respond_to?(a.first) - end + # like direct subclasses of +BasicObject+. + ## + # :method: try! + # + # :call-seq: + # try!(*a, &b) + # # Same as #try, but raises a NoMethodError exception if the receiver is # not +nil+ and does not implement the tried method. # # "a".try!(:upcase) # => "A" # nil.try!(:upcase) # => nil # 123.try!(:upcase) # => NoMethodError: undefined method `upcase' for 123:Fixnum - def try!(*a, &b) - if a.empty? && block_given? - if b.arity.zero? - instance_eval(&b) - else - yield self - end - else - public_send(*a, &b) - end - end +end + +class Delegator + ## + # :method: try + # + # :call-seq: + # try(a*, &b) + # + # See Object#try + + ## + # :method: try! + # + # :call-seq: + # try!(a*, &b) + # + # See Object#try! end class NilClass |