What is the easiest way to create an object on the fly with accessor methods defined by a hash? For example, if I have a hash:
{foo: "Foo", bar: "Bar"}
I want to have an object that has accessor methods foo
, foo=
, bar
, and bar=
with the initial value "Foo"
, and "Bar"
, respectively. I can think of doing:
module ObjectWithAccessor
def self.new h; Struct.new(*h.keys).new(*h.values) end
end
o = ObjectWithAccessor.new(foo: "Foo", bar: "Bar")
o.foo # => "Foo"
but, I don't need to have multiple instances of them with the same particular set of keys, but rather want to create new instances of it each time with possibly different set of keys, so creating a new class with Struct
each time for each object seems overkill, and I want to avoid that. Is there a better way to do this?
OpenStruct
already provides what you want:
require 'ostruct'
o = OpenStruct.new foo: "Foo", bar: "Bar"
o.foo #=> "Foo"
o.bar #=> "Bar"
o.bar = 'BAR'
o.bar #=> "BAR"
Alternatively, if you don’t want to be able to define arbitrary attributes after object creation (like you can with OpenStruct
, you could do something like this:
class ObjectWithAccessor
def initialize attrs
attrs.each do |name, val|
singleton_class.send :attr_accessor, name.to_sym
public_send :"#{name}=", val
end
end
end
o = ObjectWithAccessor.new foo: "Foo", bar: "Bar"
o.foo #=> "Foo"
o.bar #=> "Bar"
o.bar = 'BAR'
o.bar #=> "BAR"
o.bsr = 'typo' #=> #<NoMethodError: undefined method `bsr=' for #<Object:0x007fa4160847f8>>
This still doesn’t create a new class just to use it once, and avoids the “openness” of OpenStruct
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With