2010-07-15 3 views
5

Ich versuche, eine Ruby-Klasse zu schreiben, die ähnlich wie Rails AactiveRecord Modell in der Art und Weise funktioniert, dass Attribute gehandhabt werden:Update-Ruby-Klasse Attribute Hash, wenn eine Eigenschaft ändert

class Person 
    attr_accessor :name, :age 

    # init with Person.new(:name => 'John', :age => 30) 
    def initialize(attributes={}) 
    attributes.each { |key, val| send("#{key}=", val) if respond_to?("#{key}=") } 
    @attributes = attributes 
    end 

    # read attributes 
    def attributes 
    @attributes 
    end 

    # update attributes 
    def attributes=(attributes) 
    attributes.each do |key, val| 
     if respond_to?("#{key}=") 
     send("#{key}=", val) 
     @attributes[key] = name 
     end 
    end 
    end 
end 

Was ich meine ist, dass, wenn ich Initiiere die Klasse, ein "Attribut" -Hash wird mit den relevanten Attributen aktualisiert:

>>> p = Person.new(:name => 'John', :age => 30) 
>>> p.attributes 
=> {:age=>30, :name=>"John"} 
>>> p.attributes = { :name => 'charles' } 
>>> p.attributes 
=> {:age=>30, :name=>"charles"} 

So weit so gut. Was ich will, geschehen ist für die Attribute zu aktualisieren Hash, wenn ich eine individuelle Eigenschaft:

>>> p.attributes 
=> {:age=>30, :name=>"John"} 
>>> p.name 
=> "John" 
>>> p.name = 'charles' # <--- update an individual property 
=> "charles" 
>>> p.attributes 
=> {:age=>30, :name=>"John"} # <--- should be {:age=>30, :name=>"charles"} 

ich, dass für jedes Attribut durch das Schreiben einen Setter und Getter tun könnte stattdessen attr_accessor zu verwenden, aber das wird saugen für ein Modell mit vielen Feldern. Jeder schnelle Weg, dies zu erreichen?

+0

In Ihrer 'initialize' Methode müssen Sie keine Attribute mit' send' einstellen. Aktualisiere stattdessen einfach den '@ attributes' Hash. Dasselbe gilt für 'attributes =' method. –

+0

Ich denke, das wäre genug, wo jemand es zu einem einfachen Juwel machen könnte. – NullVoxPopuli

Antwort

7

Das Problem ist, dass Sie Ihre Attribute sowohl als separate Ivars, als auch innerhalb eines @attributes Hash halten. Sie sollten nur eine Möglichkeit wählen und verwenden.

Wenn Sie einen Hash verwenden möchten, sollten Sie Ihren eigenen Weg zur Schaffung von Accessoren machen, die sie zu einer einzigen Methode „Umleiten“ würde die und aus einem Hash bekommen würde eingestellt:

class Class 
def my_attr_accessor(*accessors) 
    accessors.each do |m| 

    define_method(m) do 
     @attributes[m] 
    end   

    define_method("#{m}=") do |val| 
     @attributes[m]=val 
    end 
    end 
end 
end 

class Foo 
    my_attr_accessor :foo, :bar 

    def initialize 
    @attributes = {} 
    end 
end 

foo = Foo.new 

foo.foo = 123 
foo.bar = 'qwe' 
p foo 
#=> #<Foo:0x1f855c @attributes={:foo=>123, :bar=>"qwe"}> 

Wenn Sie Möchten Sie Ivars verwenden, sollten Sie wiederum Ihre eigene attr_accessor Methode erstellen, die sich außerdem daran erinnert, welche Ivars "Attribute" sein sollten, und diese Liste in der attributes Methode verwenden. Und attributes Methode würde einen Hash von ihnen im laufenden Betrieb erstellen und es zurückgeben.

Here können Sie einen schönen Artikel über die Implementierung von Accessoren finden.

+0

klingt cool. Würde es Ihnen etwas ausmachen, einen Code-Vorschlag zu schreiben, wie ich das alles machen könnte? Danke – sa125

+0

Ich illustrierte die erste Methode, die andere für Ihre Praxis verlassen ...;) –

+0

genial, das ist genau das, was ich brauchte. – sa125

Verwandte Themen