Ruby on rails 为什么太阳黑子会改变搜索DSL块中的“self”?
我注意到(并在太阳黑子代码中验证)以下行为Ruby on rails 为什么太阳黑子会改变搜索DSL块中的“self”?,ruby-on-rails,ruby,sunspot,Ruby On Rails,Ruby,Sunspot,我注意到(并在太阳黑子代码中验证)以下行为 class Foo < ActiveRecord::Base def bar search_str = "foo" Boo.search do keywords(search_str) p self.id p self end end end 注2 我在Sunspot源代码树中找到了修改正常块行为的代码。我的问题是关于这样操纵绑定的原因 注3 具体来说,我在调用块中的id方法时发
class Foo < ActiveRecord::Base
def bar
search_str = "foo"
Boo.search do
keywords(search_str)
p self.id
p self
end
end
end
注2
我在Sunspot源代码树中找到了修改正常块行为的代码。我的问题是关于这样操纵绑定的原因
注3
具体来说,我在调用块中的id
方法时发现了一个问题。search
方法将块内的方法调用委托给DSL对象,如果未找到该方法,则调用将重新委托给调用上下文。在注册委托代码之前,Search方法从DSL对象中除去基本方法以外的所有方法。id
方法未被剥离。这就是问题的根源。对于所有其他方法,委托都可以很好地工作
太阳黑子方法文档中没有记录这种行为 这不只是一个
实例评估吗?除非您谈论的是从调用上下文访问实例变量,否则这是正常的闭包行为
我假设实例\u eval
(自身的变化)用于向块提供关键字和其他相关方法。好的,我知道它是如何工作的:
在util.rb的ContextBoundDelegate
中可以找到这种魔力
- 它创建一个空白的slate delegator对象
- 委托人将所有方法调用转发给“接收方”。在您的示例中,“接收者”可能是包含方法
关键字和with
和任意等的对象
- 如果在“receiver”中找不到给定的方法,则它将方法调用转发到“context”对象
- 上下文对象是保存块绑定的对象
- 通过执行以下操作可以找到给定块的上下文对象:
eval('self',block.binding)
理由:
因此,所有这些的效果是,块不仅可以访问搜索对象中的方法(lainstance\u eval
),还可以访问块调用范围中的本地方法
当然,块还可以访问块的调用范围中的局部变量,但这只是正常的闭包行为
但是,块不能访问块调用范围内的实例变量
下面的代码可能很有用,因为它遵循了大致相同的思想,但简单得多,也不太复杂:不,它不是标准的instance\u eval
。太阳黑子库附带了一个实用程序类,方法就在该类中。在典型的块中,在创建块的过程中设置self
的值。Sunspot DSL块中的行为不是标准的。@Kandada,您的示例代码只显示了一个普通的实例的行为。\u eval
。您能否提供示例代码来演示实例\u eval
未解释的行为?或者提供一个链接,指向您声称非常特殊的方法的实现@Kandada,在看了github上关于太阳黑子的代码之后,我同意这不是一个直接的instance\u eval
。看看我的新答案。但是,您的示例并未演示此行为。:)即使您进行了更新,栏中的行为仍然可以通过实例\u eval
来解释。您要做的是访问搜索
块中的本地方法。简单地证明self
返回一个意外的对象是不相关的---这在instance\u eval
中是正常的。更新您的示例以调用搜索
块中的本地方法调用。使用附加注释更新问题。
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