From: zverok.offline@... Date: 2015-11-20T16:18:46+00:00 Subject: [ruby-core:71610] [Ruby trunk - Feature #11717] Object#trap -- pass object to block and return result 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", #] {"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/