Block

Блок - это произвольный код, который можно передать любому методу в качестве неявного последнего аргумента. Это конструкция do end. Блок очень похож на функцию, которая передается в функцию times(). Но передается довольно необычным способом. Ключевое слово do начинается после того, как закрыты вызывающие скобки у метода. Блок просто отделяется пробелом от вызова самой функции -

5.times() do |i|
puts i
end
# => 0
# => 1
# => 2
# => 3
# => 4

Блок работает как замыкание, а значит внутри него можно использовать любые переменные, определенные снаружи и выше блока -

name = 'ruby'
3.times do # параметры блока можно опускать
puts name
end
# => ruby
# => ruby
# => ruby

У блоков есть альтернативный синтаксис. Пример выше можно было записать так:

5.times { |i| puts i }


Существует два способа выполнить код блока, переданный методу. Ключевое слово yield в теле блока и аргумент &block.

Когда в теле метода вызывается yield, то подразумевается следующее: «отдай управление блоку, а когда тот закончит, верни управление этому методу».

def say_hello
puts "before block"
yield
puts "after block"
end

say_hello { puts "inside block" }
# => before block
# => inside block
# => after block

Но, если не передать блок в метод, то вызов последнего будет выполнен с ошибкой -

def say_hello
puts "before block"
yield
puts "after block"
end

say_hello
# => 'Object#say_hello': no block given (yield) (LocalJumpError)

Чтобы избежать этой ошибки, необходимо удостоверится, что блок был передан с помощью метода block_given?

def say_hello
puts "before block"
yield if block_given?
puts "after block"
end

say_hello
# => before block
# => after block

Второй способ выполнить код блока, использовать аргумент &block

def say_hello(&block)
puts "before block"
block.call
puts "after block"
end

say_hello { puts "inside block" }
# => before block
# => inside block
# => after block