What's this &block in Ruby? And how does it get passed in a method here?
ruby, ruby-on-rails
Solution
Blocks are a fairly basic part of ruby. They're delimited by either `do |arg0,arg1| ... end` or `{ |arg0,arg1,arg2| ... }`.
They allow you to specify a callback to pass to a method. This callback can be invoked two ways - either by capturing it by specifying a final argument prefixed with `&`, or by using the `yield` keyword:
irb> def meth_captures(arg, &block)
block.call( arg, 0 ) + block.call( arg.reverse , 1 )
end
#=> nil
irb> meth_captures('pony') do |word, num|
puts "in callback! word = #{word.inspect}, num = #{num.inspect}"
word + num.to_s
end
in callback! word = "pony" num = 0
in callback! word = "ynop" num = 1
#=> "pony0ynop1"
irb> def meth_yields(arg)
yield(arg, 0) + yield(arg.upcase, 1)
end
#=> nil
irb> meth_yields('frog') do |word, num|
puts "in callback! word = #{word.inspect}, num = #{num.inspect}"
word + num.to_s
end
in callback! word = "frog", num = 0
in callback! word = "FROG", num = 1
#=> "frog0FROG1"
Note that our callback was the same in each case - we can remove repetition by saving our callback in an object, and then passing it to each method. This can be done using `lambda` to capture the callback in an object, and then passed to a method by prefixing it with `&`.
irb> callback = lambda do |word, num|
puts "in callback! word = #{word.inspect}, num = #{num.inspect}"
word + num.to_s
end
#=> #<Proc:0x0052e3d8@(irb):22>
irb> meth_captures('unicorn', &callback)
in callback! word = "unicorn", num = 0
in callback! word = "nrocinu", num = 1
#=> "unicorn0nrocinu1"
irb> meth_yields('plate', &callback)
in callback! word = "plate", num = 0
in callback! word = "PLATE", num = 1
#=> "plate0PLATE1"
It's important to understand the different uses of `&` here as a prefix to the last argument of a function
- in a function definition, it captures any passed block into that object
- in a function call, it expands the given callback object into a block
If you look around blocks are used all over the place, especially in iterators, like `Array#each`.
Problem
Saw this piece of code in a Ruby on Rails book. This first one is from a view and the second one is a helper module. I don't understand how that `&block` and the `attributes={}` thing work. Can anyone guide me to a tutorial of some kind explaining this? ``` <% hidden_div_if(@cart.items.empty?, :id => "cart") do %> <%= render(:partial => "cart", :object => @cart) %> <% end %> module StoreHelper def hidden_div_if(condition, attributes = {}, &block) if condition attributes["style"] = "display: none" end content_tag("div", attributes, &block) end end ```