Assume that I have the following class, how can I access the var
variable
Variables whose identifier starts with a lowercase letter are local variables. Local variables are local to the scope they are defined in, that's why they are called "local" variables.
The variable you have defined is just a boring old standard local variable, just like any other local variable. There is nothing special or different about it. It can be accessed just like any other local variable: by simply writing out its name.
E.g.:
class Test
var = "value"
puts var # See? Nothing special, just like any other local variable.
end
# value
The last expression evaluated inside a module definition body is the value of the module definition expression, so you could extract the content of the variable like this:
another_local_variable = class Test
var = "value"
var
end
another_local_variable
#=> "value"
You can also access the local variable in nested scopes. Again, there is absolutely nothing special or different about this. It's just a local variable that behaves exactly like every other local variable you may have already used.
The only constructs in Ruby that create nested scopes are blocks and lambda literals. So, you could do something like this:
class Test
var = "value"
define_method(:m1) do var end
define_singleton_method(:m2) do var end
end
Test.new.m1 #=> "value"
Test.m2 #=> "value"
If you can get access to the Binding
object (using the Kernel#binding
method) for the lexical scope in which the local variable is defined, then you can retrieve its value using Binding#local_variable_get
:
b = class Test
var = "value"
binding
end
b.local_variable_get(:var) #=> "value"
But again, I must repeat: nothing about this is in any way special. This local variable behaves 100% exactly like every other local variable. A local variable is simply a local variable.
Local variables are very useful in Ruby, because they are the only language construct that provides perfect encapsulation. All other means of encapsulation in Ruby (instance variables, private
, etc.) can be circumvented by reflection (e.g. using Object#instance_variable_get
or Object#send
), and reflection is always available to everyone with no access controls.
But unless someone explicitly gives you a Binding
object, local variables cannot be accessed outside of their local scope. It used to be very useful for implementing this pattern:
class Foo
def bar
'Hello'
end
end
class Foo
old_bar = instance_method(:bar)
define_method(:bar) do
old_bar.bind(self).() + ' World'
end
end
Foo.new.bar # => 'Hello World'
You can read more about this pattern in this answer of mine under the heading Method Wrapping: https://stackoverflow.com/a/4471202/2988
While this specific pattern has been made obsolete by the introduction of Module#prepend
, there are other similar situations where it is still useful, e.g. for memoization.