simple way to encapsulate class << self ; attr_accessor :xyz ; end?

G

Giles Bowkett

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 Bowkett

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

Stefano Crocco

Alle venerd=EC 7 settembre 2007, Giles Bowkett ha scritto:
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 =3D Boat.new
boat.add_xsor:)need)
boat.need =3D "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.

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=20
singleton class by using the fact that the return value of a class construc=
t=20
is the return value of the last expression (self, in this case). This allow=
s=20
to use the singleton class object in the context of def add_xsor, where nam=
es=20
is visible.

I hope this helps

Stefano
 
R

Robert Klemme

2007/9/7 said:
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.
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,

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
 
P

Pat Maddox

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 Bowkett

Blog: http://gilesbowkett.blogspot.com
Portfolio: http://www.gilesgoatboy.org
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
 
T

Trans

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.

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.
 
B

Ben Tompkins

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
 
L

Logan Capaldo

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.
 
A

ara.t.howard

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/
 
B

Ben Tompkins

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,965
Messages
2,570,148
Members
46,710
Latest member
FredricRen

Latest Threads

Top