tags:

views:

1365

answers:

6

I need to convert a passed in argument (single object or collection) to an Array. I don't know what the argument is. If it is an Array already, I want to leave it, otherwise create a one-element array from it. I'm looking to allow both method(:objs => obj) and method(:objs => [obj1, obj2])

This seems to be the best way (Array.to_a returns self):

arg = arg.to_a

But the ruby docs say Object.to_a will soon be obsolete. Is there convenient replacement?

Anything more succinct than this?

arg = arg.respond_to?(:to_a) ? arg.to_a : [arg]
A: 

What about Array.new(1, arg)?

Keltia
The point is that I don't know what the argument is. If it is an array already, I want to leave it, otherwise create a one-element array.
Daniel Beardsley
+2  A: 

It seems only Object.to_a is deprecated, removing a default to_a and forcing each class to define its own (e.g., Hash.to_a).

self.to_a       #=> -:1: warning: default `to_a' will be obsolete
"hello".to_a    #=> ["hello"]
Time.new.to_a   #=> [39, 54, 8, 9, 4, 2003, 3, 99, true, "CDT"]

h = { "c" => 300, "a" => 100, "d" => 400, "c" => 300  }
h.to_a   #=> [["a", 100], ["c", 300], ["d", 400]]

If your argument is an instance of Object, try:

Hash.new(obj).to_a


@Daniel [comment to Ollivier]: The point is that I don't know what the argument is. If it is an array already, I want to leave it, otherwise create a one-element array.

If that's the case, try:

obj = [obj] if !obj.is_a?(Array)
Jonathan Lonowski
Not exactly what I was looking for, and Hash.new(obj).to_a always returns [].
Daniel Beardsley
obj = [obj] unless obj.is_a?(Array) might be easier to read.. unless you don't like 'unless' of course!
Yaser Sulaiman
Nope. Just never used it before. Still a bit green with Ruby. ;)
Jonathan Lonowski
+2  A: 

You can take the duck typing aproach if that suits the problem better, make a list of all the methods you need, and check if the object already have them, if not, make it an array:

[:[], :each, :etc...].all? { |m| obj.respond_to? m } ? obj : [obj]

The advantage is that you give the object a chance to implement it's own semantics for indexed access.

krusty.ar
+1  A: 

I'm not sure if this helps, but what I often need is not that the arg be an array, but that the arg responds to each.

arg = [arg] unless arg.respond_to? :each
theschmitzer
A: 

I do this a lot, and always use:

arg = [arg] unless arg.is_a?(Array)

Though if you know you're never passing in arrays as individual arguments you can also do:

arg = [arg].flatten
glenn mcdonald
+7  A: 

Use the method Kernel#Array:

Array([1,2,3]) #=> [1, 2, 3]
Array(123) #=> [123]

Yes it may look like a class at first but this is actually a method that starts with a capital letter.

nertzy
Perfect! Exactly what I was looking for.
Daniel Beardsley
A couple things to keep in mind, though: 1) If you pass a hash to Array() you'll get hash.to_a, not [hash]. 2) If you pass nil to Array() you'll get [], not [nil].
glenn mcdonald
Ruby is so cool. Everything is an object. I mean, sometimes. Well, Kernel, that's an object, and it's also got some objecty methods on it too, with capital letters! So what does `Kernel.Array` do anyway? Oh yeah, it calls the `to_ary` method on the object. If that doesn't work, it puts your parameter into a single-element array. Tricky!
Yar
No wait, that was wrong. Sorry, this is so clear in the docs. It calls `to_a`... Oh, here it is from 1.9 "Returns arg as an Array. First tries to call arg.to_ary, then arg.to_a." WTF?????
Yar
Just to be clear, both nil.to_a and Array(nil) return an empty array.
henning-koch