2010-07-15 1 views
5

Я пытаюсь написать класс Ruby, который работает аналогично модели Rails AactiveRecord в том, что атрибуты обрабатываются:Update рубин атрибуты класса хэш, когда свойство изменяет

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 

Что я имею в виду, что, когда я init класс, хеш атрибутов обновляется с соответствующими атрибутами:

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

Пока все хорошо. То, что я хочу, чтобы это произошло для атрибутов хэш для обновления, когда я установил индивидуальную собственность:

>>> 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"} 

Я мог бы сделать это, написав и присваивателя для каждого атрибута вместо attr_accessor, но это будет сосать для модель, в которой много полей. Любой быстрый способ сделать это?

+0

В вашем методе 'initialize' вам не нужно устанавливать атрибуты с помощью' send'. Просто обновите хэш '@ attributes'. То же самое касается метода 'attributes ='. –

+0

Я чувствую, что это было бы достаточно распространено, когда кто-то мог превратить его в простой драгоценный камень. – NullVoxPopuli

ответ

7

Проблема в том, что вы сохраняете свои атрибуты как отдельными иварами, так и в хеше @attributes. Вы должны выбирать и использовать только один способ.

Если вы хотите использовать хэш, вы должны сделать свой собственный путь создания аксессоров, который бы «перенаправлять» их в один метод, который установил бы и получить из хэша:

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"}> 

Если у вас вы хотите использовать ivars, вы должны снова опрокинуть свой собственный метод attr_accessor, который, кроме того, помнит, какие ivars должны быть «атрибутами», и использовать этот список в методе attributes. И метод attributes создавал бы хэш из них на лету и возвращал его.

Here вы можете найти хорошую статью о внедрении аксессуаров.

+0

звучит круто. не могли бы вы напомнить о некоторых предложениях о том, как я могу все это сделать? спасибо – sa125

+0

Я проиллюстрировал первый метод, оставив другой для вашей практики ...;) –

+0

Удивительно, это именно то, что мне нужно. – sa125