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.

···

--
Chad Perrin [ 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 Thu, Jul 21, 2011 at 10:17 PM, Chad Perrin <code@apotheon.net> wrote:

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.

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

Chad Perrin 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
=> #<struct Foo one=nil, two=nil>
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

···

--
Posted via http://www.ruby-forum.com/\.

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.

···

On Thu, Jul 21, 2011 at 4:17 PM, Chad Perrin <code@apotheon.net> wrote:

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.

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

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.

···

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

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

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

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 Jul 21, 2011, at 4:41 PM, Sean O'Halpin wrote:

On Thu, Jul 21, 2011 at 10:17 PM, Chad Perrin <code@apotheon.net> wrote:

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.

--
Chad Perrin [ 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}>

Tim Pease 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

=> #<OpenStruct foo=1, bar=2>

os.foo

=> 1

os.bar

=> 2

···

--
Posted via http://www.ruby-forum.com/\.

Brian Candler wrote in post #1012394:

Tim Pease 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

=> #<OpenStruct 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

···

--
Posted via http://www.ruby-forum.com/\.