2017-04-18 1 views
0

Ich habe ein Projekt, wo ich dynamisch Attribute für eine Klasse erstellen und diese Attribute werden auch als Hash in einer anderen Eigenschaft gespeichert, die als eine Sammlung all dieser Attribute und ihrer Werte dient. Was ich möchte in der Lage sein, das Attribut zu tun ist, zu aktualisieren, wenn der Hash aktualisiert wird und umgekehrt.Update-Attribut auf der Grundlage der Aktualisierung von Hash

Etwas wie folgt aus:

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 

Verbrauch:

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 

ich das letzte Aufforderung von möchten:

x.abc 

10 zurück, weil der Wert der Konfiguration aktualisiert wurde . Ist das möglich? Wenn ja, wie mache ich das? Hier

+0

@engineersmnky auslesen würde, obwohl beide Richtungen das funktionieren? Ich mag „@configuration“ aktualisiert werden, wenn die „@abc“ aktualisiert und „@abc“ aktualisiert, wenn „@configuration“ aktualisiert –

Antwort

1

ist ein erweitertes Beispiel dafür, was ich glaube, Sie zu erreichen versuchen.

I Eine Klasse für Configuration erstellt, um vordefinierte Schlüssel zu verwalten, sodass Sie die Schlüssel im Hash nicht ändern können. Ich habe es nur Zugang zu [] und []= und hinzugefügt to_h für Hash aber düpiert die @configuration so können Sie es nicht manipulieren durch entweder dort.

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 

Dann sollen Sie Ihren Anwendungsfall entsprechend arbeiten. Alles, was Sie tun müssen, ist den Schlüssel aus der Datei anstelle der statisch definierten PREDEFINED_KEYS

Nutzungs

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

Das ist großartig. Ich sehe Ihre Implementierung der Konfigurationsklasse nicht. Kannst du das bitte posten? –

+0

Nevermind ich sehe es. Scroll nicht im Codeblock nach unten. Vielen Dank! –

Verwandte Themen