What is the most efficient way to initialize a Class in Ruby with different parameters and default values? What is the most efficient way to initialize a Class in Ruby with different parameters and default values? ruby ruby

What is the most efficient way to initialize a Class in Ruby with different parameters and default values?


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}"  endendputs(Fruit.new)                                    # prints: green pearputs(Fruit.new(:color => 'red', :type => 'grape')) # prints: red grapeputs(Fruit.new(:type => 'pomegranate')) # prints: green pomegranate

A good overview is here: http://deepfall.blogspot.com/2008/08/named-parameters-in-ruby.html


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}"  endendputs(Fruit.new)                                    # prints: green pearputs(Fruit.new(:color => 'red', :type => 'grape')) # prints: red grapeputs(Fruit.new(:type => 'pomegranate')) # prints: green pomegranate

Some interesting notes on this topic:


Brian's answer is excellent but I would like to suggest some modifications to make it mostly meta:

class Fruit  # Now this is the only thing you have to touch when adding defaults or properties  def set_defaults    @color ||= 'green'    @type  ||= 'pear'  end  def initialize(params = {})    params.each { |key,value| instance_variable_set("@#{key}", value) }    set_defaults    instance_variables.each {|var| self.class.send(:attr_accessor, var.to_s.delete('@'))}  end  def to_s    instance_variables.inject("") {|vars, var| vars += "#{var}: #{instance_variable_get(var)}; "}  endendputs Fruit.newputs Fruit.new :color => 'red', :type => 'grape'  puts Fruit.new :type => 'pomegranate'puts Fruit.new :cost => 20.21puts Fruit.new :foo => "bar"f = Fruit.new :potato => "salad"puts "f.cost.nil? #{f.cost.nil?}"

Which outputs:

@color: green; @type: pear; @color: red; @type: grape; @color: green; @type: pomegranate; @color: green; @type: pear; @cost: 20.21; @color: green; @type: pear; @foo: bar; f.cost.nil? true

Of course this wouldn't be a perfect solution for everything but it gives you some ideas on making your code more dynamic.