ruby-on-rails - 为什么太阳黑子会更改搜索 DSL block 中的 `self`?

标签 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

在上面的代码中,DSL block 可以访问定义在 上下文。但是 block 内的 self 指向一个实例 Sunspot::DSL::Search 类(而不是 Foo 类的实例。) 当我尝试访问 self.id 时,而不是获取 Fooid 目的;我获得了 Sunspot::DSL::Search 对象的 id

我认为 Sunpot 正在 Util.instance_eval_or_call 方法中执行一些绑定(bind)交换/委托(delegate)魔法。

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

编辑:

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

下面的代码将说明我的观点。在方法 foo 中,我有一个行为符合预期的 block 。在方法 bar 中,该 block 没有行为。

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 源代码树中找到了修改正常 block 行为的代码。我的问题是关于像这样安装绑定(bind)的原因。

注释3

具体来说,我在调用 block 内部的 id 方法时发现了一个问题。 search 方法将 block 内的方法调用委托(delegate)给 DSL 对象,如果找不到该方法,则将调用重新委托(delegate)给调用上下文。在注册委托(delegate)代码之前,搜索方法会从 DSL 对象中剥离除基本方法之外的所有方法。 id 方法没有被删除。这是造成问题的原因。对于所有其他方法,委托(delegate)工作正常。

太阳黑子方法文档中未记录此行为。

最佳答案

好的,我知道它是如何工作的:

神奇之处在于 util.rb 中的 ContextBoundDelegate

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

理由:

因此,所有这一切的效果是,该 block 不仅可以访问搜索对象中的方法(类似于 instance_eval),而且还可以访问该对象的调用范围中的本地方法。 block 。

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

但是,该 block 不能访问该 block 调用范围内的实例变量。

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

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

相关文章:

ruby-on-rails-3 - 太阳黑子 : boost scalar fields

ruby-on-rails - Ruby on Rails - 在前端异步进行长时间的 api 调用并将值返回给 js 的最佳方式?

ruby-on-rails - 在另一个表中查找具有两个特定记录的记录

ruby-on-rails - Ruby on Rails 项目的设计问题

java - Sunspot::Solr::Server::JavaMissing:您需要一个 Java 运行时环境来运行 Solr 服务器

ruby-on-rails-3 - 从太阳黑子 solr 结果中排除?

ruby-on-rails - 有条件地从 rails 表单中排除字段

sql - 使用 * 通配符按条件查找

java - 可定制的邮件服务器 - 我有哪些选择?

ruby-on-rails - 在不丢失 gem 的情况下更新 Ruby 1.9.3 -> 2.0.0