Confusion with block local variable declaration with block variable declaration within the pipe `|`

Why are we not allowed to create local variables or new object with
block variables?

The below are allowed :

a = "hello world".split(//).each{ |x;newstr = Array.new() | newstr =
x.capitalize;puts newstr }

H
E
L
L
O

W
O
R
L
D
=> ["h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"]

and

[1,2,3].each {|num|temp =0 ; temp = num ; print temp}
#123=> [1, 2, 3]

For what reasons the below are not allowed?

[1,2,3].each {|num;temp =0| temp = num;print temp}

#SyntaxError: (irb):5: syntax error, unexpected '=', expecting '|'
#[1,2,3].each {|num;temp =0| temp = num;print}
                         ^
#(irb):5: syntax error, unexpected '}', expecting $end
# from C:/Ruby193/bin/irb:12:in `<main>'

and

a = "hello world".split(//).each{ |x;newstr = Array.new() | newstr =
x.capitalize;puts newstr }

···

--
Posted via http://www.ruby-forum.com/.

You're looking for "Inject"
http://ruby-doc.org/core-2.0/Enumerable.html#method-i-inject

···

--
Posted via http://www.ruby-forum.com/.

look for #each_with_object and #inject/#reduce

but i think in this sample is an job for #map/#collect

···

--
Posted via http://www.ruby-forum.com/.

because this variables are reseted back to nil, every time the block is
run, and an "init" would not make sense

in you want something that survive longer than one iteration look at
each_with_object / with_object or inject

and before you can ask: this parameters are NOT useless because they can
shadow other local variables from outside the block without overriding
them

···

--
Posted via http://www.ruby-forum.com/.

Your first example does not work for me in any version of Ruby. But this
does

a = "hello world".split(//).each{ |x,newstr = Array.new() | newstr =
x.capitalize;puts newstr }

Note the use of a , rather than a ; between the | ... |
Also why are you assigning an Array to newstr? It makes absolutely no sense
as x.capitalize will simply replace it with a string.

The use of , rather than ; holds for all your examples.

This has nothing to do with creating local variables and everything to do
with writing bad code.

its when each yields more than one object, then you can see a difference

{1=>"a",2=>"b",3=>"c"}.each{|x;y| p y}
nil
nil
nil

{1=>"a",2=>"b",3=>"c"}.each{|x,y| p y}
"a"
"b"
"c"

···

x;y=0| is still an syntax error

--
Posted via http://www.ruby-forum.com/\.

it does not work because blocks does not allow "default" parameters like
that

blocks are different from methods.

But you can do that:

def talk(x,y=1)
p "X = #{x}"
p "Y = #{y}"
end

[1,2,3].each &method(:talk)
"X = 1"
"Y = 1"
"X = 2"
"Y = 1"
"X = 3"
"Y = 1"

···

--
Posted via http://www.ruby-forum.com/.

In the "Book of Ruby" author wrote the below paragraph:

a = "hello world".split(//).each{ |x| newstr << x.capitalize } (<~~ But
this code is not working in my `IRB`. And I think it should not. As
`newstr` is not initialized before it's used. - Is this the reason for
the code not to work.)

So, at each iteration, a capitalized character is appended to newstr,
and the following is displayed...

H
HE
HEL
HELL
HELLO
HELLO
HELLO W
HELLO WO
HELLO WOR
HELLO WORL
HELLO WORLD

As we are using the capitalize method here (with no terminating !
character), the characters in the array, a, remain as they began, all
lowercase, since the capitalize method does not alter the receiver
object (here the receiver objects are the characters passed into the
block). Be aware, however, that this code would not work if you were to
use the capitalize! method to modify the original characters. ** This is
because capitalize! returns nil when no changes are made so when the
space character is encountered nil would be returned and our attempt to
append (<<) a nil value to the string, newstr, would fail.**

I didn't catch him with ***points.

" ".capitalize!

=> nil

a =" ".capitalize!

=> nil

a

=> nil

a= 12

=> 12

a =" ".capitalize!

=> nil

a

=> nil

No error I did encounter.

Can anyone tell me what's the wrong? Does the author said wrong or my
caught is wrong?

···

--
Posted via http://www.ruby-forum.com/\.

***capitalize! returns nil when no changes are made***

so you can do:

if(str.capitalize!)
  puts "Changed!"
else
  puts "Not Changed!"
end

***append (<<) a nil value to the string***

a=""
a << " ".capitalize! #raise an error

···

--
Posted via http://www.ruby-forum.com/.

Okay!

Thanks for your help!

a=""

=> ""

a << " ".capitalize!

TypeError: can't convert nil into String
        from (irb):2
        from C:/Ruby193/bin/irb:12:in `<main>'

Got the above one.

Well. `a = "hello world".split(//).each{ |x| newstr << x.capitalize }`
is running on your IRB. I think it should not.

a = "hello world".split(//).each{ |x| newstr << x.capitalize }

NameError: undefined local variable or method `newstr' for main:Object
        from (irb):3:in `block in irb_binding'
        from (irb):3:in `each'
        from (irb):3
        from C:/Ruby193/bin/irb:12:in `<main>'

The error is so obvious. But don't know why author choose this code to
explain.:frowning:

···

--
Posted via http://www.ruby-forum.com/\.

maybe the newstr was defined in the paragraph before, or there is a
failure in the book

Thanks for your help!

a=""

=> ""

a << " ".capitalize!

TypeError: can't convert nil into String
       from (irb):2
       from C:/Ruby193/bin/irb:12:in `<main>'

Got the above one.

did you finally understand the difference between capitalize and
capitalize! and why

this works:
newstr =""
a = "hello world".split(//).each{ |x| newstr << x.capitalize }

but this does not?
newstr =""
a = "hello world".split(//).each{ |x| newstr << x.capitalize! }

??

···

--
Posted via http://www.ruby-forum.com/\.

Joel Pearson wrote in post #1101045:

You're looking for "Inject"
Module: Enumerable (Ruby 2.0.0)

No, please look at the symbol `;`, which is used to declare block local
variables with the block parameters inside the `|`.

[1,2,3].each {}

=> [1, 2, 3]

[1,2,3].each {|x;y| print y}

=> [1, 2, 3]

[1,2,3].each {|x;y| y=x; print y}

123=> [1, 2, 3]

See above. Here `x` is block parameter and `y` is local variable to the
block. The only problem if you try to get that `y` to initialize in the
same place inside the `|`. - Why so?

···

--
Posted via http://www.ruby-forum.com/\.

Hans Mackowiak wrote in post #1101051:

because this variables are reseted back to nil, every time the block is
run, and an "init" would not make sense

Yes! You are right. I know the importance of such declaration of local
variables inside the block.

Tell me the difference between |x,y| and |x;y=0| ? Hope answer to this
question will make sense to me.

···

and before you can ask: this parameters are NOT useless because they can
shadow other local variables from outside the block without overriding
them

--
Posted via http://www.ruby-forum.com/\.

Actually the error message is the clue here.

[1,2,3].each {|num;temp =0| temp = num;print temp}

#SyntaxError: (irb):5: syntax error, unexpected '=', expecting '|'
#[1,2,3].each {|num;temp =0| temp = num;print}

Again why you assigning to temp and when you immediately overwrite it? This
works

[1,2,3].each {|num;temp| temp = num;print temp}

Hans Mackowiak wrote in post #1101086:

did you finally understand the difference between capitalize and
capitalize! and why

this works:
newstr =""
a = "hello world".split(//).each{ |x| newstr << x.capitalize }

but this does not?
newstr =""
a = "hello world".split(//).each{ |x| newstr << x.capitalize! }

??

You explained it very cool way. So I have to digest it and I did also.

Thankkkkk youuuuu veryyyyy much :slight_smile: :):smiley:

···

--
Posted via http://www.ruby-forum.com/\.

In the "Book of Ruby" author wrote the below paragraph:

a = "hello world".split(//).each{ |x| newstr << x.capitalize } (<~~ But
this code is not working in my `IRB`. And I think it should not. As
`newstr` is not initialized before it's used. - Is this the reason for
the code not to work.)

So, at each iteration, a capitalized character is appended to newstr,
and the following is displayed...

H
HE
HEL
HELL
HELLO
HELLO W
HELLO WO
HELLO WOR
HELLO WORL
HELLO WORLD

As we are using the capitalize method here (with no terminating !
character), the characters in the array, a, remain as they began, all
lowercase, since the capitalize method does not alter the receiver
object (here the receiver objects are the characters passed into the
block). Be aware, however, that this code would not work if you were to
use the capitalize! method to modify the original characters. ** This is
because capitalize! returns nil when no changes are made so when the
space character is encountered nil would be returned and our attempt to
append (<<) a nil value to the string, newstr, would fail.**

I didn't catch him with ***points.

" ".capitalize!

=> nil

a =" ".capitalize!

=> nil

a

=> nil

a= 12

=> 12

a =" ".capitalize!

=> nil

a

=> nil

No error I did encounter.

Because you did not try to append nil to a string!

···

Am 11.03.2013 13:22, schrieb Love U Ruby:

Can anyone tell me what's the wrong? Does the author said wrong or my
caught is wrong?

--
<https://github.com/stomar/&gt;

Peter Hickman wrote in post #1101060:

Again why you assigning to temp and when you immediately overwrite it?

The below also doesn't work.

[1,2,3].each {|num;temp =0| print temp}

SyntaxError: (irb):7: syntax error, unexpected '=', expecting '|'
[1,2,3].each {|num;temp =0| print temp}
                         ^
(irb):7: syntax error, unexpected tIDENTIFIER, expecting keyword_do or
'{' or '(
'
[1,2,3].each {|num;temp =0| print temp}
                                      ^
        from C:/Ruby193/bin/irb:12:in `<main>'

When we write the method block as below, its work.

def talk(x,y=1)
p "X = #{x}"
p "Y = #{y}"
end

=> nil

talk(5)

"X = 5"
"Y = 1"
=> "Y = 1"

talk(5,3)

"X = 5"
"Y = 3"
=> "Y = 3"

The same way I also tried to put the default value to `temp` as

[1,2,3].each {|num;temp =0| temp = num ; print temp}

···

--
Posted via http://www.ruby-forum.com/\.