The Elements of Style in Ruby #3: Make sure something is an array
The subject of today’s post is the following rule from the Ruby Style Guide:
Use
[*var]orArray()instead of an explicitArraycheck, when dealing with a </br> variable you want to treat as an Array, but you’re not certain it’s </br> an array.
Countless times I’ve seen code like this:
paths = [paths] unless paths.is_a? Array
paths.each { |path| do_something(path) }
It seems that paths could be either an Array object or an object
of some other class. The author of the code needed to make sure
paths would be an array so he creates a single element array in the
case paths is not already an array.
While the above code works it’s not something an experienced Rubyist
would write. The most popular alternative is the use of the mighty splat
operator(*):
[*paths].each { |path| do_something(path) }
It case you’re puzzled by the preceding snippet consider the following example:
elems = 1
[*elems]
# => [1]
elems = [1, 2, 3]
[*elems]
# = [1, 2, 3]
Hope that makes clear what’s going on.
While I’m extremely fond of this particular usage of * I tend to
avoid it, since there is another equally powerful, but more readable
alternative to it - Kernel#Array. Here’s it in action:
Array(paths).each { |path| do_something(path) }
Array looks like the name of class, but it’s not. It’s a totally
normal method defined in the Kernel module. There is a whole family
of conversion methods similar to Array there - Array, Complex,
Float, Hash, Integer, Rational and String. They are all used
for often in practice and we’ll probably revisit them in a separate
post somewhere down the road.
The Array method operates exactly like * - it takes a single argument and
converts it to an Array object if necessary:
Array(1)
# => [1]
Array([1, 2, 3])
# => [1, 2, 3]
You can also use * and Array to convert to array other data
composite data structures (like hashes and sets), but that’s
irrelevant to today’s discussion.
That’s all I have for you today, mates. As usual I’m looking forward to hearing your thoughts here and on Twitter!