There are three main uses.
The block is a closure. That is, ** free variables appearing in the code inside the block follow the block's external environment **. Free variables in a block are resolved in the context outside the block, which is the external environment.
In the example below, the local variable count is shared outside and inside the block.
str = 'Hello, World'
count = 0
str.each_line do |line|
print line
count += 1
end
print count # => 1
Local variables, self, instance variables associated with self, method calls, etc. can all be used in the block in the same way as outside.
def some_method
3.times { p self } #self is not 3 but some_method self
end
** The external environment referenced by the block is preserved as long as the block exists **. Even if the method execution is completed, the internal code block uses the local variable at the time of method execution.
In the example below, create_counter converts the code block inside the method into a Proc object and returns it to the caller. Calling the Proc # call method executes a block of code.
The local variable count in the execution context of the create_counter method can only be referenced by the Proc returned by the method. That is, the internal state can be concealed.
def create_counter
count = 1
return Proc.new do
count += 1
p count
end
end
counter = create_counter
p counter.class # => Proc
counter.call # => 2
counter.call # => 3
counter2 = create_counter
counter2.call # => 2
counter.call # => 4
counter2.call # => 3
The block passed to the method can receive arguments when it is called back from the method. Blocks can also have their own local variable = block parameter.
a = "str"
[1, 2, 3].each { |a| p a } #This a is different from the above a
p a # => "str"
There are two points to be aware of from what we have learned so far.
def foo_bar_baz
yield "foo"
yield "bar"
yield "baz"
end
#Or
def foo_bar_baz
#Enum when not given a block_Generate and return Enumerator with for
return enum_for(:foo_bar_baz) unless block_given?
%w[ foo bar baz ].each do |item|
yield item
end
end
foo_bar_baz do |item|
puts item
end
# => foo
# bar
# baz
def my_map
[yield(1), yield(2), yield(3)]
end
p my_map { |i| i + 1 }
# => [2, 3, 4]
Proc
If you want to get the calling block as an object, use a Proc object.
The & handler in the example below is called the block argument.
class SleepyPerson
def register_handler(&handler)
@event_handler = handler
end
def wake_up!
@event_handler.call Time.now, "woke up"
end
end
john = SleepyPerson.new
john.register_handler { |time, message| p [time, message] }
john.wake_up!
proc = Proc.new { puts "Proc was called" }
3.times(&proc)
# => Proc was Called
# Proc was Called
# Proc was Called
For the time being, this seems to be important
Recommended Posts