Setter method for Hash value

Hi

I guess there is a simple solution to this, but right now, I can't come up
with it.

I want to wrap two external functions to behave like a regular hash.

      class MyClass
        def props
          some_data = SomeClass::get_prop
          some_data.to_h
        end
        def props[key]=(value) # Not a valid construct
          SomeClass::set_prop(key, value)
        end
      end

      props["timeout"]
      =>"10"

      props["timeout"]="20"
      => nil

Now, the getter method works perfectly, but I don't know how to declare the
setter method :o(

Anyone?

Kind regards,
Rolf

just a crude example,

class C
def initialize
  @h={}
end
def (index)
  @h[index]
end
def =(index,value)
  @h[index]=value
end
def h
  @h
end
end
#=> nil
c=C.new
#=> #<C:0x8873e8c @h={}>
c[:a]=1
#=> 1
c[:b]=2
#=> 2
c[:a]
#=> 1
c.h
#=> {:a=>1, :b=>2}
c
#=> #<C:0x8873e8c @h={:a=>1, :b=>2}>

best regards -botp

···

On Fri, Feb 4, 2011 at 12:12 AM, Rolf Pedersen <rolfhsp@gmail.com> wrote:

   def props\[key\]=\(value\)       \# Not a valid construct

Try calling it props= for the method name itself.

Something like

def props=(key, value) maybe?

···

-----Original Message-----
From: Rolf Pedersen [mailto:rolfhsp@gmail.com]
Sent: Thursday, February 03, 2011 11:12 AM
To: ruby-talk ML
Subject: Setter method for Hash value

Hi

I guess there is a simple solution to this, but right now, I can't come
up with it.

I want to wrap two external functions to behave like a regular hash.

      class MyClass
        def props
          some_data = SomeClass::get_prop
          some_data.to_h
        end
        def props[key]=(value) # Not a valid construct
          SomeClass::set_prop(key, value)
        end
      end

      props["timeout"]
      =>"10"

      props["timeout"]="20"
      => nil

Now, the getter method works perfectly, but I don't know how to declare
the setter method :o(

Anyone?

Kind regards,
Rolf

class MyClass
  def []=(key, value)
    SomeClass::set_prop(key, value)
  end
end

···

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

I see I have forgotten something when extracting code to a more generic
example: making an instance of the class...
So the corrected version:

      class MyClass
        def props
          some_data = SomeClass::get_prop
          some_data.to_h
        end
        def props[key]=(value) # Not a valid construct
          SomeClass::set_prop(key, value)
        end
      end

      my_instance = MyClass.new
      my_instance.props["timeout"]
      =>"10"

      my_instance.props["timeout"]="20"
      => nil

-Rolf

···

On Thu, Feb 3, 2011 at 5:09 PM, Rolf Pedersen <rolfhsp@gmail.com> wrote:

Hi

I guess there is a simple solution to this, but right now, I can't come up
with it.

I want to wrap two external functions to behave like a regular hash.

      class MyClass
        def props
          some_data = SomeClass::get_prop
          some_data.to_h
        end
        def props[key]=(value) # Not a valid construct
          SomeClass::set_prop(key, value)
        end
      end

      props["timeout"]
      =>"10"

      props["timeout"]="20"
      => nil

Now, the getter method works perfectly, but I don't know how to declare the
setter method :o(

Anyone?

Kind regards,
Rolf

Rolf Pedersen wrote in post #979431:

        def props[key]=(value) # Not a valid construct

def =(key,value)

      props["timeout"]="20"
      => nil

foo = MyClass.new
foo["timeout"]="20"

···

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

You might want to have a look at http://www.ruby-doc.org/stdlib/libdoc/forwardable/rdoc/index.html

cheers

Hi Brian (and others who have contributed with suggestions along the same
line)

It's not the class MyClass that I'd like to behave like a Hash.
I'm trying to make getter and setter methods for a virtual hash property
called props.
Under the hood, the implementation calls external methods to retrieve or
store the given values for a given key.

Kind regards,
-Rolf

···

On Thu, Feb 3, 2011 at 7:24 PM, Brian Candler <b.candler@pobox.com> wrote:

Rolf Pedersen wrote in post #979431:

> def props[key]=(value) # Not a valid construct

def =(key,value)

> props["timeout"]="20"
> => nil

foo = MyClass.new
foo["timeout"]="20"

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

objects receive methods wc return objects, wc in turn can receive
another method, and so fort on the chain..

eg,

class MyClass
  def props
    some_data = SomeClass::get_prop
  end
  def =(key,value)
    SomeClass::set_prop(key, value)
  end
end
#=> nil

class SomeClass
  class << self
    @@h={}
    def get_prop
      @@h
    end
    def set_prop key,value
      @@h[key]=value
    end
    def show
      @@h
    end
  end
end
#=> nil

c=MyClass.new
#=> #<MyClass:0x888f6b4>
c.props
#=> {}
c.props[:a]=1
#=> 1
c.props[:b]=2
#=> 2
c.props
#=> {:a=>1, :b=>2}
SomeClass::show
#=> {:a=>1, :b=>2}

best regards -botp

···

On Fri, Feb 4, 2011 at 2:52 AM, Rolf Pedersen <rolfhsp@gmail.com> wrote:

I'm trying to make getter and setter methods for a virtual hash property
called props. Under the hood, the implementation calls external methods to retrieve or
store the given values for a given key.

Rolf Pedersen wrote in post #979464:

Hi Brian (and others who have contributed with suggestions along the
same
line)

It's not the class MyClass that I'd like to behave like a Hash.
I'm trying to make getter and setter methods for a virtual hash property
called props.

Then the 'props' object which you return needs methods and =
defined, which do whatever you want them to do.

I see you are using these methods on the class itself (not instances of
the class):

    SomeClass::set_prop(key, value)

In that case, you can define them as class methods:

    class SomeClass
      def self.(key)
        get_prop(key)
      end
      def self.=(key,value)
        set_prop(key,value)
      end
    end

And then simply return the class itself:

    class MyClass
       def props
         SomeClass
       end
     end

If you were using *instances* of SomeClass, then personally I would just
define methods and = as instance methods. Depending on how
Hash-like you want this object to be, you may want to define some other
methods too.

If there is some particular reason why you can't do that, then you would
have to return a proxy object, whose and = methods are relayed to
get_prop and set_prop on the underlying SomeClass object.

If you still want props to return an actual Hash, then it will have to
be a Hash which has been modified so that = performs the operation on
the underlying object.

You can use delegate.rb, or you can explicitly delegate those methods
which you want to. Here is some code from CouchTiny which wraps a Hash:

module CouchTiny
  # A class which delegates a small subset of methods to a Hash (to keep
  # the space as clear as possible for accessor names)
  class DelegateDoc
    attr_accessor :doc

    def initialize(doc = {})
      @doc = doc.to_hash
    end

    def to_hash
      @doc
    end

    def ==(other)
      @doc == other # .to_hash is done by Hash#==
    end

    def to_json(*args)
      @doc.to_json(*args)
    end

    alias :orig_respond_to? :respond_to?
    def respond_to?(*m)
      orig_respond_to?(*m) || @doc.respond_to?(*m)
    end

    def (k)
      @doc[k.to_s]
    end

    def =(k,v)
      @doc[k.to_s] = v
    end

    def key?(k)
      @doc.key?(k)
    end

    def has_key?(k)
      @doc.has_key?(k)
    end

    def delete(k)
      @doc.delete(k)
    end

    def merge!(h)
      @doc.merge!(h)
    end

    def update(h)
      @doc.update(h)
    end

    def dup
      self.class.new(@doc.dup)
    end

    #def method_missing(m, *args, &block)
    # @doc.__send__(m, *args, &block)
    #end
  end
end

Regards,

Brian.

···

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

sorry, ignore the previous unclear post..

try again,

class MyClass
  def props
    some_data = SomeClass::get_prop
    self
  end
  def []=(key,value)
    p "i was called"
    SomeClass::set_prop(key, value)
  end
end
#=> nil

class SomeClass
  class << self
    @@h={}
    def get_prop
      @@h
    end
    def set_prop key,value
      @@h[key]=value
    end
    def show
      @@h
    end
  end
end
#=> nil

c=MyClass.new
#=> #<MyClass:0x8887b94>
c.props
#=> #<MyClass:0x8887b94>
c.props[:a]=1
"i was called"
#=> 1
c.props[:b]=2
"i was called"
#=> 2
c.props
#=> #<MyClass:0x8887b94>
SomeClass::show
#=> {:a=>1, :b=>2}

best regards -botp

···

On Fri, Feb 4, 2011 at 11:22 AM, botp <botpena@gmail.com> wrote:

Hei Brian

Thanks for the answer.
I do have a solution now which works for c.props[:key] and c.props[:key] =
"value", but that solves just part of my problem.
I realize that I need to elaborate on the "requirements" a bit further.

MyClass should have a "virtual hash property", props.
I want to interact with props, like it was a regular hash, but under the
hood, it should perform calls towards the external library.

SomeClass (renamed to DataClass in code below) just represents a sample
external library with some functions getting or setting some internal data:
* get_props() # Gets all the properties, data format is not
important, could be a comma separated list. The receiver should handle the
conversion to Hash.
* get_prop(key) # Gets one value for a given key
* set_props(data) # Set all the properties. Again, data format is not
important.
* set_prop(key, value) # Set one particular property.

With MyClass I should be able to to the following:
c = MyClass.new
(1)
c.props # under the hood, this will call SomeClass::get_props() and convert
the response to a hash
=> {:a=>1, :b=>2, :c=>3}
(2)
c.props[:a] # This should make a call to SomeClass::get_prop("a")
=> 1
(3)
c.props={:a=>"a", :b=>"b", :c=>"c"} # This should make a call to e.g.
SomeClass::set_props("a", "a", "b", "b", "c", "c")
=> {:a=>"a", :b=>"b", :c=>"c"}
(4)
c.props[:d] = "d" # This should make a call to SomeClass::set_prop("d")
=> "d"
(5)
c.props # Again, make a vall to SomeClass::get_props(), to check that
new data is stored.
=> {:a=>"a", :b=>"b", :c=>"c", :d=>"d"}

Now, following your first suggestion, Brian, I came up with the following
code, where I use a DataClass which represents the external interface, and
which happens to operate on Hash data, to make it simple:

      class DataClass
        @@data = {:a=>1, :b=>2, :c=>3}
        def self.get_props()
          @@data
        end
        def self.get_prop(key)
          @@data[key]
        end
        def self.set_props(data)
          @@data = data
        end
        def self.set_prop(key, value)
          @@data[key] = value
        end
      end

      class PropsClass
        def (key)
          DataClass::get_prop(key)
        end
        def =(key, value)
          DataClass::set_prop(key, value)
        end
      end

      class MyClass
        def initialize
          @props = PropsClass.new
        end
        def props
          @props
        end
      end

Now this works for (2) and (4), but not for (1) and (3).
(1) just returns
      #<PropsClass:0x1418748>
and (3) returns
      test_props.rb:35:in `<main>': undefined method `props=' for
#<MyClass:0x14202d8 @props=#<PropsClass:0x14202c0>> (NoMethodError)

The reason is obvious. I haven't even found a way to call get_props and
set_props.
Clearly, something is missing.
I don't have a method that redefines = in the PropsClass. (This method
cannot be redefined, right?).
And according to my requirements, c.props should not return the PropsClass
instance, but rather call and return a value from a PropsClass function,
which I assume is not possible to do either.
So, I don't understand how (if possible) to go about achieving what I
want.... Maybe this is a dead end?
:o(

About your other suggestion, delegates, I have to study this a bit more. I'm
still a low-level Ruby programmer :o)

Best regards,
Rolf

···

On Fri, Feb 4, 2011 at 9:56 AM, Brian Candler <b.candler@pobox.com> wrote:

Rolf Pedersen wrote in post #979464:
> Hi Brian (and others who have contributed with suggestions along the
> same
> line)
>
> It's not the class MyClass that I'd like to behave like a Hash.
> I'm trying to make getter and setter methods for a virtual hash property
> called props.

Then the 'props' object which you return needs methods and =
defined, which do whatever you want them to do.

I see you are using these methods on the class itself (not instances of
the class):

   SomeClass::set_prop(key, value)

In that case, you can define them as class methods:

   class SomeClass
     def self.(key)
       get_prop(key)
     end
     def self.=(key,value)
        set_prop(key,value)
     end
   end

And then simply return the class itself:

   class MyClass
      def props
        SomeClass
      end
    end

If you were using *instances* of SomeClass, then personally I would just
define methods and = as instance methods. Depending on how
Hash-like you want this object to be, you may want to define some other
methods too.

If there is some particular reason why you can't do that, then you would
have to return a proxy object, whose and = methods are relayed to
get_prop and set_prop on the underlying SomeClass object.

If you still want props to return an actual Hash, then it will have to
be a Hash which has been modified so that = performs the operation on
the underlying object.

You can use delegate.rb, or you can explicitly delegate those methods
which you want to. Here is some code from CouchTiny which wraps a Hash:

module CouchTiny
# A class which delegates a small subset of methods to a Hash (to keep
# the space as clear as possible for accessor names)
class DelegateDoc
   attr_accessor :doc

   def initialize(doc = {})
     @doc = doc.to_hash
   end

   def to_hash
     @doc
   end

   def ==(other)
     @doc == other # .to_hash is done by Hash#==
   end

   def to_json(*args)
     @doc.to_json(*args)
   end

   alias :orig_respond_to? :respond_to?
   def respond_to?(*m)
     orig_respond_to?(*m) || @doc.respond_to?(*m)
   end

   def (k)
     @doc[k.to_s]
   end

   def =(k,v)
     @doc[k.to_s] = v
   end

   def key?(k)
     @doc.key?(k)
   end

   def has_key?(k)
     @doc.has_key?(k)
   end

   def delete(k)
     @doc.delete(k)
   end

   def merge!(h)
     @doc.merge!(h)
   end

   def update(h)
     @doc.update(h)
   end

   def dup
     self.class.new(@doc.dup)
   end

   #def method_missing(m, *args, &block)
   # @doc.__send__(m, *args, &block)
   #end
end
end

Regards,

Brian.

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

Thanks for the input, botp.
Your example does the job allright, but designwise, I don't like that the
= method is made available for MyClass itself.
However, I'll take whatever works for now! :o)

Best regards,
Rolf

···

On Fri, Feb 4, 2011 at 4:44 AM, botp <botpena@gmail.com> wrote:

On Fri, Feb 4, 2011 at 11:22 AM, botp <botpena@gmail.com> wrote:

sorry, ignore the previous unclear post..

try again,

class MyClass
def props
   some_data = SomeClass::get_prop
    self
end
def =(key,value)
   p "i was called"
    SomeClass::set_prop(key, value)
end
end
#=> nil

class SomeClass
class << self
   @@h={}
   def get_prop
     @@h
   end
   def set_prop key,value
     @@h[key]=value
   end
   def show
     @@h
   end
end
end
#=> nil

c=MyClass.new
#=> #<MyClass:0x8887b94>
c.props
#=> #<MyClass:0x8887b94>
c.props[:a]=1
"i was called"
#=> 1
c.props[:b]=2
"i was called"
#=> 2
c.props
#=> #<MyClass:0x8887b94>
SomeClass::show
#=> {:a=>1, :b=>2}

best regards -botp

What about this:

class MyClass
  def props
    @props = DataClass::get_props()
    Props.new @props
  end

  def props=(h)
    DataClass::set_props h
  end
end

class Props
  def initialize h
    @h = h
  end

  def [](key)
    DataClass::get_prop key
  end

  def []=(key,value)
    DataClass::set_prop key,value
  end

  def inspect; @h.inspect; end
  def to_s; @h.to_s; end
end

class DataClass
  @@data = {:a=>1, :b=>2, :c=>3}
  def self.get_props()
    @@data
  end
  def self.get_prop(key)
    @@data[key]
  end
  def self.set_props(data)
    @@data = data
  end
  def self.set_prop(key, value)
    @@data[key] = value
  end
end

Jesus.

Rolf Pedersen wrote in post #979601:

MyClass should have a "virtual hash property", props.
I want to interact with props, like it was a regular hash, but under the
hood, it should perform calls towards the external library.

Then simply return an object with those characteristics. This is Ruby,
remember :slight_smile:

With MyClass I should be able to to the following:
c = MyClass.new
(1)
c.props # under the hood, this will call SomeClass::get_props() and
convert
the response to a hash
=> {:a=>1, :b=>2, :c=>3}

So you are now saying you must return an *actual* hash at this point?
Then that is a separate object, and any mutations made will be local to
that hash.

(2)
c.props[:a] # This should make a call to SomeClass::get_prop("a")
=> 1

No it won't, if c.props returned a Hash. So your requirements (1) and
(2) are contradictory.

I suggest you go with option 2: return some object, which when you call
the method on that object, it in turn calls SomeClass.get_prop(xxx).
That's the "proxy" object I was talking about before.

(3)
c.props={:a=>"a", :b=>"b", :c=>"c"} # This should make a call to e.g.
SomeClass::set_props("a", "a", "b", "b", "c", "c")
=> {:a=>"a", :b=>"b", :c=>"c"}

That's easy enough. Your c object can have a props=(h) method which
iterates over h, or turns it into an Array, and calls set_props
accordingly.

(4)
c.props[:d] = "d" # This should make a call to SomeClass::set_prop("d")
=> "d"

That's a different requirement: that the object returned by c.props have
specific behaviour when its = method is called, similar to (2).

However (3) and (4) are not contradictory. You can implement both if you
wish.

(5)
c.props # Again, make a vall to SomeClass::get_props(), to check
that
new data is stored.
=> {:a=>"a", :b=>"b", :c=>"c", :d=>"d"}

That is the same as (1), which contradicts (2).

Actually, you can have an almost-Hash, by either subclassing Hash, or by
defining singleton methods on a Hash object. Then it can be a Hash which
does magic things when you assign to it. This may or may not be good
design - I try to avoid magic if possible

h = {"foo"=>1, "bar"=>2}
def h.=(key,val)
  puts "Hah, tricked you, you tried to set #{key} to #{val}!"
end

h
h["foo"]
h["foo"]=999

By setting an instance variable on the Hash (more magic) you can
remember which object you want to proxy = to.

      class DataClass
        @@data = {:a=>1, :b=>2, :c=>3}

Try to avoid class variables. An instance variable of the class (@data)
would work just as well here. @@var has really strange semantics which I
can never entirely remember, and once you've been bitten by them, you'll
choose to use instance variables as well.

Note that an instance variable of the class is not the same as an
instance variable of an instance of that class.

Just change @@data to @data throughout.

(1) just returns
      #<PropsClass:0x1418748>

Yep, it's returning that object, not a hash. You can choose between
returning an object with Hash-like properties, or an actual Hash.

and (3) returns
      test_props.rb:35:in `<main>': undefined method `props=' for
#<MyClass:0x14202d8 @props=#<PropsClass:0x14202c0>> (NoMethodError)

You simply forgot to define this method. You have:

       def props
          @props
       end

but you also need:

       def props=(val)
         # do stuff, e.g. @props.h.replace(val)
         # except you haven't made h an accessor; I suggest
         # you do, otherwise you need something ugly:
         @props.instance_variable_get(:@h).replace(val)
       end

I don't have a method that redefines = in the PropsClass. (This method
cannot be redefined, right?).

foo.bar = baz

is a method called "bar=", and you can define that.

B.

···

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

Hi Jesus

It does seem to be working. At least the example "requirements" that I
defined does give the expected response.
I have to admit, I need to study this a bit, to figure out HOW it is
working, though. ;o)

I will try to incorporate this into the actual code now, and check if it
still holds.

Thanks.

Best regards,
Rolf

···

2011/2/4 Jesús Gabriel y Galán <jgabrielygalan@gmail.com>

What about this:

class MyClass
def props
         @props = DataClass::get_props()
   Props.new @props
end

def props=(h)
   DataClass::set_props h
end
end

class Props
def initialize h
   @h = h
end

def (key)
   DataClass::get_prop key
end

def =(key,value)
   DataClass::set_prop key,value
end

  def inspect; @h.inspect; end
def to_s; @h.to_s; end
end

class DataClass
@@data = {:a=>1, :b=>2, :c=>3}
def self.get_props()
   @@data
end
def self.get_prop(key)
   @@data[key]
end
def self.set_props(data)
   @@data = data
end
def self.set_prop(key, value)
   @@data[key] = value
end
end

Jesus.

Hi Jesus

It does seem to be working. At least the example "requirements" that I
defined does give the expected response.
I have to admit, I need to study this a bit, to figure out HOW it is
working, though. ;o)

You have two sets of requirements:

1.- Calls on the instance of MyClass: props and props=
2.- Calls on the object returned by the previous props calls: and =

You need to forward these 4 calls to another class. The first two are
easy: we just implement the MyClass#props and MyClass#props= to do
what we want.

For the other two, you need a proxy object that can delegate and
= to DataClass too. For this to work, MyClass#props needs to wrap
the actual hash returned by DataClass with a wrapper object (Props).
As you need this proxy object to have some hash like behaviour, you
can implement whatever methods you need to behave like a hash. As an
example, apart from and = I have implemented inspect and to_s.

Try to avoid class variables. An instance variable of the class (@data)
would work just as well here. @@var has really strange semantics which I
can never entirely remember, and once you've been bitten by them, you'll
choose to use instance variables as well.

I completely agree. I was in a rush when I wrote my previous post, so
I left it as it is. Using instance variables on the DataClass object
is cleaner:

irb(main):030:0> class DataClass
irb(main):031:1> @data = {:a=>1, :b=>2, :c=>3}
irb(main):032:1> def self.get_props()
irb(main):033:2> @data
irb(main):034:2> end
irb(main):035:1> def self.get_prop(key)
irb(main):036:2> @data[key]
irb(main):037:2> end
irb(main):038:1> def self.set_props(data)
irb(main):039:2> @data = data
irb(main):040:2> end
irb(main):041:1> def self.set_prop(key, value)
irb(main):042:2> @data[key] = value
irb(main):043:2> end
irb(main):044:1> end
=> nil
irb(main):045:0> c = MyClass.new
=> #<MyClass:0xb7881b40>
irb(main):046:0> c.props
=> {:b=>2, :a=>1, :c=>3}
irb(main):047:0> c.props = {:a => 3, :b => 0, :c => 5, :d => 6}
=> {:b=>0, :a=>3, :c=>5, :d=>6}
irb(main):048:0> c.props
=> {:b=>0, :a=>3, :c=>5, :d=>6}
irb(main):049:0> c.props[:a]
=> 3
irb(main):050:0> c.props[:a] = 55
=> 55
irb(main):051:0> c.props[:a]
=> 55
irb(main):052:0> c.props
=> {:b=>0, :a=>55, :c=>5, :d=>6}

I hope it's clearer now. Let me know if you need further help
understanding this.

Jesus.

···

On Fri, Feb 4, 2011 at 5:03 PM, Rolf Pedersen <rolfhsp@gmail.com> wrote:
On Fri, Feb 4, 2011 at 3:45 PM, Brian Candler <b.candler@pobox.com> wrote:

Hi Jesus

···

2011/2/4 Jesús Gabriel y Galán <jgabrielygalan@gmail.com>

On Fri, Feb 4, 2011 at 5:03 PM, Rolf Pedersen <rolfhsp@gmail.com> wrote:
> Hi Jesus
>
> It does seem to be working. At least the example "requirements" that I
> defined does give the expected response.
> I have to admit, I need to study this a bit, to figure out HOW it is
> working, though. ;o)

You have two sets of requirements:

1.- Calls on the instance of MyClass: props and props=
2.- Calls on the object returned by the previous props calls: and =

You need to forward these 4 calls to another class. The first two are
easy: we just implement the MyClass#props and MyClass#props= to do
what we want.

For the other two, you need a proxy object that can delegate and
= to DataClass too. For this to work, MyClass#props needs to wrap
the actual hash returned by DataClass with a wrapper object (Props).
As you need this proxy object to have some hash like behaviour, you
can implement whatever methods you need to behave like a hash. As an
example, apart from and = I have implemented inspect and to_s.

On Fri, Feb 4, 2011 at 3:45 PM, Brian Candler <b.candler@pobox.com> wrote:

> Try to avoid class variables. An instance variable of the class (@data)
> would work just as well here. @@var has really strange semantics which I
> can never entirely remember, and once you've been bitten by them, you'll
> choose to use instance variables as well.

I completely agree. I was in a rush when I wrote my previous post, so
I left it as it is. Using instance variables on the DataClass object
is cleaner:

irb(main):030:0> class DataClass
irb(main):031:1> @data = {:a=>1, :b=>2, :c=>3}
irb(main):032:1> def self.get_props()
irb(main):033:2> @data
irb(main):034:2> end
irb(main):035:1> def self.get_prop(key)
irb(main):036:2> @data[key]
irb(main):037:2> end
irb(main):038:1> def self.set_props(data)
irb(main):039:2> @data = data
irb(main):040:2> end
irb(main):041:1> def self.set_prop(key, value)
irb(main):042:2> @data[key] = value
irb(main):043:2> end
irb(main):044:1> end
=> nil
irb(main):045:0> c = MyClass.new
=> #<MyClass:0xb7881b40>
irb(main):046:0> c.props
=> {:b=>2, :a=>1, :c=>3}
irb(main):047:0> c.props = {:a => 3, :b => 0, :c => 5, :d => 6}
=> {:b=>0, :a=>3, :c=>5, :d=>6}
irb(main):048:0> c.props
=> {:b=>0, :a=>3, :c=>5, :d=>6}
irb(main):049:0> c.props[:a]
=> 3
irb(main):050:0> c.props[:a] = 55
=> 55
irb(main):051:0> c.props[:a]
=> 55
irb(main):052:0> c.props
=> {:b=>0, :a=>55, :c=>5, :d=>6}

I hope it's clearer now. Let me know if you need further help
understanding this.

Jesus.

Clear as crystal. Just what I needed! :o)
Appreciate all the help I got on this.

Best regards,
Rolf

Instead of implementing other methods to make the wrapper object behave more
like a Hash object, why not let Props inherit Hash, and just redefine those
methods that I need to behave differently? Perhaps like this:

class Props < Hash
  def initialize h
    replace h
  end
  def (key)
    ...
  end
  def =(key, value)
    ...
  end
end

Best regards,
-Rolf

···

2011/2/4 Jesús Gabriel y Galán <jgabrielygalan@gmail.com>

For the other two, you need a proxy object that can delegate and
= to DataClass too. For this to work, MyClass#props needs to wrap
the actual hash returned by DataClass with a wrapper object (Props).
As you need this proxy object to have some hash like behaviour, you
can implement whatever methods you need to behave like a hash. As an
example, apart from and = I have implemented inspect and to_s.

Hi,

In fact I was going to follow up the discussion with a further idea.
What I sent has a flaw, and it's the fact that the Props object gets
initialized with the hash, while ideally it should delegate also all
reads to the DataClass. It doesn't make sense to have a reference to
the resulting hash. This way, if the hash in DataClass is modified by
other means, the new values will be available to all instances of
Props (in the current implementation this might be true, because we
are returning references to the same hash, but this can be a weak
point). It's cleaner this way, in my opinion:

class MyClass
def props
   Props.new
end

def props=(h)
   DataClass::set_props h
end
end

class Props
def (key)
   DataClass::get_prop key
end

def =(key,value)
   DataClass::set_prop key,value
end

def inspect; DataClass::get_props.inspect; end
def to_s; DataClass::get_props.to_s; end
end

class DataClass
@data = {:a=>1, :b=>2, :c=>3}
def self.get_props()
   @data
end
def self.get_prop(key)
   @data[key]
end
def self.set_props(data)
   @data = data
end
def self.set_prop(key, value)
   @data[key] = value
end
end

As for your question about inheriting from Hash: read a bit about
Inheritance vs Composition. It's generally considered that Composition
is more flexible.

Jesus.

···

On Sun, Feb 6, 2011 at 10:23 PM, Rolf Pedersen <rolfhsp@gmail.com> wrote:

2011/2/4 Jesús Gabriel y Galán <jgabrielygalan@gmail.com>

For the other two, you need a proxy object that can delegate and
= to DataClass too. For this to work, MyClass#props needs to wrap
the actual hash returned by DataClass with a wrapper object (Props).
As you need this proxy object to have some hash like behaviour, you
can implement whatever methods you need to behave like a hash. As an
example, apart from and = I have implemented inspect and to_s.

Instead of implementing other methods to make the wrapper object behave more
like a Hash object, why not let Props inherit Hash, and just redefine those
methods that I need to behave differently? Perhaps like this:

class Props < Hash
def initialize h
replace h
end
def (key)
...
end
def =(key, value)
...
end
end