Ruby Module NameError - 订单有关系吗?

Nic*_*k B 3 ruby module ruby-on-rails mixins

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
Run Code Online (Sandbox Code Playgroud)

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

但是,当我将M2移动到M1的顶部时,它会毫无问题地解析引用.这只是Ruby的工作原理 - 解释器不会在第一遍中获取范围内的所有有效名称吗?你能解释一下这种行为吗?

iai*_*ain 5

这种行为的原因是Ruby文件从上到下读取.类的主体是可执行代码.因此,名称错误的简单原因是Ruby解释器尚未到达代码的那一部分.

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

class Foo

  puts "hello from inside a class"

end
Run Code Online (Sandbox Code Playgroud)

类的定义只是另一种表达方式.并且,就像Ruby中的每个表达式一样,它具有返回值,因此以下工作原理:

two = class Foo

  def bar
  end

  1 + 1

end
Run Code Online (Sandbox Code Playgroud)

当您使用替代语法创建类时,它变得更加明显:

Foo = Class.new do
  puts "Hello"
end
Run Code Online (Sandbox Code Playgroud)

唯一的区别是,当您以这种方式编写时,不要输入命名空间.

您已在ActiveRecord中看到此行为:

class Post < ActiveRecord::Base
  has_many :comments
end
Run Code Online (Sandbox Code Playgroud)

这里has_many只是一个存在的方法调用ActiveRecord::Base.它将在加载文件时直接执行.这就是为什么一些参数has_many和其他关系作为字符串传递的原因.

class Post < ActiveRecord::Base
   belongs_to :author, :class_name => "User"
end
Run Code Online (Sandbox Code Playgroud)

如果你要提到类User本身,它会引发一个NameError,因为User加载时可能没有Post加载.(在Rails中实际情况并非如此,因为Rails拦截了NameErrors并试图找到所需的文件,但除了这里的重点之外).存储关系的"定义",并且只有在稍后访问关系时,才会将这些部分放在一起.

在这方面,模块完全相同.