Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby: forward receiver, arguments and block across procs

Tags:

ruby

proc

Given code like this:

p = proc do |*args, &block|
  p self
  p args
  p block[] if block
end

q = proc do |*args, &block|
  p 'before'
  instance_exec(*args, &p)
end

o = Object.new
o.define_singleton_method(:my_meth, q)
o.my_meth(1, 2) { 3 }

How can I completely forward the call from p to q while keeping q's receiver? Basically I want 3 printed as well, but instance_exec, like all ruby methods, can take only one block. Is it possible without changing p, so that I can use p and q interchangeably (the idea is to make q sometimes wrap p).

like image 411
Artefacto Avatar asked Nov 09 '18 18:11

Artefacto


People also ask

What is the difference between procs and blocks?

When using parameters prefixed with ampersands, passing a block to a method results in a proc in the method's context. Procs behave like blocks, but they can be stored in a variable. Lambdas are procs that behave like methods, meaning they enforce arity and return as methods instead of in their parent scope.

What is the difference between block proc and lambda?

A Proc object is an encapsulation of a block of code, which can be stored in a local variable, passed to a method or another Proc, and can be called. Lambdas are anonymous functions, objects of the class Proc, they are useful in most of the situations where you would use a proc.

What is a block what are the two ways to write one Ruby?

A ruby block is one or more lines of code that you put inside the do and end keywords (or { and } for inline blocks).

What are Ruby blocks explain with example?

Ruby blocks are anonymous functions that can be passed into methods. Blocks are enclosed in a do-end statement or curly braces {}. do-end is usually used for blocks that span through multiple lines while {} is used for single line blocks. Blocks can have arguments which should be defined between two pipe | characters.


1 Answers

It is possible defining another singleton method:

p = proc do |*args, &block|
  p self
  p args
  p block[] if block
end

q = proc do |*args, &block|
  p 'before'
  define_singleton_method(:pp, p)
  pp(*args, &block)
end

o = Object.new
o.define_singleton_method(:my_meth, q)
o.my_meth(1, 2) { 3 }

Output:

"before"
#<Object:0x007f5903c2de28>
[1, 2]
3
=> 3
like image 92
André Guimarães Sakata Avatar answered Oct 20 '22 13:10

André Guimarães Sakata