Best Explanation of Ruby Blocks

What exactly do the blocks represent?

In other languages the syntax may look something like this:

ark = ["Cat", "dog", "pig", "goat"];
ark.each(function (animal) { puts animal; });

Does that clear it up? It's the syntax for an anonymous function. If you're not familiar with that concept, how about this?

function putAnimal(animal) {
puts animal;
}

ark = ["Cat", "dog", "pig", "goat"];
ark.each(putAnimal);

|animal| is the argument list for the anonymous function. Very roughly speaking, Ruby's syntax for the common function (arg) { ... } is do |arg| ... end.

Understanding some Ruby code

It's a block. In Ruby exists blocks, procs and lambdas. Check this link to understand it better.

http://www.reactive.io/tips/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/

Ruby documentation for a complete beginner

We can find documentation of Ruby's Array class here: http://www.ruby-doc.org/core-2.1.5/Array.html including it's each instance method: http://www.ruby-doc.org/core-2.1.5/Array.html#method-i-each

There we see:

each { |item| block } → ary

Calls the given block once for each element in self, passing that element as a parameter.

Which is a good hint that we want to learn more about "blocks" (the chunk of code wrapped in those {}s) so we could look at a related question like Best explanation of Ruby blocks? or look for related documentation like http://docs.ruby-doc.com/docs/ProgrammingRuby/html/tut_containers.html

do..end vs curly braces for blocks in Ruby

The general convention is to use do..end for multi-line blocks and curly braces for single line blocks, but there is also a difference between the two that can be illustrated with this example:

puts [1,2,3].map{ |k| k+1 }
2
3
4
=> nil
puts [1,2,3].map do |k| k+1; end
#<Enumerator:0x0000010a06d140>
=> nil

This means that {} has a higher precedence than do..end, so keep that in mind when deciding what you want to use.

One more example to keep in mind while you develop your preferences.

The following code:

task :rake => pre_rake_task do
something
end

really means:

task(:rake => pre_rake_task){ something }

And this code:

task :rake => pre_rake_task {
something
}

really means:

task :rake => (pre_rake_task { something })

So to get the actual definition that you want, with curly braces, you must do:

task(:rake => pre_rake_task) {
something
}

Maybe using braces for parameters is something you want to do anyways, but if you don't it's probably best to use do..end in these cases to avoid this confusion.

Ruby yield example explanation?

Let's build this up step-by-step. We will simplify things a bit by taking it out of the class context.

For this example it is intuitive to think of an iterator as being a more-powerful replacement for a traditional for-loop.

So first here's a for-loop version:

seq1 = (0..2)
seq2 = (0..2)
for x in seq1
for y in seq2
p [x,y] # shorthand for puts [x, y].inspect
end
end

Now let's replace that with more Ruby-idiomatic iterator style, explicitly supplying blocks to be executed (i.e., the do...end blocks):

seq1.each do |x|
seq2.each do |y|
p [x,y]
end
end

So far, so good, you've printed out your cartesian product. Now your assignment asks you to use yield as well. The point of yield is to "yield execution", i.e., pass control to another block of code temporarily (optionally passing one or more arguments).

So, although it's not really necessary for this toy example, instead of directly printing the value like above, you can yield the value, and let the caller supply a block that accepts that value and prints it instead.

That could look like this:

 def prod(seq1, seq2)
seq1.each do |x|
seq2.each do |y|
yield [x,y]
end
end
end

Callable like this:

prod (1..2), (1..2) do |prod| p prod end

The yield supplies the product for each run of the inner loop, and the yielded value is printed by the block supplied by the caller.



Related Topics



Leave a reply



Submit