Issue #11717 has been updated by Victor Shepelev.


> "trap" already means "trap a signal", it comes from long-standing Unix terminology

Ooops. Completely forgot about this one :(

> Clearly this is something the Ruby community wants. Just as clearly, it's something nobody can name.

Yeah, can see it now.

Thinking further, I wonder if just `Object#yield` could be parsed correctly...

> If you did in fact know that you were essentially requesting an alias for #instance_eval, this was a remarkably roundabout way to go about it.

But hey. It is NOT, in fact:

~~~
class MyClass
  attr_accessor :data

  def with_instance_eval(filename)
    File.read(filename).instance_eval{|s| p [s, self]; parse(s)}
  end

  def with_trap(filename)
    File.read(filename).trap{|s| p [s, self]; parse(s)}
  end

  def parse(str)
    JSON.parse(str)
  end
end

puts "#trap:"
p MyClass.new.with_trap('test.json')

puts "#instance_eval:"
p MyClass.new.with_instance_eval('test.json')
~~~

Output:

~~~
#trap:
["{\"test\": 1}\n", #<MyClass:0x911f428>]
{"test"=>1}

#instance_eval:
["{\"test\": 1}\n", "{\"test\": 1}\n"]
trap.rb:in `block in with_instance_eval': undefined method `parse' for "{\"test\": 1}\n":String (NoMethodError)
~~~

----------------------------------------
Feature #11717: Object#trap -- pass object to block and return result
https://bugs.ruby-lang.org/issues/11717#change-54994

* Author: Victor Shepelev
* Status: Open
* Priority: Normal
* Assignee: 
----------------------------------------
`Object#trap` can be thought as useful counterpart for `Object#tap`: like tap, it passes object to the block; **unlike** tap, it returns results of the block, not object itself.

**Rationale**

`#trap` could allow to gracefully chain processing of objects, which isn't `Enumerable`, therefore enforcing "functional" style in Ruby (which considered good).

**Use case**

~~~
# Assume we grab some resource from web:
SomeWebClient.get('http://some/url', param1: 'value1', param2: 'value2').body

# And now, the body of response is JSON, and we want it parsed. How to express it?

# Option 1: wrap:
JSON.parse(SomeWebClient.get('http://some/url', param1: 'value1', param2: 'value2').body)
# Downside: messy parenthesis, and need to jump back and forth to understand the meaning

# Option 2: intermediate variable:
s = SomeWebClient.get('http://some/url', param1: 'value1', param2: 'value2').body
JSON.parse(s)
# Downside: intermediate variable is not elegant

# Option 3: monkey-patch (or refine)
SomeWebClient.get('http://some/url', param1: 'value1', param2: 'value2').body.from_json
# Downside: monkey-patching is a last resort; also, your classes should be already patched when you stuck with this case

# Option 4 (proposed): trap
SomeWebClient.get('http://some/url', param1: 'value1', param2: 'value2').body.
  trap{|s| JSON.parse(s)} # => parsed JSON
~~~

And when you are thinking with code, experimenting with code (especially in irb, but in editor too), only last option is "natural" river of thoughts: do this, then do that (extract data from web, then parse it).

**Naming**

* it is similar enough to `tap`;
* it is specific enough to not be used widely in some popular library (or isn't it?);
* mnemonic is "do something and trap (catch) the value".

WDYT?



-- 
https://bugs.ruby-lang.org/