2016-03-01 77 views
2

在Rails項目上,我收集了一個帶有10-15個鍵值對的散列,並將它傳遞給一個類(服務對象)進行實例化。除非沒有值(或nil),否則應從哈希中的值設置對象屬性。在這種情況下,該屬性將被理想地設置爲默認值。將`nil`傳遞給使用默認命名參數的方法

而不是在創建一個對象之前檢查散列中的每個值是不是nil,我想找到一個更有效的方法來做到這一點。

我想使用默認值的命名參數。我不知道這是否合理,但我想用nil調用參數時使用默認值。我爲此功能創建了一個測試:

class Taco 
    def initialize(meat: "steak", cheese: true, salsa: "spicy") 
    @meat = meat 
    @cheese = cheese 
    @salsa = salsa 
    end 
    def assemble 
    "taco with: #@meat + #@cheese + #@salsa" 
    end 
end 

options1 = {:meat => "chicken", :cheese => false, :salsa => "mild"} 
chickenTaco = Taco.new(options1) 
puts chickenTaco.assemble 
# => taco with: chicken + false + mild 

options2 = {} 
defaultTaco = Taco.new(options2) 
puts defaultTaco.assemble 
# => taco with: steak + true + spicy 

options3 = {:meat => "pork", :cheese => nil, :salsa => nil} 
invalidTaco = Taco.new(options3) 
puts invalidTaco.assemble 
# expected => taco with: pork + true + spicy 
# actual => taco with: pork + + 
+1

感謝格式幫助澤 – phpete

回答

1

如果要遵循面向對象的方法,你可以在一個單獨的方法分離您的默認值,然後使用Hash#merge

class Taco 
    def initialize (args) 
    args = defaults.merge(args) 
    @meat = args[:meat] 
    @cheese = args[:cheese] 
    @salsa = args[:salsa] 
    end 

    def assemble 
    "taco with: #{@meat} + #{@cheese} + #{@salsa}" 
    end 

    def defaults 
    {meat: 'steak', cheese: true, salsa: 'spicy'} 
    end 
end 

然後下面的S通過@sawa uggestion(感謝),使用Rails的Hash#compact對於已經明確定義nil值的輸入哈希,你將有以下的輸出:

taco with: chicken + false + mild 
taco with: steak + true + spicy 
taco with: pork + true + spicy 

編輯:

如果你不想要使用Rails的精彩Hash#compact方法,可以使用Ruby的Array#compact方法。更換第一行initialize法內:

args = defaults.merge(args.map{|k, v| [k,v] if v != nil }.compact.to_h) 
+0

除了'Hash#compact'之外,還使用'Hash#merge'是確保我的對象獲得默認值而不是'nil'值的一個好方法。非常感謝你! – phpete

0

我不認爲關鍵字參數適合您的情況。看起來Hash更合適。

class Taco 
    attr_accessor :ingredients 

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

    def assemble 
     "taco with: #{ingredients[:meat]} + #{ingredients[:cheese]} + #{ingredients[:salsa]}" 
    end 
end 

你甚至可以短assemble方法列出所有成分

def assemble 
    string = "taco with: " + ingredients.values.join(" + ") 
end 

,也將努力爲你所期望

options1 = {:meat => "chicken", :cheese => false, :salsa => "mild"} 
chicken_taco = Taco.new(options1) 
puts chicken_taco.assemble() # output: taco with: chicken + false + mild 

值得一提的是紅寶石喜歡chicken_tacos超過chickenTacos

+1

謝謝您的回答!有沒有什麼辦法可以爲你的答案中提到的一些'成分'哈希鍵提供默認值?例如,如果「肉」不是作爲配料給出的,它仍然會打印「taco:{default_meat} + {other_ingredient_a} + ...'? – phpete

+1

'成分[:肉] || =「默認肉類」將允許您有條件地爲該鍵分配默認值,如果沒有給出。 –

1

一旦您使用命名參數傳遞值,則該方法調用將無法訪問該參數的默認值。

您必須(i)不是在方法配置文件中指定默認值,而是在方法主體中指定默認值,如在sagarpandya82的答案中;或者(ii)在將參數傳遞給像這樣的方法之前,刪除nil值, Hash#compact

options3 = {:meat => "pork", :cheese => nil, :salsa => nil} 
invalidTaco = Taco.new(options3.compact) 
+0

我刪除了我的答案,因爲我無法獲得OP所需的輸出。如果你知道如何解決隨意融入你的答案。 –

+0

@ sagarpandya82我的答案沒有看到任何問題。至少,它比接受的答案要好得多,它甚至沒有考慮到默認值(除了對OP評論的事後迴應外)。 – sawa

+0

OP想要第一個串有'taco:chicken + false + mild'。我的代碼打印出'taco:chicken + true + mild'。這是唯一的原因。你能看到修復嗎? –