Sunday January 1, 2006

Using PHP as a Macro Pre-processor

I've been using macro pre-processors (e.g., cpp, m4) since I switched to Unix a couple of decades ago. I've also used assorted ad hoc processors. The shell makes a handy a runtime pre-processor for awk and sed scripts. "Little language" processors can be written using Perl, YAML, etc. In short, macro processing is not a new concept for me.

Nor, for that matter, is its application to document markup languages (e.g., Troff, HTML). In fact, I've written several special-purpose processors to generate and/or massage documents. Consequently, I'm a bit embarrassed to realize that I've been missing out on a nifty way to use macros in web pages.


I use raw HTML for most of my hand-edited web pages. I like the control that this gives me and don't mind the extra typing (or mousing) it requires. I also take the trouble to format my HTML "code" (e.g., indenting, folding lines), so that it is easy to read, edit, etc.

Unfortunately, the occasional humongous URL really gets in the way of my formatting preferences. URLs can't be folded; about the best I've been able to do is to put long URLs on lines by themselves, so the damage is localized. Repeating common portions of URLs (e.g., is also a pain. Grumble.

Enter PHP, by way of Ruby

Despite PHP's growing popularity, I've never been all that interested in trying it. Looks kind of like Perl, only broken (e.g., no support for variable argument lists!). On the other hand, it certainly isn't difficult.

Meanwhile, I've been trying to wrap my AARP-qualified, procedurally-oriented brain around the wild and crazy world of Ruby and Rails. One of the niftier tricks that Ruby offers (and Rails uses) is something called Embedded Ruby (aka ERb, eRuby).

The basic idea is that you can interleave arbitrary Ruby code with declarative languages such as HTML, XML, YAML, etc. So, you can expand variables, make method calls, iteratively generate blocks of text, etc. Quite cool, really...

Unfortunately, ERb isn't (yet) part of the typical web server offerings. So, as I was editing a bunch of HTML, I started thinking about PHP. Yeah, it's not Ruby (or even Perl), but it isn't bad. Maybe I could use it to spare my poor, tired fingers.

Show Us the Code!

Ok, Ok... The following code defines a string ($WP) and a function (ah) that generates a typical HTML link. I added a "target" attribute to the link, to keep the original page from going away, but still, it's all pretty vanilla:

  $WP = '';

  # ah - generate an "a href" link 
  function ah($url, $text) {

    print "<a href='$url'\n"
        . "   target='_blank'\n" 
        . "  >$text<a>" 

Here is some HTML/PHP source code, drawn from one of my Model-based Documentation pages:

   About half of the pages are generated by 
   <?= ah("$WP/Doxygen",                 'Doxygen'); ?>, a well-known
   <?= ah("$WP/Documentation_generator", 'documentation generator'); ?>;
   the rest are generated by custom Perl scripts.
I won't claim that this is exactly pretty, but it's a lot shorter and easier to read (IMHO) than the pure HTML form:
   About half of the pages are generated by 
   <a href=''
     >Doxygen<a>, a well-known
   <a href=''
     >documentation generator<a>;
   the rest are generated by custom Perl scripts.
One of the real joys of this approach is that I can format the calls as desired, break URLs any place I like, etc:
  <? $T1 = 'Some Really Enormous URL...'; ?>

    <?= ah($T1, 'yada yada...'); ?>
<?= ah('' . '?tag1=1234567890123456789012345678901234567890' . '&tag2=1234567890123456789012345678901234567890', 'Clues are optional...'); ?>
Also note that, if I need to fiddle with the link format, I may get lucky and be able to edit just the function definition!

It Gets Worse...

Because I wanted a navigation sidebar on each page, and the ability to generate a "printable version" of the pages, I actually ended up writing 200+ lines of function definitions, etc. However, this meant that each web page needed very little code:

  <? include 'mbd_defines.php';
     do_page('Case Study');
    <?= sect_head('Design Goals'); ?>
    <?= sect_head('Implementation'); ?>
    <?= next_link('mbd_advice.php', 'Advice'); ?>
  <? page_footer(); ?>

Although all of this may be old hat to most PHP programmers (let alone those Agile Rubyists :-), I've found it to be a very useful addition to my bag of tricks. Now, if I could only convince ecto to expand my PHP to HTML, on its way to Movable Type...

Technorati Tags: , ,

Using PHP as a Macro Pre-processor in Computers , Technology - posted at Sun, 01 Jan, 22:44 Pacific | «e» | TrackBack