2013-02-17 52 views
2

我有兩個類A和B,他們都有一些選項,通常我會用一個哈希來存儲選項,如@options[:name]='xxxx';現在我想重構使用元編程它,如何在Ruby中像這樣設置哈希實例的值?

class A 
    set_option :name, "james" 
    set_option :address, "some street" 

    def hello 
     puts @options[:name] 
     puts @options[:address] 
    end 
end 


class B 
    set_option :age, 18 

    def greeting 
     put @options[:age] 
    end 
end 

在這裏,我想用set_option設置鍵&值對一個哈希例如@options,我該怎麼辦呢?

此外我想將解決方案包裝到單獨的模塊中。

更新:

首先感謝,所有的答案都對我有價值,讓我更清楚,現在我知道有些事情我想也不是那麼準確,所以如果我作出這樣的問題?

  • 怎樣用一種方法option來代替@options
  • A和B兩個類都可以爲同一個鍵設置不同的選項,所以可能會有一些答案'@@options將不起作用?我希望不同的類可以有不同的哈希實例。

``` 這樣的:

class A 
    set_option :name, "james" 
    set_option :provider, 'twitter' 

    def hello 
     puts option[:name] 
    end 
end 


class B 
    set_option :name, "not james" 

    def greeting 
     put option[:name] 
    end 
end 

左思右想,我認爲我真正想要的是不同的類,而不是類的實例不同的選項哈希實例。

這是我想要的,它可以工作。

module HasOptions 
    def self.included(cls) 
    cls.class_eval do 
     def self.set_option(key, value) 
     options[key] = value 
     end 

     def self.options 
     @options ||= {} 
     end 

     def options 
     self.class.options 
     end 
    end 
    end 
end 


class Baz 
    include HasOptions 
    set_option :name, "bad" 

    def greeting 
     puts options[:name] 
    end 
end 

class Foo 
    include HasOptions 
    set_option :name, "foo" 

    def greeting 
     puts options[:name] 
    end 
end 

感謝您的幫助。

回答

5

正如你試圖做的那樣使用一個實例變量是行不通的。但是,你可以使用的方法是這樣的:

module HasOptions 
    def self.included(cls) 
    cls.class_eval do 
     def self.set_option(key, value) 
     (@@options ||= {})[key] = value 
     end 
    end 
    end 

    def options 
    @options ||= @@options.dup 
    end 
end 

此實現允許您設置每個實例的選項,而不會覆蓋所有實例的共同選擇。

1

如果你想要初始化實例選項,你應該使用實例方法來完成它。

module OptionSetter 
    def set_option(key, value) 
    @options[key] = value 
    end 
end 

class Base 
    def initialize(options = {}) 
    @options = {} 
    options.each do |key, value| 
     set_option key, value 
    end 
    end 
end 

class A < Base 
    include OptionSetter 

    def hello 
    puts @options[:name] 
    puts @options[:address] 
    end 
end 

class B < Base 
    include OptionSetter 

    def greeting 
    puts @options[:age] 
    end 
end 

A.new(name: "james", address: "some street").hello 
B.new(age: 18).greeting 

,使其在Ruby中比較常見的方法是使用attr_accessor

class Base 
    attr_accessor :options 

    def initialize(options = {}) 
    @options = options 
    end 
end 

class A < Base 
    def hello 
    puts @options[:name] 
    puts @options[:address] 
    end 
end 

class B < Base 
    def greeting 
    puts @options[:age] 
    end 
end 

A.new(name: "james", address: "some street").hello 
B.new(age: 18).greeting 

# another approach 
james = A.new 
james.options[:name] = "james" 
james.options[:address] = "some street" 
james.hello 
2

它看起來像你搞亂的東西一點點。讓我試着列出要解決的問題:

  • 存儲選項類的一個實例變量Hash(爲什麼我得到了它正確的酮哈希你的類的所有實例?);
  • 使用漂亮的表示法來設置選項。

上述內容都不需要實際的元編程。爲了滿足第一個條件,您只需簡單地找到所有類的第一個共同祖先,然後[monkey]用您的@@options var和set_option方法修補它。如果您決定不提供自己的父類所有的類,讓我們修補非常祖先(如Kernel模塊):

module Kernel 
    def set_option name, value 
    (@@options ||= {})[name.to_sym] = value 
    end 
end 

現在,任何一個分類可以包括set_option「指令」把選項共享選項如果你想擁有的選項設置花花哨的語法(使用默認值,就地跳棋,ruches和豪華哈希(考慮使用實例變量@options,而不是@@options使特定實例的選項,或使用亞歷克斯·D的解決方案。)

商品),您在這裏使用DSLthis article中的第一個示例顯示瞭如何使用DSL實現純粹的set_option。進一步的調整隻限於你的想象力。

+0

感謝@mudasobwa,對於您列出的問題項目,第一個不是我想要的,我想爲不同的類使用不同的哈希實例。 – donnior 2013-02-18 03:36:35

+0

@donnior然後在評論中建議的任何解決方案中簡單地擺脫雙「@」,轉而選擇「@ options」.-) – mudasobwa 2013-02-18 06:15:04