翌日を返すインスタンスメソッド_Date#next
_を定義したい。そこで、次のようにDateExtension
モジュールを作成しました。
_module DateExtension
def next(symb=:day)
dt = DateTime.now
{:day => Date.new(dt.year, dt.month, dt.day + 1),
:week => Date.new(dt.year, dt.month, dt.day + 7),
:month => Date.new(dt.year, dt.month + 1, dt.day),
:year => Date.new(dt.year + 1, dt.month, dt.day)}[symb]
end
end
_
それを使う:
_class Date
include DateExtension
end
_
メソッドd.next(:week)
を呼び出すと、RubyエラーがスローされますArgumentError: wrong number of arguments (1 for 0)
。デフォルトのnext
メソッドをDate
DateExtension
モジュールで宣言されたクラスを持つクラス?
Ruby 2.0以降では Module#prepend
:
class Date
prepend DateExtension
end
以前の元の答えRubyバージョンは以下のとおりです。
include
の問題( 次の図 に示すように)は、クラスのメソッドをそのクラスに含まれるモジュールでオーバーライドできないことです(解決策は図に従います):
この1つのメソッドだけのサブクラスの日付:
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インスタンスが自動的に独自のモジュールのメソッドを使用できるようにするための(これまでに示した手法の)唯一の方法です。
しかし、これを行う場合は、モジュールを完全にスキップして、モンキーパッチランドに直接移動することもできます。
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
独自の環境でこの機能が本当に必要な場合は、banisterfiendの Prepend ライブラリを使用すると、モジュールが混在するクラスの前にモジュールでルックアップを実行できるようになることに注意してください。
Module#prepend
は Ruby 2. 。に入る)のように見えますnext
のDate
メソッドはDate
クラスで定義され、クラスで定義されたメソッドは、インクルードされたモジュールで定義されたメソッドよりも優先されます。したがって、これを行うと:
class Date
include DateExtension
end
next
のバージョンを取得していますが、next
で定義されているDate
が引き続き優先されます。 next
をDate
に入れる必要があります。
class Date
def next(symb=:day)
dt = DateTime.now
{:day => Date.new(dt.year, dt.month, dt.day + 1),
:week => Date.new(dt.year, dt.month, dt.day + 7),
:month => Date.new(dt.year, dt.month + 1, dt.day),
:year => Date.new(dt.year + 1, dt.month, dt.day)}[symb]
end
end
プログラミングからRuby クラスとオブジェクト)の章 :
クラスにモジュールが含まれている場合、そのモジュールのインスタンスメソッドは、クラスのインスタンスメソッドとして使用可能になります。これは、モジュールがそれを使用するクラスのスーパークラスになるかのようです。当然のことながら、それはそれがどのように機能するかについてです。モジュールをインクルードすると、Rubyはそのモジュールを参照する匿名プロキシクラスを作成し、インクルードを行ったクラスの直接のスーパークラスとしてそのプロキシを挿入します。