tags:

views:

117

answers:

3

I want to change the default arguments passed to a Ruby function. For example, instead of each time writing

[1,2,3].do_stuff(:option => ' my option ')

I want to modify the defaults so that I can write

[1,2,3].do_stuff

What is the simplest, cleanest, most Ruby-like way of changing default parameters?

+2  A: 
>> [1, 2, 3].do_stuff
=> Result I get
>> [1, 2, 3].do_stuff :an_option => a_value
=> Result I really want, but don't want to specify the argument

I like to use super for this. It allows us to add some functionality to the method apart from just changing default arguments:

class Array
  def do_stuff(options = {})
     # Verify if caller has not passed the option
     options[:argument_i_want_to_change] = default_value_i_want unless options.has_key? :argument_i_want_to_change
     # call super
     super
  end
end

Result:

>> [1, 2, 3].do_stuff
=> Result that I really want

UPDATE: Removed reverse_merge! dependency. (Now looking for a better alternatives to using []= method)

Swanand
A: 

Are you wanting a solution for code you didn't write yourself? There are two options I'm aware of.

Code you wrote yourself:

def some_method_you_wrote(options)

becomes:

def some_method_you_wrote(options = { :option1 => 'value' })

(Swanand's answer is nice too)

For code you didn't write, look into aliasing methods. (Rails provides something called alias_method_chain for this purpose, IIRC.)

Benjamin Oakes
The problem with this approach is that the option 'option1' doesn't get set if they do pass in a hash of options without the 'option1' key set.
Benjamin
+1  A: 

(moved from your original question)

I assume you are talking about a method Array#do_stuff that already exists, but you want to modify it slightly (in your case by changing a default parameter).

A post here gives a nice way of doing it. It doesn't suffer from the same problems as the alias technique, as there isn't a leftover "old" method.

Here how you could use that technique with your example problem (tested with ruby 1.9)

class Array
  old_do_stuff = instance_method(:do_stuff)
  define_method(:do_stuff) { |options = {}|

    options[:option] ||= " option "
    old_do_stuff.bind(self).call(options)
  }
end

You might also want read up on UnboundMethod if the above code is confusing. Note that old_do_stuff goes out of scope after the end statement, so it isn't a problem for future uses of Array.

nanothief