2016-05-05 86 views

回答

6

而不是每個鍵的實例變量,這需要一些不必要的笨重的代碼,爲什麼不只是像下面的單個哈希。此外,define_methoddefine_singleton_method可以是你的朋友,以避免不好的壞eval s。

class MyStorageClass 
    def initialize 
    @data = {} 
    end 

    def add_entry(key, value) 
    (@data[key] ||= []) << value 
    define_singleton_method(key){ @data[key] } 
    end 

    def get_entry(key) 
    @data.key?(key) or raise NoMethodError 
    @data[key] 
    end 
end 

你可能要檢查你沒有(在add_entry方法都不能做到的頂部[email protected]?(key) && self.respond_to?(key))覆蓋預定義的方法首先,但那是另一個談話。例如,如果有人試圖添加名爲inspect,class或哦,get_entry的密鑰,可能會很糟糕!

+0

你也可以初始化@data與Hash.new {[]},所以你不需要,|| =部分add_entry方法 – karina

+1

危險!它必須是'Hash.new {| h,k | h [k] = []}',否則所有新鍵獲得與其他鍵相關的值。你傳遞的[]對象是內存中的一個單獨對象,將被所有的鍵引用,我們使用的'<<'運算符會修改該對象。試試看! 'h = Hash.new([]); h [:x] << 1; h [:y]'給你'[1]'。除了保存'|| =' –

+0

以外,我通常會選擇使用哈希的塊初始化程序,但我確實使用了大括號。 – karina

0

我不知道你所說的「更合理」,但這裏是模板而不eval s到開始::

class MyStorageClass 

    def add_entry key, value 
     eval "(@#{key} ||= []) << value; def #{key}; @#{key}; end" 
    end 

end 

於是我可以如下檢索值

def add_entry key, value 
    # define instance variable unless it is already defined 
    instance_variable_set :"@#{key}", [] \ 
    unless instance_variable_defined? :"@#{key}" 
    # add value to the array 
    instance_variable_set :"@#{key}", instance_variable_get(:"@#{key}") + value 
    # define getter 
    self.class.send :define_method key { instance_variable_get :"@#{key}" } \ 
    unless self.class.instance_methods.include?(key) 
end 

吸氣劑可能以更易讀的方式定義:

self.class.send :attr_reader, key \ 
    unless self.class.instance_methods.include?(key) 
0

這可以通過使用instance_variable_setattr_accessor來實現:

class MyStorageClass 
    def add_entry(key, value) 
    if respond_to?(key) 
     key << value 
    else 
     instance_variable_set("@#{key}", [value]) 
     self.class.send(:attr_accessor, key) 
    end 
    end 
end 

然而如其他人所說,一個更簡潔的方法就是使用一個Hash,而不是定義爲每個變量一個新的實例方法。

1

IMO這是一個非常糟糕的想法。不要這樣做!你將會增加複雜性,而且收益甚微。

我推薦改爲OpenStruct。這些都是偉大的對象 - 您可以隨意調用getter和setter,而無需事先指定屬性。也許有點低效,但通常並不重要。

OpenStruct的一個好處是您可以將您的屬性分組爲邏輯集,例如, connection_options,formatting_options,等等。這裏是一個示例腳本來說明:

#!/usr/bin/env ruby 

require 'ostruct' 

class MyClass 

    attr_reader :config_options # only if you want to expose this 

    def initialize 
    @config_options = OpenStruct.new 
    end 

    def do_something 
    config_options.color = 'yellow' 
    config_options.size = 'medium' 
    end 

    def to_s 
    config_options.to_h.to_s 
    end 
end 

my_class = MyClass.new 
my_class.do_something 
puts my_class # outputs: {:color=>"yellow", :size=>"medium"} 
+0

['Hashie :: Mash'](https://github.com/intridea/hashie#mash)? – mudasobwa

+0

@mudasobwa上下文/細化,請問 –

+0

我只是想放下一個偉大的圖書館的鏈接,那就是[恕我直言]所有的意思都是更好的「OpenStruct」。 – mudasobwa