Simulating Keyword Arguments


A function or method can accept many optional arguments. You want to let callers pass in only the arguments they have values for, but Ruby doesn't support keyword arguments as Python and Lisp do.


Write your function to accept as its final argument a map of symbols to values. Consult the map as necessary to see what arguments were passed in.

	def fun_with_text(text, args={})
	 text = text.upcase if args[:upcase]
	 text = text.downcase if args[:downcase]
	 if args[:find] and args[:replace]
	 text = text.gsub(args[:find], args[:replace])
	 text = text.slice(0, args[:truncate_at]) if args[:truncate_at]
	 return text

Ruby has syntactic sugar that lets you define a hash inside a function call without putting it in curly brackets. This makes the code look more natural:

	fun_with_text("Foobar", {:upcase => true, :truncate_at => 5})
	# => "FOOBA"
	fun_with_text("Foobar", :upcase => true, :truncate_at => 5)
	# => "FOOBA"
	fun_with_text("Foobar", :find => /(o+)/, :replace => '1d', :downcase => true)
	# => "foodbar"



This simple code works well in most cases, but it has a couple of shortcomings compared to "real" keyword arguments. These simulated keyword arguments don't work like regular arguments because they're hidden inside a hash. You can't reject an argument that's not part of the "signature," and you can't force a caller to provide a particular keyword argument.

Each of these problems is easy to work around (for instance, does a required argument really need to be a keyword argument?), but it's best to define the workaround code in a mixin so you only have to do it once. The following code is based on a KeywordProcessor module by Gavin Sinclair:

	# This mix-in module lets methods match a caller's hash of keyword
	# parameters against a hash the method keeps, mapping keyword
	# arguments to default parameter values.
	# If the caller leaves out a keyword parameter whose default value is
	# :MANDATORY (a constant in this module), then an error is raised.
	# If the caller provides keyword parameters which have no
	# corresponding keyword arguments, an error is raised.
	module KeywordProcessor

	 def process_params(params, defaults)
	 # Reject params not present in defaults.
	 params.keys.each do |key|
	 unless defaults.has_key? key
	 raise ArgumentError, "No such keyword argument: #{key}"
	 result = defaults.dup.update(params)

	 # Ensure mandatory params are given.
	 unfilled = { |k,v| v == MANDATORY }.map { |k,v| k.inspect }
	 unless unfilled.empty?
	 msg = "Mandatory keyword parameter(s) not given: #{unfilled.join(', ')}"
	 raise ArgumentError, msg

	 return result

Here's KeywordProcessor in action. Note how I set a default other than nil for a keyword argument, by defining it in the default value of args:

	class TextCanvas

	 def render(text, args={}.freeze)
	 args = process_params(args, {:font => 'New Reykjavik Solemn', :size => 36,
	 :bold => false, :x => :MANDATORY,
	 :y => :MANDATORY }.freeze)
	 # …
	 puts "DEBUG: Found font #{args[:font]} in catalog."
	 # …

	canvas =

	canvas.render('Hello', :x => 4, :y => 100)
	# DEBUG: Found font New Reykjavik Solemn in catalog.

	canvas.render('Hello', :x => 4, :y => 100, :font => 'Lacherlich')
	# DEBUG: Found font Lacherlich in catalog.

	canvas.render('Hello', :font => "Lacherlich")
	# ArgumentError: Mandatory keyword parameter(s) not given: :x, :y

	canvas.render('Hello', :x => 4, :y => 100, :italic => true)
	# ArgumentError: No such keyword argument: italic

Ruby 2.0 will, hopefully, have full support for keyword arguments.

See Also

  • Recipe 8.8, "Delegating Method Calls to Another Object"
  • The KeywordProcessor module is based on the one in "Emulating Keyword Arguments in Ruby"; I modified it to be less oriented around the initialize method (



Date and Time



Files and Directories

Code Blocks and Iteration

Objects and Classes8

Modules and Namespaces

Reflection and Metaprogramming


Graphics and Other File Formats

Databases and Persistence

Internet Services

Web Development Ruby on Rails

Web Services and Distributed Programming

Testing, Debugging, Optimizing, and Documenting

Packaging and Distributing Software

Automating Tasks with Rake

Multitasking and Multithreading

User Interface

Extending Ruby with Other Languages

System Administration

Ruby Cookbook
Ruby Cookbook (Cookbooks (OReilly))
ISBN: 0596523696
EAN: 2147483647
Year: N/A
Pages: 399 © 2008-2020.
If you may any questions please contact us: