Variable declaration behavior in if clause Ruby [duplicate] - ruby

This question already has answers here:
Confusion with the assignment operation inside a falsy `if` block [duplicate]
(3 answers)
Ruby: method inexplicably overwritten and set to nil
(2 answers)
Closed 9 years ago.
I am bit baffled about the below behavior
if true
foo = "true"
end
if false
bar = "false"
end
foo # => "true"
bar # => nil
buzz # =>
# ~> -:11:in `<main>': undefined local variable or method `buzz' for main:Object (NameError)
I expect bar to throw a NameError but it does not, I actually hit this when I was playing around with some friends but nobody could give a clear explanation to this behavior, thanks in anticipation of a clear answer

In ruby, the variables declared inside the if block have the exact same scope as the variables which are declared at the top level inside a method. Since the interpreter has gone through the line where it has seen bar, its fine with it.

Related

Non executed line (blocked by "if false") still affects results [duplicate]

This question already has answers here:
Ruby instance method & conditional local variable assignment with same name
(2 answers)
Closed 3 years ago.
I wanted to use the classical ||= re-assignment (cf Set Ruby variable if it is not already defined) with ActiveInteraction pretty much like in https://github.com/AaronLasseigne/active_interaction/issues/395
However by testing different syntaxes in ActiveInteraction I stumbled upon a much more peculiar issue that happens even in vanilly Ruby.
A non-executed line (blocked by a if false) can still have a major impact on the rest of the code:
class A
attr_accessor :a
def run
(puts defined? a; a) if true
end
def run2
(puts 'change a'; a = 0) if false
puts defined? a
a
end
end
x = A.new
x.run # "method"; nil
x.run2 # "local-variable"; nil
x.a = 5
x.run # "method"; 5
x.run2 # "local-variable"; nil
Can anyone explain if this is a bug or a feature? And if a feature: how come? It seems very odd.
EDIT: Thanks to the answer of #Sergio Tulentsev I managed to find that my question is pretty much a duplicate of Ruby instance method & conditional local variable assignment with same name with a different focus for the title name.
[is this] a bug or a feature?
Neither. It's a... peculiarity. What happens is, when parser sees assignment to local variable in the code, it goes ahead and adds the name to the scope (starting from that line, possibly shadowing other names, like your method here). With default value of nil. If the actual assignment is then never executed, the new local variable is still in scope and still evaluates to nil.
This is documented in https://docs.ruby-lang.org/en/2.5.0/syntax/assignment_rdoc.html#label-Local+Variables+and+Methods.

Use 'puts' with block accepting method over multiple lines [duplicate]

This question already has answers here:
Ruby Print Inject Do Syntax
(3 answers)
Closed 7 years ago.
Let's say I have the following (working) pseudo-code:
puts results.fields.inject('') { |string, key|
lengths[key] = calculate_length(key)
string << format(key)
}
Following the ruby-style-guide I should
Omit parentheses for 'keyword methods', i.e. puts, (which would create }) or end) anyway)
Use do...end for multi-line blocks
However, when replacing {...} with do...end it raises
undefined method `' for :title:Symbol (NoMethodError)
Therefore, is it possible to refactor this code without violenting the guideline?
There is a difference in precedence between {} and do end
If you use do end the block is associated with the puts statement, whereas the braces are associated with the results.field.inject('')
If you want to use do end then you have to remove the ambiguity of association by parentheses. It's one of those "gotchas" where the guidelines are recognized as guidelines, not absolute rules.
See also this answer...
In Ruby, why is a method invocation not able to be treated as a unit when "do" and "end" is used?

Why does the block of this if statement seem to be executed before the conditional in ruby? [duplicate]

This question already has answers here:
Undefined local variable based on syntax in Ruby
(1 answer)
Variable scope and order of parsing vs. operations: Assignment in an "if"
(3 answers)
Closed 7 years ago.
I'm currently working on a codegolf challenge, and so I'm trying to use as few characters as possible.
This code:
#example data
x=[1,2,3]
a=5.times.map{5.times.map{' '}}
#problematic code:
a[b][c]=x.pop if a[b=rand(5)][c=rand(5)] == ' '
returns a (quite strange) error:
test.rb:5:in `<main>': undefined local variable or method `b' for main:Object (NameError)
Did you mean? b
Which boils down to "Can't find b, did you mean b?". (to which the answer is yes).
This only happens with a 2D array with an inline if statement.
This code also runs fine:
if a[b=rand(5)][c=rand(5)] == ' '
a[b][c]=x.pop
end
It seems like it should be exactly the same, but it behaves differently. Why is this?
I thought it might have something to do with precedence, but I had a look at the ruby precedence table and everything would seem to be what I expect, so I'm not sure.

How does ruby keep track of variables [duplicate]

This question already has answers here:
Confusion with the assignment operation inside a falsy `if` block [duplicate]
(3 answers)
Closed 9 years ago.
I am confused with the way Ruby keeps track of variables. For example:
case 1:
if true
a
end
will give you an error saying undefined local variable or method a.
case 2:
if false
a
end
a
will give you same the error for the second a, not for the first a.
case 3:
if false
a=2
end
a #=> nil
defined? a #=> 'local-variable'
If you compare case 2 and case 3, in case 2 it ignored the error first a. I think its because of ruby's execution path has not reached the variable a due to false in condition. Same thing when I do with assignment in case 3. It gives me variable a defined but with nil value. Can someone explain the way it works?
In parse time if Ruby found any assignment such a=2,then local variable is created at that moment.It does not matter if you put in inside of any false conditional expression or not. Otherwise a legitimate error will be thrown as undefined local variable or method a,if you try to use the variable such as a here,before it's creation with the assignment(=) operator.
Look Confusion with the assignment operation inside the fallacy if block

Assigning an undefined variable in a one line condition [duplicate]

This question already has answers here:
Ruby if vs end of the line if behave differently?
(5 answers)
Closed 8 years ago.
In Ruby, why can you write :
# b is not defined yet.
#
if b = true
a = b
end
# => a = true
But not a one-liner :
a = b if b = true
# => NameError: undefined local variable or method `b' for main:Object
Because the Ruby interpreter "creates" a local variable when it sees an assignment.
In the second case, it hasn't yet seen the assignment, so the variable doesn't exist when the expression is parsed.
To be more precise, a method is first parsed into an internal representation, and then, perhaps, the code will eventually be called and actually executed.
Variables are "created" in that parsing pass. It's really more a matter of declaration, it just means that the interpreter becomes aware of them. They won't be created in the sense of being given space or a value until the surrounding method is called by someone.

Resources