What is the right way to:
is_array("something") # => false (or 1)
is_array(["something", "else"]) # => true (or > 1)
or to get the count of items in it?
What is the right way to:
is_array("something") # => false (or 1)
is_array(["something", "else"]) # => true (or > 1)
or to get the count of items in it?
You probably want to use kind_of().
>> s = "something"
=> "something"
>> s.kind_of?(Array)
=> false
>> s = ["something", "else"]
=> ["something", "else"]
>> s.kind_of?(Array)
=> true
kind_of?() over other solutions? Some explanation on the benefits of your answer over others would be helpful for future readers.Are you sure it needs to be an array? You may be able to use respond_to?(method) so your code would work for similar things that aren't necessarily arrays (maybe some other enumberable thing). If you do actually need an array, then the post describing the Array#kind\_of? method is best.
['hello'].respond_to?('each')
respond_to?(:to_ary).Instead of testing for an Array, just convert whatever you get into a one-level Array, so your code only needs to handle the one case.
t = [*something] # or...
t = Array(something) # or...
def f *x
...
end
Ruby has various ways to harmonize an API which can take an object or an Array of objects, so, taking a guess at why you want to know if something is an Array, I have a suggestion.
The splat operator contains lots of magic you can look up, or you can just call Array(something) which will add an Array wrapper if needed. It's similar to [*something] in this one case.
def f x
p Array(x).inspect
p [*x].inspect
end
f 1 # => "[1]"
f [1] # => "[1]"
f [1,2] # => "[1, 2]"
Or, you could use the splat in the parameter declaration and then .flatten, giving you a different sort of collector. (For that matter, you could call .flatten above, too.)
def f *x
p x.flatten.inspect
end # => nil
f 1 # => "[1]"
f 1,2 # => "[1, 2]"
f [1] # => "[1]"
f [1,2] # => "[1, 2]"
f [1,2],3,4 # => "[1, 2, 3, 4]"
And, thanks gregschlom, it's sometimes faster to just use Array(x) because when it's already an Array it doesn't need to create a new object.
[*nil] => []. So you might end up with an empty array.Array(foo) is much more efficient than [*foo][1,2,3].is_a? Array evaluates to true.
is_a? in this whole thread. The closest is a [1,2,3].is_a? Enumerable. I still think it's worth while to have this answer.It sounds like you're after something that has some concept of items. I'd thus recommend seeing if it is Enumerable. That also guarantees the existence of #count.
For example,
[1,2,3].is_a? Enumerable
[1,2,3].count
note that, while size, length and count all work for arrays, count is the right meaning here - (for example, 'abc'.length and 'abc'.size both work, but 'abc'.count doesn't work like that).
Caution: a string is_a? Enumerable, so perhaps this isn't what you want... depends on your concept of an array like object.
Also consider using Array(). From the Ruby Community Style Guide:
Use Array() instead of explicit Array check or [*var], when dealing with a variable you want to treat as an Array, but you're not certain it's an array.
# bad
paths = [paths] unless paths.is_a? Array
paths.each { |path| do_something(path) }
# bad (always creates a new Array instance)
[*paths].each { |path| do_something(path) }
# good (and a bit more readable)
Array(paths).each { |path| do_something(path) }
to_a is called on each argument added to the new array, so Array({id: 100}) returns [[:id, 100]]