Question

I've only been learning the deep parts of Ruby for a few months so apologies if this is a bit of a dumb question. I'm attempting to recursively iterate through an Array that may contain nested Arrays and as such I need to check the type of the current element. I have the following code as a small test:

arr = [ 1..2, [3..4, [5..6]], [7..8, [9..10]] ]

arr.each do |node|
  p node.class
  p node.instance_of? Array
end

When I run it, I get the following output:

Range
false
Array
false
Array
false

I expected the last two to return True, given I have an Array containing a Range and two nested Arrays.

What's even weirder, is if I write the following:

node.class.name == "Array"

It returns True, as it should.

What's happening here?

Ruby Version: MRI 1.9.3-p194

Note: I eventually realised that this was occurring due to the way I namespace my code using modules to avoid code-collision, like so, but also verify object identity in a naughty way:

module MyProg
  class MyClass
    attr_reader :my_array

    def initialize(size)
      @my_array = Array.new(size)
    end
  end
end

MyProg::MyClass.new

Doing this isolates your code but has the downfall of causing all class lookups to be resolved starting from under your namespace. This means that in the above example, my_array.class would actually resolve to MyProg::Array instead of the global Array class.

If you namespace like this and you still want to use this method, you can remedy it by using the double-colon global identifier before the class to force Ruby to begin lookup from the global namespace:

arr.is_a? ::Array
arr.is_a? ::String

Given Ruby's Duck Typing abilities however (and for better code maintenance later on), you should really be testing the behaviour of the object as-per Peter's suggestion below. As such I'm marking his answer as correct for some excellent help given to a learner!

Was it helpful?

Solution

I wrote another answer, but one major question is - why are you doing this? Why not, instead, just call flatten on the array so you just get the entries? Or, check for the behavior of the objects instead. You might need to give more detail about what you require.

OTHER TIPS

You really mean is_a?, which is a more general test to see if the node is of type Array, rather than a specific instance of the specific Array class that you mention. See here for more details. But if you just use is_a? everything will make sense.

I ran your code and got these results.

Range
false
Array
true
Array
true

I'm running ruby 1.9.3p125

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top