2011-09-23 24 views
18

我試圖從哈希(與嵌套哈希)生成attr_reader,以便它自動鏡像instance_variable創建。Ruby:動態生成attribute_accessor

這裏是我到目前爲止有:

data = {:@datetime => '2011-11-23', :@duration => '90', :@class => {:@price => '£7', :@level => 'all'}} 


class Event 
#attr_reader :datetime, :duration, :class, :price, :level 
    def init(data, recursion) 
    data.each do |name, value| 
    if value.is_a? Hash 
     init(value, recursion+1) 
    else 
     instance_variable_set(name, value) 
     #bit missing: attr_accessor name.to_sym 
    end 
    end 
end 

但我不能找到一個辦法做到這一點:(

回答

33

你需要調用(私人)類方法attr_accessorEvent類:

self.class.send(:attr_accessor, name) 

我建議你在這一行添加@

instance_variable_set("@#{name}", value) 

並且不要在散列中使用它們。

data = {:datetime => '2011-11-23', :duration => '90', :class => {:price => '£7', :level => 'all'}} 
+0

你是我的新朋友!!!!這只是工作,是如此簡單...紅寶石是魔術:)而你是一個明星:)(我很高興,因爲我看了一會兒) –

+0

只是一個簡單的問題更多,是否有任何方式預先命名包含散列的訪問者名稱,以便我可以調用my_class.class.price,或類似的東西? –

+0

首先,'class'是一個保留關鍵字,不要使用它。你在這裏評論中的第二個問題超出了這個特定問題的範圍。你可能想開始一個新的問題,因爲它處理遞歸等,而不是屬性訪問器。 (PS,不要忘記接受最好的答案) – rdvdijk

1

attr_accessor是一個類方法,因此需要在類上調用它。它也是一個私有方法,因此您需要在類對象爲self的上下文中調用它。

舉個例子:

class C 
    def foo 
    self.class.instance_eval do 
     attr_accessor :baz 
    end 
    end 
end 

創造C實例,並在該實例上調用foo,該實例後 - 和所有未來實例 - 將包含方法bazbaz=

3

你可以做一點的元魔解決這個問題,使用的method_missing:

class Event 
    def method_missing(method_name, *args, &block) 
    if instance_variable_names.include? "@#{method_name}" 
     instance_variable_get "@#{method_name}" 
    else 
     super 
    end 
    end 
end 

這將完成是允許訪問對象通過object.variable語法實例變量,如果對象具有這些變量而不需要通過attr_accessor來修改整個類。