How to pass a block to another in Ruby? - ruby

Assuming I have the following proc:
a = Proc.new do
puts "start"
yield
puts "end"
end
Also assuming I pass a to another method which subsequently calls instance_eval on another class with that block, how can I now pass a block onto the end of that method which gets yielded in a.
For example:
def do_something(a,&b)
AnotherClass.instance_eval(&a) # how can I pass b to a here?
end
a = Proc.new do
puts "start"
yield
puts "end"
end
do_something(a) do
puts "this block is b!"
end
Output should of course should be:
start
this block is b!
end
How can I pass the secondary block to a in the instance_eval?
I need something like this for the basis of a Ruby templating system I'm working on.

You can't use yield in a. Rather, you have to pass a Proc object. This would be the new code:
def do_something(a,&b)
AnotherClass.instance_exec(b, &a)
end
a = Proc.new do |b|
puts "start"
b.call
puts "end"
end
do_something(a) do
puts "this block is b!"
end
yield is only for methods. In this new code, I used instance_exec (new in Ruby 1.9) which allows you to pass parameters to the block. Because of that, we can pass the Proc object b as a parameter to a, which can call it with Proc#call().

a=Proc.new do |b|
puts "start"
b.call
puts "end"
end
def do_something(a,&b)
AnotherClass.instance_eval { a.call(b) }
end

Related

Yielding a block to a proc (or creating a method that accepts a block from a proc that yields)

I'm currently working on an interface that allows me to wrap arbitrary method calls with a chain of procs. Without going into too much detail, I currently have an interface that accepts something like this:
class Spy
def initialize
#procs = []
end
def wrap(&block)
#procs << block
end
def execute
original_proc = Proc.new { call_original }
#procs.reduce(original_proc) do |memo, p|
Proc.new { p.call &memo }
end.call
end
def call_original
puts 'in the middle'
end
end
spy = Spy.new
spy.wrap do |&block|
puts 'hello'
block.call
end
spy.wrap do |&block|
block.call
puts 'goodbye'
end
spy.execute
What I'd like to do though is remove the |&block| and block.call from my API and use yield instead.
spy.wrap do
puts 'hello'
yield
end
This didn't work and raised a LocalJumpError: no block given (yield) error.
I've also tried creating methods by passing the proc the define_singleton_method in the reduce, but I haven't had any luck.
def execute
original_proc = Proc.new { call_original }
#procs.reduce(original_proc) do |memo, p|
define_singleton_method :hello, &p
Proc.new { singleton_method(:hello).call(&memo) }
end.call
end
Is there another approach I can use? Is there anyway to yield from a Proc or use the Proc to initialize something that can be yielded to?
Using yield in your wrap block does not make much sense unless you passed a block to the caller itself:
def foo
spy.wrap do
puts "executed in wrap from foo"
yield
end
end
If you call foo without a block it will raise the exception since yield can't find a block to execute. But if you pass a block to foo method then it will be invoked:
foo do
puts "foo block"
end
Will output
executed in wrap from foo
foo block
In conclusion I think you misunderstood how yield works and I don't think it is what you want to achieve here.

Performing the same code block (yield)

How can I make sure that the method is executed once. If method A is inserted inside the method Ai as a block to the secondary methods are is not performed. Something like this:
def a
puts "|start|"
yield
puts "|end|"
end
a do
a { "|test_one|" }
a { "|test_two|" }
end
=> "|start||test_one||test_two||end|"
Not like this:
=> "|start|test_one|start|end|test_two|end|"
In your current example you are calling your function a recursively twice.
If you change your code as follow it will execute the block only once and get the output that you describe:
def a
puts "|start|"
yield
puts "|end|"
end
a do
puts "|test_one|"
puts "|test_two|"
end
In your example the method a will run three times, because you execute it once in a main part and two time in a block. To have a desired output, you don't have to run this method in a block. Just execute the block which contains two instructions:
irb(main):066:0> a do
irb(main):067:1* puts "|test_one|"
irb(main):068:1> puts "|test_two|"
irb(main):069:1> end
|start|
|test_one|
|test_two|
|end|
You're calling method a but not printing the block that is been yielded.
yield replaces the whole block that has been passed as an argument, inside the method where it is written.
so your method actually becomes like this when ruby interprets the code.
puts "|start|"
puts "|start|" #
"|test_one|" # replaced for yield on call `a {"|test_one|"}`
puts "|end|" #
puts "|start|" #
"|test_two|" # replaced for yield on call `a {"|test_two|"}`
puts "|end|" #
puts "|end|"
Output:
|start||start||end||start||end||end|
If you want to see if what the block is returning then add a puts before yield
def a
puts "|start|"
puts yield
puts "|end|"
end
Then call your method the same way and now the output will be.
|start||start||test_one||end||start||test_two||end||end|
Correct me if I'm missing anything.

Get name of Block while in Block (self) Ruby

I am wondering how to get the name of a block/proc while in the block that will then be passed to a method. I need the name of a block like so:
method("hello") do
puts "My name is #{self}"
end
Which would print out something like when the method runs the block:
"My name is #<Proc:0xa3de668#/path/to/file.rb:8>"
You can get a reference to the implicitly passed block inside the method yield-ing it, by calling Proc.new (inside the method) without supplying a block. For instance:
def speak
puts yield
block = Proc.new # Creates a proc object from the implictly passed block.
puts block.call
end
speak { "Hello, from implicit block!" }
Can't do this for blocks, but for procs...
def hello
puts yield
end
my_proc = Proc.new {"I am #{my_proc}"}
method("hello").call(&my_proc)
#I am <#Proc:0x0...#...>

what's main use of yield method in ruby? [duplicate]

def any?
if block_given?
method_missing(:any?) { |*block_args| yield(*block_args) }
else
!empty?
end
end
In this code from ActiveRecord, what is the purpose of a yield statement that exists within a block?
Basically if the current method has been given a code-block (by the caller, when it was invoked), the yield executes the code block passing in the specified parameters.
[1,2,3,4,5].each { |x| puts x }
Now { |x| puts x} is the code-block (x is a parameter) passed to the each method of Array. The Array#each implementation would iterate over itself and call your block multiple times with x = each_element
pseudocode
def each
#iterate over yourself
yield( current_element )
end
Hence it results
1
2
3
4
5
The *block_args is a Ruby way to accept an unknown number of parameters as an array. The caller can pass in blocks with different number of arguments.
Finally let's see what yield within a block does.
class MyClass
def print_table(array, &block)
array.each{|x| yield x}
end
end
MyClass.new.print_table( [1,2,3,4,5] ) { |array_element|
10.times{|i| puts "#{i} x #{array_element} = #{i*array_element}" }
puts "-----END OF TABLE----"
}
Here Array#each yields each element to the block given to MyClass#print_table...
It does not mean anything special. It's just a yield like any other yield.
def test_method
["a", "b", "c"].map {|i| yield(i) }
end
p test_method {|i| i.upcase }
# => ["A", "B", "C"]
In the code snippet from active record, the purpose is to yield every time the block of any? is called.
This helped me understand: yield is a way to insert blocks into a method you already wrote, which means "execute something here". For instance,
Without parameter
def original_method
puts "a"
puts "b"
end
What if you want to execute some unknown block between those two p?
def updated_method
puts "a"
yield
puts "b"
end
# these two are the same:
updated_method { puts "execute something here" }
updated_method do puts "execute something here" end
The result would be
a
execute something here
b
You can have as many yields in a method as you like.
With parameter
def updated_method
puts "a"
yield
puts "b"
end
What if you want to execute some unknown block on the string "Execute something on me!"?
def updated_method_with_argument
puts "a"
yield("Execute something on me!")
puts "b"
end
updated_method_with_argument do |argument|
puts "This argument gets put out: " << argument
end
The result would be
a
This argument gets put out: Execute something on me!
b

What does it mean to yield within a block?

def any?
if block_given?
method_missing(:any?) { |*block_args| yield(*block_args) }
else
!empty?
end
end
In this code from ActiveRecord, what is the purpose of a yield statement that exists within a block?
Basically if the current method has been given a code-block (by the caller, when it was invoked), the yield executes the code block passing in the specified parameters.
[1,2,3,4,5].each { |x| puts x }
Now { |x| puts x} is the code-block (x is a parameter) passed to the each method of Array. The Array#each implementation would iterate over itself and call your block multiple times with x = each_element
pseudocode
def each
#iterate over yourself
yield( current_element )
end
Hence it results
1
2
3
4
5
The *block_args is a Ruby way to accept an unknown number of parameters as an array. The caller can pass in blocks with different number of arguments.
Finally let's see what yield within a block does.
class MyClass
def print_table(array, &block)
array.each{|x| yield x}
end
end
MyClass.new.print_table( [1,2,3,4,5] ) { |array_element|
10.times{|i| puts "#{i} x #{array_element} = #{i*array_element}" }
puts "-----END OF TABLE----"
}
Here Array#each yields each element to the block given to MyClass#print_table...
It does not mean anything special. It's just a yield like any other yield.
def test_method
["a", "b", "c"].map {|i| yield(i) }
end
p test_method {|i| i.upcase }
# => ["A", "B", "C"]
In the code snippet from active record, the purpose is to yield every time the block of any? is called.
This helped me understand: yield is a way to insert blocks into a method you already wrote, which means "execute something here". For instance,
Without parameter
def original_method
puts "a"
puts "b"
end
What if you want to execute some unknown block between those two p?
def updated_method
puts "a"
yield
puts "b"
end
# these two are the same:
updated_method { puts "execute something here" }
updated_method do puts "execute something here" end
The result would be
a
execute something here
b
You can have as many yields in a method as you like.
With parameter
def updated_method
puts "a"
yield
puts "b"
end
What if you want to execute some unknown block on the string "Execute something on me!"?
def updated_method_with_argument
puts "a"
yield("Execute something on me!")
puts "b"
end
updated_method_with_argument do |argument|
puts "This argument gets put out: " << argument
end
The result would be
a
This argument gets put out: Execute something on me!
b

Resources