Attr_accessor for hash keys

Is there a way to use attr_accessor, or something like it (without
writing it from scratch), for hash keys? For instance:

class Foo
  attr_accessor :bar[:one], :bar[:two]
  def initialize(bar)
    @bar = bar
  end
end

Obviously, :bar[:one] and :bar[:two] won’t work, because symbols don’t
have [] methods, but that should illustrate the general gist of what I’m
asking (I hope). I’d just like to avoid the clutter of writing a bunch
of basic accessors myself, the long way, in a class definition where I’d
like to keep all the data in a hash but have direct accessor method ways
to work with specific key=>value pairs.

On Thu, Jul 21, 2011 at 10:17 PM, Chad P. [email protected] wrote:

Obviously, :bar[:one] and :bar[:two] won’t work, because symbols don’t
have [] methods, but that should illustrate the general gist of what I’m
asking (I hope). I’d just like to avoid the clutter of writing a bunch
of basic accessors myself, the long way, in a class definition where I’d
like to keep all the data in a hash but have direct accessor method ways
to work with specific key=>value pairs.


Chad P. [ original content licensed OWL: http://owl.apotheon.org ]

This is reasonably close to what you described:

module HashAccessor
def hash_accessor(hash_name, *key_names)
key_names.each do |key_name|
define_method key_name do
instance_variable_get(“@#{hash_name}”)[key_name]
end
define_method “#{key_name}=” do |value|
instance_variable_get(“@#{hash_name}”)[key_name] = value
end
end
end
end

class Foo
extend HashAccessor
hash_accessor :bar, :one, :two
def initialize(bar)
@bar = bar
end
end

foo = Foo.new(:one => 1, :two => 2) # => #<Foo:0x9c28310
@bar={:one=>1, :two=>2}>
foo.one # => 1
foo.one = 42
foo # => #<Foo:0x9c28310
@bar={:one=>42, :two=>2}>

Regards,
Sean

On Jul 21, 2011, at 4:41 PM, Sean O’Halpin wrote:

 end

end

foo = Foo.new(:one => 1, :two => 2) # => #<Foo:0x9c28310
@bar={:one=>1, :two=>2}>
foo.one # => 1
foo.one = 42
foo # => #<Foo:0x9c28310
@bar={:one=>42, :two=>2}>

This sounds like a job for method_missing …

class Foo
def initialize( bar )
@bar = bar
end

def method_missing( key, *args, &block )
  super unless @bar.has_key? key
  @bar[key]
end

end

Also, take a look at Ara Howard’s “Map” gem and see if that will get you
what you need.

m = Map(:one => 1, :two => 2)
s = m.struct
s.one #=> 1
s.two #=> 2

Blessings,
TwP

On Thu, Jul 21, 2011 at 4:17 PM, Chad P. [email protected] wrote:

Obviously, :bar[:one] and :bar[:two] won’t work, because symbols don’t
have [] methods, but that should illustrate the general gist of what I’m
asking (I hope). I’d just like to avoid the clutter of writing a bunch
of basic accessors myself, the long way, in a class definition where I’d
like to keep all the data in a hash but have direct accessor method ways
to work with specific key=>value pairs.


Chad P. [ original content licensed OWL: http://owl.apotheon.org ]

You could coerce forwardable into kind of behaving like this:

require ‘forwardable’
class Foo
extend Forwardable
def_delegator ‘@bar’, ‘[], :one’, ‘one’
def_delegator ‘@bar’, ‘[], :two’, ‘two’

def initialize(bar)
@bar = bar
end

end

foo = Foo.new one: 1, two: 2
foo.one # => 1
foo.two # => 2

But if they ever change its implementation, this will break >.<

Honestly, I’d probably do what Sean did.

Tim P. wrote in post #1012284:

This sounds like a job for method_missing …

In which case, you might as well just use OpenStruct.

require ‘ostruct’
=> true

os = OpenStruct.new :foo=>1, :bar=>2
=> #

os.foo
=> 1

os.bar
=> 2

Chad P. wrote in post #1012264:

Is there a way to use attr_accessor, or something like it (without
writing it from scratch), for hash keys? For instance:

class Foo
  attr_accessor :bar[:one], :bar[:two]
  def initialize(bar)
    @bar = bar
  end
end

Obviously, :bar[:one] and :bar[:two] won’t work, because symbols don’t
have [] methods, but that should illustrate the general gist of what I’m
asking (I hope). I’d just like to avoid the clutter of writing a bunch
of basic accessors myself, the long way, in a class definition where I’d
like to keep all the data in a hash but have direct accessor method ways
to work with specific key=>value pairs.

irb(main):001:0> Foo = Struct.new :one, :two
=> Foo
irb(main):002:0> f = Foo.new
=> #
irb(main):003:0> f[:one]
=> nil
irb(main):004:0> f[:one] = 1
=> 1
irb(main):005:0> f.one
=> 1
irb(main):006:0> f.one = 111
=> 111
irb(main):007:0> f[:one]
=> 111
irb(main):008:0> Hash[*f.members.zip(f.to_a).flatten]
=> {:one=>111, :two=>nil}
irb(main):009:0> class Struct
irb(main):010:1> def to_hash;Hash[*members.zip(to_a).flatten];end
irb(main):011:1> end
=> nil
irb(main):012:0> f.to_hash
=> {:one=>111, :two=>nil}

Kind regards

robert

On Fri, Jul 22, 2011 at 06:17:36AM +0900, Chad P. wrote:

Is there a way to use attr_accessor, or something like it (without
writing it from scratch), for hash keys?

Judging by the responses, the answer is basically “no”. I appreciate
the
work-around examples, though; some of them are pretty interesting, and
I’ll make use of (one of?) them.

Thanks for the responses.

Brian C. wrote in post #1012394:

Tim P. wrote in post #1012284:

This sounds like a job for method_missing …

In which case, you might as well just use OpenStruct.

require ‘ostruct’
=> true

os = OpenStruct.new :foo=>1, :bar=>2
=> #

os.foo
=> 1

os.bar
=> 2

im new to this. i was wondering if the tutorial in try ruby is usefull
and worth the time.i use to do turbo c