Code Blocks

Ref. WGR Section 6.3, "Iterators and code blocks"

What is a block?

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

method vs. block vs. proc

(Of these three, only a proc can be stored in a variable or named parameter.)

How do you declare a block?

3.times do
  puts "Hip! Hip! Hooray!"
end
3.times { puts "Hip! Hip! Hooray!" }

What are blocks for?

A 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...

The "Hole In The Middle" Pattern

http://blog.enfranchisedmind.com/posts/the-hole-in-the-middle-pattern/

proc

say_hi = proc { puts "hi" }
say_hi.call  # prints "hi\n"

procs can take parameters too

capitalize_it = proc { |word| word.capitalize }
capitalize_it.call("banana")   #=> "Banana"
capitalize_it.call("cherry")   #=> "Cherry"

Passing Blocks to Methods Explicitly with Procs

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

The Default Block

yield

Passing Blocks to Methods Implicitly with the Default Block

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 poetry

Which 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" }

The default block can accept parameters

def twice
  yield 0
  yield 1
end

twice do |i|
  puts "#{i+1} Mississippi"
end

prints

1 Mississippi
2 Mississippi

Passing Blocks Implicitly

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

Blocks can also return values

map_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?

Making the default block visible

& 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

You can also use & in the caller

turns a proc into a default block

capitalize_word = proc {|w|w.capitalize}
s.split.map(&capitalize_word).join

lambdas

Ruby also has a keyword lambda that works just like proc, except for a few technical details.

proc is easier to use but lambda is more nerdy

Next Lesson 

Outline

[menu]

/