Ruby blocks + Yield

Today I was doing some Ruby and reading blocks. Along came Yield… WTF???? Did some research then…

Ruby Code blocks are definitely one of the coolest features of Ruby and are chunks of code between braces or between do- end that you can associate with method invocations, almost as if they were parameters.

In ruby, methods may receive code block.

A Ruby block is a way of grouping statements, and may appear only in the source adjacent to a method call; the block is written starting on the same line as the method call’s last parameter (or the closing parenthesis of the parameter list).

The code in the block is not executed at the time it is encountered. Instead, Ruby remembers the context in which the block appears (the local variables, the current object, and so on) and then enters the method.

The Ruby standard is to use braces for single-line blocks and do- end for multi-line blocks. When a method expects a block, it invokes it by calling the yield function.
Let’s look at an example of the yield statement:

def test
   puts "You are in the method"
   yield
   puts "You are again back to the method"
   yield
end
test {puts "You are in the block"}

This will produce following result:

You are in the method
You are in the block
You are again back to the method
You are in the block

You also can pass parameters with the yield statement. Here is an example:

def test
   yield 5
   puts "You are in the method test"
   yield 100
end
test {|i| puts "You are in the block #{i}"}

This will produce following result:

You are in the block 5
You are in the method test
You are in the block 100

Here the yield statement is written followed by parameters. You can even pass more than one parameter. In the block, you place a variable between two vertical lines (||) to accept the parameters. Therefore, in the preceding code, the yield 5 statement passes the value 5 as a parameter to the test block.

If you want to pass more than one parameters, then the yield statement becomes:

yield a, b

and the block is:

test {|a, b| statement}

for example

def call_block
	yield('hello', 99)
     end
call_block {|str, num| puts str + ' ' + num.to_s}

The output is:

       hello 99

A nice example from stackoverflow is the following: Define a Person class initialized with a name, and provide a do_with_name method that when invoked, would just pass the name attribute, to the block received.

class Person 
    def initialize( name ) 
         @name = name
    end
    def do_with_name 
        yield( @name ) 
    end
end

This would allow to call that method an pass an arbitrarily code block

For instance to print the name we would do:

person = Person.new("Oscar")

#invoking the method passing a block
person.do_with_name {|string|
    puts "Hey, his name is #{string}"
}

Would print:

Hey, his name is Oscar

Notice, the block receives as parameter a string variable. When the code invokes yield it fills this parameter with the value of @name

yield( @name )

We could provide another block to perform a different action, for instance, reverse the name:

#variable to hold the name reversed
the_name = ""
#invoke the method passing a different block
person.do_with_name { |variable| 
    the_name = variable.reverse
}
puts the_name

Prints racsO

This is exactly the same method, it is just a different block. Notice also the variable name in the block may be different. This sample is trivial, more interesting usages are for instance to filter all the elements in an array:

 days = ["monday", "tuesday", "wednesday", "thursday", "friday"]  
=> ["monday", "tuesday", "wednesday", "thursday", "friday"]
 # select those which start with 't' 
 days.select { | item |
     item.match /^t/
 }
=> ["tuesday", "thursday"]

Or, we can also provide a custom sort algorithm, for instance based on the string size:

 days.sort { |x,y|
    x.size <=> y.size
 }
=> ["monday", "friday", "tuesday", "thursday", "wednesday"]

I hope this help you to understand it better.

BTW, if the block is optional you should call it like:

yield(value) if block_given?

If is not optional, just invoke it.


George Psistakis

I love technology and working with people. That is why I am trying to offer as much as I can at the local startup ecosystem and at the same time building Apirise. A platform to reduce time and effort required to integrate and maintain APIs. Simply, fast and efficiently!
I am co-organizer of the Agile Greece and API Athens meetups and I contribute at the Developer Economics Blog.


Discuss with me…

I’d love to know your ideas and thoughts on this post.
Connect with me on Twitter or Google+

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s