代码之家  ›  专栏  ›  技术社区  ›  Harish Shetty

为什么太阳黑子会改变搜索DSL块中的“自我”?

  •  2
  • Harish Shetty  · 技术社区  · 15 年前

    我注意到(并在太阳黑子代码中验证了)以下行为

    class Foo < ActiveRecord::Base
      def  bar
        search_str = "foo"
        Boo.search do
          keywords(search_str)
          p self.id
          p self
       end
     end
    end
    

    在上面的代码中,DSL块可以访问中定义的变量。 上下文。但是 self 在块内,指向 Sunspot::DSL::Search 类(而不是 Foo 类。) 当我试图进入 self.id ,而不是 id A的 对象;我得到 身份证件 A的 太阳黑子::DSL::搜索 对象。

    我认为Sunpot正在做一些绑定交换/授权魔法 Util.instance_eval_or_call 方法。

    我很好奇为什么太阳黑子会这样做,为什么没有警告 文档中的这种行为。

    编辑:

    太阳黑子的搜索方法可以在这里找到 link

    下面的代码将说明我的观点。在方法中 foo 我有一个按预期运行的块。在方法中 bar ,块不工作。

    class Order < ActiveRecord::Base  
    
      def foo
        p self.class.name # prints Order
    
        # The `self` inside the block passed to the each method
        # points to an object of type Order (as expected)
        # This is the normal block behavior.
        [1,2,3].each do |val|
          p self.class.name # prints Order
        end
      end
    
    
      def bar
    
        p self.class.name # prints Order
    
        # the `self` inside the block passed to the search method
        # points to an object of type Sunspot::DSL::Search.
        # This is NOT the normal block behavior.
    
        Order.search do
          keywords("hello")
          p self.class.name # prints Sunspot::DSL::Search
        end
    end
    

    备注2

    我在太阳黑子源树中找到了修改正常块行为的代码。我的问题是为什么要用这种方法来捆绑。

    注意事项3

    具体来说,我在调用 身份证件 方法。这个 search 方法将块内的方法调用委托给DSL对象,如果找不到该方法,则将调用重新委托给调用上下文。在注册委派代码之前,search方法会从DSL对象中除去所有必需的方法。这个 身份证件 方法未被剥离。这就是问题的根源。对于所有其他方法,授权都可以。

    太阳黑子方法文档中没有记录这种行为。

    2 回复  |  直到 11 年前
        1
  •  5
  •   Community CDub    8 年前

    好吧,我知道它是怎么工作的:

    魔法在 ContextBoundDelegate 在Util.rb中。

    • 它创建一个空白的Slate委托程序对象。
    • 委托程序将所有方法调用转发给“receiver”。在您的示例中,“receiver”可能是包含方法的对象 keywords with any_of 等等。
    • 如果在“receiver”中找不到给定的方法,则它将方法调用转发到“context”对象上
    • 上下文对象是保存块绑定的对象。
    • 通过执行以下操作,可以找到给定块的上下文对象: eval('self', block.binding)

    理论基础:

    因此,所有这些的效果是,块不仅可以访问搜索对象(LA)中的方法 instance_eval )但它也可以访问块调用范围中的本地方法。

    当然,块也可以访问块调用范围内的局部变量,但这只是正常的闭包行为。

    这个街区有 但是,可以访问块的调用范围中的实例变量。

    下面的代码可能很有用,因为它遵循大致相同的思想,但更简单,更不复杂: Using methods from two different scopes?

        2
  •  1
  •   horseyguy    15 年前

    它不只是一个 instance_eval ?除非你在谈论访问 实例变量 从调用上下文来看,这是正常的闭包行为。

    我假设 实例评估 (自我的改变)是用来提供 keywords 以及其他相关的方法。

    推荐文章