Code Block Passed to Each Works With Brackets But Not With 'Do'-'End' (Ruby)

Code block passed to each works with brackets but not with 'do'-'end' (ruby)

puts mystring.gsub(art[0]).each do
art[1][rand(art[1].length) -1]
end

Here you called puts without parens, the do ... end refers to the puts method, that does nothing with a block and prints mystring.gsub(art[0]).each (with is a Enumerator).

The { ... } is called with the nearest method. Becomes ugly, but you can do it with do ... end:

puts(mystring.gsub(art[0]).each do
art[1][rand(art[1].length) -1]
end)

Or, better, put the result in a variable and print the variable:

var = mystring.gsub(art[0]).each do
art[1][rand(art[1].length) -1]
end
puts var

Anyway, the each don't changes the object, it just iterate and returns the object itself. You may be wanting the map method, test it.

Passing block into a method - Ruby

The difference between do .. end and curly braces is that the curly braces bind to the rightmost expression, while do .. end bind to the leftmost one. Observe the following examples:

def first(x=nil)
puts " first(#{x.inspect}): #{block_given? ? "GOT BLOCK" : "no block"}"
"f"
end

def second(x=nil)
puts " second(#{x.inspect}): #{block_given? ? "GOT BLOCK" : "no block"}"
"s"
end

first second do |x| :ok end # second(nil): no block
# first("s"): GOT BLOCK

first second {|x| :ok } # second(nil): GOT BLOCK
# first("s"): no block

In the first case, the block made with do..end will be bound to the first function (leftmost). In the second case the block made with curly brackets will be bound to the second function (rightmost).

Usually it's good idea to use parentheses if you have two functions and a block - just for readability and to avoid mistakes.

It's very easy to accidentally pass a block to puts method, just as in your question.

Instance_eval does not work with do/end block, only with {}-blocks

It's because when you pass block with curly braces, it is passed to instance_eval method. But if you pass it with do-end, it's passed to puts method, so instance_eval doesn't get block and raises an error.

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.

Using do block vs braces {}

Ruby cookbook says bracket syntax has higher precedence order than do..end

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

1.upto 3 do |x|
puts x
end

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

Second example only works when parentheses is used, 1.upto(3) { |x| puts x }

Block not called in Ruby

Add parentheses to puts

puts(m do
x = 2
y = 3
x * y
end)

The output is 6.

Your code is equivalent to

puts(m) do 
x = 2
y = 3
x * y
end

Ruby multiline block without do end

There is a subtle difference between the two syntaxes. { } are higher precedence than do ... end. Thus, the following will pass bar and a block to method foo:

foo bar do ... end

while the following will pass a block to bar, and the result of that to foo:

foo bar { ... }

So your examples will act the same. However, if you left the parentheses off:

> 3.upto 9 { 
puts "Hi"
}
SyntaxError: compile error
(irb):82: syntax error, unexpected '{', expecting $end
3.upto 9 {
^
from (irb):82
from :0

> 3.upto 9 do
puts "Hi"
end
Hi
Hi
Hi
Hi
Hi
Hi
Hi
=> 3

So, { } are more likely to catch you up if you leave off parentheses in Ruby, which is fairly common; for this reason, and because Ruby conditionals and other control constructs all use end as a delimiter, people usually use do ... end for multi-line code blocks that come at the end of a statement.

However, { } is frequently use in places where do ... end would be cumbersome, for instance, if you are chaining several methods together which take blocks. This can allow you to write short, one line little blocks which can be used as part of a method chain.

> [1,2,3].sort{|x,y| y<=>x}.map{|x| x+1}
=> [4, 3, 2]

Here's an example to illustrate this difference:

def foo arg
if block_given?
puts "Block given to foo"
yield arg
else
puts "No block given to foo"
arg
end
end


def bar
if block_given?
puts "Block given to bar"
yield "Yielded from bar"
else
puts "No block given to bar"
end
"Returned from bar"
end

irb(main):077:0> foo bar { |arg| puts arg }
Block given to bar
Yielded from bar
No block given to foo
=> "Returned from bar"
irb(main):078:0> foo bar do |arg| puts arg end
No block given to bar
Block given to foo
Returned from bar
=> nil


Related Topics



Leave a reply



Submit