我有一个项目,我在一个类上动态创建属性,这些属性也作为哈希存储在另一个属性中,该属性用作所有这些属性及其值的集合。我希望能够做的是在更新哈希时更新属性,反之亦然。
这样的事情:
class SomeClass
def initialize
#code that creates the attributes on the class
config_list.each { |config| self.class.send(:attr_accessor, config) }
end
#list of attributes that are dynamically added to the class
#this is normally read from a config file but I added it here to simplify
def config_list
[:abc, :def, :ghi]
end
def configuration
config_list.inject({}) do |r,e|
r[e] = instance_variable_get("@#{e.to_s}"); r
end
end
end
用法:
x = SomeClass.new
#=> #<SomeClass:0x007f9931990710>
x.abc = 5
#=> 5
x.configuration
#=> {:abc=>5, :def=>nil, :ghi=>nil}
x.configuration[:abc] = 10
#=> 10
x.abc
#=> 5
我想要最后一次电话会议:
x.abc
返回10,因为配置的值已更新。那可能吗?如果是这样,我该怎么做?
答案 0 :(得分:1)
以下是我认为你想要实现的一个扩展示例。
我为Configuration
创建了一个类来管理预定义的键,这样就无法操作哈希中的键。我只授予其[]
和[]=
访问权限,并为to_h
添加了Hash
,但却欺骗了@configuration
,因此您无法通过其中操纵它。
class SomeClass
# build this list in anyway you see fit
PREDEFINED_KEYS = [:abc, :def, :ghi]
# define getter/setter methods for the PREDEFINED_KEYS
PREDEFINED_KEYS.each do |m|
define_method(m) do
@configuration[m]
end
define_method("#{m}=") do |val|
@configuration[m] = val
end
end
# intialize a new Configuration with the PREDEFINED_KEYS
def initialize
@configuration = Configuration.new(PREDEFINED_KEYS)
end
# alternate implementation using initialize instead of a constant
# def initialize(keys)
# @configuration = Configuration.new(keys)
# instance_eval do
# keys.each do |m|
# define_singleton_method(m) do
# @configuration[m]
# end
# define_singleton_method("#{m}=") do |val|
# @configuration[m] = val
# end
# end
# end
# end
# Usage: SomeClass.new([:abc,:def,:ghi])
# accept a block and return the configuration class
def configuration
yield @configuration if block_given?
@configuration
end
# convert to a proper Hash
def to_h
@configuration.to_h
end
class Configuration
class UndefinedKeyError < StandardError;end
# start out all keys with a value of nil
def initialize(keys)
@configuration = Hash[keys.product([nil])]
end
# retrieve value by key just like a normal Hash
def [](k)
@configuration[k]
end
# set value by key like a normal Hash
# excepting the key must be one of the keys defined in initialization
def []=(k,v)
raise(UndefinedKeyError, "must be one of #{@configuration.keys}") unless @configuration.has_key?(k)
@configuration[k] = v
end
def to_h
@configuration.dup
end
end
end
然后您的用例应该正常工作。您所要做的就是从文件中读出密钥,而不是静态定义的PREDEFINED_KEYS
用法
s = SomeClass.new
s.abc = 12
s.to_h
#=> {abc: 12, def: nil, ghi: nil}
s.configuration[:def] = 19
s.to_h
#=> {abc: 12, def: 19, ghi: nil}
s.configuration do |c|
c[:ghi] = 22
end.to_h
#=> {abc: 12, def: 19, ghi: 22}
s.ghi
#=> 22
s.configuration[:rbc] = 19
#=> SomeClass::Configuration::UndefinedKeyError: must be one of [:abc, :def, :ghi]
s.configuration[:lmn]
#=> nil