A method that applies self to a proc
Asked Answered
G

3

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
Gonion answered 6/3, 2012 at 20:13 Comment(8)
Why would you want to introduce a new dependency when the small function listed above accomplishes your goal?Kaka
@Kaka If there is a built in way, I want to use that.Gonion
Why not just use a lambda? f = ->(x) { x * 3 }; six = f[2]Iseabal
@muistooshort Actually, that is not good.Gonion
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?Iseabal
Is that not identical to def apply; yield self; end ?Nadean
@Nadean Yes. It is. I want to have that effect with self as the receiver.Gonion
ActiveSupport has the try method defined on object. It also takes a method. The trick is it's defined on nil to return nil. Apart from that, it does the same thing.Nadean
M
3

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

"Abc".tap do |str|
  puts str
end
Maestoso answered 6/3, 2012 at 20:17 Comment(5)
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 requestPelota
tap is also a Ruby 1.9 method and needs to be monkey-patched into Ruby 1.8 if backward compatibility is an issuePelota
Re: Ruby 1.9 - not really, it's present in 1.8.7.Maestoso
@AleksanderPohl Actually as Gareth writes, this is not what I want.Gonion
Yes, there is a little difference between tap and your method - the returned value. I haven't spotted it in the first place.Maestoso
M
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
Marquetry answered 6/3, 2012 at 22:2 Comment(0)
N
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}"}
Nadean answered 6/3, 2012 at 22:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.