2017-04-18 83 views
0

我有一個項目,我在一個類上動態創建屬性,這些屬性也作爲散列存儲在另一個屬性中,作爲所有這些屬性及其值的集合。我希望能夠做的是在更新散列時更新屬性,反之亦然。基於哈希更新的更新屬性

事情是這樣的:

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

@engineersmnky將這項工作雖然兩者兼得?我希望「@configuration」在更新「@abc」時更新,當「@configuration」更新時更新「@abc」 –

回答

1

下面是我相信你試圖實現的一個擴展示例。

我創建了一個Configuration的類來管理預定義的鍵,以便您無法操作散列中的鍵。我只給了它[][]=的訪問權限,併爲Hash添加了to_h,但是騙了@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 
+0

這很棒。我沒有看到你的配置類的實現。你可以發佈嗎? –

+0

沒關係,我看到它。沒有在代碼塊中向下滾動。謝謝! –