Ruby Optional Parameters

A method with an optional parameter


def some_func(variable = nil)
...
end

Order of optional parameters in initializer

If you define optional parameters before AND after mandatory parameters, in some cases it will be impossible to decide how a goven list or arguments should map to the defined parameters.

In your case, when defining this method:

class A
def initialize(a = "default val", b, c = [])
#...
end
end

How would you handle this when giving two arguments,. i.e.

A.new 'hello', 'world'

You could then assign

a = 'hello'
b = 'world'
c = []

but you could equally set

a = 'default val'
b = 'hello'
c = 'world'

Given this unambiguity, Ruby rejects those constructs. You thus have to define all optional parameters either at the front or the back of your parameter list, while it is commonly accepted standard to define optional arguments only at the end.

If you want to be more specific about which arguments should be set with a large number of optional parameters, you can also use keyword arguments. Since you have to specify the name of the arguments when calling the method here, the order of mandatory and optional keyword arguments doesn't matter.

ArgumentError with optional parameters

In Ruby < 3.0, if the last argument is a hash, and the method being called accepts keyword arguments, then it is always converted to keyword arguments.

Ruby 3.0 fixes this.

You should upgrade to Ruby 3.0 if you can, or else think of a different API.

Ruby optional parameters

This isn't possible with ruby currently. You can't pass 'empty' attributes to methods. The closest you can get is to pass nil:

ldap_get(base_dn, filter, nil, X)

However, this will set the scope to nil, not LDAP::LDAP_SCOPE_SUBTREE.

What you can do is set the default value within your method:

def ldap_get(base_dn, filter, scope = nil, attrs = nil)
scope ||= LDAP::LDAP_SCOPE_SUBTREE
... do something ...
end

Now if you call the method as above, the behaviour will be as you expect.

Ruby Methods and Optional parameters

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)
...

Best way to send() optional parameter in Rails

If you're using Ruby 2.2.0 or later you can call #itself on any object and get that object. So in your example you can do

def foo param_1, param_2 = :itself
object.send(param_1).send(param_2)
end

And it will be the same as

def foo param_1, param_2 = nil
thing = object.send(param_1)
if param_2
thing.send(param_2)
else
thing
end
end

I also second Surya's advice to always use #public_send instead.

Rails optional argument

It's as simple as this:

class Person
attr_accessor :name, :age

def initialize(name = '', age = 0)
self.name = name
self.age = age
end
end


Person.new('Ivan', 20)
Person.new('Ivan')

However, if you want to pass only age, the call would look pretty ugly, because you have to supply blank string for name anyway:

Person.new('', 20)

To avoid this, there's an idiomatic way in Ruby world: options parameter.

class Person
attr_accessor :name, :age

def initialize(options = {})
self.name = options[:name] || ''
self.age = options[:age] || 0
end
end

Person.new(name: 'Ivan', age: 20)
Person.new(age: 20)
Person.new(name: 'Ivan')

You can put some required parameters first, and shove all the optional ones into options.

Edit

It seems that Ruby 2.0 will support real named arguments.

def example(foo: 0, bar: 1, grill: "pork chops")
puts "foo is #{foo}, bar is #{bar}, and grill is #{grill}"
end

# Note that -foo is omitted and -grill precedes -bar
example(grill: "lamb kebab", bar: 3.14)

Ruby's Faraday - Send optional parameters in get method

You don't have to concatenate params with the url on your own. Faraday can accept a hash of params (or nil). You can pass them to the get method like so:

response = connection.get(customer_url, params)

Have into the "GET, HEAD, DELETE, TRACE" section of the documentation for more examples.

Side note: you don't event have to concatenate url and the path. You can pass them as separate arguments.

Ruby Object Initialize with Optional Arguments

If you're going to do that you need to accept not an array of arguments (varargs style) like you've specified, but either an options hash or the new keyword-args style option.

The classic approach:

def initialize(attributes = nil)
attributes and attributes.each do |k,v|
instance_variable_set("@#{k}", v) unless v.nil?
end
end

The new keyword-arguments approach:

def initialize(**options)
options.each do |k,v|
instance_variable_set("@#{k}", v) unless v.nil?
end
end

You can also subclass OpenStruct to get behaviour like this for free.

Keep in mind there's a new option style that might be a good mix of both these approaches:

def initialize(sid: '123', token: '...', ...)
@sid = sid
@token = token
# ...
end

You can specify defaults for the named keyword arguments.



Related Topics



Leave a reply



Submit