Ответ 1
В Ruby постоянный поиск не совпадает с поиском метода. Для поиска метода вызов foo
всегда совпадает с вызовом self.foo
(при условии, что он не является приватным). Вызов константы foo
сильно отличается от self::FOO
или singleton_class::FOO
.
Использование неквалифицированной константы (например, foo
) будет выполнять поиск в открытых модулях. Модуль открывается с помощью module Mod
, class Klass
, class << obj
или module_eval
и вариантов. При определении m1
это B
, а затем B.singleton_class
. При определении m2
открывается только B
.
module Foo
X = 42
class Bar
def self.hello
X
end
end
end
В этом коде Foo::Bar.hello
вернет 42, хотя X
не является константой Bar
, ее одноэлементным классом или предком. Кроме того, если позднее вы добавите константу X
в Bar
, это значение будет возвращено. Наконец, следующее определение не эквивалентно:
module Foo
X = 42
end
class Foo::Bar
def self.hello
X
end
end
Foo::Bar.hello # => uninitialized constant Foo::Bar::X
В самом деле, когда hello
определен, открывается только класс Foo::Bar
, а в предыдущем примере открываются как foo
, так и Foo::Bar
.
Последний пример, чтобы показать разницу, которую явная область может иметь с наследованием:
class Base
X = 42
def self.foo
X
end
def self.bar
self::X
end
end
class Parent < Base
X = :other
end
Parent.foo # => 42
Parent.bar # => :other
В вашем случае вы, вероятно, захотите include
вашего модуля, а не extending
он, no?
В противном случае вы можете использовать singleton_class::VAR
, ваш код будет работать так, как вы ожидаете.
module A
VAR = 'some_constant'
end
class B
extend A
class << self
def m1
puts singleton_class::VAR # not necessary here, as singleton_class is opened
end
end
def self.m2
puts singleton_class::VAR # necessary here!
end
end
B.m1 # => OK
B.m2 # => OK