Рубиновые доработки получили
В метапрограммировании Ruby 2 в главе 2 раздела "Уточнения" я обнаружил следующий фрагмент кода Ruby:
class MyClass
def my_method
"original my_method()"
end
def another_method
my_method
end
end
module MyClassRefinement
refine MyClass do
def my_method
"refined my_method()"
end
end
end
using MyClassRefinement
MyClass.new.my_method # => "refined my_method()"
MyClass.new.another_method # => "original my_method()" - How is this possible?
В соответствии с автором:
Тем не менее, призыв к
another_method
может застать вас врасплох: даже если вы позвонитеanother_method
послеusing
Призыв кmy_method
само по себе происходит раньшеusing
- так он вызывает оригинальную, не определенную версию метода.
Это полностью сбивает меня с толку.
Зачем MyClass.new.another_method
печатает "оригинальный my_method()", так как он используется после using MyClassRefinement
и что автор пытается здесь сказать?
Может ли кто-нибудь дать более интуитивное / лучшее объяснение?
Благодарю.
1 ответ
Лучшее объяснение, которое я могу найти, из документов:
Уточнения носят лексический характер. Уточнения активны только в области действия после вызова
using
, Любой код доusing
У заявления не будет активированного уточнения.
Это означает, что ваш метод уточнения должен быть вызван где-то после вызова using
, Фактическое местоположение вызова метода имеет значение, а не как метод был вызван или откуда метод был вызван.
Вот что происходит.
using
т.е.using MyClassRefinement
активируетmy_method
уточнение.MyClass.new.my_method
выполнен.- Поиск метода следует из точной точки вызова:
При поиске метода для экземпляра
class C
Рубиновые чеки:
- Если уточнения активны для
C
в обратном порядке они были активированы
- Готовые модули из уточнения для
C
- Уточнение для
C
- Включенные модули из уточнения для
C
- Предустановленные модули
C
C
- Включенные модули
C
- Уточнения активны, и
my_method
возвращает код из уточнения"refined my_method()"
MyClass.new.another_method
выполнен.- Поиск метода вытекает из точной точки вызова.
- Уточнения активны в этот момент вызова, но
another_method
это не уточнение, поэтому Ruby ищетanother_method
в классеMyClass
и находит это. - Внутри метода класса
another_method
, методmy_method
найден и вызван. - Поиск метода вытекает из точной точки вызова.
- В момент вызова нет активных уточнений, потому что не было вызовов
using
выше линии (т.е. физически до) гдеmy_method
вызывается. Руби продолжает искатьmy_method
в классеMyClass
и находит это. my_method
возвращает код из метода класса"original my_method()"
,
Мы можем сделать простое сравнение. Допустим, у меня есть один изолированный file.rb
со следующим кодом:
puts puppy
puppy = 'waggle'
puppy
не может быть использован, пока он не определен. Переменная имеет лексическую область видимости, и ее использование зависит от местоположения ее определения в изолированной file.rb
,
Точно так же уточнение не может быть вызвано, пока оно не было активировано через using
на предыдущей строке (или где-то физически предыдущий в файле исходного кода). Уточнение лексически ограничено.
В языках с лексической областью (также называемой статической областью) разрешение имен зависит от местоположения в исходном коде и лексического контекста, который определяется тем, где определена именованная переменная или функция...
Лексическое разрешение может быть определено во время компиляции и также известно как раннее связывание, в то время как динамическое разрешение обычно может быть определено только во время выполнения, и, таким образом, известно как позднее связывание.
Ваша конкретная проблема с уточнениями обсуждается в последнем разделе этой статьи. Автор также объясняет, как using
Физическое местоположение оператора в файле определяет, является ли уточнение активным.