我注意到(并在太阳黑子代码中验证了)以下行为
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
的{{1}}
宾语;我得到Foo
对象的id
。
我认为Sunpot正在Sunspot::DSL::Search
方法中进行一些绑定交换/委托魔术。
我很好奇为什么Sunspot这样做以及为什么没有警告 文档中的这种行为。
修改
可以在此link
找到太阳黑子搜索方法以下代码将说明我的观点。在方法Util.instance_eval_or_call
中,我有一个行为符合预期的块。在方法foo
中,块不起作用。
bar
注2
我在Sunspot源代码树中找到了修改正常块行为的代码。我的问题是关于这样绑定绑定的原因。
注3
具体来说,我在块中调用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
方法时发现了一个问题。 id
方法将块内的方法调用委托给DSL对象,如果找不到方法,则将调用重新委托给调用上下文。在注册委托代码之前,搜索方法从DSL对象中删除除基本方法之外的所有方法。 search
方法未被删除。这导致了这个问题。对于所有其他方法,委托工作正常。
Sunspot方法文档中未记录此行为。
答案 0 :(得分:5)
好的,我知道它是如何运作的:
魔法可以在util.rb中找到ContextBoundDelegate
。
keywords
和with
以及any_of
等的对象。eval('self', block.binding)
<强>理由:强>
所以这一切的效果是该块不仅可以访问搜索对象中的方法(la instance_eval
),而且还可以访问块的调用范围内的本地方法。 / p>
当然,该块也可以访问块的调用范围内的局部变量,但这只是正常的闭包行为。
该块不,但是,可以访问块的调用范围内的实例变量。
以下代码可能有用,因为它遵循大致相同的想法,但更简单,更复杂:Using methods from two different scopes?
答案 1 :(得分:1)
不仅仅是instance_eval
吗?除非您正在讨论从调用上下文访问实例变量,否则这是正常的关闭行为。
我假设instance_eval
(自我更改)用于向块提供keywords
和其他相关方法。