Extending object instances with <<

Discussion in 'Ruby' started by Tim Becker, Feb 24, 2007.

  1. Tim Becker

    Tim Becker Guest

    Hi,

    I'm trying to write a class with a method to extend instances of
    itself to contain additional accessors. I thought using `class <<
    self` would be the most elegant way to go about it, but I'm running
    into some problems. To illustrate:

    class Test
    # takes an array of symbols to add to the instance.
    def add syms
    syms.each { |sym|
    @@__tmp = sym
    $__tmp = sym
    class << self
    #attr_accessor sym # this would be my preferance, but sym
    isn't in scope here
    #attr_accessor $__tmp # this works, but uses globals
    attr_accessor @@__tmp # this is nearly as bad as using globals
    end # <<
    } # each
    end # add
    end # Test

    t = Test.new
    t.add [:thingie, :thingie2]

    t.thingie="whatever"
    t.thingie2="bla"
    puts t.thingie
    puts t.thingie2



    I don't like the idea of using globals to transport the symbol
    information and the class members approach is nearly as bad
    (synchronization issues mainly, apart from elegance). But I can't
    think of another way to transport dynamic data into the `class<<self`
    block.

    Alternatives would be to handle this using `method_missing` though
    that wouldn't just affect a single instance or using `eval` which
    would involve executing strings I'm banging together.

    Another thing I tried was:

    ...
    self.class.attr_accessor sym
    ...

    but that doesn't work because `attr_accessor` is private (contrary to
    what it says in the documentation...)

    Any ideas? Am I missing something?
    -tim
    Tim Becker, Feb 24, 2007
    #1
    1. Advertising

  2. On 24.02.2007 13:52, Tim Becker wrote:
    > Hi,
    >
    > I'm trying to write a class with a method to extend instances of
    > itself to contain additional accessors. I thought using `class <<
    > self` would be the most elegant way to go about it, but I'm running
    > into some problems. To illustrate:
    >
    > class Test
    > # takes an array of symbols to add to the instance.
    > def add syms
    > syms.each { |sym|
    > @@__tmp = sym
    > $__tmp = sym
    > class << self
    > #attr_accessor sym # this would be my preferance, but sym
    > isn't in scope here
    > #attr_accessor $__tmp # this works, but uses globals
    > attr_accessor @@__tmp # this is nearly as bad as using globals
    > end # <<
    > } # each
    > end # add
    > end # Test
    >
    > t = Test.new
    > t.add [:thingie, :thingie2]
    >
    > t.thingie="whatever"
    > t.thingie2="bla"
    > puts t.thingie
    > puts t.thingie2
    >
    > I don't like the idea of using globals to transport the symbol
    > information and the class members approach is nearly as bad
    > (synchronization issues mainly, apart from elegance). But I can't
    > think of another way to transport dynamic data into the `class<<self`
    > block.


    There is:

    irb(main):017:0> class Bar
    irb(main):018:1> def add(*syms)
    irb(main):019:2> cl = class<<self;self;end
    irb(main):020:2> cl.instance_eval { attr_accessor *syms }
    irb(main):021:2> end
    irb(main):022:1> end
    => nil
    irb(main):023:0> f=Bar.new
    => #<Bar:0x3c1a40>
    irb(main):024:0> f.add :bar
    => nil
    irb(main):025:0> f.bar=10
    => 10
    irb(main):026:0> f.bar
    => 10

    > Alternatives would be to handle this using `method_missing` though
    > that wouldn't just affect a single instance or using `eval` which
    > would involve executing strings I'm banging together.
    >
    > Another thing I tried was:
    >
    > ..
    > self.class.attr_accessor sym
    > ..
    >
    > but that doesn't work because `attr_accessor` is private (contrary to
    > what it says in the documentation...)
    >
    > Any ideas? Am I missing something?


    See above. Apart from that you could simply use OpenStruct or inherit
    OpenStruct which does all this for you already automagically:

    irb(main):013:0> require 'ostruct'
    => true
    irb(main):014:0> f=OpenStruct.new
    => #<OpenStruct>
    irb(main):015:0> f.bar=10
    => 10
    irb(main):016:0> f.bar
    => 10

    Major difference is that you do not explicitly control accessor creation
    but automatically get *all* - even spelling errors.

    Kind regards

    robert
    Robert Klemme, Feb 24, 2007
    #2
    1. Advertising

  3. Tim Becker

    Ken Bloom Guest

    On Sat, 24 Feb 2007 14:08:19 +0100, Robert Klemme wrote:

    > On 24.02.2007 13:52, Tim Becker wrote:
    >> Hi,
    >>
    >> I'm trying to write a class with a method to extend instances of itself
    >> to contain additional accessors. I thought using `class << self` would
    >> be the most elegant way to go about it, but I'm running into some
    >> problems. To illustrate:
    >>
    >> class Test
    >> # takes an array of symbols to add to the instance. def add syms
    >> syms.each { |sym|
    >> @@__tmp = sym
    >> $__tmp = sym
    >> class << self
    >> #attr_accessor sym # this would be my preferance, but sym
    >> isn't in scope here
    >> #attr_accessor $__tmp # this works, but uses globals
    >> attr_accessor @@__tmp # this is nearly as bad as using globals
    >> end # <<
    >> } # each
    >> end # add
    >> end # Test
    >> Any ideas? Am I missing something?

    >
    > See above. Apart from that you could simply use OpenStruct or inherit
    > OpenStruct which does all this for you already automagically:
    >
    > irb(main):013:0> require 'ostruct'
    > => true
    > irb(main):014:0> f=OpenStruct.new
    > => #<OpenStruct>
    > irb(main):015:0> f.bar=10
    > => 10
    > irb(main):016:0> f.bar
    > => 10
    >
    > Major difference is that you do not explicitly control accessor creation
    > but automatically get *all* - even spelling errors.


    Test=Struct.new(*syms)
    or
    Test=Struct.new:)foo,:bar,:baz)

    This will guard you against spelling errors.

    --Ken

    --
    Ken Bloom. PhD candidate. Linguistic Cognition Laboratory.
    Department of Computer Science. Illinois Institute of Technology.
    http://www.iit.edu/~kbloom1/
    Ken Bloom, Feb 26, 2007
    #3
  4. On 26.02.2007 02:38, Ken Bloom wrote:
    > On Sat, 24 Feb 2007 14:08:19 +0100, Robert Klemme wrote:
    >> Major difference is that you do not explicitly control accessor creation
    >> but automatically get *all* - even spelling errors.

    >
    > Test=Struct.new(*syms)
    > or
    > Test=Struct.new:)foo,:bar,:baz)
    >
    > This will guard you against spelling errors.


    That's true. However, I interpreted the OP's posting that he needs to
    to the extension on a per instance basis. That does not work with the
    approach you presented.

    Kind regards

    robert
    Robert Klemme, Feb 26, 2007
    #4
  5. I think you're correct. The original poster's problem was to add
    accessors to instances, splats are handy in the general case but
    instance_eval is what you need here.

    On 2/26/07, Robert Klemme <> wrote:
    > On 26.02.2007 02:38, Ken Bloom wrote:
    > > On Sat, 24 Feb 2007 14:08:19 +0100, Robert Klemme wrote:
    > >> Major difference is that you do not explicitly control accessor creation
    > >> but automatically get *all* - even spelling errors.

    > >
    > > Test=Struct.new(*syms)
    > > or
    > > Test=Struct.new:)foo,:bar,:baz)
    > >
    > > This will guard you against spelling errors.

    >
    > That's true. However, I interpreted the OP's posting that he needs to
    > to the extension on a per instance basis. That does not work with the
    > approach you presented.
    >
    > Kind regards
    >
    > robert
    >
    >



    --
    Giles Bowkett
    http://www.gilesgoatboy.org
    http://gilesbowkett.blogspot.com
    http://gilesgoatboy.blogspot.com
    Giles Bowkett, Feb 27, 2007
    #5
    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. John Wohlbier
    Replies:
    2
    Views:
    358
    Josiah Carlson
    Feb 22, 2004
  2. Rakesh
    Replies:
    10
    Views:
    12,147
    Mike Schilling
    Apr 8, 2008
  3. Replies:
    8
    Views:
    446
    James Stroud
    Jan 29, 2009
  4. Lipper, Matthew

    Basic Syntax for Extending Instances

    Lipper, Matthew, Jan 5, 2004, in forum: Ruby
    Replies:
    1
    Views:
    83
    Jamis Buck
    Jan 5, 2004
  5. Jim Crossley
    Replies:
    1
    Views:
    77
    Rick DeNatale
    Nov 14, 2009
Loading...

Share This Page