Search code examples
rubyconstructorinstance-variablessplat

Method: Loop Through Arguments with Defaults


I am building a Ruby object that has defaults for arguments in its initialize method:

attr_accessor :one, :two, :three

def initialize(one: nil, two: nil, three: nil)
  @one = one
  @two = two
  @three = three
end

As you can see, this isn't very DRY, especially as the number of initializable variables grows. Ultimately, I would like to be able to loop through each of the arguments and assign an instance variable (some combination of a splat operator and instance_variable_set?), but always have a defined list of expected instance variables with defaults if they aren't defined.


Solution

  • Typically having an initialize method require a whole bunch of arguments usually leads to the use of an options hash rather than splat.

    With an options hash you're able to dry up your initialize method, set instance variables and attr_readers in a very ruby way:

    class Animal
      def initialize(opts = {})
        options = defaults.merge(opts)
        options.each do |k, v|
          instance_variable_set("@#{k}", v)
          self.class.send(:attr_reader, k)
        end
      end
    
      private
    
      def defaults
        {
          type: nil,
          age: 100,
          name: "Unknown"
        }
      end
    end
    
    animal = Animal.new(type:'cat', age: 99)
    puts animal
    puts animal.type
    puts animal.age
    puts animal.name
    

    Output:

    #<Animal:0x007f9773132650>
    cat
    99
    Unknown