从方法外部获取方法内部定义的局部变量名称

Getting local variable names defined inside a method from outside the method

在 Ruby 中是否可以使用元编程从方法外部获取方法内部定义的所有局部变量名称?

def foo
  var = 100
  arr = [1,2]
end

类似于foo.local_variables

我只需要检索变量名,而不是它们的值。

为什么我要尝试查找这些变量名称:我有一个class,我想在其中为在“#initialize”中初始化的所有实例变量动态生成设置器”。

为了做到这一点,在 "initialize" 中,我使用了类似 instance_variables.each do |inst_var_name| define_singleton_method(...) do ...

的东西

这有效:每个实例化对象都将其设置器作为单例方法获取。但是,我正在寻找一种解决方案,我可以从 "initialize" 方法外部读取实例变量名称,以便能够为它们使用“#define_method”,并创建常规方法而不是单例方法。

正如 Jordan 指出的那样,这些变量只存在很短的时间,它们只在方法主动执行时存在,并在执行后立即被丢弃。

如果你想对这些进行检测,你需要在方法中进行。该方法本身不允许这种反射。

您可以(重新)解析该方法并检查 S-EXPR 树。请参阅下面的概念证明。您可以使用 Method#source_location 获取定义方法的文件,然后读取该文件。我的代码肯定有改进的余地,但应该让你开始。它是一段功能齐全的代码,只需要 ruby 解析器 gem (https://github.com/whitequark/parser).

require 'parser/current'
node = Parser::CurrentRuby.parse(DATA.read) # DATA is everything that comes after __END__

def find_definition(node, name)
  return node if definition_node?(node, name)
  if node.respond_to?(:children)
    node.children.find do |child|
      find_definition(child, name)
    end
  end
end

def definition_node?(node, name)
  return false if !node.respond_to?(:type)
  node.type == :def && node.children.first == name
end

def collect_lvasgn(node)
  result = []
  return result if !node.respond_to?(:children)

  node.children.each do |child|
    if child.respond_to?(:type) && child.type == :lvasgn
      result << child.children.first
    else
      result += collect_lvasgn(child)
    end
  end

  result
end

definition = find_definition(node, :foo)
puts collect_lvasgn(definition)

__END__

def foo
  var = 100
  arr = [1,2]
  if something
    this = 3 * var
  end
end

def bar
  var = 200
  arr = [3, 4]
end

您介意告诉我们您为什么要查找变量吗?