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

Discussion in 'Ruby' started by Giles Bowkett, Sep 7, 2007.

  1. 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/
     
    Giles Bowkett, Sep 7, 2007
    #1
    1. Advertising

  2. 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
     
    Stefano Crocco, Sep 7, 2007
    #2
    1. Advertising

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


    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
     
    Robert Klemme, Sep 7, 2007
    #3
  4. Giles Bowkett

    Pat Maddox Guest

    On 9/7/07, Giles Bowkett <> 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.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
     
    Pat Maddox, Sep 7, 2007
    #4
  5. Giles Bowkett

    Trans Guest

    On Sep 7, 2:24 am, "Giles Bowkett" <> 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.
     
    Trans, Sep 7, 2007
    #5
  6. Giles Bowkett, Sep 8, 2007
    #6
  7. Giles Bowkett

    Ben Tompkins Guest

    Re: simple way to encapsulate class << self ; attr_accessor

    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-forum.com/.
     
    Ben Tompkins, Sep 8, 2007
    #7
  8. Re: simple way to encapsulate class << self ; attr_accessor

    On 9/8/07, Ben Tompkins <> 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-forum.com/.
    >
    >
     
    Logan Capaldo, Sep 8, 2007
    #8
  9. Giles Bowkett

    ara.t.howard Guest

    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://drawohara.com/
    --
    we can deny everything, except that we have the possibility of being
    better. simply reflect on that.
    h.h. the 14th dalai lama
     
    ara.t.howard, Sep 8, 2007
    #9
  10. Giles Bowkett

    Ben Tompkins Guest

    Re: simple way to encapsulate class << self ; attr_accessor

    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 <> 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-forum.com/.
     
    Ben Tompkins, Sep 12, 2007
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Christof Krueger
    Replies:
    1
    Views:
    601
    Christof Krueger
    Dec 19, 2003
  2. TBass
    Replies:
    6
    Views:
    332
    mlimber
    Jun 21, 2006
  3. Replies:
    6
    Views:
    117
    Vivek
    Jan 25, 2006
  4. Brian Hartin
    Replies:
    13
    Views:
    249
    David A. Black
    Apr 29, 2009
  5. juglesh
    Replies:
    5
    Views:
    217
    Thomas 'PointedEars' Lahn
    May 15, 2005
Loading...

Share This Page