Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby Methods and Optional parameters

People also ask

How do you make an optional argument in Ruby?

Flexible Methods With Optional Arguments You may want to make some of your arguments optional by providing a default value. Now you can call write with 2 arguments, in which case mode will equal the default value ( "w" ), or you can pass in 3 arguments to override the default value & get different results.

What is * args in Ruby?

In the code you posted, *args simply indicates that the method accepts a variable number of arguments in an array called args . It could have been called anything you want (following the Ruby naming rules, of course).

What are parameters in Ruby?

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.

What's the difference between a parameter and an argument Ruby?

Parameter is the variable in the declaration of the function. Argument is the actual value of this variable that gets passed to the function.


The way optional arguments work in ruby is that you specify an equal sign, and if no argument is passed then what you specified is used. So, if no second argument is passed in the second example, then

{age: 27, weight: 160, city: "New York"}

is used. If you do use the hash syntax after the first argument, then that exact hash is passed.

The best you can do is

def my_info2(name, options = {})
  options = {age: 27, weight: 160, city: "New York"}.merge(options)
...

The problem is the default value of options is the entire Hash in the second version you posted. So, the default value, the entire Hash, gets overridden. That's why passing nothing works, because this activates the default value which is the Hash and entering all of them also works, because it is overwriting the default value with a Hash of identical keys.

I highly suggest using an Array to capture all additional objects that are at the end of your method call.

def my_info(name, *args)
  options = args.extract_options!
  age = options[:age] || 27
end

I learned this trick from reading through the source for Rails. However, note that this only works if you include ActiveSupport. Or, if you don't want the overhead of the entire ActiveSupport gem, just use the two methods added to Hash and Array that make this possible.

rails / activesupport / lib / active_support / core_ext / array / extract_options.rb

So when you call your method, call it much like you would any other Rails helper method with additional options.

my_info "Ned Stark", "Winter is coming", :city => "Winterfell"

If you want to default the values in your options hash, you want to merge the defaults in your function. If you put the defaults in the default parameter itself, it'll be over-written:

def my_info(name, options = {})
  options.reverse_merge!(age: 27, weight: 160, city: "New York")

  ...
end

In second approach, when you say,

my_info2 "Bill", age: 28

It will pass {age: 28}, and entire original default hash {age: 27, weight: 160, city: "New York"} will be overridden. That's why it does not show properly.


You can also define method signatures with keyword arguments (New since, Ruby 2.0, since this question is old):

def my_info2(name, age: 27, weight: 160, city: "New York", **rest_of_options)
    p [name, age, weight, city, rest_of_options]
end

my_info2('Joe Lightweight', weight: 120, age: 24, favorite_food: 'crackers')

This allows for the following:

  • Optional parameters (:weight and :age)
  • Default values
  • Arbitrary order of parameters
  • Extra values collected in a hash using double splat (:favorite_food collected in rest_of_options)

For the default values in your hash you should use this

def some_method(required_1, required_2, options={})
  defaults = {
    :option_1 => "option 1 default",
    :option_2 => "option 2 default",
    :option_3 => "option 3 default",
    :option_4 => "option 4 default"
  }
  options = defaults.merge(options)

  # Do something awesome!
end