Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

try that try

  • Loading branch information...
commit 97687504305c141b8f98dfbd8d4490b8b72a8606 1 parent 6a105ba
Richard Hooker authored
2  lib/motion_support/core_ext/object/try.rb
View
@@ -0,0 +1,2 @@
+require 'bubble-wrap/loader'
+BubbleWrap.require('motion/core_ext/object/try.rb')
55 motion/core_ext/object/try.rb
View
@@ -0,0 +1,55 @@
+class Object
+ # Invokes the public method identified by the symbol +method+, passing it any arguments
+ # and/or the block specified, just like the regular Ruby <tt>Object#public_send</tt> does.
+ #
+ # *Unlike* that method however, a +NoMethodError+ exception will *not* be raised
+ # and +nil+ will be returned instead, if the receiving object is a +nil+ object or NilClass.
+ #
+ # If try is called without a method to call, it will yield any given block with the object.
+ #
+ # Please also note that +try+ is defined on +Object+, therefore it won't work with
+ # subclasses of +BasicObject+. For example, using try with +SimpleDelegator+ will
+ # delegate +try+ to target instead of calling it on delegator itself.
+ #
+ # Without +try+
+ # @person && @person.name
+ # or
+ # @person ? @person.name : nil
+ #
+ # With +try+
+ # @person.try(:name)
+ #
+ # +try+ also accepts arguments and/or a block, for the method it is trying
+ # Person.try(:find, 1)
+ # @people.try(:collect) {|p| p.name}
+ #
+ # Without a method argument try will yield to the block unless the receiver is nil.
+ # @person.try { |p| "#{p.first_name} #{p.last_name}" }
+ #
+ # +try+ behaves like +Object#public_send+, unless called on +NilClass+.
+ def try(*a, &b)
+ if a.empty? && block_given?
+ yield self
+ else
+ public_send(*a, &b)

Curious - why public_send? In ActiveSupport this doesn't restrict to public methods and is intended to work just like :send.

https://github.com/rails/rails/blob/6ef9fda1a39f45e2d18aba4881f60a19589a2c77/activesupport/lib/active_support/core_ext/object/try.rb#L32

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ end
+ end
+end
+
+class NilClass
+ # Calling +try+ on +nil+ always returns +nil+.
+ # It becomes specially helpful when navigating through associations that may return +nil+.
+ #
+ # nil.try(:name) # => nil
+ #
+ # Without +try+
+ # @person && !@person.children.blank? && @person.children.first.name
+ #
+ # With +try+
+ # @person.try(:children).try(:first).try(:name)
+ def try(*args)
+ nil
+ end
+end
+
+
60 spec/core_ext/object/try_spec.rb
View
@@ -0,0 +1,60 @@
+describe "ObjectTry"do
+ before do
+ @string = "Hello"
+ end
+
+ it "nonexisting method" do
+ method = :undefined_method
+ @string.respond_to?(method).should.not == true
+ lambda{ @string.try(method)}.should.raise(NoMethodError)
+ end
+
+ it "nonexisting method with arguments" do
+ method = :undefined_method
+ @string.respond_to?(method).should.not == true
+ lambda{ @string.try(method, 'llo', 'y') }.should.raise(NoMethodError)
+ end
+
+ it "valid method" do
+ @string.try(:size).should == 5
+ end
+
+ it "argument forwarding" do
+ @string.try(:sub, 'llo', 'y').should.equal("Hey")
+ end
+
+ it "block forwarding" do
+ @string.try(:sub, 'llo') { |match| 'y' }.should.equal("Hey")
+ end
+
+ it "nil to type" do
+ nil.try(:to_s).should == nil
+ nil.try(:to_i).should == nil
+ end
+
+ it "false try" do
+ false.try(:to_s).should == 'false'
+ end
+
+ it "try only block" do
+ @string.try { |s| s.reverse }.should == @string.reverse
+ end
+
+ it "try only block nil" do
+ ran = false
+ nil.try { ran = true }
+ ran.should == false
+ end
+
+ it "try with private method" do
+ klass = Class.new do
+ private
+
+ def private_method
+ 'private method'
+ end
+ end
+
+ lambda{ klass.new.try(:private_method) }.should.raise(NoMethodError)
+ end
+end
Doug Puchalski

Curious - why public_send? In ActiveSupport this doesn't restrict to public methods and is intended to work just like :send.

https://github.com/rails/rails/blob/6ef9fda1a39f45e2d18aba4881f60a19589a2c77/activesupport/lib/active_support/core_ext/object/try.rb#L32

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