On Aug 20, 2006, at 11:10 AM, ara.t.howard@noaa.gov 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