Ref. WGR Section 6.3, "Iterators and code blocks"
a block is a chunk of code
the term "block" overlaps with the terms...
closure, proc, lambda, function, function pointer, anonymous function, callback, runnable, functor, delegate
def
do
(Of these three, only a proc can be stored in a variable or named parameter.)
3.times do
puts "Hip! Hip! Hooray!"
end
3.times { puts "Hip! Hip! Hooray!" }
do...end
for multiple linesA block is a piece of code that is declared but not run in the place it's written. The idea is to leave it up to the receiver of the block to decide when to call it. -- Wolfram Arnold
So you use blocks for...
http://blog.enfranchisedmind.com/posts/the-hole-in-the-middle-pattern/
proc
proc
keyword defines a blockcall
methodsay_hi = proc { puts "hi" }
say_hi.call # prints "hi\n"
capitalize_it = proc { |word| word.capitalize }
capitalize_it.call("banana") #=> "Banana"
capitalize_it.call("cherry") #=> "Cherry"
twice
is a less cool version of times
that takes a proc parameter
def twice(action)
action.call
action.call
end
You can assign a proc to a variable and pass it as a parameter
say_hi = proc do
puts "hi!"
end
twice(say_hi) # prints "hi!\n" twice
You can also define proc inline rather than assigning it to a variable
twice(proc do
puts "hi!"
end) # prints "hi!\n" twice
yield
twice
is a less cool version of times
that takes a default block (invisible parameter)
def twice
yield
yield
end
twice do
puts "hi!"
end
"twice do" kind of almost resembles English a little, right?
yield
turns prose into poetryWhich is more beautiful?
Using procs:
def twice block
block.call
block.call
end
twice(proc { puts "hi" })
Using the default block:
def twice
yield
yield
end
twice { puts "hi" }
def twice
yield 0
yield 1
end
twice do |i|
puts "#{i+1} Mississippi"
end
prints
1 Mississippi
2 Mississippi
for_each
is a less cool version of Array.each
def for_each(array)
i = 0
while i < array.size
yield array[i]
i += 1
end
array
end
names = ["alice", "bob", "charlie"]
for_each(names) do |item|
puts "hi, #{item}"
end
array
is a parameter to the for_each
functionitem
is a parameter to the blockmap_it
is a less cool version of Array.map
def map_it(array)
i = 0
out = []
while i < array.size
out << yield(array[i])
i += 1
end
out
end
names = ["alice", "bob", "charlie"]
map_it(names) do |item|
item.reverse
end
#=> ["ecila", "bob", "eilrahc"]
block_given?
is true if a block was passedcommon use:
yield if block_given?
&
turns the default block into a proc
def for_each(array, &p)
i = 0
while i < array.size
p.call(array[i])
i += 1
end
array
end
a = ["alice", "bob", "charlie"]
for_each(a) do |item|
puts "hi, #{item}"
end
turns a proc into a default block
capitalize_word = proc {|w|w.capitalize}
s.split.map(&capitalize_word).join
Ruby also has a keyword lambda
that works just like proc
, except for a few technical details.
return
exits the block, not the enclosing method
proc
is easier to use but lambda
is more nerdy
/