Scope problem in controller

I am writing a small helper to walk a hash or an array of arrays to
find a nested key. (by the way, if there is an existing function for
this in Ruby I will willingly take it instead).

The call is this

keywalk(collection, key)

the def is this

def keywalk(collection,key)
key = key.to_s
collection.each do |check|
return check[1] if check[0] == key
keywalk(check,key) if (check.is_a?(Array) or check.is_a?(Hash))
end
nil
end

The problem that I have is that key is always nil inside
collection.each even though it is define inside the method and a puts
shows that it has the value passed as that parameter. Why is key
evidently out of scope inside the iterator?

On Jan 19, 9:54Â pm, byrnejb [email protected] wrote:

  keywalk(check,key) if (check.is_a?(Array) or check.is_a?(Hash))
 end
 nil
end

The problem that I have is that key is always nil inside
collection.each even though it is define inside the method and a puts
shows that it has the value passed as that parameter. Â Why is key
evidently out of scope inside the iterator?

blocks can see variables created outside them (but local variables
created inside the block do not persist outside it)
Your keywalk function will however almost always return nil - when you
recurse and call keywalk a second time you are ignoring the return
value

Fred

On Jan 19, 7:17Â pm, Frederick C. [email protected]
wrote:

blocks can see variables created outside them (but local variables
created inside the block do not persist outside it)
Your keywalk function will however almost always return nil - when you
recurse and call keywalk a second time you are ignoring the return
value

Fred

OK. Then I am missing something simple. And, I am probably trying
too hard. I will revisit the problem.

I am clearly misunderstanding something fundamental about ruby methods
and the return statement.

I have finally gone for the blunt force solution so that I can follow
along with what is happening.

def keywalk(tcoll,tkey,result=nil)

if result
  puts("result returned = #{result}")
  return result
end

print tcoll.to_yaml
puts("")

tcoll.each_pair do | tk, tv |
  puts("tkey is #{tkey} and tk is: #{tk} and tv is #{tv}")
  if tk.to_s == tkey.to_s
    puts("keys are equal and tv is #{tv}")
    result = { tkey => tv.to_s }
    puts("The result is = #{result}")
    return
  end

  if tv.kind_of?(Array)
    puts("Array = #{tv.inspect}")
    tv.each do |tva|
      if tva.kind_of?(Hash)
        keywalk(tva,tkey,result)
      end
    end
  elsif tv.kind_of?(Hash)
    puts("Hash = #{tv.inspect} class is #{tv.class}")
    keywalk(tv,tkey,result)
  else
    # puts("Something else = #{tv.inspect} with class #

{tv.class}")
end
end
puts(“The final result was = #{result}”)
result
end

Why, even when I finally find the inner key which this does
accomplish, do I always get nil returned? What do I misapprehend
about returns?

tkey is user_id and tk is: user_id and tv is 339
keys are equal and tv is 339
The result is = user_id339
This is what keywalk returns:

Exactly right.

“return” alone will always return “nil”.

Aleksey

Quoting byrnejb [email protected]:

  return result
    puts("The result is = #{result}")
    return
  end

Do you mean ‘return result’ here?

Jeffrey

Jeffrey L. Taylor wrote:

Quoting byrnejb [email protected]:

  return result
    puts("The result is = #{result}")
    return
  end

Do you mean ‘return result’ here?

You may also be confused by the ActiveSupport “returning” method.

Jeffrey

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Jeffrey L. Taylor wrote:

  end

Do you mean ‘return result’ here?

Jeffrey

Thank you for pointing out the error with the return. I fixed that
and and then finally realised that I was not assigning my return value
when calling the method recursively. This was why the result was
disappearing after I found it.

The final code looks like this:

def keywalk(tcoll,tkey,result=nil)

tcoll.each_pair do | tk, tv |

  if tk.to_s == tkey.to_s
    result = { tkey => tv.to_s }
    return result if result
  end

  if tv.kind_of?(Array)
    puts("Array = #{tv.inspect}")
    tv.each do |tva|
      if tva.kind_of?(Hash)
        result = keywalk(tva,tkey,result)
        return result if result
      end
    end
  elsif tv.kind_of?(Hash)
    puts("Hash = #{tv.inspect} class is #{tv.class}")
    result = keywalk(tv,tkey,result)
    return result if result
  end
end

return result

end

A bit bit wordy but at least I can follow along with it in my head.

Regards,