Parsing rule for this code?

1)
class ABC
    def do_something
       number = 10
       puts number
    end
end

ABC.new.do_something

--output:--
10

2)
class ABC
    def do_something
        3.times do |x|
            number = 10
        end
        puts number
    end
end

ABC.new.do_something

--output:--
Line 6:in `do_something': undefined local variable or method `number'
for #<ABC:0x401bfaa4> (NameError)
  from t.rb:10

Why does ruby get confused by the setter v. local variable assignment
when adding a block?

···

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

ruby is not confused :slight_smile:

try these eg,

class ABC
  def do_something
     number=0
     3.times do
       number=10
     end
     p number
  end
end
#=> nil
ABC.new.do_something
10
#=> 10

class ABC
  def do_something
    number = 0
     3.times do |;number|
       number=10
     end
     p number
  end
end
#=> nil
ABC.new.do_something
0
#=> 0

best regards -botp

···

On Fri, Feb 25, 2011 at 11:41 AM, 7stud -- <bbxx789_05ss@yahoo.com> wrote:

...
Why does ruby get confused by the setter v. local variable assignment
when adding a block?

As a rule of thumb, variables exist until you reach the "end" or
closing brace of the innermost block that they're still contained in.
In your case, you have this:

def do_something
3.times do |x|
number = 10
end
puts number
end

The local variable `number` is created with the value 10 and then
immediately discarded. This happens three times, since the block
executes three times.

The goal of the next statement is to print a local variable called
`number`. But there is no such local variable in this block. So Ruby
rightfully complains that you didn't define it. If instead you had
written this:

def do_something
       number = 0 # create `number` in this lexical scope
3.times do |x|
number = 10
end
puts number
end

then it would work as you probably expect.

~ jf

···

--
John Feminella
Principal Consultant, BitsBuilder
LI: http://www.linkedin.com/in/johnxf
SO: User John Feminella - Stack Overflow

On Thu, Feb 24, 2011 at 22:41, 7stud -- <bbxx789_05ss@yahoo.com> wrote:

1)
class ABC
def do_something
number = 10
puts number
end
end

ABC.new.do_something

--output:--
10

2)
class ABC
def do_something
3.times do |x|
number = 10
end
puts number
end
end

ABC.new.do_something

--output:--
Line 6:in `do_something': undefined local variable or method `number'
for #<ABC:0x401bfaa4> (NameError)
from t.rb:10

Why does ruby get confused by the setter v. local variable assignment
when adding a block?

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

There's no "setter" here. Both of those are local variable assignments. In
the second example, the variable is created local to the block. After the
block ends, the variable ceases to exist.

If you want the variable to exist in the outher block, just create it
there:

class ABC
    def do_something
        number = 0
        3.times do |x|
            number = 10
        end
        puts number
    end
end

ABC.new.do_something

···

7stud -- <bbxx789_05ss@yahoo.com> wrote:

1)
class ABC
   def do_something
      number = 10
      puts number
   end
end

ABC.new.do_something

--output:--
10

2)
class ABC
   def do_something
       3.times do |x|
           number = 10
       end
       puts number
   end
end

ABC.new.do_something

--output:--
Line 6:in `do_something': undefined local variable or method `number'
for #<ABC:0x401bfaa4> (NameError)
from t.rb:10

Why does ruby get confused by the setter v. local variable assignment
when adding a block?

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Thanks. I got confused by the error message--it lead me to believe the
problem was a setter v. variable assignment parsing problem. Instead it
was a beginner scope problem.

···

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

Ok, the following code exhibits the problem I was trying to demonstrate:

class Roulette
  def method_missing(name, *args)
    person = name.to_s.capitalize

    3.times do
      number = rand(10) + 1
      puts "#{number}..."
    end

    #puts "#{person} got a #{number}"

  end
end

Roulette.new.xxx

If I uncomment the commented line, I get an infinite loop. Why? I'm
pretty sure that is a local variable assignment v. setter problem.

···

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

Good Afternoon,

Ok, the following code exhibits the problem I was trying to demonstrate:

class Roulette
def method_missing(name, *args)
   person = name.to_s.capitalize

   3.times do
     number = rand(10) + 1
     puts "#{number}..."
   end

   #puts "#{person} got a #{number}"

end
end

Roulette.new.xxx

If I uncomment the commented line, I get an infinite loop. Why? I'm
pretty sure that is a local variable assignment v. setter problem.

It's not a problem - the issue is that number is scoped only to the 3.times
do block. That means that by the time you get to the puts, number is already
out of scope. Thus Ruby looks for the next alternative which is a instance
method by the name of number - not finding one it ends up back at
method_missing and thus the loop of death ensues.

Try this instead

class Roulette
def method_missing(name, *args)
   person = name.to_s.capitalize

   number = nil #you now have "number" scoped at the method level instead of
the block level

   3.times do
     number = rand(10) + 1
     puts "#{number}..."
   end

   puts "#{person} got a #{number}"

end
end

Roulette.new.xxx

John

···

On Fri, Feb 25, 2011 at 4:12 PM, 7stud -- <bbxx789_05ss@yahoo.com> wrote:

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

John Feminella wrote in post #983784:

As a rule of thumb, variables exist until you reach the "end" or
closing brace of the innermost block that they're still contained in.
In your case, you have this:

   def do_something
       3.times do |x|
           number = 10
       end
       puts number
   end

The local variable `number` is created with the value 10 and then
immediately discarded. This happens three times, since the block
executes three times.

The goal of the next statement is to print a local variable called
`number`. But there is no such local variable in this block. So Ruby
rightfully complains that you didn't define it.

Actually, I think the parser determines that 'number' in the line:

  puts number

is a method. See this code:

class Dog

  def method_missing(name, *args)
    puts "*** #{name.to_s} ***"
    super
  end

  def test
     3.times do
       number = 10
       puts number
     end

     puts number
  end
end

Dog.new.test

--output:--
10
10
10
*** number ***

Line 5:in `method_missing': undefined local variable or method `number'
for #<Dog:0x401bf798> (NameError)
  from t.rb:14:in `test'
  from t.rb:18

···

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

John W Higgins wrote in post #984017:

Good Afternoon,

Thanks. I realized my code was just another version of the out of scope
problem discussed earlier.

···

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

The parser does not think `number` is a method by virtue of writing
"puts number". It tries to invoke a method called number because there
is no local variable named number, because the local variable that you
named `number` is no longer in scope.

To see this for yourself, consider this snippet:

   number = 10

   def number
     20
   end

   puts number
   # => 10

Notice Ruby correctly picks the local variable named `number`,
not the method called `number`.

~ jf

···

--
John Feminella
Principal Consultant, BitsBuilder
LI: http://www.linkedin.com/in/johnxf
SO: User John Feminella - Stack Overflow

On Fri, Feb 25, 2011 at 19:40, 7stud -- <bbxx789_05ss@yahoo.com> wrote:

John Feminella wrote in post #983784:

As a rule of thumb, variables exist until you reach the "end" or
closing brace of the innermost block that they're still contained in.
In your case, you have this:

def do_something
3.times do |x|
number = 10
end
puts number
end

The local variable `number` is created with the value 10 and then
immediately discarded. This happens three times, since the block
executes three times.

The goal of the next statement is to print a local variable called
`number`. But there is no such local variable in this block. So Ruby
rightfully complains that you didn't define it.

Actually, I think the parser determines that 'number' in the line:

puts number

is a method. See this code:

class Dog

def method_missing(name, *args)
puts "*** #{name.to_s} ***"
super
end

def test
3.times do
number = 10
puts number
end

puts number

end
end

Dog.new.test

--output:--
10
10
10
*** number ***

Line 5:in `method_missing': undefined local variable or method `number'
for #<Dog:0x401bf798> (NameError)
from t.rb:14:in `test'
from t.rb:18

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

No problem - some horses just really do need to be beaten well beyond death
:slight_smile:

John

···

On Fri, Feb 25, 2011 at 4:43 PM, 7stud -- <bbxx789_05ss@yahoo.com> wrote:

John W Higgins wrote in post #984017:
> Good Afternoon,

Thanks. I realized my code was just another version of the out of scope
problem discussed earlier.