Cho*_*ett 11 ruby class-method instance-method
在Ruby中,假设我有一个类Foo允许我对我的大量Foos进行编目.所有Foos都是绿色和球形的,这是一个基本的自然法则,所以我定义了类方法如下:
class Foo
def self.colour
"green"
end
def self.is_spherical?
true
end
end
Run Code Online (Sandbox Code Playgroud)
这让我做到了
Foo.colour # "green"
Run Code Online (Sandbox Code Playgroud)
但不是
my_foo = Foo.new
my_foo.colour # Error!
Run Code Online (Sandbox Code Playgroud)
尽管事实上my_foo是明显的绿色.
显然,我可以定义一个colour调用的实例方法self.class.colour,但是如果我有很多这样的基本特征,那就很难实现.
我也可以通过定义method_missing为任何缺失的方法尝试类来做到这一点,但我不清楚这是我应该做的事情还是丑陋的黑客,或者如何安全地进行(特别是因为我实际上在ActiveRecord下在Rails中,我理解用method_missing做一些Clever Fun Stuff).
你会推荐什么?
Way*_*rad 23
Ruby附带的Forwardable模块可以很好地完成这项工作:
#!/usr/bin/ruby1.8
require 'forwardable'
class Foo
extend Forwardable
def self.color
"green"
end
def_delegator self, :color
def self.is_spherical?
true
end
def_delegator self, :is_spherical?
end
p Foo.color # "green"
p Foo.is_spherical? # true
p Foo.new.color # "green"
p Foo.new.is_spherical? # true
Run Code Online (Sandbox Code Playgroud)
Vad*_*rov 11
如果它是普通的Ruby,那么使用Forwardable就是正确的答案
如果它是Rails,我会使用委托,例如
class Foo
delegate :colour, to: :class
def self.colour
"green"
end
end
irb(main):012:0> my_foo = Foo.new
=> #<Foo:0x007f9913110d60>
irb(main):013:0> my_foo.colour
=> "green"
Run Code Online (Sandbox Code Playgroud)
您可以定义一个直通设施:
module Passthrough
def passthrough(*methods)
methods.each do |method|
## make sure the argument is the right type.
raise ArgumentError if ! method.is_a?(Symbol)
method_str = method.to_s
self.class_eval("def #{method_str}(*args) ; self.class.#{method_str}(*args) ; end")
end
end
end
class Foo
extend Passthrough
def self::colour ; "green" ; end
def self::is_spherical? ; true ; end
passthrough :colour, :is_spherical?
end
f = Foo.new
puts(f.colour)
puts(Foo.colour)
Run Code Online (Sandbox Code Playgroud)
我通常不喜欢使用eval,但在这里它应该非常安全。