Passing parameters into a singleton class def?

Hi,

I’m a little new to Ruby, so please feel free to suggest a completely
different and better way to do this, if you have one. I’m trying to
figure out a way to access a variable within a singleton class
definition that is defined outside the singleton class definition.
Basically, I want to be able to add new, user-defined instance variables
and readers and writers for the instance variables to an object. I can
do it fine if I construct the list of instance variables inline. Given
a definition of MyClass, of course, the following code works
beautifully:

var = MyClass.new
class << var
attr_accessor :field1, :field2, :field3
end

However, I need to be able to build the list prior to doing the
singleton class definition (ideally, I want to be able to pass the list
of instance variables into an instance method and have it take care of
the singleton class definition on itself). This is the way code is
written right now:

class MyClass

def add_fields(*field_list)
class << self
attr accessor *field_list
end
end
end

I’ve also tried the following in irb (identical to the above code that
works, except that the list of fields is assigned to a variable instead
of being constructed inline):

var = MyClass.new
list = :field1, :field2, :field3
class << var
attr_accessor list
end

Both throw an error because field_list is not defined within the
singleton class definition? Am I making a simple mistake, or should I
be doing this differently?

Thanks,
Doug G.

On Saturday 23 August 2008 20:09:52 Doug G. wrote:

class MyClass

def add_fields(*field_list)
class << self
attr accessor *field_list
end
end
end
[snip]
Both throw an error because field_list is not defined within the
singleton class definition? Am I making a simple mistake, or should I
be doing this differently?

Well, if you actually have fields called :field1, :field2, and :field3,
I
might suggest an array… Assuming that’s not the case.

I don’t even remember the actual Ruby way to do this, but _why’s metaid
gem
would let you do it like this:

def add_fields(*field_list)
meta_eval do
attr_accessor *field_list
end
end

The key, however, is that it’s some sort of _eval method – that it’s
taking a
block, which means you get to inherit the parent scope. In fact, if it’s
actually a singleton (as in, only one instance of this class will be
defined), you can do this:

def add_fields(*field_list)
self.class.class_eval do
attr_accessor *field_list
end
end

In this case, self.class refers to the actual class that the current
object is
an instance of. On the other hand, self.metaclass or meta_eval (both
from
metaid) refer to the current object’s metaclass, or eigenclass.

Given that you were doing “class << foo” stuff, I’m assuming you wanted
the
metaclass.

One more hack before I’m through:

def add_fields(*field_list)
self.metaclass.send :attr_accessor, *field_list
end

I haven’t tested any of this. Let me know how it works for you.

On Sun, Aug 24, 2008 at 2:09 AM, Doug G. [email protected]
wrote:

beautifully:
written right now:

Both throw an error because field_list is not defined within the
singleton class definition? Am I making a simple mistake, or should I
be doing this differently?

Thanks,
Doug G.

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

Something like this?

class A
end

a = A.new
fields = [:a, :b]
(class << a; self; end).class_eval do
attr_accessor *fields
end
a.a = 1
a.b = 2
p a
b = A.new
b.a = 3
END
#<A:0x25094 @a=1, @b=2>
rt.rb:13: undefined method `a=’ for #<A:0x24f40> (NoMethodError)

Regards,
Sean

Sean O’halpin wrote:

Something like this?

class A
end

a = A.new
fields = [:a, :b]
(class << a; self; end).class_eval do
attr_accessor *fields
end
a.a = 1
a.b = 2
p a
b = A.new
b.a = 3
END
#<A:0x25094 @a=1, @b=2>
rt.rb:13: undefined method `a=’ for #<A:0x24f40> (NoMethodError)

Regards,
Sean

David M. wrote:

Well, if you actually have fields called :field1, :field2, and :field3,
I
might suggest an array… Assuming that’s not the case.

I don’t even remember the actual Ruby way to do this, but _why’s metaid
gem
would let you do it like this:

def add_fields(*field_list)
meta_eval do
attr_accessor *field_list
end
end

The key, however, is that it’s some sort of _eval method – that it’s
taking a
block, which means you get to inherit the parent scope. In fact, if it’s
actually a singleton (as in, only one instance of this class will be
defined), you can do this:

def add_fields(*field_list)
self.class.class_eval do
attr_accessor *field_list
end
end

In this case, self.class refers to the actual class that the current
object is
an instance of. On the other hand, self.metaclass or meta_eval (both
from
metaid) refer to the current object’s metaclass, or eigenclass.

Given that you were doing “class << foo” stuff, I’m assuming you wanted
the
metaclass.

One more hack before I’m through:

def add_fields(*field_list)
self.metaclass.send :attr_accessor, *field_list
end

I haven’t tested any of this. Let me know how it works for you.

Thanks very much to both of you! I’m not using why’s metaid gem, but I
am familiar with the way he does things. I had tried using class_eval,
as Sean suggested, but I wasn’t using it quite correctly. Sean’s code
worked perfectly, but I wanted to make it a little more
compartmentalized, so I used some of why’s strategy. Here’s the final
working example code:

class MyClass
def metaclass
class << self
self
end
end

def add_fields(*field_list)
metaclass.class_eval do
attr_accessor *field_list
end
end
end

Of course, it would be better to move the metaclass method into a mixin,
or just use why’s metaid gem.

Thanks again,
Doug