让我们先看看代码,这将对我想要实现的目标有所帮助:
class PostalInfo
attr_reader :name, :code
def initialize (id, name, code)
@id = id
@name = name
@code = code
end
def method_missing(method, *args, &blk)
if method.to_s == "#{name}"
return code
else
super
end
end
end
pi1 = PostalInfo.new(1, 'united_states', 'US')
pi2 = PostalInfo.new(2, 'united_kingdom', 'UK')
因此,当我运行以下代码时,其输出为:
pi1.united_states => 'US'
pi2.united_kingdom => 'UK'
到现在为止还不错,但我也想做类似的事情
PostalInfo.united_states => 'US'
PostalInfo.united_kingdom => 'UK'
该如何做,请先谢谢
答案 0 :(得分:0)
这将设置一个类属性来保存数据,并且每当实例被初始化时,它就会添加到该数据结构中,并使用类似的类级别method_missing
。
class PostalInfo
attr_reader :name, :code
@@postal_info = {}
def self.method_missing(method, *args, &blk)
name = method.to_s
if @@postal_info[name]
@@postal_info[name]
else
super
end
end
def initialize (id, name, code)
@id = id
@name = name
@code = code
@@postal_info[@name] = @code
end
def method_missing(method, *args, &blk)
if method.to_s == "#{name}"
return code
else
super
end
end
end
pi1 = PostalInfo.new(1, 'united_states', 'US')
pi2 = PostalInfo.new(2, 'united_kingdom', 'UK')
PostalInfo.united_states #=> 'US'
PostalInfo.united_kingdom #=> 'UK'
我会说,这似乎是一个怪异的设计,我通常建议避免在类方法中使用可变状态,并尽可能避免使用method_missing
。
答案 1 :(得分:0)
您可以这样写:
class PostalInfo
POSTAL_HASH = {
united_states: 'US',
united_kingdom: 'UK',
}.freeze
def self.method_missing(method, *args, &blk)
POSTAL_HASH[method] || super
end
end
跳过缺少的方法可能会导致更好的性能:
class PostalInfo
POSTAL_HASH = {
united_states: 'US',
united_kingdom: 'UK',
}.freeze
class << self
POSTAL_HASH.each do |name, code|
define_method(name) do
code
end
end
end
end
答案 2 :(得分:0)
除了一个例外,您需要在类的单例类中模拟答案的第一部分中的代码。区别在于实例变量的初始化。无需使用PostalInfo::new
和PostalInfo#initialize
,而是需要创建一个用于执行此操作的类方法(我将其称为add_country_data
)。请注意,由于未使用类的实例变量id
,因此我没有将其包含在代码中。
class PostalInfo
class << self
attr_reader :country_data
def add_country_data(name, code)
(@country_data ||= {})[name] = code
end
def add_country_data(name, code)
@country_data[name] = code
end
def method_missing(method, *args, &blk)
return country_data[method.to_s] if country_data.key?(method.to_s)
super
end
end
end
PostalInfo.add_country_data('united_states', 'US')
PostalInfo.add_country_data('united_kingdom', 'UK')
PostalInfo.united_states
#=> "US"
PostalInfo.united_kingdom
#=> "UK"
PostalInfo.france
#=> NoMethodError (undefined method `france' for PostalInfo:Class)
尽管这符合您的要求,但我倾向于以更常规的方式构造该类:
class PostalInfo
attr_reader :name, :code
@instances = []
def initialize(name, code)
@name = name
@code = code
self.class.instances << self
end
singleton_class.public_send(:attr_reader, :instances)
end
us = PostalInfo.new('united_states', 'US')
uk = PostalInfo.new('united_kingdom', 'UK')
us.code
#=> "US"
uk.code
#=> "UK"
PostalInfo.instances
#=> [#<PostalInfo:0x00005c1f24c5ccf0 @name="united_states", @code="US">,
# #<PostalInfo:0x00005c1f24c71858 @name="united_kingdom", @code="UK">]