Turn hash into object variables?


(David Naseby) #1

From: Ruby Baby [mailto:ruby@hitmedia.com]
I know beautiful Ruby has an easier way to do this:

class SomeClass
def initialize(someHash)
@name = someHash[‘name’]
@address = someHash[‘address’]
@blah = someHash[‘blah’]
# etc for many key=>value pairs …
end
end

How can I make it do that for every key in the hash?

class SomeClass
def initialize( h )
h.each do | key, val |
instance_variable_set( “@#{key}”.intern, val )
end
end
end

David Naseby
http://homepages.ihug.com.au/~naseby/


(Harry Ohlsen) #2

David Naseby wrote:

class SomeClass
def initialize( h )
h.each do | key, val |
instance_variable_set( “@#{key}”.intern, val )
end
end
end

Also, if you want others to be able to access those instance variables, you’ll probably want to define readers and/or writers for them.

The code I came up with before David beat me to the punch was …

class SomeClass
def initialize(h)
h.each do |key, value|
instance_eval %{
@#{key} = value

    def #{key}
      @#{key}
    end
  }
end

end
end

I tried to replace the “def #{key} …” with “attr_reader :#{key}.intern”, but that didn’t work, for some reason that I don’t have time to look at. I’d be interested to hear from anyone who can explain why it doesn’t.

By the way, unless I’m mistaken, neither of these will work properly if the hash’s keys are something other than strings or symbols (ie, things for which #{key} generates a simple string). However, I’m guessing that’s all you intended them to be.

Harry O.


(Peter) #3

I tried to replace the “def #{key} …” with “attr_reader
:#{key}.intern”, but that didn’t work, for some reason that I don’t have
time to look at. I’d be interested to hear from anyone who can explain
why it doesn’t.

attr_reader is defined in Module, so it can be used in module and class
definitions. It is not defined in Object or so, so you can’t call it on an
instance, but that is what you were trying to do. You can add it to the
object’s singleton class though:

instance_eval %Q{
class << self ; attr_reader #{key.intern.inspect} ; end
}

Peter