In Ruby 2.0 and later you can use Module#prepend
:
class Date
prepend DateExtension
end
Original answer for older Ruby versions is below.
The problem with include
(as shown in the following diagram) is that methods of a class cannot be overridden by modules included in that class (solutions follow the diagram):
Solutions
-
Subclass Date just for this one method:
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
-
Extend just the instances you need with your own method:
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
-
When including your module, perform a gross hack and reach inside the class and destroy the old ‘next’ so that yours gets called:
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
This method is far more invasive than just including a module, but the only way (of the techniques shown so far) to make it so that new Date instances returned by system methods will automatically use methods from your own module.
-
But if you’re going to do that, you might as well skip the module altogether and just go straight to monkeypatch land:
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
-
If you really need this functionality in your own environment, note that the Prepend library by banisterfiend can give you the ability to cause lookup to occur in a module before the class into which it is mixed.
- Note that
Module#prepend
looks to be coming in Ruby 2.0.
- Note that