{"id":4102,"date":"2014-07-01T09:00:24","date_gmt":"2014-07-01T12:00:24","guid":{"rendered":"http:\/\/blog.plataformatec.com.br\/?p=4102"},"modified":"2014-07-01T11:31:03","modified_gmt":"2014-07-01T14:31:03","slug":"ruby-blocks-precedence","status":"publish","type":"post","link":"http:\/\/blog.plataformatec.com.br\/2014\/07\/ruby-blocks-precedence\/","title":{"rendered":"Ruby blocks precedence"},"content":{"rendered":"
When we start programming with Ruby, one of the first niceties we learn about are the Ruby blocks. In the beginning it’s easy to get tricked by the two existing forms of blocks and when to use each:<\/p>\n
\n%w(a b c).each { |char| puts char }\n%w(a b c).each do |char| puts char end\n<\/pre>\nThe Ruby Community has sort of created a “guideline” for when to use one versus another: for short or inline blocks, use curly brackets {..}<\/code>, for longer or multiline blocks, use the do..end<\/code> format. But did you know there is actually a slight difference between them? So sit tight, we’ll cover it now.<\/p>\nOperators Precedence<\/h2>\n
Languages contain operators, and these operators must obey a precedence rule so that the interpreter knows the order of execution, which means one operator will be executed first if it has higher precedence than others in a piece of code. Consider the following example:<\/p>\n
\na || b && c\n<\/pre>\nWhat operation gets executed first, a || b<\/code>, or b && c<\/code>? This is where operator precedence takes action. In this case, the code is the same as this:<\/p>\n\na || (b && c)\n<\/pre>\nWhich means &&<\/code> has higher precedence than ||<\/code> in Ruby. However, if you want the condition a || b<\/code> to be evaluated first, you can enforce it with the use of ()<\/code>:<\/p>\n\n(a || b) && c\n<\/pre>\nThis way you are explicitly telling the interpreter that the condition inside the ()<\/code> should be executed first.<\/p>\nWhat about blocks?<\/h2>\n
It turns out blocks have precedence too! Lets see an example that mimics the Rails router with the redirect<\/code><\/a> method:<\/p>\n\ndef get(path, options = {}, &block)\n puts \"get received block? #{block_given?}\"\nend\n\ndef redirect(&block)\n puts \"redirect received block? #{block_given?}\"\nend\n\nputs '=> brackets { }'\nget 'eggs', to: redirect { 'eggs and bacon' }\n\nputs\n\nputs '=> do..end'\nget 'eggs', to: redirect do 'eggs and bacon' end\n<\/pre>\nThis example shows a rather common code in Rails apps: a get<\/code> route that redirects to some other route in the app (some arguments from the real redirect<\/code> block were omitted for clarity). And all these methods do is outputting whether they received a block or not.<\/p>\nAt a glance these two calls to get + redirect<\/code> could be considered exact the same, however they behave differently because of the blocks precedence. Can you guess what’s the output? Take a look:<\/p>\n\n=> brackets {..}\nredirect received block? true\nget received block? false\n\n=> do..end\nredirect received block? false\nget received block? true\n<\/pre>\nThe curly brackets have higher precedence than the do..end<\/code>, which means the block with {..}<\/code> will attach to the inner method, in this example redirect<\/code>, whereas the do..end<\/code> will attach to the outer method, get<\/code>.<\/p>\nWrapping up<\/h2>\n
This blog post originated from a real Rails issue<\/a>, where you can read a little bit more about the subject and see that even Rails got it wrong in its documentation (which is now fixed). The precedence is a subtle but important difference between {..}<\/code> and do..end<\/code> blocks, so be careful not to be caught off guard by it.<\/p>\nDo you know any other interesting fact about Ruby blocks that people may not be aware of? Or maybe you learned something tricky about Ruby recently? Please share it on the comments section, we would love to hear.<\/em><\/p>\n\n
<\/a><\/span><\/span>
\n<\/p>\n","protected":false},"excerpt":{"rendered":"When we start programming with Ruby, one of the first niceties we learn about are the Ruby blocks. In the beginning it’s easy to get tricked by the two existing forms of blocks and when to use each: %w(a b c).each { |char| puts char } %w(a b c).each do |char| puts char end The … \u00bb<\/a><\/p>\n","protected":false},"author":7,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[1],"tags":[185,60],"aioseo_notices":[],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/4102"}],"collection":[{"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/comments?post=4102"}],"version-history":[{"count":8,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/4102\/revisions"}],"predecessor-version":[{"id":4106,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/4102\/revisions\/4106"}],"wp:attachment":[{"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/media?parent=4102"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/categories?post=4102"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/tags?post=4102"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}