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.
Related
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
I am passing a block to a method for delayed execution something like
a = Proc.new do
puts "call me later"
end
Let's say I'm using this for caching expensive calls. Now lets say I wan't part of my code to run now, and part of my code to run later something like this
a = Proc.new do |c|
puts "call me later"
c.some_method do
puts "call me now"
end
end
Is it possible to get the output of "call me now" once you have the object a without calling the code to output "call me later"?
I'm not sure exactly what you're trying to accomplish, but what you have is a Proc that expects an object to be passed as a parameter, and that object has a method that accepts a block.
module ModB
def self.some_method
puts 'some_method before yield'
yield
puts 'some_method after yield'
end
end
proc_a = Proc.new do |b|
puts 'proc_a called'
b.some_method do
puts 'block called'
end
end
proc_a.(ModB)
# proc_a called
# some_method before yield
# block called
# some_method after yield
So, proc_a either needs a flag of some sort
proc_a = Proc.new do |run_me, b|
puts 'proc_a called' if run_me
b.some_method do
puts 'block called'
end
end
Or, you should be storing the block for some_method separately.
proc_a = Proc.new do
puts 'proc_a called'
end
proc_b = Proc.new do
puts 'block called'
end
proc_a.()
# proc_a called
ModB.some_method(&proc_b)
# some_method before yield
# block called
# some_method after yield
When I write methods that take an optional block, I typically use something like
block.call if block_given?
However, in method defined dynamically like the one below, block_given? doesn't seem to work.
class Foo
%w[bar baz].each do |method_name|
define_singleton_method(method_name) do |&block|
puts "Was #{method_name} given a block? #{block_given?}"
puts block.call
end
end
end
Foo.bar { puts 'I am a block' }
The block is called as expected, but block_given? returns false.
Why is this?
Blocks are closures, so they remember local variables (eg method_name). They also remember blocks: yield and block_given? are looking for the block that was active at the time that define_method was called, not the block passed to bar. There wasn't one, so block given returns false.
A better illustration of this is
def create_method
define_singleton_method('foo') do |&block|
puts "Was given a block? #{block_given?}"
puts yield
puts block.call
end
end
create_method {'block passed to create_method'}
foo {'block passed to the created method'}
which outputs
Was given a block? true
block passed to create_method
block passed to the created method
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
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