What is the most efficient way to initialize a Class in Ruby with different parameters and default values?
Solution 1
The typical way to solve this problem is with a hash that has a default value. Ruby has a nice syntax for passing hash values, if the hash is the last parameter to a method.
class Fruit
attr_accessor :color, :type
def initialize(params = {})
@color = params.fetch(:color, 'green')
@type = params.fetch(:type, 'pear')
end
def to_s
"#{color} #{type}"
end
end
puts(Fruit.new) # prints: green pear
puts(Fruit.new(:color => 'red', :type => 'grape')) # prints: red grape
puts(Fruit.new(:type => 'pomegranate')) # prints: green pomegranate
A good overview is here: http://deepfall.blogspot.com/2008/08/named-parameters-in-ruby.html
Solution 2
Since Ruby 2.0 there is support of named or keyword parameters.
You may use:
class Fruit
attr_reader :color, :type
def initialize(color: 'green', type: 'pear')
@color = color
@type = type
end
def to_s
"#{color} #{type}"
end
end
puts(Fruit.new) # prints: green pear
puts(Fruit.new(:color => 'red', :type => 'grape')) # prints: red grape
puts(Fruit.new(:type => 'pomegranate')) # prints: green pomegranate
Some interesting notes on this topic:
Solution 3
I'd do it like this:
class Fruit
attr_accessor :color, :type
def initialize(args={})
options = {:color => 'green', :type => 'pear'}.merge(args)
self.color = options[:color]
self.type = options[:type]
end
end
apple = Fruit.new(:color => 'red', :type => 'apple')
This way, you never have to worry about missing arguments--or their order--and you'll always have your default values right there. .merge
will of course overwrite the default values if they're present.
Solution 4
I like vonconrad's answer but would have a separate defaults
method. Maybe it's not efficient in terms of lines of code, but it's more intention-revealing and involves less cognitive overhead, and less cognitive overhead means more efficient dev onboarding.
class Fruit
attr_accessor :color, :type
def initialize(args={})
options = defaults.merge(args)
@color = options.fetch(:color)
@type = options.fetch(:type)
end
def defaults
{
color: 'green',
type: 'pear'
}
end
end
apple = Fruit.new(:color => 'red', :type => 'apple')
Solution 5
More simple way:
class Fruit
attr_accessor :color, :type
def initialize(color = 'green', type = 'pear')
@color = color
@type = type
end
def to_s
"#{color} #{type}"
end
end
puts Fruit.new # prints: green pear
puts Fruit.new('red','apple') # prints: red apple
puts Fruit.new(nil,'pomegranate') # prints: green pomegranate
![Istvan](https://i.stack.imgur.com/ptOi1.jpg?s=256&g=1)
Istvan
Hands On Data & Cloud Architect with Leadership Experience. Things I care about: Systems Engineering Data Engineering Machine Learning Functional Programming
Updated on July 22, 2020Comments
-
Istvan almost 4 years
I would like to have a class and some attributes which you can either set during initialization or use its default value.
class Fruit attr_accessor :color, :type def initialize(color, type) @color=color ||= 'green' @type=type ||='pear' end end apple=Fruit.new(red, apple)
-
Brian Clapper over 13 yearsYes, except this approach requires that you pass the parameters in order. With the hash approach, you must specify the parameter name (i.e., the hash key), but you can pass those keys in any order.
-
Hoang Le almost 9 yearsI like this solution the most among the others. The reason is we won't need to create any further significant objects (imagine a big class instance for example) in case the params already has those options. But I also would like to use even cleaner syntax (just my opinion) like this: @color = params[:color] || 'green'
-
WestCoastProjects over 4 yearsI'm going to have an opportunity to do a little ruby/jruby! After 7 years!
-
aceofbassgreg over 3 yearsTo be clear, this is by far the best answer here, though as knut said kwargs weren't available until Ruby 2.0.
-
Patrick Barattin over 2 yearsThis doesn’t allow you to set default values.