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的工作原理 - 解释器不会在第一遍中获取范围内的所有有效名称吗?你能解释一下这种行为吗?
答案 0 :(得分:5)
这种行为的原因是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
,因为加载User
时可能无法加载Post
。 (这在Rails中实际上并非如此,因为Rails拦截了NameErrors并试图找到所需的文件,但除此之外还有其他内容)。 &#39;定义&#39;存储关系,并且只有在稍后访问关系时,才会将这些部分组合在一起。
模块在这方面完全相同。
答案 1 :(得分:1)
是的,你是对的。当Ruby解释代码并且不知道常量时,它会引发名称错误:
class ModuleA
include ModuleB
end
module ModuleB
end
但是,如果代码未运行,则不会引发:
def some_method
include ModuleC
end
module ModuleC
end
some_method