Если вы переопределите метод, то вы измените его определение. Звонок super
не будет работать; оригинальный метод не все еще существует как нечто для переадресации вызова сообщения.
Есть несколько способов решить эту проблему. «Классическим» способом было бы вообще не переопределять метод, а вместо этого определить свой собственный подкласс из Set
:
require 'set'
class MySet < Set
def add(*args)
args.each { |arg| super arg }
self
end
end
s = MySet.new
s.add 1,2
#=> #<MySet: {1, 2}>
... Но это не может быть идеальным, так как вам нужно ссылаться на MySet
(или как вы его называете) по всей базе кода, а не Set
.
Если вы хотите изменить поведение Set
напрямую, тогда "ru-way" старой школы ( больше не рекомендуется , по состоянию на ruby v2.0+
) - это alias
оригинальный метод с другим именем, затем создайте свою собственную версию и вызовите оригинальный:
require 'set'
class Set
alias_method :original_add, :add
def add(*args)
args.each { |arg| original_add(arg) }
self
end
end
s = Set.new
s.add 1,2
#=> #<Set: {1, 2}>
Rails также используется для предоставления вспомогательного метода: alias_method_chain
, что немного облегчает выполнение этого общего обходного пути.
Но очевидно, что это не очень хорошее решение, так как вы в конечном итоге загрязняете класс странными методами, такими как original_<foo>
или <foo>_with(out)_<feature>
. К счастью, в Ruby 2.0 добавлен новый метод: Module#prepend
, который обеспечивает более чистое решение проблемы:
require 'set'
module AddWithMultipleArgs
def add(*args)
args.each { |arg| super arg }
self
end
end
class Set
prepend AddWithMultipleArgs
end
# Or, you can just call:
# Set.prepend(AddWithMultipleArgs)
s = Set.new
s.add 1,2
#=> #<Set: {1, 2}>
Это работает путем введения вашего нового метода перед исходной версией в цепочке предков класса:
Set.ancestors
#=> [AddWithMultipleArgs, Set, Enumerable, Object, PP::ObjectMixin, Kernel, BasicObject]
Поскольку вы никогда не изменяли исходную версию метода, в самом классе Set
вызов super
будет работать, как вы ожидаете.