Skip to content

Commit 5e51bdd

Browse files
author
David Heinemeier Hansson
committed
We tenderized the wrong method! Object#try already had the yield option, just needed some tenderloving instance_eval to fit the bill
1 parent 39691ba commit 5e51bdd

File tree

5 files changed

+20
-34
lines changed

5 files changed

+20
-34
lines changed

activesupport/CHANGELOG.md

+4-9
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
1-
* Added yield to Object#presence, so you can do this:
1+
* Added instance_eval version to Object#try, so you can do this:
22

3-
project.account.owner.presence { name.first } || 'Nobody'
3+
person.try { name.first }
44

5-
instead of calling twice (which may incur double SQL calls):
5+
instead of:
66

7-
project.account.owner ? project.account.owner.name.first || 'Nobody'
8-
9-
or assigning to local variable:
10-
11-
owner = project.account.owner
12-
owner ? owner.name.first || 'Nobody'
7+
person.try { |person| person.name.first }
138

149
*DHH*
1510

activesupport/lib/active_support/core_ext/object/blank.rb

+2-14
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,9 @@ def present?
3939
#
4040
# region = params[:state].presence || params[:country].presence || 'US'
4141
#
42-
# You can also use this with a block that will be yielded if the object is present
43-
# and the result of that block will then be returned. The block itself is run against
44-
# the instance you're running #presence on (using instance_eval)
45-
#
46-
# project.account.owner.presence { name.first } || 'Nobody'
47-
#
4842
# @return [Object]
49-
def presence(&block)
50-
if present?
51-
if block_given?
52-
instance_eval(&block)
53-
else
54-
self
55-
end
56-
end
43+
def presence
44+
self if present?
5745
end
5846
end
5947

activesupport/lib/active_support/core_ext/object/try.rb

+10-1
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,23 @@ class Object
3333
# ...
3434
# end
3535
#
36+
# You can also call try with a block without accepting an argument, and the block
37+
# will be instance_eval'ed instead:
38+
#
39+
# @person.try { upcase.truncate(50) }
40+
#
3641
# Please also note that +try+ is defined on +Object+, therefore it won't work
3742
# with instances of classes that do not have +Object+ among their ancestors,
3843
# like direct subclasses of +BasicObject+. For example, using +try+ with
3944
# +SimpleDelegator+ will delegate +try+ to the target instead of calling it on
4045
# delegator itself.
4146
def try(*a, &b)
4247
if a.empty? && block_given?
43-
yield self
48+
if b.arity.zero?
49+
instance_eval(&b)
50+
else
51+
yield self
52+
end
4453
else
4554
public_send(*a, &b) if respond_to?(a.first)
4655
end

activesupport/test/core_ext/object/blank_test.rb

-10
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,4 @@ def test_present
2828
BLANK.each { |v| assert_equal false, v.present?, "#{v.inspect} should not be present" }
2929
NOT.each { |v| assert_equal true, v.present?, "#{v.inspect} should be present" }
3030
end
31-
32-
def test_presence
33-
BLANK.each { |v| assert_equal nil, v.presence, "#{v.inspect}.presence should return nil" }
34-
NOT.each { |v| assert_equal v, v.presence, "#{v.inspect}.presence should return self" }
35-
end
36-
37-
def test_presence_with_a_block
38-
assert_equal "THIS WAS TENDERLOVE'S IDEA", "this was tenderlove's idea".presence { upcase } || "Nobody"
39-
assert_equal "Nobody", nil.presence { upcase } || "Nobody"
40-
end
4131
end

activesupport/test/core_ext/object/try_test.rb

+4
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ def test_try_only_block_nil
6565
assert_equal false, ran
6666
end
6767

68+
def test_try_with_instance_eval_block
69+
assert_equal @string.reverse, @string.try { reverse }
70+
end
71+
6872
def test_try_with_private_method_bang
6973
klass = Class.new do
7074
private

0 commit comments

Comments
 (0)