[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

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

Giles Bowkett

9/7/2007 9:24:00 AM

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.bl...
Portfolio: http://www.gilesg...
Tumblelog: http://giles.t...

9 Answers

Stefano Crocco

9/7/2007 9:48:00 AM

0

Alle venerdì 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 = 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.

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

Robert Klemme

9/7/2007 9:49:00 AM

0

2007/9/7, Giles Bowkett <gilesb@gmail.com>:
> 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:

<snip/>

> 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

Pat Maddox

9/7/2007 10:21:00 AM

0

On 9/7/07, Giles Bowkett <gilesb@gmail.com> wrote:
> 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.bl...
> Portfolio: http://www.gilesg...
> Tumblelog: http://giles.t...
>
>

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

Trans

9/7/2007 11:25:00 AM

0



On Sep 7, 2:24 am, "Giles Bowkett" <gil...@gmail.com> wrote:
> 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.


Giles Bowkett

9/8/2007 1:53:00 AM

0

> 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

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

--
Giles Bowkett

Blog: http://gilesbowkett.bl...
Portfolio: http://www.gilesg...
Tumblelog: http://giles.t...

Ben Tompkins

9/8/2007 12:33:00 PM

0

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

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

Logan Capaldo

9/8/2007 7:22:00 PM

0

On 9/8/07, Ben Tompkins <nbitspoken@comcast.net> 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.
> Ben
>
> --
> Posted via http://www.ruby-....
>
>

ara.t.howard

9/8/2007 10:04:00 PM

0


On Sep 7, 2007, at 7:52 PM, Giles Bowkett 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://draw...
--
we can deny everything, except that we have the possibility of being
better. simply reflect on that.
h.h. the 14th dalai lama




Ben Tompkins

9/12/2007 7:02:00 AM

0

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 Capaldo wrote:
> On 9/8/07, Ben Tompkins <nbitspoken@comcast.net> 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.

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