考虑这个课程
class Duck
attr_accessor :name
def initialize(name)
@name = name || 'Donald'
end
# Some quacking methods..
def to_s
"#{@name} (Duck)"
end
end
我希望我的鸭子回复upcase
,sub
,gsub
等方法,以便我能做到
my_duck = Duck.new("Scrooge")
my_duck.upcase
--> "SCROOGE (DUCK)"
除了手动实现这些方法之外,还有一种很好的方法我可以选择不会自我变异的String方法并自动让我的类响应那些,然后调用to_s
然后调用结果上的方法字符串?
答案 0 :(得分:7)
您可以使用Forwardable
模块:
require 'forwardable'
class Duck
extend Forwardable
# This defines Duck#upcase and Duck#sub, you can
# add as many methods as you like.
def_delegators(:to_s, :upcase, :sub)
# All the other code here...
end
Duck.new('duffy').upcase
# => DUFFY (DUCK)
Duck.new('rubber').respond_to?(:upcase)
# => true
通常,调用def_delegators(:foo, :bar)
等同于手动定义bar
方法:
def bar(*args, &block)
foo.bar(*args, &block)
end
def_delegators
的第一个参数可以是实例变量的名称,即def_delegators(:@foo, :bar, :baz)
。
答案 1 :(得分:2)
您可以使用method_missing
方法检查to_s
实现的返回值是否响应此方法并调用它,如果是这种情况。
class Duck
attr_accessor :name
def initialize(name)
@name = name || 'Donald'
end
# Some quacking methods..
def to_s
"#{@name} (Duck)"
end
def method_missing(m, *args, &block)
raise NoMethodError unless self.to_s.respond_to? m
self.to_s.send(m, *args, &block)
end
end
d = Duck.new "Donald"
puts d.upcase # DONALD (DUCK)
puts d.swapcase # dONALD (dUCK)
puts d.downcase # donald (duck)
puts d.sub('D') { |m| m.downcase } # donald (Duck)
答案 2 :(得分:1)
正如我理解你的问题,你希望有一些字符串模块可以混合到你的Animal类中。但是,String是一个类,从String访问方法的唯一方法是继承String和类之间紧密耦合的负担。
如果你需要重复使用很多String操作,我会定义一个模块:
module StringMixins
def upcase
# see e.g. Rubinius link below
end
# ...
end
和include StringMixins
进入目标类。那看起来像是:
class Duck
include StringMixins
# ...
end
Rubinius upcase实施:https://github.com/rubinius/rubinius/blob/master/kernel/common/string.rb#L735-L738