Home arrow Ruby-on-Rails arrow Code Blocks and Iteration
RUBY-ON-RAILS

Code Blocks and Iteration


Code blocks can be very confusing to newcomers to Ruby, despite the fact that many computer languages have something that functions in a similar manner. This article, the first of three parts, introduces you to code blocks. It is excerpted from chapter eight of the Ruby Cookbook, written by Lucas Carlson and Leonard Richardson (O'Reilly, 2006; ISBN: 0596523696). Copyright © 2006 O'Reilly Media, Inc. All rights reserved. Used with permission from the publisher. Available from booksellers or direct from O'Reilly Media.

Author Info:
By: O'Reilly Media
Rating: 5 stars5 stars5 stars5 stars5 stars / 13
March 01, 2007
TABLE OF CONTENTS:
  1. · Code Blocks and Iteration
  2. · 7.1 Creating and Invoking a Block
  3. · 7.2 Writing a Method That Accepts a Block
  4. · 7.3 Binding a Block Argument to a Variable

print this article
SEARCH DEVARTICLES

Code Blocks and Iteration
(Page 1 of 4 )

In Ruby, a code block (or just “block”) is an object that contains some Ruby code, and the context neccesary to execute it. Code blocks are the most visually distinctive aspect of Ruby, and also one of the most confusing to newcomers from other languages. Essentially, a Ruby code block is a method that has no name.

Most other languages have something like a Ruby code block: C’s function pointers, C++’s function objects, Python’s lambdas and list comprehensions, Perl’s anonymous functions, Java’s anonymous inner classes. These features live mostly in the corners of those languages, shunned by novice programmers. Ruby can’t be written without code blocks. Of the major languages, only Lisp is more block-oriented.

Unlike most other languages, Ruby makes code blocks easy to create and imposes few restrictions on them. In every other chapter of this book, you’ll see blocks passed into methods like it’s no big deal (which it isn’t):

  [1,2,3].each { |i| puts i}
  # 1
  # 2
  # 3

In this chapter, we’ll show you how to write that kind of method, the kinds of method that are useful to write that way, and when and how to treat blocks as first-class objects.

Ruby provides two syntaxes for creating code blocks. When the entire block will fit on one line, it’s most readable when enclosed in curly braces:

  [1,2,3].each { |i| puts i }
  # 1
  # 2
  # 3

When the block is longer than one line, it’s more readable to begin it with thedokeyword and end it with theendkeyword:

  [1,2,3].each do |i|
    if i % 2 == 0
      puts "#{i} is even."
    else
      puts "#{i} is odd."
   
end
  end
  # 1 is odd.
  # 2 is even.
  # 3 is odd.

Some people use the bracket syntax when they’re interested in the return value of the block, and thedo...endsyntax when they’re interested in the block’s side effects.

Keep in mind that the bracket syntax has a higher precedence than thedo..endsyntax. Consider the following two snippets of code:

  1.upto 3 do |x|
   
putsx
  end
  # 1
  # 2
  # 3

  1.upto 3 { |x| puts x }
  # SyntaxError: compile error

In the second example, the code block binds to the number 3, not to the function call1.upto 3. A standalone variable can’t take a code block, so you get a compile error. When in doubt, use parentheses.

  1.upto(3) { |x| puts x }
  # 1
  # 2
  # 3

Usually the code blocks passed into methods are anonymous objects, created on the spot. But you can instantiate a code block as aProcobject by callinglambda. See Recipe 7.1 for more details.

  hello = lambda { "Hello"}
  hello.call
  # => "Hello"

  log = lambda { |str| puts "[LOG] #{str}" }
  log.call("A test log message.")
  # [LOG] A test log message.

Like any method, a block can accept arguments. A block’s arguments are defined in a comma-separated list at the beginning of the block, enclosed in pipe characters:

  {1=>2, 2=>4}.each { |k,v| puts "Key #{k}, value #{v}" }
  # Key 1, value 2
  # Key 2, value 4

Arguments to blocks look almost like arguments to methods, but there are a few restrictions: you can’t set default values for block arguments, you can’t expand hashes or arrays inline, and a block cannot itself take a block argument.*

SinceProcobjects are created like other objects, you can create factory methods whose return values are customized pieces of executable Ruby code. Here’s a simple factory method for code blocks that do multiplication:

  def times_n(n)
   
lambda { |x| x * n }
  end

The following code uses the factory to create and use two customized methods:

  times_ten = times_n(10)
 
times_ten.call(5)           # => 50
  times_ten.call(1.25)        # => 12.5

  circumference = times_n(2*Math::PI)
  circumference.call(10)  #
=> 62.8318530717959
  circumference.call(3)       #
=> 18.8495559215388
  [1, 2, 3].collect(&circumference)
 
# => [6.28318530717959, 12.5663706143592, 18.8495559215388]

You may have heard people talking about Ruby’s “closures.” What is a closure, and how is it different from a block? In Ruby, there is no difference between closures and blocks. Every Ruby block is also a closure.†

So what makes a Ruby block a closure? Basically, a Ruby block carries around the context in which it was defined. A block can reference the variables that were in scope when it was defined, even if those variables later go out of scope. Here’s a simple example; see Recipe 7.4 for more.

  ceiling = 50
  # Which of these numbers are less than the target?
  [1, 10, 49, 50.1, 200].select { |x| x < ceiling }
  # => [1, 10, 49]

The variableceilingis within scope when the block is defined, but it goes out of scope when the flow of execution enters theselectmethod. Nonetheless, the block can accessceilingfrom withinselect, because it carries its context around with it. That’s what makes it a closure.

We suspect that a lot of people who say “closures” when talking about Ruby blocks just do it to sound smart. Since we’ve already ruined any chance we might have had at sounding smart, we’ve decided refer to Ruby closures as just plain “blocks” throughout this book. The only exceptions are in the rare places where we must discuss the context that makes Ruby’s code blocks real closures, rather than “dumb” blocks.


blog comments powered by Disqus
RUBY-ON-RAILS ARTICLES

- Ruby-on-Rails Faces Second Security Flaw in ...
- Ruby 2.0 Prepped for February 2013 Release
- Why LinkedIn Switched from Ruby on Rails
- Adding Style with Action Pack
- Handling HTML in Templates with Action Pack
- Filters, Controllers and Helpers in Action P...
- Action Pack and Controller Filters
- Action Pack Categories and Events
- Logging Out, Events and Templates with Actio...
- Action Pack Sessions and Architecture
- More on Action Pack Partial Templates
- Action Pack Partial Templates
- Displaying Error Messages with the Action Pa...
- Action Pack Request Parameters
- Creating an Action Pack Registration Form

Watch our Tech Videos 
Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 
Support 

Developer Shed Affiliates

 




© 2003-2017 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap
Popular Web Development Topics
All Web Development Tutorials