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