【问题标题】:Ruby Module NameError -- order matters?Ruby Module NameError——顺序很重要?
【发布时间】:2011-12-31 16:09:59
【问题描述】:

Ruby 1.9.2 p290 和 Rails 3.0.9

我有一个结构如下的 .rb 文件:

module M1
  # .... some method defs ...

  # Code in the middle, outside of any def:

  if Rails.version >= '3'
    class Railtie < ::Rails::Railtie

      ActiveSupport.on_load :action_controller do

        ActionController::Base.send :include, ::M1::M2 # <- throws an error..

      end
    end
  end

  module M2
  # ... method defs ...
  end
end

ActionController::Base.send :include, ::M1::M2 行抛出 NameError - 它找不到 M2。

但是,当我将 M2 移动到 M1 的顶部时,它可以毫无问题地解析引用。这就是 Ruby 的工作方式吗?解释器没有第一次通过来获取范围内的所有有效名称?你能解释一下这种行为吗?

【问题讨论】:

  • 定义您自己的从 ActionController::Base 继承的控制器后是否会出现该错误?
  • 这段代码来自 open_id_authentication gem (github.com/Velir/open_id_authentication),尽管我更改了模块的名称以使其更易于阅读。每当我尝试运行服务器时都会发生错误(rails s)
  • 从源代码中可以看出,代码将on_load 块定义为ActionController::Base.send :include, ControllerMethods,而不是ActionController::Base.send :include, ::OpenIdAuthentication::ControllerMethods。如果我错了,请纠正我
  • 你是对的 - 我在本地代码中更改了它,因为源代码的东西也不起作用;同样的问题。打算在 github 上分叉它并提出拉取请求.. 不确定它对任何人的工作方式。

标签: ruby-on-rails ruby module mixins


【解决方案1】:

是的,你是对的。当 Ruby 解释代码并且不知道常量时,它会引发名称错误:

class ModuleA
  include ModuleB
end

module ModuleB
end

但是,如果代码没有运行,它不会引发:

def some_method
  include ModuleC
end

module ModuleC
end

some_method

【讨论】:

    【解决方案2】:

    这种行为的原因是 Ruby 文件是从上到下读取的。类的主体是可执行代码。所以名称错误的简单原因是 Ruby 解释器还没有到达那部分代码。

    所以,这实际上是完全合法的 Ruby 代码:

    class Foo
    
      puts "hello from inside a class"
    
    end
    

    类的定义只是另一种表达方式。而且,就像 Ruby 中的每个表达式一样,它有一个返回值,所以下面的工作:

    two = class Foo
    
      def bar
      end
    
      1 + 1
    
    end
    

    当您使用另一种语法来创建类时,这一点会变得更加明显:

    Foo = Class.new do
      puts "Hello"
    end
    

    唯一的区别是这样写的时候不用输入命名空间。

    您已经在 ActiveRecord 中看到了这种行为:

    class Post < ActiveRecord::Base
      has_many :comments
    end
    

    这里,has_many 只是存在于ActiveRecord::Base 上的一个方法调用。加载文件时会直接执行。这就是为什么has_many和其他关系的一些参数是作为字符串传入的。

    class Post < ActiveRecord::Base
       belongs_to :author, :class_name => "User"
    end
    

    如果您要提及类 User 本身,它会引发 NameError,因为在加载 Post 时可能不会加载 User。 (在 Rails 中实际上并非如此,因为 Rails 会拦截 NameErrors 并尝试找到所需的文件,但这不是这里的重点)。关系的“定义”被存储,只有在以后访问关系时,才会将各个部分放在一起。

    模块在这方面完全一样。

    【讨论】:

      猜你喜欢
      • 2021-03-10
      • 2020-11-27
      • 2012-06-14
      • 1970-01-01
      • 2015-03-14
      • 2015-03-25
      • 2012-12-11
      • 2015-06-02
      • 2013-05-18
      相关资源
      最近更新 更多