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

87 Views Asked by At

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.

2

There are 2 best solutions below

0
mu is too short On BEST ANSWER

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.

0
Cary Swoveland On

As I'm sure you know, you could eliminate one splat by using Array#concat:

[1,2].concat([*[4,5]].map { |e| 2*e })
  #=> [1, 2, 8, 10]
[1,2].concat([*4].map { |e| 2*e })
  #=> [1, 2, 8]

or Array#+:

[1,2] + [*[4,5]].map { |e| 2*e }
  #=> [1, 2, 8, 10]
[1,2] + [*4].map { |e| 2*e }
  #=> [1, 2, 8]