#ruby
#ruby
Вопрос:
Есть ли способ переопределить оператор класса, создав новый операторный метод внутри модуля, затем смешав этот модуль с классом?
например, это переопределяет оператор Fixnum :
class Fixnum
def (x)
product = x
product = product * self
return product
end
end
p 3 3
# => 9
Это не переопределяет оператор Fixnum :
module NewOperators
def (x)
product = x
product = product * self
return product
end
end
class Fixnum
include NewOperators
end
p 3 3
# => 6
Комментарии:
1. Это дубликат переопределяющего метода другим, определенным в модуле, и можете ли вы переопределить метод, включив модуль? плюс, я подозреваю, пара других. Короткий ответ таков: нет, вы не можете переопределять методы в подклассе методами в суперклассе, потому что наследование работает не так. Все с точностью до наоборот.
Ответ №1:
Ваш вопрос привел меня к этой интересной статье, в которой описывается проблема:
Исправление модели наследования Ruby с помощью Metamorph
На мой взгляд, это основная проблема с моделью наследования Ruby. Поскольку mixins всегда имеют более низкий приоритет, чем методы, определенные непосредственно в теле класса, #foo не может быть переопределен путем включения mixin. Более того, поскольку mixins имеют более низкий приоритет, чем методы, #foo теперь нарушает инкапсуляцию […]
И его решение заключается в прозрачном определении всех новых методов внутри анонимного внутреннего модуля:
class Object
def self.method_added(name)
return if name == :initialize
const_set(:InstanceMethods, Module.new) unless defined?(self::InstanceMethods)
meth = instance_method(name)
self::InstanceMethods.send(:define_method, name) {|*args, amp;block| meth.bind(self).call(*args, amp;block) }
remove_method(name)
include self::InstanceMethods
end
end
Это также удобно упаковано в библиотеку под названием metamorph, которая позволяет вам использовать методы mixin для переопределения методов класса, просто требуя этого.
Ответ №2:
Нет, потому что при поиске метода у вас нет возможности использовать методы, которые были определены в mixins или родительских классах, пока вы на самом деле не посмотрите на текущий класс.
Тем не менее, вы можете создать метод, который при вызове в классе будет создавать методы в этом классе. Это может дать вам возможность легко внедрять операторы в классы.
Имейте в виду, что на самом деле это хороший способ преподнести сюрприз. Это вдвойне верно, когда вы меняете стандартные модули, на поведение которых полагаются другие. Смотрите http://avdi.org/devblog/2008/02/23/why-monkeypatching-is-destroying-ruby / для контекста.
Комментарии:
1. Интересная статья! Я вижу, как обезьянье исправление вышло бы из-под контроля для больших проектов.