laziness, impatience, and hubris | |
PerlMonks |
Re: RFC and Questions regarding a module to automate and centralize infrastructure administrationby stevieb (Canon) |
on Mar 25, 2017 at 02:39 UTC ( [id://1185855]=note: print w/replies, xml ) | Need Help?? |
" For instance, the line where I access the array of commands: for my $cmd (@{$ctxt->{commands}}) { ..." That depends. In one of my distributions where I knew extensibility would be required, I built an "engine" type system. It was filter based, so I had these phases:
That compromised the "core" of the project. How I designed it was that the engine was a part of the core, where the "processor" phase was at its root (the absolute core), and input to it needed to be in an expected format, and output from it would be in an expected format. What the pre-proc did before it reached the proc phase was irrelevant (so long as the proc phase got the proper formatted data), and the output from the post proc and engine was irrelevant as well, as the upper-level methods would output the data, according to the documentations spec. How I accomplished this, was to create hash tables containing subroutine references to various functionality methods, then 'register' those routines within the main object. Here's a public method I made available for development and convenience that lists the non-private 'registered' engine methods:
The Engine module initialization code (new()), along with the dispatch table that links a command to an actual function:
...here's an example of an Engine itself:
...and finally, the _core() code that looks for the engine specific code and loads it, whether it's an already registered engine, or a user-supplied code reference of a new/custom one:
Now, when someone calls the all() method on the main object, this is what is executed:
...run() is the method that actually instigates the whole process. The above all() is the most simplistic as it gets. If more phases were involved, this method kicks it off, it'll process through all of the phases, then gets it back for return to the method that originally called it for return to the user:
Then, when _core() is called, it iterates through the phases, calling each one at a time (if they are needed), and in this case, it'll eventually see an engine is located. This is how that phase is executed. $engine is the subroutine callback (code reference) specified, and that's how we can call it as a function like below.
After that, there's further processing, but since "engine" is the last phase, eventually, $subs gets put back into $struct, and when things are done, that is what is returned back to run(), which is returned back to all() which is returned back to the user caller. So, that was kind of fun going back through some of the code I wrote that I had fun designing that allowed the shifting in and out of code blocks for different purposes. That's just one way to make things a bit modular. Note, I said one way. There are many, and the deeper and more complex you get, the more convoluted your code may become, unless you have a great test suite, and a whole crapload of good documentation. Those two things are key to building a system that you're looking at approaching :) fwiw, the code above belongs to my Devel::Examine::Subs. update: Good thing is when you go back and examine your code a few years later, you can see a whole lot of "NOPE" that you wouldn't do now and it looks out of place, which means refactoring ;)
In Section
Seekers of Perl Wisdom
|
|