I seem to not be able to do this (which I used to be able 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 by their respective order.. but what if I want to give arg2 at some point in my programming and want the default values for arg1 and arg3?
I tried writing someMethod(arg2=4) but this doesn't seem to work in Ruby 1.9. What it does is it still thinks that arg1 is 4. In python I could at least get away with this, but in ruby I am not sure. Does anyone have any elegant ideas?
Only elegant solution for now is to use hash as parameters list:
def some_method(options = {})
defaults = {:arg1 => 1, :arg2 => 2, :arg3 => 3}
options = defaults.merge(options)
...
end
and later in code use implicit hash when calling your method:
some_method()
some_method(:arg1 => 2, :arg2 => 3, :arg3 => 4)
some_method(:arg2 => 4)
In Ruby 1.9 you can use new hash keys syntax to get ir more like in Python:
some_method(arg1: 2, arg2: 3, arg3: 4)
If you want simpler syntax and still be able to use positional parameters, then I would suggest to play 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 would like to mimic Ruby arguments number check for 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 Jonas Elfström's comment
For what you are trying to do the best way would be to use a Hash as only Argument.
def someMethod(args={})
args[:arg1] ||= 1
args[:arg2] ||= 2
args[:arg3] ||= 3
...
This method would then be called like this
someMethod(:arg1 => 2, :arg3 => 5)
all hashvalues not set will be replaced by their default value (e.g. arg2 = 2).
Ruby doesn't have keyword argument passing. (Not yet, anyway, it is one of the things that might make it into Ruby 2.0. However, there are no guarantees, and work on Ruby 2.0 hasn't even started yet, so there's no telling when or even if we will see keyword arguments in Ruby.)
What really happens, is this: you are passing the expression arg2 = 4
as the only argument in the argument list. Ruby is a strict language with pass-by-value, 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. everything returns a value), there are no statements). You are assigning the immediate literal Fixnum
value 4
to the local variable arg2
. Assignment expressions always return the value of their right-hand side, in this case 4
.
So, you are passing the value 4
as the only argument into your method, which means that it gets bound to the first mandatory parameter if there is one (in this case, there isn't), otherwise to the first optional parameter (in this case arg1
).
The usual way to deal with situations like this is to use a Hash
instead, like this:
some_method({:arg2 => 4})
Because this pattern is used so often, there is special syntactic support: if the last argument to a method is a Hash
, you can leave off the curly braces:
some_method(:arg2 => 4)
In Ruby 1.9, there is another syntactical convenience form: because Hash
es are so often used with Symbol
keys, there is an alternative Hash
literal syntax for that:
some_method({arg2: 4})
Combine them both, and you almost have keyword arguments:
some_method(arg2: 4)
(In fact, both of these shortcuts were specifically added to provide an easy migration path towards possible future versions of Ruby with keyword arguments.)
MacRuby actually supports Smalltalk-style multipart message selectors for interoperability with Objective-C. Note, however, that Smalltalk-style multipart message selectors are not keyword arguments, they behave very differently. Also, of course, this extension is specific to MacRuby and not part of the Ruby Specification and not portable to MRI, YARV, JRuby, XRuby, IronRuby, MagLev, Rubinius, tinyrb, RubyGoLightly, BlueRuby, SmallRuby or any other Ruby Implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With