Skip to content

Commit

Permalink
try that try
Browse files Browse the repository at this point in the history
  • Loading branch information
hookercookerman committed Jul 23, 2012
1 parent 6a105ba commit 9768750
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lib/motion_support/core_ext/object/try.rb
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,2 @@
require 'bubble-wrap/loader'
BubbleWrap.require('motion/core_ext/object/try.rb')
55 changes: 55 additions & 0 deletions motion/core_ext/object/try.rb
Original file line number Original file line Diff line number Diff line change
@@ -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)

This comment has been minimized.

Copy link
@DougPuchalski

DougPuchalski Jan 25, 2013

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

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 changes: 60 additions & 0 deletions spec/core_ext/object/try_spec.rb
Original file line number Original file line Diff line number Diff line change
@@ -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

0 comments on commit 9768750

Please sign in to comment.