1

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.

Phrogz
  • 296,393
  • 112
  • 651
  • 745

2 Answers2

5

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.

mu is too short
  • 426,620
  • 70
  • 833
  • 800
1

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]
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100