2016-03-01 1 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 

затем следуя сек uggestion по @sawa (спасибо), использовать Rails' Hash#compact для ввода хэшей, которые явно определены nil значения, и вы будете иметь следующий вывод:

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

EDIT:

Если вы не хотите для использования замечательного метода Rails Hash#compact вы можете использовать метод Ruby's Array#compact. Замена первой строки в методе initialize для:

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

Использование 'Hash # merge' в дополнение к' Hash # compact' является отличным методом обеспечения того, чтобы мой объект получал значение по умолчанию вместо значений nil для его свойств. Большое спасибо! – phpete

0

Я не думаю, что аргументы ключевых слов были бы уместны в вашем случае. Кажется, Хэш лучше подходит.

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

спасибо за Ваш ответ! Есть ли способ предоставить значения по умолчанию для некоторых хэш-ключей «ингредиентов», как вы упомянули в своем ответе? Например, если 'meat' не указывается в качестве ингредиента, он все равно будет печатать' taco с: {default_meat} + {other_ingredient_a} + ... '? – phpete

+1

'components [: meat] || =« default meat »' позволит вам условно присвоить значение по умолчанию для этого ключа, если ни один не был указан. –

1

После передачи значения с помощью именованного параметра доступ к значению по умолчанию для этого параметра исчез для этого вызова метода.

Вы должны либо (i) назначить значение по умолчанию не в профиле метода, а в теле метода, как в ответе sagarpandya82, или (ii) удалить значения nil перед передачей аргументов методу, подобному этому, используя Rails ' 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'. Это единственная причина. Вы видите исправление? –