Feature #11717
closedObject#trap -- pass object to block and return result
Description
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?
Updated by 0x0dea (D.E. Akers) over 10 years ago
Updated by zverok (Victor Shepelev) over 10 years ago
Nope.
I'm aware of #instance_eval last 10 years or so (I even can recall times when #instance_exec were external library method, not part of the core).
Primary goal/usage of #instance_eval is to "dig inside". Primary goal/usage of #trap is to "apply next transormation". Even if #trap will be implemented as a simple alias of #instance_eval, it will have some usage/popularity outside of #instance_eval's domain. On my opinion only, of course.
Updated by phluid61 (Matthew Kerwin) over 10 years ago
Updated by phluid61 (Matthew Kerwin) over 10 years ago
Victor Shepelev wrote:
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?
"trap" already means "trap a signal", it comes from long-standing Unix terminology; see Signal#trap
Updated by 0x0dea (D.E. Akers) over 10 years ago
Victor Shepelev wrote:
Even if
#trapwill be implemented as a simple alias of#instance_eval...
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.
Updated by zverok (Victor Shepelev) over 10 years ago
"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
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:
Updated by nobu (Nobuyoshi Nakada) over 10 years ago
- Is duplicate of Feature #6721: Object#yield_self added
Updated by nobu (Nobuyoshi Nakada) almost 10 years ago
- Has duplicate Feature #12760: Optional block argument for `itself` added
Updated by nobu (Nobuyoshi Nakada) over 9 years ago
- Has duplicate Feature #13172: Method that yields object to block and returns result added
Updated by nobu (Nobuyoshi Nakada) about 9 years ago
- Status changed from Open to Closed
Applied in changeset trunk|r58528.
object.c: Kernel#yield_self
- object.c (rb_obj_yield_self): new method which yields the
receiver and returns the result.
[ruby-core:46320] [Feature #6721]