ruby interpreter: when is a variable defined? [duplicate] - ruby

This question already has answers here:
Why can I refer to a variable outside of an if/unless/case statement that never ran?
(3 answers)
Closed 5 years ago.
I noticed a pretty odd behaviour in a ruby irb console. If I execute:
irb(main):001:0> defined?(a)
=> nil
irb(main):002:0> a = true if defined?(a)
=> true
irb(main):003:0> a
=> true
since I haven't defined a and defined?(a) returns false I would expect a = true to not be executed. But that's not the case and a = true is actually executed and a has value true.
This can be simplified to
irb(main):001:0> a = "hello" if false
=> nil
irb(main):002:0> defined?(a)
=> "local-variable"
What I thought at the beginning is that a is defined before checking the condition but converting this into:
irb(main):001:0> (a = "hello") if false
=> nil
irb(main):002:0> defined?(a)
=> "local-variable"
Who can explain this behaviour to me? How does ruby evaluate such statement?
if false
a = "hello"
end
defined?(a) # true

It has nothing to do with defined?. It seems the parser needs to define that variable in advance if there's a chance it needs that. Check this
a
NameError (undefined local variable or method `a' for main:Object
a = 4 if false
nil
a
nil

Related

What does "[]" represent in the following context?

Could someone please explain the difference between:
&.[](:key)
.try(:[],:key)
.try(:key)
Specially what the "[]" represents in the first and second?
.[] is a method on the Hash object.
x.[](:key) calls the [] method with the :key argument and is equivalent to x[:key]
& is the safe navigation operator. x&.[](:key) would return nil if x is nil while x.[](:key) would cause an error.
x = {key: 123}
x[:key]
# => 123
x.[](:key)
# => 123
x = nil
x.[](:key)
# NoMethodError: undefined method `[]' for nil:NilClass
x&.[](:key)
# => nil
As far as the differences go, I don't believe there are any between the first and second, however x.try(:key) would try to call a key method on x and that would error out because it doesn't exist.
x.try(:[], :key) calls the .[] method with :key as an argument and is equivalent to what we saw above. As with the safe navigation operator, try returns nil if x is nil.
For better understanding, [] is a special method similar to fetch on Hash:
hash = {a: 1}
hash.[](:a) # => 1
hash.fetch(:a) # => 1
try is from Rails, could be used with syntax Hash#try(:method, argument):
hash.try(:[], :a) # => 1
hash.try(:fetch, :a) # => 1

!! (double bang) meaning in Ruby [duplicate]

This question already has answers here:
Why would you use a !! operator
(5 answers)
Closed 6 years ago.
What does !! mean in the following method?
def include?(record)
!!#association.include?(record)
end
It casts a variable into type boolean and determine its truthy or falsy value
For example:-
# Numbers...
!!1 # => true
!!0 # => true
# Numbers as strings...
!!'1' # => true
!!'0' # => false
# Truthy strings (case insensitive)...
!!'true' # => true (alias: 't')
!!'false' # => false (alias: 'f')
!!'yes' # => false (alias: 'y')
!!'no' # => false (alias: 'n')
# Booleans...
!!true # => true
!!false # => false
# Nil...
!!nil # => false
It helps you get boolean results.
For Example:
a = nil
!a
#=> true
!!a
#=> false
Similarly
a = 1
!a
#=> false
!!a
#=> true
The double exclamation mark will convert the result to a boolean value so that, in this case, if #assication.include?(record) returns nil that will get converted to false.

In Ruby, are val and val.nil? same? [duplicate]

This question already has answers here:
Ruby: "if !object.nil?" or "if object"
(5 answers)
Closed 8 years ago.
As the title, are the following two statements same:
if val
and
if !val.nil?
No.
2.0.0-p481 :001 > val = false
=> false
2.0.0-p481 :002 > val.nil?
=> false
In ruby, nil and false are both falsey, but only nil is nil.
No they both are different. Here is an example for you
irb(main):001:0> val = 10
=> 10
irb(main):002:0> if val
irb(main):003:1> puts"kranthi"
irb(main):004:1> end
kranthi
=> nil
irb(main):005:0> val = nil
=> nil
irb(main):006:0> if val
irb(main):007:1> puts"kranthi"
irb(main):008:1> end
=> nil
irb(main):009:0> val = "test"
=> "test"
irb(main):010:0> if val
irb(main):011:1> puts "kranthi"
irb(main):012:1> end
kranthi
=> nil

How do I dynamically create a local variable in Ruby?

I am trying to dynamically create local variables in Ruby using eval and mutate the local-variables array. I am doing this in IRB.
eval "t = 2"
local_variables # => [:_]
eval "t"
# => NameError: undefined local variable or method `t' for main:Object
local_variables << "t".to_sym # => [:_, :t]
t
# => NameError: undefined local variable or method `t' for main:Object
You have to synchronize the evaluations with the same binding object. Otherwise, a single evaluation has its own scope.
b = binding
eval("t = 2", b)
eval("local_variables", b) #=> [:t, :b, :_]
eval("t", b) # => 2
b.eval('t') # => 2
You have to use the correct binding. In IRB for example this would work:
irb(main):001:0> eval "t=2", IRB.conf[:MAIN_CONTEXT].workspace.binding
=> 2
irb(main):002:0> local_variables
=> [:t, :_]
irb(main):003:0> eval "t"
=> 2
irb(main):004:0> t
=> 2
You could set instance variables like this:
instance_variable_set(:#a, 2)
#a
#=> 2

What does ! mean at the end of a Ruby method definition? [duplicate]

This question already has answers here:
Why are exclamation marks used in Ruby methods?
(12 answers)
Closed 9 years ago.
I'm trying to learn Ruby by reading code, but I bumped into the following situation, which I cannot find in any of my tutorials/cheatsheets.
def foo!
# do bar
return bar
end
What is the point of "!" in a method definition?
Ruby doesn't treat the ! as a special character at the end of a method name. By convention, methods ending in ! have some sort of side-effect or other issue that the method author is trying to draw attention to. Examples are methods that do in-place changes, or might throw an exception, or proceed with an action despite warnings.
For example, here's how String#upcase! compares to String#upcase:
1.9.3p392 :004 > foo = "whatever"
=> "whatever"
1.9.3p392 :005 > foo.upcase
=> "WHATEVER"
1.9.3p392 :006 > foo
=> "whatever"
1.9.3p392 :007 > foo.upcase!
=> "WHATEVER"
1.9.3p392 :008 > foo
=> "WHATEVER"
ActiveRecord makes extensive use of bang-methods for things like save!, which raises an exception on failure (vs save, which returns true/false but doesn't raise an exception).
It's a "heads up!" flag, but there's nothing that enforces this. You could end all your methods in !, if you wanted to confuse and/or scare people.
! is a "bang" method, which changes the receiver and is a convention in Ruby.
You can define a ! version which might work like a non-bang method, but then it would then mislead other programmers if they didn't look at your method definition.
bang method in turn returns nil when no changes made to the receiver.
Examples without ! - You can see that the source string has not been changed:
str = "hello"
p str.delete("l") #=> "heo"
p str #=> "hello"
Examples with ! - You can see that the source string has been changed:
str = "hello"
p str.delete!("l") #=> "heo"
p str #=> "heo"
NOTE: There are some non-bang version methods, which also can change the receiver object:
str = "hello"
p str.concat(" world") #=> "hello world"
p str #=> "hello world"
! is not a method definition but is an convention used when you declaring an method and this method will change the object.
1.9.3-p194 :004 > a="hello "
=> "hello "
1.9.3-p194 :005 > a.strip
=> "hello"
1.9.3-p194 :006 > a
=> "hello "
1.9.3-p194 :007 > a.strip!
=> "hello"
1.9.3-p194 :008 > a
=> "hello"

Resources