I've written a method to turn a hash (nested if necessary) of values into a chain that can be used with eval to dynamically return values from an object.
E.g. passed a hash like { :user => { :club => :title }}, it will return "user.club.title", which I can then eval. (The point of this is to write a method for views that will allow me to dump the contents of objects rapidly, by passing in the object and a list of attributes that I want to display, e.g.: item_row(@user, :name, :email, { :club => :title })
Here's what I've got. It works, but I know it can be improved. Curious to see how you'd improve it.
# hash = { :user => { :club => :title }}
# we want to end up with user.club.title
def hash_to_eval_chain(hash)
raise "Hash cannot contain multiple key-value pairs unless they are nested" if hash.size > 1
hash.each_pair do |key, value|
chain = key.to_s + "."
if value.is_a? String or value.is_a? Symbol
chain += value.to_s
elsif value.is_a? Hash
chain += hash_to_eval_chain(value)
else
raise "Only strings, symbols, and hashes are allowed as values in the hash."
end
# returning from inside the each_pair block only makes sense because we only ever accept hashes
# with a single key-value pair
return chain
end
end
puts hash_to_eval_chain({ :club => :title }) # => club.title
puts hash_to_eval_chain({ :user => { :club => :title }}) # => user.club.title
puts hash_to_eval_chain({ :user => { :club => { :owners => :name }}}) # => user.club.owners.name
puts ({ :user => { :club => { :owners => :name }}}).to_s # => userclubownersname (close, but lacks the periods)