Отлично; Ваш пример кода очень понятен. То, что у вас есть, - это круговая зависимость для разнообразия садов, скрытая из-за особенностей оператора разрешения области видимости в Ruby.
Когда вы запускаете код Ruby require 'foo'
, ruby находит foo.rb
и выполняет его, а затем находит foo/bar.rb
и выполняет его. Поэтому, когда Ruby встречает ваш класс Foo
и выполняет include Foo::Bar
, он ищет константу с именем Bar
в классе Foo
, потому что это то, что обозначает Foo::Bar
. Когда он не может найти его, он ищет в других областях действия константы с именем Bar
и в конечном итоге находит его на верхнем уровне. Но , что Bar
является классом, и поэтому не может быть include
d.
Даже если бы вы смогли убедить require
запустить foo/bar.rb
до foo.rb
, это не помогло бы; module Foo::Bar
означает «найти константу Foo
, и, если это класс или модуль, начните определять модуль внутри нее с именем Bar
». Foo
еще не было создано, поэтому требование все равно не будет выполнено.
Переименование Foo::Bar
в Foo::UserBar
также не поможет, так как столкновение имен в конечном итоге не является ошибкой.
Так что же может вы делаете? На высоком уровне вы должны как-то разорвать цикл. Проще всего определить Foo
в двух частях, например:
# bar.rb
class Bar
A = 4
end
# foo.rb
class Foo
# Stuff that doesn't depend on Foo::Bar goes here.
end
# foo/bar.rb
module Foo::Bar
A = 5
end
class Foo # Yep, we re-open class Foo inside foo/bar.rb
include Bar # Note that you don't need Foo:: as we automatically search Foo first.
end
Bar::A # => 4
Foo::Bar::A # => 5
Надеюсь, это поможет.