0

I want to have a method defined on Object that takes a block and applies the receiver to the block. An implementation will be like the following:

class Object
    def apply ≺ pr.call(self) end
end

2.apply{|x| x * 3} # => 6

Is there already a standard way to do this or a well known library that has a method with similar use? If so, I didn't want to reinvent the wheel.

It happens to me very often that, I have a method that takes an optional block, and when there is no block, I want to return some return_value calculated within the method, but when there is a block, I want to return the return value of the return_value applied to the block. For now, I have bunches of lines like:

def method ..., &pr
  ...
  pr ? pr.call(return_value) : return_value
end

but I want to consistently write

def method ..., &pr
  ...
  pr ? return_value.apply(&pr) : return_value
end

or even better, with a slightly modified definition of apply,

def method ..., &pr
  ...
  return_value.apply(&pr)
end
Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
sawa
  • 165,429
  • 45
  • 277
  • 381
  • 1
    Why would you want to introduce a new dependency when the small function listed above accomplishes your goal? – maerics Mar 06 '12 at 20:16
  • @maerics If there is a built in way, I want to use that. – sawa Mar 06 '12 at 20:17
  • 2
    Why not just use a lambda? `f = ->(x) { x * 3 }; six = f[2]` – mu is too short Mar 06 '12 at 20:41
  • @muistooshort Actually, that is not good. – sawa Mar 06 '12 at 20:51
  • Looks like you might have your blocks in the wrong place. Why not just return the value and let the caller do what they want with it? – mu is too short Mar 06 '12 at 21:19
  • Is that not identical to `def apply; yield self; end` ? – steenslag Mar 06 '12 at 21:21
  • @steenslag Yes. It is. I want to have that effect with `self` as the receiver. – sawa Mar 06 '12 at 21:24
  • ActiveSupport has [the try method](http://api.rubyonrails.org/classes/Object.html#method-i-try) defined on object. It also takes a method. The trick is it's defined on [nil](https://github.com/rails/rails/blob/82d41c969897cca28bb318f7caf301d520a2fbf3/activesupport/lib/active_support/core_ext/object/try.rb#L28) to return nil. Apart from that, it does the same thing. – steenslag Mar 06 '12 at 21:44

3 Answers3

3

I guess Object.tap is what you are looking for:

"Abc".tap do |str|
  puts str
end
Aleksander Pohl
  • 1,675
  • 10
  • 14
  • 2
    `tap` also has the side effect of returning the object you're tapping, which may or may not be desired (it's useful for inserting calls into method chains), but is slightly different from the original request – Gareth Mar 06 '12 at 20:20
  • `tap` is also a Ruby 1.9 method and needs to be monkey-patched into Ruby 1.8 if backward compatibility is an issue – Gareth Mar 06 '12 at 20:22
  • 1
    Re: Ruby 1.9 - not really, it's present in 1.8.7. – Aleksander Pohl Mar 06 '12 at 20:23
  • @AleksanderPohl Actually as Gareth writes, this is not what I want. – sawa Mar 06 '12 at 20:24
  • Yes, there is a little difference between `tap` and your method - the returned value. I haven't spotted it in the first place. – Aleksander Pohl Mar 06 '12 at 20:27
1

Is that not identical to def apply; yield self; end? – steenslag

@steenslag Yes. It is. I want to have that effect with self as the receiver. – sawa

Is this what you mean?

2.instance_eval { * 3 }
# => 6

Unfortunately, that doesn't work. instance_eval simply runs code as if the receiver was self. Operators don't presume self as the receiver, so you'd actually have to write this:

2.instance_eval { self * 3 }
# => 6

However, as a proof of concept, this is possible:

Numeric.send(:define_method, :plus) { |x| self + x }
2.instance_eval { plus 3 }
# => 5
Community
  • 1
  • 1
Matheus Moreira
  • 17,106
  • 3
  • 68
  • 107
0

(Aftwer reading OP's edit) AFAIK the canonical way to write this is:

def purpose(*args)  #no &bl or &pr
  res = 42 #huge calculation
  return res unless block_given?
  yield res
end

p purpose(1,2)
purpose{|n| puts "from the block: #{n}"}
steenslag
  • 79,051
  • 16
  • 138
  • 171