Ответ 1
В Ruby 2.0 и более поздних версиях вы можете использовать Module#prepend
:
class Date
prepend DateExtension
end
Оригинальный ответ для более старых версий Ruby приведен ниже.
Проблема с include
(как показано в на следующей диаграмме) заключается в том, что методы класса не могут быть переопределены модулями, включенными в это класс (решения следуют диаграмме):
Решение
-
Подкласс Дата только для этого метода:
irb(main):001:0> require 'date'; module Foo; def next(a=:hi); a; end; end #=> nil irb(main):002:0> class MyDate < Date; include Foo; end #=> MyDate irb(main):003:0> MyDate.today.next(:world) #=> :world
-
Расширьте только нужные вам экземпляры с помощью собственного метода:
irb(main):001:0> require 'date'; module Foo; def next(a=:hi); a; end; end #=> nil irb(main):002:0> d = Date.today; d.extend(Foo); d.next(:world) #=> :world
-
При включении вашего модуля выполняйте грубый взлом и попадаете внутрь класса и уничтожаете старый "следующий", чтобы ваш вызов вызывался:
irb(main):001:0> require 'date' #=> true irb(main):002:0> module Foo irb(main):003:1> def self.included(klass) irb(main):004:2> klass.class_eval do irb(main):005:3* remove_method :next irb(main):006:3> end irb(main):007:2> end irb(main):008:1> def next(a=:hi); a; end irb(main):009:1> end #=> nil irb(main):010:0> class Date; include Foo; end #=> Date irb(main):011:0> Date.today.next(:world) #=> :world
Этот метод гораздо более инвазивен, чем просто модуль, но единственный способ (из тех методов, которые были показаны до сих пор) сделать так, чтобы новые экземпляры Date, возвращаемые системными методами, автоматически использовали методы из вашего собственного модуля.
-
Но если вы собираетесь это сделать, вы можете также полностью пропустить модуль и просто перейти прямо к земле monkeypatch:
irb(main):001:0> require 'date' #=> true irb(main):002:0> class Date irb(main):003:1> alias_method :_real_next, :next irb(main):004:1> def next(a=:hi); a; end irb(main):005:1> end #=> nil irb(main):006:0> Date.today.next(:world) #=> :world
-
Если вам действительно нужна эта функциональность в вашей собственной среде, обратите внимание, что библиотека Prepend by banisterfiend может дать вам возможность чтобы вызвать поиск в модуле перед классом, в который он был смешан.
- Обратите внимание, что
Module#prepend
выглядит входящим в Ruby 2.0.
- Обратите внимание, что