arraysrubysplat

Idiomatic way to receive an object or array of objects, transform them, and add to existing array


I have a method that can receive either a single object, or an array of those objects. (The YAML file I'm pulling from sometimes has foo: bar and sometimes a list of foo: [bar1, bar2].)

Each time this method is called, it should transform the value or values, and add them to an internal array.

I originally had this:

class YamlEater
  def initialize
    @foos = []
  end

  def add(o)
    if o.is_a?(Array)
      o.each{ self.add(_1) }
    else
      @foos << FooItem.new(o)
    end
  end
end

After I needed to use that pattern in many different methods, I changed it to a non-recursive, more terse version that's splat-heavy and perhaps only a golfer could love:

  def add(o)
    @foos.push(*[*o].map{ FooItem.new(_1) })
  end

I'm thinking there's a more elegant way to accomplish the same goal, and hoping someone will share it.


Solution

  • I'd probably use Kernel#Array and Array#concat:

    def add(o)
      @foos.concat(Array(o).map { FooItem.new(_1) })
    end
    

    That nicely handles o.nil? as a bonus.