Setting defaults in a Ruby options hash I have a specific method that I like because it lets me decide whether or not I want to use the default. If I want anything different I enter in :option =&gt; value otherwise I get the default. Here's a concrete example that works, but is a little ugly.

How can I accomplish the same thing in a more elegant manner?

def connect_to_oracle opts = {}
  host_name = opts[:host_name]
  host_name ||= 'a_default_host_name'
  db_name = opts[:db_name]
  db_name ||= 'a_default_db_name'
  userid = opts[:userid]
  userid ||= 'a_default_userid'
  password = opts[:password]
  password ||= 'a_default_password'
  url = "jdbc:oracle:thin:#{userid}/#{password}@#{host_name}:1521:#{db_name}"
  $db = Sequel.connect(url)
end
You don't need the ||= you can use ||:

def connect_to_oracle( opts = {} )
  host_name = opts[:host_name] ||'a_default_host_name'
  db_name = opts[:db_name] || 'a_default_db_name'
  userid = opts[:userid] || 'a_default_userid'
  password = opts[:password] ||'a_default_password'

  url = "jdbc:oracle:thin:#{userid}/#{password}@#{host_name}:1521:#{db_name}"
  $db = Sequel.connect(url)
end


Another approach is Hash.merge:

DEFAULT = {
  host_name: 'a_default_host_name',
  db_name:  'a_default_db_name',
  userid: 'a_default_userid',
  password: 'a_default_password',
}

def connect_to_oracle( opts = {} )
  opts = DEFAULT.merge(opts)

  host_name = opts[:host_name]
  db_name = opts[:db_name]
  userid = opts[:userid]
  password = opts[:password]

  url = "jdbc:oracle:thin:#{userid}/#{password}@#{host_name}:1521:#{db_name}"
  $db = Sequel.connect(url)
end


or:

DEFAULT = {
  host_name: 'a_default_host_name',
  db_name:  'a_default_db_name',
  userid: 'a_default_userid',
  password: 'a_default_password',
}

def connect_to_oracle( interface_opts = {} )
  opts = DEFAULT.merge(interface_opts )

  url = "jdbc:oracle:thin:%s/%s@%s:1521:%s" % [
    opts[:userid],
    opts[:password],
    opts[:host_name],
    opts[:db_name],
    ]
  $db = Sequel.connect(url)
end
connect_to_oracle()
connect_to_oracle(:host_name =&gt; :xxxxxxxx)


I prefer the version with merge. So I get a constant with all default parameters in my documentation.

Another advantage: I can easily add checks if my interface contains correct keys.

Example:

DEFAULT = {
  host_name: 'a_default_host_name',
  db_name:  'a_default_db_name',
  userid: 'a_default_userid',
  password: 'a_default_password',
}

def connect_to_oracle( myopts = {} )
  (myopts.keys - DEFAULT.keys).each{|key|
    puts "Undefined key #{key.inspect}"
  }
  opts = DEFAULT.merge(myopts)

  url = "jdbc:oracle:thin:%s/%s@%s:1521:%s" % [
    opts[:userid],
    opts[:password],
    opts[:host_name],
    opts[:db_name],
    ]
  #~ $db = Sequel.connect(url)
end
connect_to_oracle(:host_nam =&gt; :xxxxxxxx)


My method call contains an error (forgotten 'e'), but when you call it, you get a warning Undefined key host_nam. This often helps to detect errors. (in a real scenario I replace the puts with a logger-warning/error).