Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating an object on the fly with accessor methods

Tags:

ruby

accessor

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?

like image 385
sawa Avatar asked Feb 09 '13 16:02

sawa


Video Answer


1 Answers

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.

like image 144
Andrew Marshall Avatar answered Oct 17 '22 13:10

Andrew Marshall