res*_*a87 37 ruby methods module
我想定义一个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
Run Code Online (Sandbox Code Playgroud)
使用它:
class Date
include DateExtension
end
Run Code Online (Sandbox Code Playgroud)
调用该方法d.next(:week)
会使Ruby抛出错误ArgumentError: wrong number of arguments (1 for 0)
.如何使用模块中声明的next
方法覆盖Date
类中的默认方法DateExtension
?
Phr*_*ogz 107
在Ruby 2.0及更高版本中,您可以使用Module#prepend
:
class Date
prepend DateExtension
end
Run Code Online (Sandbox Code Playgroud)
旧版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
Run Code Online (Sandbox Code Playgroud)使用您自己的方法扩展您需要的实例:
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
Run Code Online (Sandbox Code Playgroud)在包含你的模块时,执行一个严重的黑客攻击并进入类内部并销毁旧的'next'以便调用你的模块:
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
Run Code Online (Sandbox Code Playgroud)
这种方法比仅包含一个模块更具侵入性,但是(目前为止所示技术)的唯一方法是使系统方法返回的新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
Run Code Online (Sandbox Code Playgroud)如果您确实需要在自己的环境中使用此功能,请注意banisterfiend的Prepend库可以使您能够在混合它的类之前在模块中进行查找.
Module#prepend
看起来将在Ruby 2.0中出现.类中定义的next
方法和类中Date
定义的Date
方法优先于包含模块中定义的方法.所以,当你这样做时:
class Date
include DateExtension
end
Run Code Online (Sandbox Code Playgroud)
您正在提取您的版本,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
Run Code Online (Sandbox Code Playgroud)
从关于类和对象的编程Ruby章节:
当类包含模块时,该模块的实例方法可用作类的实例方法.这几乎就像模块成为使用它的类的超类一样.毫不奇怪,这是关于它是如何工作的.当您包含一个模块时,Ruby会创建一个引用该模块的匿名代理类,并将该代理作为执行该类的类的直接超类插入.
归档时间: |
|
查看次数: |
24349 次 |
最近记录: |