Ruby methods and the order of multiple defaults

I can't seem to do this (which I used to do in Python). Let me explain ..

Suppose I have the following method in Ruby:

def someMethod(arg1=1,arg2=2,arg3=3) ... ... ... end 

Now, to call this method, I could do

 someMethod(2,3,4) someMethod(2,3) someMethod(2) 

and the arguments are taken in their order .. but what if I want to give arg2 at some point in my programming and you want the default values ​​for arg1 and arg3?

I tried to write someMethod (arg2 = 4), but this does not seem to work in Ruby 1.9. What he does is still think arg1 is 4. In python, I could at least get away from this, but I'm not sure about the ruby. Anyone have any nifty ideas?

+6
ruby
source share
3 answers

The only elegant solution at the moment is to use a hash in the form of a list of parameters:

 def some_method(options = {}) defaults = {:arg1 => 1, :arg2 => 2, :arg3 => 3} options = defaults.merge(options) ... end 

and later, the code uses an implicit hash when calling the method:

 some_method() some_method(:arg1 => 2, :arg2 => 3, :arg3 => 4) some_method(:arg2 => 4) 

In Ruby 1.9, you can use the new hash key syntax to get more like Python:

 some_method(arg1: 2, arg2: 3, arg3: 4) 

If you want to simplify the syntax and still be able to use positional parameters, I would suggest playing with something like this:

 def some_method(*args) defaults = {:arg1 => 1, :arg2 => 2, :arg3 => 3} options = args.last.is_a?(::Hash) ? args.pop : {} options = defaults.merge(options) arg1 = args[0] || options[:arg1] arg2 = args[1] || options[:arg2] arg3 = args[2] || options[:arg3] ... end some_method() some_method(2) some_method(3,4,5) some_method(arg2: 5) some_method(2, arg3: 10) 

If you want to emulate the Ruby argument number for a method, you can add:

 fail "Unknown parameter name(s) " + (options.keys - defaults.keys).join(", ") + "." unless options.length == defaults.length 

EDIT:
I updated my answer with a comment by Jonas Elfström

+13
source share

For what you are trying to do in the best way, it would be to use Hash as the only argument.

 def someMethod(args={}) args[:arg1] ||= 1 args[:arg2] ||= 2 args[:arg3] ||= 3 ... 

Then this method will be called as

 someMethod(:arg1 => 2, :arg3 => 5) 

all hashvalues ​​will not be replaced with their default value (e.g. arg2 = 2).

+2
source share

Ruby does not pass keyword arguments. (Not yet, in any case, this is one of the things that could turn it into Ruby 2.0. However, there are no guarantees, and work on Ruby 2.0 has not yet begun, so it is not reported when or even if we see keywords in Ruby .)

What really happens is: you pass the expression arg2 = 4 as the only argument in the argument list. Ruby is a rigorous pass-by-value language, which means that all arguments are fully evaluated before they are passed to the method. In this case, arg2 = 4 is an assignment expression (in Ruby, everything is an expression (i.e., All returns a value), there are no instructions). You assign the current Fixnum Fixnum value 4 value of the local variable arg2 . Assignment expressions always return the value of their right-hand side, in this case 4 .

So, you pass the value 4 as the only argument to your method, which means that it is bound to the first required parameter, if there is one (in this case it is not), otherwise the first optional parameter (in this case arg1 ).

The usual way to deal with such situations is to use Hash , namely:

 some_method({:arg2 => 4}) 

Since this pattern is used so often, there is special syntactic support: if the last argument to the method is Hash , you can leave curly braces:

 some_method(:arg2 => 4) 

There is another syntactic form of convenience in Ruby 1.9: since Hash es are often used with Symbol keys, there is an alternative Hash syntax for this:

 some_method({arg2: 4}) 

Combine them both, and you almost have keyword arguments:

 some_method(arg2: 4) 

(In fact, both of these shortcuts have been specifically added to provide an easy way to get to possible future versions of Ruby with keyword arguments.)

MacRuby actually supports Smalltalk-style multiple message selectors for interacting with Objective-C. Note, however, that Smalltalk multipoint selector types are not keyword arguments; they behave differently. In addition, this extension applies to MacRuby, but does not apply to the Ruby specification, but is not ported to MRI, YARV, JRuby, XRuby, IronRuby, MagLev, Rubinius, tinyrb, RubyGoLightly, BlueRuby, SmallRuby, or any other Ruby implementation.

+2
source share

All Articles