Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing `nil` to method using default named parameters

On a Rails project, I am gathering a hash with 10-15 key-value pairs, and passing it to a class (service object) for instantiation. The object properties should be set from the values in the hash except when there is no value (or nil). In this case, the property would desirably get set to a default value.

Instead of checking whether every value in the hash is not nil before creating an object, I would like to find a more efficient way of doing this.

I'm trying to use named parameters with default values. I don't know if this makes sense, but I would like to use the default value when the parameter is called with nil. I created a test for this functionality:

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 +  +
like image 600
phpete Avatar asked Jun 02 '26 10:06

phpete


1 Answers

If you want to follow a Object-Oriented approach, you could isolate your defaults in a separate method and then use 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

Then following the suggestion by @sawa (thanks), use Rails' Hash#compact for your input hashes that have explicitly defined nil values and you will have the following output:

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

EDIT:

If you do not want to use Rails' wonderful Hash#compact method, you can use Ruby's Array#compact method. Replacing the first line within the initialize method to:

args = defaults.merge(args.map{|k, v| [k,v] if v != nil }.compact.to_h)
like image 127
Sagar Pandya Avatar answered Jun 05 '26 07:06

Sagar Pandya