2017-05-22 68 views
0

我有一個Rails應用程序,需要重複設置默認屬性。有時候用戶會爲將被尊重的屬性提供值,但在其他情況下,模型或用戶可能希望這些屬性被忽略原始值的默認值覆蓋。使用可選的默認值創建屬性訪問器

我猜想這個問題需要一個砰的一聲(!)和non-banged方法設置默認值,允許用戶和程序切換到適當的狀態。非打破的setter只會在默認值不爲零時設置默認值,而被打破的版本將始終用默認值覆蓋屬性。所不同的是次要的:

class BangDiBang 
    attr_accessor :value 

    def set_default 
    self.value ||= do_some_suff_to_determine_default_value 
    end 

    def set_default! 
    self.value = do_some_suff_to_determine_default_value 
    end 

    ... 
end 

這段代碼的問題是,如果我有一堆的變量設置,我將結束重複相同的代碼兩次,每次變量。

我的問題是如何偏出這段代碼?用一種方法保存邏輯,並用兩種方法set_valueset_value!用不同的賦值操作符調用中心邏輯。

我已經想出了一個解決方案:將中心邏輯寫爲文本,從setter方法中替換賦值操作並進行評估(但這不太合適)。我怎麼不重複自己?

+0

如何創建關注點並將它們包含在需要它們的任何地方? – Severin

回答

0

因爲您打電話給set_default,但是您沒有指定哪個變量,所以您要這樣做的方式不適用於多個參數。理想情況下,您需要定義每個變量的行爲。有跡象表明,處理這樣的事情庫,但你可以滾你自己很容易:

class Example 
    def self.default_param(name, default_value) 
    define_method("default_#{name}") { default_value } 

    define_method(name) do 
     instance_variable_get("@#{name}") || default_value 
    end 

    attr_writer name 
    end 

    default_param :foo, 'foo default' 
end 

ex = Example.new 
ex.foo #=> "foo default" 
ex.foo = 'bar' 
ex.foo #=> "bar" 
ex.default_foo #=> "foo default" 

我已經改名爲set_defaultset_default!更加清晰:用默認值每個變量,創建三個方法(例如,使用foo作爲變量名):

  1. foo - 返回的@foo值,如果它是truthy,和default_foo否則
  2. foo= - 設置的值
  3. default_foo - 返回指定的默認

您可以劃分和乾涸上面一些進一步的代碼,創建一個default_params(複數)方​​法取一個散列,提取類宏關注:

module DefaultParams 
    def default_param(name, default_value) 
    define_method("default_#{name}") { default_value } 

    define_method(name) do 
     instance_variable_get("@#{name}") || default_value 
    end 

    attr_writer name 
    end 

    def default_params(params) 
    params.each { |default| default_param(*default) } 
    end 
end 

class Example 
    extend DefaultParams 
    default_params foo: 'default foo', bar: 'my favorite bar' 
end 
+0

我需要一點小小的提示,起初我沒有想到:爲每個應該有默認值的屬性設置一個default_value方法。謝謝。 –

0

我已經從coreyward獲得很大靈感的解決方案。起初我並沒有意識到,而不是有兩種設置默認值數組的方法,我需要將默認值分隔成單個方法。這爲應用程序的設計提供了極大的靈活性。所以非常感謝答案。

對於軌道的設置,我加入到application_record.rb

def set_attr_from_defaults 
    default_attrs.each do |atr| 
    eval("self.#{atr[0..atr.length-9]} ||= self.#{atr}") 
    end 
end 

def set_attr_from_defaults! 
    default_attrs.each do |atr| 
    eval("self.#{atr[0..atr.length-9]} = self.#{atr}") 
    end 
end 

def set_default_attr params 
    params.each { |key, value| self.define_singleton_method(key){value} } 
end 

def default_attrs 
    self.attributes.keys.map{|i| (i+'_default').to_sym} & self.methods 
end 

default_attrs產生符號關閉默認屬性的列表。 set_default_attr定義了單例方法,用於像attrname_default: 'default_value' ...這樣的散列中的解析。set_attr_from_defaults將設置屬性的默認值,當一個屬性有一對像var: var_default9的長度是_default + 1的長度。