How do I recursively traverse a data structure containing a mix of types?

For starters, I’m a total ruby noob who needs to be able to structure
the input data in such a way that it can be accessed & structured
sensibly.
I found an example on here that I’ve modified to the best of my
ability…but it does not do what I want.
The attached input file contains a real-life piece of data.

Here is the recursive function: I appreciate anyone who’d take a stab at
this.

def strip_hash_values(hash)

#hash.each_value do |v|
hash.each do |v|
puts " strip_hash_values – >"
case v
when String then puts “STRING #{v}”
#v.strip!
puts “<–strip_hash_values”
return v
#when Array then strip_array_values(v)# i.strip!}
when Array then v.each {|i| #puts #Z"ARRAY value: #{i}"
strip_hash_values(v)} # i.strip!}
when Hash then strip_hash_values(v)
when Integer then puts “Integer #{v}”
puts “<–strip_hash_values”
return v
else raise ArgumentError, “Unhandled type #{v.class}”
end
end
end

On Feb 24, 2012, at 15:41 , mike lupo wrote:

hash.each do |v|

that needs to be hash.each do |k,v|

Thanks Ryan D…
Problem #1, not every piece of data passed in is a hash. So
restructuring the function a little helps clarify that. Apologies for my
shoddy first attempt, and thanks again you for your input.

For the readers finding this via search, find the input contained in a
text file attached to my initial post.

#2, I have this working now. Not elegant, hardly fault tolerant, but
works.

#define a boolean “test”.
class Object
def boolean?
self.is_a?(TrueClass) || self.is_a?(FalseClass)
end
end

def traverse_data(input, indent="")
puts “#{indent}traverse_data – >”

if input.class==Fixnum
puts “#{indent}Integer: #{input}”
return
end
if input.boolean?
puts “#{indent}Boolean: #{input}”
return
end
if input.class==Bignum
puts “#{indent}Bignum: #{input}”
return
end

input.each do |v|
case v
when String then puts “#{indent}STRING #{v}”
puts “#{indent}<–traverse_data”
return
when Array then v.each_index {|i| #puts
traverse_data(v[i], "#{indent} ")}
when Hash then puts “#{indent}HASH: #{v}”
traverse_data(v, "#{indent} ")
#return v
else raise ArgumentError, “Unhandled type #{v.class}”
end
end
end

#call it now.
input = {gotten from attached text file}
traverse_data(input)

Rather than:

if input.class==Fixnum

It is often nicer to write:

if input.is_a? Fixnum

An even better way may be to decide to not
care about some kind of input and let “duck
typing” allow things to “happen”.

Like (just a general rule):

def foo(input)
@array << input # and @array could be either a string or an array.
And input as well. Yes, not the best demonstration, but a simple one
still.
end