Keyword Arguments and Required Arguments

June 12, 2013

Continuing from the previous post on the new keyword arguments in Ruby 2.0. What do you do if you have arguments that have no good default value but still cannot be nil? An example:

def label(name: nil, street: nil, zip: nil, state: nil, 
          city: nil, country: nil, att: nil)
  <<-EOS.gsub(/^\s/, '')
    #{name}
    ATT: #{att}
    #{street}
    #{zip} #{city}
    #{state}
    #{country}
  EOS
end

puts label(name: "Acme Inc.", 
           att: "John Doe", 
           street: "123 Fakestreet", 
           city: "Fakecity", 
           zip: "123456", 
           state: "FS", 
           country: "Fakistan")
# =>  Acme Inc.
# =>  ATT: John Doe
# =>  123 Fakestreet
# =>  123456 Fakecity
# =>  FS
# =>  Fakistan

Now, in this example we don’t really have good default values. On the other hand we have so many parameters that using ordinary parameters really lowers readability of the code. So, a good thing might be to check that the keys are not nil. One way to solve this could be to check each parameter in the label method. If we want to keep this DRY we could do the following with a bit of meta-programming:

def check_required_keys(binding_context, *keys)
  keys.each do |key|
    if eval "#{key}.nil?", binding_context
      raise ArgumentError, "Missing required argument :#{key}"
    end
  end
end

def label(name: nil, street: nil, zip: nil, state: nil, 
          city: nil, country: nil, att: nil)
  check_required_keys binding, :name, :street, :city, :country
  <<-EOS.gsub(/^\s/, '')
    #{name}
    ATT: #{att}
    #{street}
    #{zip} #{city}
    #{state}
    #{country}
  EOS
end

label 
# => ArgumentError: Missing required option :name

If you have a better solution please tweet me.

Share this post on Twitter
Morten Møller Riis

By Morten Møller Riis

I am a programmer, sysadmin, devops. I work for Gigahost in Copenhagen, Denmark. I am based in Odense, Denmark.

Twitter   ·   LinkedIn   ·   E-mail