Nameerror: Undefined - Have Parsing Rules for Local Variables Changed in Ruby 2.1.2

NameError: undefined - have parsing rules for local variables changed in Ruby 2.1.2?

Yes it changed in ruby 2.1.2

In 1.8.7, 1.9.3, 2.0.0 and even 2.1.1 I get 2 warnings and no errors:

2.0.0-p247 :007 > bar if bar = false
(irb):7: warning: found = in conditional, should be ==
=> nil
2.0.0-p247 :008 > bar if bar = true
(irb):8: warning: found = in conditional, should be ==
=> true

whereas in the 2.1.2 version you mention I get 2 warnings and 1 NameError error.

2.1.2 :001 > bar if bar = true
(irb):1: warning: found = in conditional, should be ==
NameError: undefined local variable or method `bar' for main:Object
from (irb):1
from /home/durrantm/.rvm/rubies/ruby-2.1.2/bin/irb:11:in `<main>'
2.1.2 :002 > bar if bar = false
(irb):2: warning: found = in conditional, should be ==
=> nil

This is on my Ubuntu 14

Why is assignment treated differently in this single line conditional?

Oddly enough, this works fine in Rubinius:

Welcome to IRB. You are using rubinius 1.2.4dev (1.8.7 7ae451a1 yyyy-mm-dd JI)
>> (puts x) if (x = 0) #=> nil
0

I'm inclined to say it's a weird parsing bug in MRI.

Variable scope and order of parsing vs. operations: Assignment in an if

It only happens when you try to assign a literal value, if you call a function it works.

def foo(a)
a
end

p 'not shown' if(value = foo(false))
p 'shown' if(value = foo(true))

# This outputs a Warning in IRB
p 'shown' if(value = false)
(irb):2: warning: found = in conditional, should be ==

If you turn on debugging (-d) you will see a warning about an used variable value

warning: assigned but unused variable - value

This "works" because the statement does evaluate to true as far as if is concerned, allowing the code preceeding it to run.

What is happening here is that if() when used as a modifier has it's own binding scope, or context. So the assignment is never seen outside of the if, and therefore makes no sense to perform. This is different than if the control structure because the block that the if statement takes is also within the same scope as the assignment, whereas the line that preceeded the if modifier is not within the scope of the if.

In other words, these are not equivelant.

if a = some(value)
puts a
end

puts a if(a = some(value))

The former having puts a within the scope of the if, the latter having puts a outside the scope, and therefore having different bindings(what ruby calls context).

Ruby Order of Operations

How come (a_method || :other) returns :other only when assigning to a var called a_method?

There have been similar questions, but not exactly the same. Jörg's answer here seems to hit the point, I'm quoting the relevant part:

At this point, foo is defined, even
though the line will never get
executed. The fact that the line never
gets executed is completely
irrelevant, because the interpreter
has nothing to do with this anyway:
local variables are defined by the
parser, and the parser obviously sees
this line.

So, in your case, regardless of the fact that a method with the same name already exists, the parser sees some_method assignment and it automatically "tags" the identifier to be local variable. So, when interpreter starts evaluating the right-hand-side of the assignment, it already considers some_method to be local variable, not a method. Its value is unassigned (nil by default), so the result of || will be :other.

Why does capturing named groups in Ruby result in undefined local variable or method errors?

Named Captures Must Use Literals

You are encountering some limitations of Ruby's regular expression library. The Regexp#=~ method limits named captures as follows:

  • The assignment does not occur if the regexp is not a literal.
  • A regexp interpolation, #{}, also disables the assignment.
  • The assignment does not occur if the regexp is placed on the right hand side.

You'll need to decide whether you want named captures or interpolation in your regular expressions. You currently cannot have both.



Related Topics



Leave a reply



Submit