现在谁收容我? (我是 A Class 的实例!耶!)

Who's Containing Me Now? (I'm An Instance Of A Class! Yay!)

我想获取此方法的封闭方法树。这是我的代码(希望有描述性注释):

enclosing_method(var1,var2) do
    enclosing_method(var3,var4) do
        get_tree # This method should return an array of it's enclosing methods
        # e.g. [get_tree, enclosing_method, enclosing_method, main]
    end
end

我该怎么做?如果不清楚,请告诉我,我的问题措辞有问题。另外,我的标题也不好。如果有人能想到更好的标题,请在评论中提出。

编辑:

我从@WandMaker 的回答 评论中得知嵌套方法不可能。所以,我正在半改变这个问题。怎么样:

class Myclass
    @@all_instances
    def initialize
        @parents = get_tree # method that will return
        # all of the containing instances / anythings
        @content = yield
        @@all_instances << self
    end
    attr_reader :content
    attr_reader :parents
end
Myclass.new do
    Myclass.new do
        # bonus points if you make this possible!
        # I don't really need this to work but
        # it's a kewl thing so please try
        get_tree # => [Myclass, Myclass, <main>]
    end
end

我正在寻找的是方法 get_tree 必须具有以下输出:

> Myclass.all_instances[0].parents # => [<main>]
> Myclass.all_instances[1].parents # => [Myclass, <main>]

让我在评论中知道这是否令人困惑或以任何方式荒谬。我会修好它。我保证。提前感谢所有天才解决了这个问题。我永远感激。

您实际上可以像您在问题中提到的那样将方法块彼此嵌套。 (简单示例:[1, 2, 3].each{|x| x.tap{|y| puts y}})以编程方式找出嵌套是什么有点棘手,但可行。

如果您正在尝试构建类似于 Erector 的 DSL,实际上有几种不同的方法可以解决该问题。也许最简单的方法是在方法调用开始时将一些值压入全局堆栈,然后在您想查看当前嵌套是什么时引用该堆栈。例如:

@call_stack = []
def some_method
  @call_stack.push("some_method")
  yield
ensure
  @call_stack.pop
end
def some_method2
  @call_stack.push("some_method2")
  yield
ensure
  @call_stack.pop
end

用法:

some_method do
  some_method2 do
    @call_stack #=> ["some_method", "some_method2"]
   end
end

另一种可能性是使用instance_exec更改块内的调用上下文,并实例化一个新对象用作每个嵌套级别的调用上下文。不过这有点复杂,所以我不会在这里介绍。

最后,为了完整起见,我应该提一下,如果您只想将其用于调试目的,还可以选择使用 caller_locations 来获取完整的堆栈跟踪。这使用起来非常简单,但在这种情况下听起来不像你想要的。