Название модуля RubyError - порядок?

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 - интерпретатор не делает первый проход, чтобы получить все допустимые имена в области видимости? Можете ли вы объяснить это поведение?

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, потому что User может не загружаться при загрузке Post. (на самом деле это не так в Rails, потому что Rails перехватывает NameErrors и пытается найти необходимый файл, но это, помимо точки здесь). "Определение" отношения сохраняется, и только при доступе к последнему позже будут собраны части.

В этом отношении модули в точности совпадают.


Да, вы правы. Когда Ruby интерпретирует код и не знает константу, он вызывает ошибку имени:

class ModuleA
 include ModuleB
end
module ModuleB
end

Однако, если код не запускается, он не будет повышаться:

def some_method
 include ModuleC
end
module ModuleC
end
some_method

licensed under cc by-sa 3.0 with attribution.