Simple way to encapsulate class << self ; attr_accessor :xyz

I’m writing some code which works in the context of a very popular Web
framework and yet bumps against limitations in that framework several
times a day. One thing I have to do constantly is this:

def foo
class << bar
attr_accessor :baz
end
do_stuff(bar.baz)
end

or sometimes even

def foo
instance_eval do
class << self
attr_accessor :bar
end
end
do_stuff(bar)
end

This pattern gets ugly fast. It would be so much easier if I could just
do

foo.add_accessor(:bar)

and get the same functionality as

class << foo
attr_accessor :bar
end

so I tried to graft this onto the base object:

class BaseObject
def add_methods(methods)
class << self
attr_accessor methods
end
end
end

But that blew up on me. There’s two flaws in that. The first is that
methods is already a method name, so using it as a variable name was a
pretty dumb idea. The second is that the arg to the method isn’t
visible once you’re inside that class << self block.

It doesn’t seem as if there’s any way to do it without using #eval,
and frankly, using #eval is so last month. Who uses #eval any more?
That’s like Fred Flintstone style.

Nonetheless, here’s how you can do it with eval:

class Base
def add_xsor(xsor)
eval(“class << self ; attr_accessor :#{xsor} ; end”)
end
end

class Boat < Base ; end
boat = Boat.new
boat.add_xsor(:need)
boat.need = “bigger”

The big flaw here, of course, is that it only works on instances, but
in practical terms I always seem to use it in an instance context.

I’m going to have to use this code for the time being but I’m
definitely on the lookout for a better way to do it. It’s clean, but
not totally satisfying.


Giles B.

Blog: http://gilesbowkett.blogspot.com
Portfolio: http://www.gilesgoatboy.org
Tumblelog: http://giles.tumblr.com/

Alle venerdì 7 settembre 2007, Giles B. ha scritto:

so I tried to graft this onto the base object:
methods is already a method name, so using it as a variable name was a
def add_xsor(xsor)
in practical terms I always seem to use it in an instance context.

I’m going to have to use this code for the time being but I’m
definitely on the lookout for a better way to do it. It’s clean, but
not totally satisfying.

I’m not sure I understand correctly your problem. You could do this:

class Base
def add_xsor(*names)
(class << self;self;end).class_eval{attr_reader *names)}
end
end

This solves the problem of names not being visible in the body of the
singleton class by using the fact that the return value of a class
construct
is the return value of the last expression (self, in this case). This
allows
to use the singleton class object in the context of def add_xsor, where
names
is visible.

I hope this helps

Stefano

2007/9/7, Giles B. [email protected]:

I’m writing some code which works in the context of a very popular Web
framework and yet bumps against limitations in that framework several
times a day.

This might be an indication that you are using the framework wrongly -
or that it’s the wrong framework for your task.

class BaseObject
visible once you’re inside that class << self block.

It doesn’t seem as if there’s any way to do it without using #eval,

There is:

irb(main):001:0> class Object
irb(main):002:1> def add_accessors(*names)
irb(main):003:2> class<<self;self;end.class_eval { attr_accessor *names
}
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> x=Object.new
=> #Object:0x7ff8602c
irb(main):007:0> x.add_accessors :foo, :bar
=> nil
irb(main):008:0> x.foo=10
=> 10
irb(main):009:0> x.bar
=> nil

But there are other solutions as well: if you know the accessors
beforehand you can do this

module MyExtension
attr_accessor :bar
end

some_object.extend MyExtension

and frankly, using #eval is so last month. Who uses #eval any more?
That’s like Fred Flintstone style.

Nonetheless, here’s how you can do it with eval:

I’m going to have to use this code for the time being but I’m
definitely on the lookout for a better way to do it. It’s clean, but
not totally satisfying.

See above. And probably rethink your framework usage.

Kind regards

robert

On Sep 7, 2:24 am, “Giles B.” [email protected] wrote:

so I tried to graft this onto the base object:
methods is already a method name, so using it as a variable name was a
def add_xsor(xsor)
in practical terms I always seem to use it in an instance context.

I’m going to have to use this code for the time being but I’m
definitely on the lookout for a better way to do it. It’s clean, but
not totally satisfying.

module Kernel
def meta
class << self; self; end
end
end

class Module
public :attr_accessor, :attr_reader, :attr_writer
end

then

def foo
meta.attr_accessor :x
end

T.

On 9/7/07, Giles B. [email protected] wrote:

so I tried to graft this onto the base object:
methods is already a method name, so using it as a variable name was a
def add_xsor(xsor)
in practical terms I always seem to use it in an instance context.
Tumblelog: http://giles.tumblr.com/

Hey,

I had a bit of trouble following along cause it’s late but I hope I
got it right.

You said that

class << self
attr_accessor :whatever
end

doesn’t work. That’s because you created a new class scope. The
simple solution is to use the (class << self; self; end) idiom with
class_eval or send. I prefer send but whatever.

Anyway here’s some mojo:

class Object
def add_methods(*methheads)
methheads.each do |m|
(class << self; self; end).send(:attr_accessor, m)
end
end
end

class Dog
def initialize(name, age)
@name, @age = name, age
end
end

irb(main):014:0> d = Dog.new “Cobi”, 2
=> #<Dog:0x5cae4 @name=“Cobi”, @age=2>
irb(main):015:0> d.name
NoMethodError: undefined method `name’ for #<Dog:0x5cae4 @name=“Cobi”,
@age=2>
from (irb):15
from :0
irb(main):016:0> d.add_methods :name, :age
=> [:name, :age]
irb(main):017:0> d.name
=> “Cobi”
irb(main):018:0> d.age
=> 2

I hope I understood what you were going for. Even if not that should
get you started.

If you want to add an attr_accessor to all instances, just use send on
the class:
Dog.send :attr_accessor, :name

Pat

then

def foo
meta.attr_accessor :x
end

Out of several excellent alternatives to my code I think this is the
most compelling.


Giles B.

Blog: http://gilesbowkett.blogspot.com
Portfolio: http://www.gilesgoatboy.org
Tumblelog: http://giles.tumblr.com/

Giles,

While you’re at it, how about overloading >> to alias << in the context
of
class OPERATOR object, as the arrows are obviously pointing the wrong
way as
it stands :). (See my “dyslexic” posting on this forum - i.e. do a
search on “dyslexic” and read my final posting for that thread.

Ben

On 9/8/07, Ben T. [email protected] wrote:

Giles,

While you’re at it, how about overloading >> to alias << in the context
of
class OPERATOR object, as the arrows are obviously pointing the wrong
way as
it stands :). (See my “dyslexic” posting on this forum - i.e. do a
search on “dyslexic” and read my final posting for that thread.

Arrows? What arrows? Those are bitshift operators.
Bitshift operators? What bitshift operators? Those are pairs of less
than and greater than symbols.

On Sep 7, 2007, at 7:52 PM, Giles B. wrote:

Out of several excellent alternatives to my code I think this is the
most compelling.

i always define this in lib/rubyext.rb

def singleton_class &b
sc =
class << self
self
end
b ? module_eval(&b) : sc
end

then

singleton_class.attr_accessor ‘foo’

or, better

singleton_class do
attr ‘a’
attr ‘b’
end

it’s a sin to define a method that has a compelling use for a block
to silently ignore said block.

another thing i use often is attributes, this lets you do this

singleton_class do
attribute ‘foo’
end

which gives

self.foo = 42 #=> @foo = 42
foo 42 #=> @foo = 42
foo #=> 42
foo? #=> true

it’s attr_accessor in steriods and a very very short lib. (gem
install attributes)

kind regards.

a @ http://drawohara.com/

The point is that in this particular case, syntax doesn’t just fail to
reflect but contradicts the semantics of the operation (i.e. “what it
does”), perhaps in favor of an implementation perspective (“how it
works”).

Ben

Logan C. wrote:

On 9/8/07, Ben T. [email protected] wrote:

Giles,

While you’re at it, how about overloading >> to alias << in the context
of
class OPERATOR object, as the arrows are obviously pointing the wrong
way as
it stands :). (See my “dyslexic” posting on this forum - i.e. do a
search on “dyslexic” and read my final posting for that thread.

Arrows? What arrows? Those are bitshift operators.
Bitshift operators? What bitshift operators? Those are pairs of less
than and greater than symbols.