Dynamic methods / accessors

(Frodo Larik) #1

Hi all,

I'm trying to setup some kind of dynamic method / accessor assignment to objects. But I don't want the other objects from the same class to know about "personal" methods. I'm just learning Ruby, so it could be I'm missing some crucial knowledge.

For example:

class MyThing
    def create_method(method)
       # I found two things on internet which can acchieve this
       # self.class.class_eval { attr_accessor method }
       # AND
       # self.class.send(:define_method, method, &block)
       # but I'm not sure which is the best one to use, but I think
       # I prefer the attr_accessor, because that's the functionality
       # I need
    end
end

# Create first object
a = MyThing.new
a.create_method('box') # Adds a method box to a
a.box = 'something inside'

# The nicest thing would be if I could do something like this:
a.create_method('box','some_value'), so a.box is populated with 'some value'

# Create second object
b = MyThing.new

# I don't want the following to happen
b.box = 'something other'

I don't want the method 'box' be available to b, only to a

How can I achieve this?

I saw it was possible to achieve this with something like this:

class YourThing < MyThing
    # A placeholder class for the dynamic methods
end

but I don't know the name of the class on forehand, so if something like this is possible:

class #{i_want_this_class} < MyThing
    # A placeholder class for the dynamic methods
end

That would be nice.

Sincerely,

Frodo Larik

(Robert) #2

You need so called singleton methods. These are present in just a single instance. You define them via the singleton class. (Disclaimer: there has been some debate about the naming of these because "singleton" can be misleading here, but AFAIK this is still the officiel term.) You access the singleton class (a class that is associated with a single instance only) like this

class <<some_instance
end

So you can do:

class MyThing
end
a = MyThing.new
class <<a
  attr_accessor :box
end
a.box = 'something inside'

If you want to have it a bit more convenient you can pack this into a method like this:

class MyThing
  def add_attribute(name, val=nil)
    class <<self;self;end.send( :attr_accessor, name )
    self.send("#{name}=", val)
  end
end
a = MyThing.new
a.add_attribute :foo, "hello"
a.foo # returns "hello"

Kind regards

    robert

···

Frodo Larik <lists@elasto.nl> wrote:

Hi all,

I'm trying to setup some kind of dynamic method / accessor assignment
to objects. But I don't want the other objects from the same class to
know about "personal" methods. I'm just learning Ruby, so it could be
I'm missing some crucial knowledge.

For example:

class MyThing
   def create_method(method)
      # I found two things on internet which can acchieve this
      # self.class.class_eval { attr_accessor method }
      # AND
      # self.class.send(:define_method, method, &block)
      # but I'm not sure which is the best one to use, but I think
      # I prefer the attr_accessor, because that's the functionality
      # I need
   end
end

# Create first object
a = MyThing.new
a.create_method('box') # Adds a method box to a
a.box = 'something inside'

# The nicest thing would be if I could do something like this:
a.create_method('box','some_value'), so a.box is populated with 'some
value'

# Create second object
b = MyThing.new

# I don't want the following to happen
b.box = 'something other'

I don't want the method 'box' be available to b, only to a

How can I achieve this?

(Frodo Larik) #3

Thanks guys!

(Robert) #4

PS: There is also OpenStruct which adds methods on the fly. So you can directly do

o = OpenStruct.new
o.bar = 10

Kind regards

    robert

···

Robert Klemme <bob.news@gmx.net> wrote:

Frodo Larik <lists@elasto.nl> wrote:

Hi all,

I'm trying to setup some kind of dynamic method / accessor assignment
to objects. But I don't want the other objects from the same class to
know about "personal" methods. I'm just learning Ruby, so it could be
I'm missing some crucial knowledge.

For example:

class MyThing
   def create_method(method)
      # I found two things on internet which can acchieve this
      # self.class.class_eval { attr_accessor method }
      # AND
      # self.class.send(:define_method, method, &block)
      # but I'm not sure which is the best one to use, but I think
      # I prefer the attr_accessor, because that's the functionality
      # I need
   end
end

# Create first object
a = MyThing.new
a.create_method('box') # Adds a method box to a
a.box = 'something inside'

# The nicest thing would be if I could do something like this:
a.create_method('box','some_value'), so a.box is populated with 'some
value'

# Create second object
b = MyThing.new

# I don't want the following to happen
b.box = 'something other'

I don't want the method 'box' be available to b, only to a

How can I achieve this?

You need so called singleton methods. These are present in just a
single instance. You define them via the singleton class.
(Disclaimer: there has been some debate about the naming of these
because "singleton" can be misleading here, but AFAIK this is still
the officiel term.) You access the singleton class (a class that is
associated with a single instance only) like this

class <<some_instance
end

So you can do:

class MyThing
end
a = MyThing.new
class <<a
attr_accessor :box
end
a.box = 'something inside'

If you want to have it a bit more convenient you can pack this into a
method like this:

class MyThing
def add_attribute(name, val=nil)
   class <<self;self;end.send( :attr_accessor, name )
   self.send("#{name}=", val)
end
end
a = MyThing.new
a.add_attribute :foo, "hello"
a.foo # returns "hello"

Kind regards

   robert