This is so simple that I can't believe it caught me.
def meth(id, options = "options", scope = "scope") puts options end meth(1, scope = "meh") -> "meh"
I tend to use hashes for argument options just because it was how the herd did it– and it is quite clean. I thought it was the standard. Today, after about 3 hours of bug hunting, I traced down an error to this gem I happen to be using that assumes named parameters will be honored. They are not.
So, my question is this: Are named parameter officially not honored in Ruby (1.9.3), or is this a side effect of something I'm missing? If they are not, why not?
What is a parameter? Parameters in ruby are variables that are defined in method definition and which represent the ability of a method to accept arguments. So, if we will not have the appropriate parameters, then we will not be able to pass arguments to a method that will contain the data we need.
If you want to accept keyword arguments, in principle you should always use def foo(k: default) or def foo(k:) or def foo(**kwargs) . Note that Ruby 3.0 doesn't behave differently when calling a method which doesn't accept keyword arguments with keyword arguments.
A method in Ruby is a set of expressions that returns a value. Within a method, you can organize your code into subroutines which can be easily invoked from other areas of their program. A method name must start a letter or a character with the eight-bit set.
What's actually happening:
# Assign a value of "meh" to scope, which is OUTSIDE meth and equivalent to # scope = "meth" # meth(1, scope) meth(1, scope = "meh") # Ruby takes the return value of assignment to scope, which is "meh" # If you were to run `puts scope` at this point you would get "meh" meth(1, "meh") # id = 1, options = "meh", scope = "scope" puts options # => "meh"
There is no support* for named parameters (see below for 2.0 update). What you're seeing is just the result of assigning "meh"
to scope
being passed as the options
value in meth
. The value of that assignment, of course, is "meh"
.
There are several ways of doing it:
def meth(id, opts = {}) # Method 1 options = opts[:options] || "options" scope = opts[:scope] || "scope" # Method 2 opts = { :options => "options", :scope => "scope" }.merge(opts) # Method 3, for setting instance variables opts.each do |key, value| instance_variable_set "@#{key}", value # or, if you have setter methods send "#{key}=", value end @options ||= "options" @scope ||= "scope" end # Then you can call it with either of these: meth 1, :scope => "meh" meth 1, scope: "meh"
And so on. They're all workarounds, though, for the lack of named parameters.
* Well, at least until the upcoming Ruby 2.0, which supports keyword arguments! As of this writing it's on release candidate 2, the last before the official release. Although you'll need to know the methods above to work with 1.8.7, 1.9.3, etc., those able to work with newer versions now have the following option:
def meth(id, options: "options", scope: "scope") puts options end meth 1, scope: "meh" # => "options"
I think 2 things are happening here:
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