Metaprogramming: Dynamic class generation

Discussion in 'Ruby' started by Luke Kanies, Aug 20, 2006.

  1. Luke Kanies

    Luke Kanies Guest

    Luke Kanies, Aug 20, 2006
    #1
    1. Advertising

  2. Luke Kanies

    Guest

    On Sun, 20 Aug 2006, Luke Kanies wrote:

    > Hi all,
    >
    > I finally wrote up how I'm dynamically generating classes (and why), and I
    > thought some of you might enjoy it:
    >
    > http://madstop.com/articles/2006/08/19/my-ruby-metaprogramming
    >
    > The article discusses a new method I've created in Puppet for making dynamic
    > class creation easier, and in the process discusses why I do this a lot and
    > some future directions for more abstraction.
    >
    > Comments and suggestions appreciated.


    first off, thanks for the article - i know this stuff is hard to write
    about...

    few questions/comments:


    - Why I dynamically generate

    can you give a little more context for the code shown:

    package { ssh: ensure => installed, type => apt }

    is this statement part of a dsl?


    - Avoiding the inherited method

    have you used delayed initialization like so:

    harp:~ > cat a.rb
    class Base
    @subs = Hash.new{|h,sub| Base.name2subs[sub].post_inherited}
    @name2subs = Hash.new

    class << self
    attr_accessor :subs
    attr_accessor :name2subs
    end

    def self.inherited sub
    Base.name2subs[sub.name] = sub
    end

    def self.post_inherited
    Base.subs[name] = self
    end
    end

    class Sub < Base
    end

    p Base.subs['Sub']
    p Base.subs


    harp:~ > ruby a.rb
    Sub
    {"Sub"=>Sub}

    i'm curious because i've faced this issue many times before too...



    - i'm curious if the generated objects really need to be classes? what i mean
    is are there instances created later? the reason i ask is that i've been
    playing with prototypes lately and wondering if that might be applicable to
    this kind of problem

    http://www.codeforpeople.com/lib/ruby/prototype/prototype-0.2.0/README


    interesting stuff.

    cheers.


    -a
    --
    to foster inner awareness, introspection, and reasoning is more efficient than
    meditation and prayer.
    - h.h. the 14th dali lama
     
    , Aug 20, 2006
    #2
    1. Advertising

  3. Luke Kanies

    Luke Kanies Guest

    On Aug 20, 2006, at 11:10 AM, wrote:=
    >
    > first off, thanks for the article - i know this stuff is hard to write
    > about...
    >
    > few questions/comments:
    >
    >
    > - Why I dynamically generate
    >
    > can you give a little more context for the code shown:
    >
    > package { ssh: ensure => installed, type => apt }
    >
    > is this statement part of a dsl?


    Yes, it is; I've got a grammar and everything for it. Before
    everyone asks why I don't just use a Ruby DSL, please see http://
    reductivelabs.com/projects/puppet/faq.html. I've actually toyed
    recently with creating a Ruby DSL, just to see what it would look
    like, and I think it would be at least as difficult, if not more so,
    because of how differently Puppet defines classes vs. Ruby.

    > - Avoiding the inherited method
    >
    > have you used delayed initialization like so:
    >
    > harp:~ > cat a.rb

    [...]
    > i'm curious because i've faced this issue many times before too...


    I had code that was similar. In thinking about the article after I
    wrote it, avoiding the 'inherited' method did make my life much
    easier but what really simplified my code were the class methods to
    create new, related classes. As I mentioned in my article, most of
    my classes are referenced by name, and having class creation happen
    in a way that inherently handles class naming and class relationships
    is much, much easier. Calling 'newclass' on the containing class is
    much easier than creating the two classes and then marking them
    related somehow.

    I think that if I tended to refer to these classes by their constants
    (i.e., their Ruby names) rather than by a human name, or if the
    dynamic classes weren't always specifically associated with some kind
    of containing class, the delayed initialization mechanism would work
    pretty well. As it is, I've had multiple compliments on how nice
    this class creation mechanism is, and it really was striking how much
    better it made my life when I made this change. Also, your code
    wouldn't work for me because the class's @name is often unrelated to
    the constant -- I would need to use an array to store the subclasses
    initially, and then hash after initialization.

    I will say, though, that the mechanism I'm using provides a bit more
    functionality than delayed initialization -- I can easily control
    what happens at class creation time, before the block runs, and after
    the block runs, and it wouldn't take much to add hooks for more class
    customization if a specific class container needed it. As Why
    pointed out in his metaprogramming article, it's always easier when
    your code makes the metaprogramming explicit -- I seem to often start
    out using 'inherited', but the code always gets cleaner when I move
    away from it. I expect that your example code could be moved into a
    module or something so that it made the metaprogramming explicit; it
    would be interesting to compare the results of that with the system I
    have. As I mentioned I'm using this class generation facility in
    about 8 different places in Puppet -- I clearly would not wnat to
    duplicate your code in all 8 of these places.

    > - i'm curious if the generated objects really need to be classes?
    > what i mean
    > is are there instances created later? the reason i ask is that
    > i've been
    > playing with prototypes lately and wondering if that might be
    > applicable to
    > this kind of problem
    >
    > http://www.codeforpeople.com/lib/ruby/prototype/prototype-0.2.0/
    > README


    Yes, instances of these classes are created. The refactoring that I
    asked about earlier this week (transactions and idempotency) might
    result in this no longer being the case for some of these classes, in
    which case prototypes would be much simpler and in some cases could
    provide more functionality.

    --
    Luke Kanies
    http://madstop.com | http://reductivelabs.com | 615-594-8199
     
    Luke Kanies, Aug 20, 2006
    #3
    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. E11
    Replies:
    1
    Views:
    4,937
    Thomas Weidenfeller
    Oct 12, 2005
  2. Michael Andersson
    Replies:
    0
    Views:
    471
    Michael Andersson
    May 2, 2005
  3. John W. Long

    HTML Generation (Next Generation CGI)

    John W. Long, Nov 22, 2003, in forum: Ruby
    Replies:
    4
    Views:
    395
    John W. Long
    Nov 24, 2003
  4. Giles Bowkett
    Replies:
    16
    Views:
    222
    Giles Bowkett
    Jun 18, 2007
  5. Phlip
    Replies:
    4
    Views:
    150
    Ari Brown
    Sep 14, 2007
Loading...

Share This Page