Прежде всего давайте проясним одну вещь.Когда они вызывают super
внутри class_eval
- это абсолютно не имеет отношения к тому, почему они использовали include Module.new {}
.На самом деле super
, который был вызван внутри метода destroy
, совершенно не имеет отношения к ответу на ваш вопрос.Внутри этого метода уничтожения может быть любой произвольный код.
Теперь, когда мы его получили, вот что происходит.
В ruby, если вы просто определяете метод класса, изатем определите его снова в том же классе, вы не сможете вызвать super
для доступа к предыдущему методу.
Например:
class Foo
def foo
'foo'
end
def foo
super + 'bar'
end
end
Foo.new.foo # => NoMethodError: super: no superclass method `foo' for #<Foo:0x101358098>
Это имеет смысл, потому что первыйfoo
не был определен ни в каком суперклассе, ни где-либо в цепочке поиска (где super
указывает).Тем не менее, вы можете определить первый foo
таким образом, чтобы при последующем его перезаписи он был доступен при вызове super
.Это именно то, чего они хотели добиться с помощью включения модуля.
class Foo
include Module.new { class_eval "def foo; 'foo' end" }
def foo
super + 'bar'
end
end
Foo.new.foo # => "foobar"
Это работает, потому что когда вы включаете модуль, ruby вставляет его в цепочку поиска.Таким образом, вы можете впоследствии вызвать super
во втором методе и ожидать вызова включенного метода.Отлично.
Однако вы можете задаться вопросом, почему бы просто не включить модуль без всех хитростей?Почему они используют блочный синтаксис?Мы знаем, что мой приведенный выше пример в точности эквивалентен следующему:
module A
def foo
'foo'
end
end
class Foo
include A
def foo
super + 'bar'
end
end
Foo.new.foo # => "foobar"
Так почему же они этого не сделали?Ответ - звонок на reflection
.Им нужно было захватить переменную (или метод), которая была доступна в текущем контексте, а именно reflection
.
Поскольку они определяют новый модуль с использованием синтаксиса блока, все переменные вне блока доступныдля использования внутри блока.Удобно.
Просто чтобы проиллюстрировать.
class Foo
def self.add_foo_to_lookup_chain_which_returns(something)
# notice how I can use variable something in the class_eval string
include Module.new { class_eval "def foo; '#{something}' end" }
end
end
# so somewhere else I can do
class Foo
add_foo_to_lookup_chain_which_returns("hello")
def foo
super + " world"
end
end
Foo.new.foo # => "hello world"
Аккуратно, да?
Теперь позвольте мне подчеркнуть это еще раз.Вызов super
внутри метода destroy
в вашем примере не имеет ничего общего с любым из вышеперечисленного.Они назвали это по своим собственным причинам, потому что, возможно, класс, где это происходит, подклассирует другой класс, который уже определил destroy
.
Надеюсь, это прояснило.