I am attempting to list all local variables and their values. This works in IRB:
local_variables.map {|var| "#{var} = " + local_variable_get(var).inspect
I would like to wrap this in a method, but when this code is placed inside a method, local_variables
no longer points to the correct list of variables. Therefore, I tried some solutions along the lines of:
class Object
def list_vars
self.__send__(:binding).local_variables.map {|var| "#{var} = " + self.__send__(:binding).local_variable_get(var).inspect}
end
end
However, it seems that the binding of the current object is different from main
, which is used when calling local_variables
directly.
Does self.send(:binding)
change depending on what method self
is in?
Your code is really complicated and obfuscated. First, let's clean up your code a bit so that we can see more clearly what's going on. You don't need self
, since it is the default receiver anyway. And you don't need send
, because you already know the name of the method you want to call. Also, Kernel#local_variables
uses the current Binding
anyway. Also, typically, such methods which are supposed to by called without an explicit receiver and don't actually make use of self
(e.g. like puts
or require
) are put into Kernel
. So, your code is equivalent to the following:
module Kernel
def list_vars
local_variables.map {|var| "#{var} = " + binding.local_variable_get(var).inspect}
end
end
Now we can immediately see the problem: you are reflecting on the local variables and the Binding
of list_vars
and not the place where it was called from! You need to pass the Binding
into the method and use that instead:
module Kernel
def list_vars(binding)
binding.local_variables.map {|var| "#{var} = " + binding.local_variable_get(var).inspect}
end
end
list_vars(binding)
Or, you could make it an instance method of Binding
:
class Binding
def list_vars
local_variables.map {|var| "#{var} = " + local_variable_get(var).inspect}
end
end
binding.list_vars