Метод const_missing
аналогичен методу method_missing
. При попытке обратиться к неизвестной константе вызывается этот метод — если он, конечно, определен. В качестве параметра ему передается символ, ссылающийся на константу.
Чтобы перехватывать обращения к отсутствующим константам глобально, определите следующий метод в самом классе Module
(это родитель класса Class
).
class Module
def const_missing(x)
'Из Module'
end
end
class X
end
p X::BAR # 'Из Module'
p BAR # 'Из Module'
p Array::BAR # 'Из Module'
Можно выполнить в нем любые действия: вернуть фиктивное значение константы, вычислить его и т.д. Помните класс Roman
из главы 6? Воспользуемся им, чтобы трактовать любые последовательности римских цифр как числовые константы:
class Module
def const_missing(name)
Roman.decode(name)
end
end
year1 = MCMLCCIV # 1974
year2 = MMVIII # 2008
Если такая глобальность вам не нужна, определите этот метод на уровне конкретного класса. Тогда он будет вызываться из этого класса и его потомков.
class Alpha
def self.const_missing(sym)
'В Alpha нет #{sym}'
end
end
class Beta
def self.const_missing(sym)
'В Beta нет #{sym}.'
end
end
class A < Alpha
end
class В < Beta
end
p Alpha::FOO # 'В Alpha нет FOO'
p Beta::FOO # 'В Beta нет FOO'
p A::FOO # 'В Alpha нет FOO'
p В::FOO # 'В Beta нет FOO'
11.3.7. Удаление определений
Вследствие динамичности Ruby практически все, что можно определить, можно и уничтожить. Это может пригодиться, например, для того, чтобы «развязать» два куска кода в одной и той же области действия, избавляясь от переменных после того, как они были использованы. Другой повод — запретить вызовы некоторых потенциально опасных методов. Но по какой бы причине вы ни удаляли определение, делать это нужно крайне осторожно, чтобы не создать себе проблемы во время отладки.
Радикальный способ уничтожить определение — воспользоваться ключевым словом undef
(неудивительно, что его действие противоположно действию def
). Уничтожать можно определения методов, локальных переменных и констант на верхнем уровне. Хотя имя класса — тоже константа, удалить определение класса таким способом невозможно.
def asbestos
puts 'Теперь не огнеопасно'
end
tax =0.08
PI = 3
asbestos
puts 'PI=#{PI}, tax=#{tax}'
undef asbestos
undef tax
undef PI
# Любое обращение к этим трем именам теперь приведет к ошибке.
Внутри определения класса можно уничтожать определения методов и констант в том же контексте, в котором они были определены. Нельзя применять undef
внутри определения метода, а также к переменной экземпляра.
Существуют (определены в классе Module
) также методы remove_method
и undef_method
. Разница между ними тонкая: remove_method удаляет текущее (или ближайшее) определение метода, a undef_method
ко всему прочему удаляет его и из суперклассов, не оставляя от метода даже следа. Это различие иллюстрирует листинг 11.6.
class Parent
def alpha
puts 'alpha: родитель'
end
def beta
puts 'beta: родитель'