|There's more than one way to do things|
RFC: Plake, a target-based file assemblerby arbingersys (Pilgrim)
|on Apr 03, 2008 at 16:38 UTC||Need Help??|
Plake is a tool that allows you to maintain sections within a single file (usually, variations of the same code/markup/content) and then assemble variations of that file according to which target you call. It was inspired by Make, used in conjunction with Make (by me), and written in Perl, hence the name "Plake".
It uses a very simple grammar, and allows you to define sections within a given text file, then define targets that assemble the sections you want, and optionally, specify a path where the assembled section will be written to disk as a new file.
Plake runs in two modes.
1. "Top-down/lazy", the default mode, which includes all sections for a given target plus lines from the file that do not have a defined section. The output is assembled top-down. This is useful for when you only need small variations of a file to be made, and want to keep Plake to a minimum.
2. "Stickler", which means that any text not attributed to a named section is ignored, and sections are assembled in the order that they are passed into target(). This means you have specific ideas about how the output will be assembled and don't want Plake to try and be intelligent about it.
NAMEPlake - Target based file assembler
SYNOPSISHere's roughly what a Plake file would look like:
And here's generally how you would use the Plake.pm package to process a Plake file:
Code sectionUse !plake: to indicate the start of a ``code'' section, where you declare your targets with the target() method, and maybe even override the default ``build'' method with your own using my_builder().
Standard section!plake \w+:, e.g. !plake section1:, indicates the start of a multi-line, standard section. The start of a new section flags the end of a previous section.
One-line sectionUse !plake \w+, e.g. !plake oneliner (followed immediately by your line) to generate a single line section.
Section endingUse !plake. to end a section explicitly. You can use it to end standard sections as well as code sections.
I use Plake in a particular software project to generate variations of a Config.pm file for different implementation scenarios.
For instance, I have a demo online, and it uses a real live SQL password I can't include with the default distro. For the default distro, I use "password" for the password. I also have verbose logging turned off for my demo and the default distro, but in my own testing environment, I want it on even though it generates lots of log activity.
These are all minor variations of the single Config.pm file for my project. With Plake, I add a target to my Makefile like
and simply "make configfiles" to get the variations of Config.pm for uploading to the demo, adding to the distro, etc. Meanwhile, every orientation is very accessible within the single Config.plk file.
Please don't think that Plake was designed merely for overriding default values in config files (670323). There are certainly better ways for doing this. I see it primarily as a development tool. Here's a few places where I thought it might be useful:
- Setting variations for builds, like what I describe above for the config file. A convenience for me since I have yet to implement a more complex (i.e. overrides) configuration system, but still have to make subtle changes (usually, by hand-editing) for various implementations at various stages of development.
- Assemble C/C++ files for specific platforms, in the stead of #ifdef, etc. The resulting .c/.cpp/.h file would be assembled dynamically when the project was make'd for a given platform, just prior to compilation. The code generated for that platform would be a bit simpler to review, since it only includes code that a person cares about in that build.
- Remove experimental features, stubs, or extra debugging from code prior to generating distros, i.e. "Cleanup".
- Branching, like what source control does. You could keep some client or "branch" specific features out of a specific build, but still maintain it in a single file.
- Template variations, like letter writing. Instead of a single boiler plate template, you have targets like "standard_greeting", "enthusiastic_greeting", "familiar_greeting", etc.
- Target-based programming for Perl. Sort of a side-effect, and one I don't see all the ramifications of, but you could use Plake to assemble code targets wholly or partially independent of each other by storing Perl code in a Plake file and doing an eval against the assembled content for a given target. (Just think -- you could keep your entire project of hundreds of modules and code files all in one single, massive text file! I can see everyone lining up now... :)
Eval'ing code from targets:
If you've made it this far, you might want to check it out yourself:
One thing I'm still pondering: Should a target be able to include other targets? This would be very Make-like, with real dependencies, but I don't know how useful it would actually be.
A blog among millions.