开发者

metaprogramming access local variables

开发者 https://www.devze.com 2023-01-21 12:32 出处:网络
class Foo def initialize bar = 10 end fiz = 5 end Is there a possibility to get thes开发者_开发百科e local values (outside the class) ?The local variable in initialize would be lost.
class Foo
  def initialize
    bar = 10
  end
  fiz = 5
end

Is there a possibility to get thes开发者_开发百科e local values (outside the class) ?


The local variable in initialize would be lost.

You are able to get the value fiz outside of the class, but only upon defining that class, and recording the return of the definition of the class.

return_of_class_definition = (class A ; fiz = 5 ; end) would assign the value of fiz to the variable.

You can also use binding but of course, this means changing the class, which may not be allowed for the exercise.

class A
  bin = 15
  $binding = binding
end

p eval 'bin', $binding


No. Once a local variable goes out of scope (for bar that is when the initialize method has run - for fiz when the end of the class definition has been reached), it's gone. No trace left.

While a local variable is still in scope you can see it (well, its name) with local_variables and get and set its value with eval (though that's definitely not recommended for sanity reasons), but once it's out of scope, that's it. No way to get it back.


In ruby we have something we could call scope gates - places when a program written in ruby leaves the previous scope. Those gates are: class, module and method (def keyword). In other words after class, module of def keyword in the code you're immediately entering into a new scope.

In ruby nested visibility doesn't happen and as soon as you create a new scope, the previous binding will be replaced with a new set of bindings.

For example if you define following class:

x = 1
class MyClass
  # you can't access to x from here
  def foo
    # ...from here too
    y = 1
    local_variables
  end
end

local_variables method call will return [:y]. It means that we don't have an access to the x variable. You can workaround this issue using ruby's technique called Flat Scopes. Basically instead defining a class using class keyword you can define it using Class.new and pass a block to this call. Obviously a block can take any local variables from the scope where it was defined since it's a closure!

Our previous example could be rewritten to something like like that:

x = 1
Foo = Class.new do
  define_method :foo do
    i_can_do_something_with(x)
    y = 1
    local_variables
  end
end

In this case local_variables will return [:x, :y].

0

精彩评论

暂无评论...
验证码 换一张
取 消