Модули идентифицируются константами. 1 Таким образом, разрешение поиска модулей определяется процедурой поиска константных ссылок. По словам "Ruby Programming Language", Дэвид Фланаган и Юкихеро Мацумото, 1-е изд. 2008 (стр. 261-262), поиск констант выполняется в следующем порядке, где mod
- самый внутренний модуль, который содержит ссылку на константу:
mod
.
- следующий включающий модуль, продолжающийся до тех пор, пока не будет больше вложенных модулей. (Верхние / глобальные константы на этом этапе не рассматриваются). Метод класса Module :: nesting возвращает массив модулей, в которых выполняется такой поиск, в порядке их поиска.
- элементы
mod.ancestors
в порядке индекса (то есть иерархия наследования).
- определения констант верхнего уровня.
- значение, возвращаемое методом Module # const_missing , где
mod
- получатель, а константа, выраженная в виде символа - аргумент, при условии, что метод был определен.
Посмотрим, что мы можем узнать, вставив в код операторы puts Module.nesting.inspect
и puts ancestors
.
module Foo
class UserBar
puts "nesting for UserBar=#{Module.nesting.inspect}"
puts "#{self}.ancestors=#{ancestors}"
end
end
# nesting for UserBar=[Foo::UserBar, Foo]
# Foo::UserBar.ancestors=[Foo::UserBar, Object, Kernel,
# BasicObject]
module Foo
class SubUserBar < UserBar
puts "nesting for SubUserBar=#{Module.nesting.inspect}"
puts "#{self}.ancestors=#{ancestors}"
end
end
# nesting for SubUserBar=[Foo::SubUserBar, Foo]
# Foo::SubUserBar.ancestors=[Foo::SubUserBar,
# Foo::UserBar, Object, Kernel, BasicObject]
module Foo
module Bar
class User
puts "nesting for User=#{Module.nesting.inspect}"
puts "#{self}.ancestors=#{ancestors}"
end
end
end
# nesting for User=[Foo::Bar::User, Foo::Bar, Foo]
# Foo::Bar::User.ancestors=[Foo::Bar::User, Object, Kernel,
# BasicObject]
module Foo
module Bar
class SubUser < User
puts "nesting for SubBar=#{Module.nesting.inspect}"
puts "#{self}.ancestors=#{ancestors}"
end
end
end
# nesting for SubBar=[Foo::Bar::SubUser, Foo::Bar, Foo]
# Foo::Bar::SubUser.ancestors=[Foo::Bar::SubUser,
# Foo::Bar::User, Object, Kernel, BasicObject]
Это говорит нам о том, что если существует класс User
, который не содержится в Foo
(как в Rails), этот класс будет объектом ссылок на User
в классах Foo::UserBar
и Foo::SubUserBar
, но не в Foo::Bar::User
или Foo::Bar::SubUser
. Это понимание должно помочь в организации модулей, чтобы избежать проблем с пространством имен.
1 Так как классы являются модулями, всякий раз, когда я ссылаюсь на «модуль» ниже, я имею в виду классы, а также модули, которые не являются классами.