Скажем, у нас есть класс, который мы не можем изменить,
class C
def foo
super
puts "Low!"
end
end
Нам нужно будет динамически определять метод foo
во что-то, что мы сможем внедрить в C. родословная. Поведение super
должно быть указано c для данного объекта, а не для всего класса. Мы сможем заключить эту логику c в анонимный модуль (назовем его сейчас):
module M
def foo
puts "High!"
end
end
Расширение экземпляра C
с помощью модуля:
c = C.new
c.extend(M)
c.foo
# High!
не будет работать, так как мы поместили метод из модуля перед методом, который мы определили в классе. Глядя на предков нашего объекта
c.singleton_class.ancestors
# => [#<Class:#<C:0x00005652be630b20>>, M, C, ...]
, я нашел уродливый обходной путь, который переопределяет методы из нашего класса в нашем singleton_class, т.е.
c.define_singleton_method(:foo, c.class.instance_method(:foo))
c.foo
# High!
# Low!
Пока это работает (делает это работать? Я проверил это немного, и, кажется, но я больше не уверен), мне интересно, упускаю ли я что-то очевидное, и есть ли более простой способ динамически определить «супер» метод для экземпляра класс.
Чтобы было ясно, мы хотим иметь возможность расширять другой экземпляр C
другим модулем, то есть
C.new.extend(Module.new do
def foo
puts "Medium!"
end
end).foo
# Medium!
# Low!
, и чтобы его выходные данные не были испорчены другими экземплярами.