Dynamically added methods

Hi all,

I'm pretty new to ruby so I will ask some dumb questions, sorry if it's
not the right place to ask :slight_smile:

I'd like to add some methods dynamically to one of my object.
I understand that with "method_missing" I can "emulate" this behaviour.

However, imagine I have an hash table. The key would be the attributes
of my object, and the keys their value. How could I add dynamically
accessors for those attributes/keys ?

Thanks in advance,

路路路

++

yk

Use OpenStruct.

  require 'ostruct'
  os = OpenStruct.new
  os.foo = "hello"
  os.bar = "world"
  puts "#{os.foo}, #{os.bar}"

-austin

路路路

On 8/11/05, Yann Klis <strass@strasslab.net> wrote:

Hi all,

I'm pretty new to ruby so I will ask some dumb questions, sorry if it's
not the right place to ask :slight_smile:

I'd like to add some methods dynamically to one of my object.
I understand that with "method_missing" I can "emulate" this behaviour.

However, imagine I have an hash table. The key would be the attributes
of my object, and the keys their value. How could I add dynamically
accessors for those attributes/keys ?

--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca

To clarify - you want to be able to do something like this:

class YourObject

   def initialize
     @myhash = {'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3'}
   end

end

YourObject.new.key1 # Returns 'value1'
YourObject.new.key2 # Returns 'value2'

.... like that?

-Shalev

路路路

On Aug 11, 2005, at 1:48 PM, Yann Klis wrote:

Hi all,

I'm pretty new to ruby so I will ask some dumb questions, sorry if it's
not the right place to ask :slight_smile:

I'd like to add some methods dynamically to one of my object.
I understand that with "method_missing" I can "emulate" this behaviour.

However, imagine I have an hash table. The key would be the attributes
of my object, and the keys their value. How could I add dynamically
accessors for those attributes/keys ?

Thanks in advance,

++

yk

In fact, I'd like to mimic the behaviour of ActiveRecord.

If I have something like this:

class Base

  def initialize(attributes)
    #do something clever with attributes
  end

end

class MyObject < Base
end

I'd like to be able to do that:

object = MyObject.new({"attribute1" => "value1", "attribute2" =>
"value2"})
val = object.attribute1

Thanks,

yk

路路路

Le vendredi 12 ao没t 2005 脿 05:29 +0900, Shalev NessAiver a 茅crit :

To clarify - you want to be able to do something like this:

class YourObject

   def initialize
     @myhash = {'key1' => 'value1', 'key2' => 'value2', 'key3' =>
'value3'}
   end

end

YourObject.new.key1 # Returns 'value1'
YourObject.new.key2 # Returns 'value2'

.... like that?

-Shalev

On Aug 11, 2005, at 1:48 PM, Yann Klis wrote:

> Hi all,
>
> I'm pretty new to ruby so I will ask some dumb questions, sorry if
> it's
> not the right place to ask :slight_smile:
>
> I'd like to add some methods dynamically to one of my object.
> I understand that with "method_missing" I can "emulate" this
> behaviour.
>
> However, imagine I have an hash table. The key would be the attributes
> of my object, and the keys their value. How could I add dynamically
> accessors for those attributes/keys ?
>
> Thanks in advance,
>
> ++
>
> yk
>
>
>

Yann Klis wrote:

In fact, I'd like to mimic the behaviour of ActiveRecord.

If I have something like this:

class Base

  def initialize(attributes)
    #do something clever with attributes
  end

end

class MyObject < Base
end

I'd like to be able to do that:

object = MyObject.new({"attribute1" => "value1", "attribute2" =>
"value2"})
val = object.attribute1

To create methods on the class itself so all instances of that class get the method you can do:

class A
   def initialize( args=nil )
     if args.is_a? Hash
       args.each { |key,val| self.class.send( :define_method, key, proc { val } ) }
     end
   end
end

a = A.new( :zzz => "testing" )
puts a.zzz
b = A.new
puts b.zzz

To create methods on the instance you have created only you can do:

class A
   def initialize( args=nil )
     if args.is_a? Hash
       s = class << self; self; end
       args.each { |key,val| s.send( :define_method, key, proc { val } ) }
     end
   end
end

a = A.new( :zzz => "testing" )
puts a.zzz
b = A.new
puts b.zzz #this will throw an error,because method zzz doesn't exist on this instance

Note, that I think the second example above is bad design. We are relying on an instance of A to give the class A extra methods for all instances. We should instead rely on a singleton method for class A to handle this task. (keep reading)

The above two solutions don't take into consideration if a method already exists though, so you could easily overwrite an existing method. Another way to do this is by overriding the method missing for your class which won't override existing methods. The below will handle things for instances only, like the first example:

class A
   def initialize( args={} )
     @args = args if args.is_a? Hash
   end

   def method_missing( method )
     @args[method] || super
   end
end

puts A.new( :a => "z" ) # prints out "z"
A.new.a #throws an error because :a wasn't passed in to this object

And you can alter that to add methods for the class also so all instances get the methods, although above in the second example I think we used bad designed. So here we fix it by using a singleton method 'add_attributes':

class A
   def self.add_attributes( attributes )
     @@attributes = attributes
   end

   def initialize( args={} )
     @args = args if args.is_a? Hash
   end

   def method_missing( method )
     @@attributes[method] || super
   end
end

A.add_attributes( :attr1 => "attribute 1", :attr2 => "attribute 2" )
puts A.new.attr1
puts A.new.attr2

I hope this helps!

Zach

Yann Klis wrote:

In fact, I'd like to mimic the behaviour of ActiveRecord.

If I have something like this:

class Base

  def initialize(attributes)
    #do something clever with attributes
  end

end

class MyObject < Base
end

I'd like to be able to do that:

object = MyObject.new({"attribute1" => "value1", "attribute2" =>
"value2"})
val = object.attribute1

As others have pointed out already, use OpenStruct:

09:51:10 [robert.klemme]: irbs

require 'ostruct'

=> true

object = OpenStruct.new( "attribute1" => "value1", "attribute2" =>

?> "value2")
=> <OpenStruct attribute1="value1" attribute2="value2">

object.attribute1

=> "value1"

object.attribute2

=> "value2"

If you need inheritance, you can do

class MyObject < OpenStruct
end

That's it.

If you need additional initialization, you'll have to do

class MyObject < OpenStruct
  def initialize(attrs)
    super(attrs)
    # do more init
  end
end

Kind regards

    robert

Robert Klemme wrote:

As others have pointed out already, use OpenStruct:

OpenStruct uses the method_missing magic as pointed out in my last post, so you know now how it does what it does. Refer to ostruct.rb for more implementation details. =)

Zach