2011-11-17 3 views
3

рубин 1.9.2 P290 и Rails 3.0.9Название модуля RubyError - порядок?

У меня есть файл .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

Появляются ли эти ошибки после определения собственного контроллера, который наследуется от ActionController :: Base? – WarHog

+0

Этот код из камня open_id_authentication (https: // github.com/Velir/open_id_authentication), хотя я изменил имена модулей, чтобы упростить их чтение. Ошибка возникает, когда я пытаюсь запустить сервер (rails s) –

+0

Как я могу видеть из источника, code're определяет блок 'on_load' как' ActionController :: Base.send: include, ControllerMethods', а не 'ActionController :: Base. send: include, :: OpenIdAuthentication :: ControllerMethods'. Pls исправить меня, если я ошибаюсь – WarHog

ответ

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

Модули точно такие же в этом отношении.

+0

Фантастическое объяснение; Спасибо! –

1

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

class ModuleA 
    include ModuleB 
end 

module ModuleB 
end 

Однако, если код получает не запускается, он не поднимет:

def some_method 
    include ModuleC 
end 

module ModuleC 
end 

some_method 
Смежные вопросы