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

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时,而不是获取idFoo
对象;我得到一个对象的id
我认为Sunpot在Sunspot::DSL::Search方法中做了一些绑定交换/委派魔术。
我很好奇为什么太阳黑子会这样做,为什么没有关于
文档中的这种行为。
编辑:
太阳黑子搜索方法可以在这里找到link
下面的代码将说明我的观点。在Util.instance_eval_or_call方法中,我有一个行为符合预期的块。在foo方法中,块不起作用。
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
我在sunspot源代码树中找到了修改正常块行为的代码。我的问题是为什么要这样操纵捆绑装置。
注意事项3
具体来说,我在调用块旁边的bar方法时发现了一个问题。id方法将块内的方法调用委托给dsl对象,如果找不到方法,则将调用重新委托给调用上下文。在注册委托代码之前,search方法从dsl对象中除去所有基本方法。search方法没有被去掉。这就是问题的根源。对于所有其他方法,委派工作都很好。
太阳黑子方法文件中没有记录这种行为。

最佳答案

好吧,我知道它是怎么工作的:
魔法可以在util.rb的ContextBoundDelegate中找到。
它创建一个空白的slate delegator对象。
delegator将所有方法调用转发给“receiver”。在您的示例中,“receiver”可能是包含方法keywordswith以及any_of等的对象。
如果在“receiver”中找不到给定的方法,则它将方法调用转发到“context”对象上
上下文对象是保存块绑定的对象。
通过执行以下操作可以找到给定块的上下文对象:eval('self', block.binding)
理论基础:
因此,这一切的结果是,块不仅可以访问搜索对象(a lainstance_eval)中的方法,而且还可以访问块调用范围中的本地方法。
当然,块也可以访问块调用范围内的局部变量,但这只是正常的闭包行为。
但是,块不能访问块调用范围中的实例变量。
下面的代码可能很有用,因为它遵循大致相同的思想,但要简单得多,而且不太复杂:Using methods from two different scopes?

关于ruby-on-rails - 为什么黑子会更改搜索DSL块中的“自我”?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3739851/

10-12 15:26