Advanced uses for makepp
There is a popular myth that makepp is for compiling programs. In fact it is an abstract rule based mechanisms for creating files from other files whenever those change.
Instead of learning one of the template engines out there, you can use
makepp's builtin &preprocess command, the language of which you know from
writing makefiles. It is not a CGI mechanism (though that should be
achievable by sourcing in the makeppbuiltin wrapper) and it doesn't have all
the bells and whistles (though you can define neat things). But this allows
you to separate content from form, and both can be dynamic at generation time,
which is enough for a medium size web site. The result is a static page,
which can of course contain AJAX elements. E.g. you can split up the page
into a head, body and foot:
%.html: %.shtml $(find-upwards $( head foot).html.mk)
# %-element must be first above, but reorder it between head and foot:
&preprocess $(HTMLFLAGS) $(inputs 2 1 3) -o $(output)
happy.html: HTMLFLAGS += TITLE='My Happy Page' KEYWORDS=happy,lucky
$(phony all): *.html
This introduces new file-types .shtml and .html.mk, the distinction
being made so that the all-target doesn't produce head.html and
foot.html. You can pick any suffixes which your editor will handle as
HTML, since the content is just that. But makepp $(...) expressions are
evaluated, and conditional statements and
include/_include, perl/makeperl/perl_begin or sub/makesub
are evaluated.
The above is a bit ugly, because it puts part of the page information, namely
the header fields, into the makefile. Instead you should use the
-a/--assignment option to set these variables within your body file and
produce the header afterwards. Instead of having two different suffixes, we
can turn the frame into a dot- or hidden file, so that *.html will not
match .frame.html:
%.html: %.shtml .frame.shtml
&preprocess -a $(HTMLFLAGS) $(input) -o $(output)
This explicitly only processes the body. Of course you would do more fancy things, maybe including a menu from yet another file:
# We don't want <title>$(TITLE)</title> turned into rc-style # <title>My</title> <title>Happy</title> <title>Page</title> makepp_simple_concatenation = 1 <html> <head> <title>$(TITLE)</title> <meta name="keywords" content="$(KEYWORDS)" /> <meta name="description" content="$(DESCRIPTION)" /> <meta name="generator" content="makepp/&preprocess" /> </head> <body> <h1>$(TITLE)</h1> define FOOTER = # Store the footer template for later. </body> </html> enddef
The body in turn must include the frame, once it has set any
parameters. At the end it must expand the FOOTER variable:
TITLE = My Happy Page KEYWORDS = happy,lucky DESCRIPTION = Feeling good today include .frame.shtml <p>This is why I'm <b>so</b> happy: ... $(FOOTER)
You can write an img function which returns an image tag with the size and
text extracted from the image. This is based on the rdjpgcom utility,
which outputs any number of comment lines, followed by two lines of meta
information. We accumulate the former, until we reach the latter, and then
output it all at once:
sub imagefilter {
if( /^JPEG image is (\d+)w \* (\d+)h/ ) {
chomp $alt;
print "width='$1' height='$2' alt='$alt'";
} else {
$alt .= $_;
}
}
%.dim: %.jpeg
&perl &imagefilter -Ii 'rdjpgcom -verbose $(input)' -o $(output)
Within &preprocess you would then have a function (best defined in a Perl
module) like:
sub f_img {
my( $name, $rest ) = split /, */, $_[0], 2;
open my $fh, "$name.dim";
"<img src='$name.jpeg' " . <$fh> . " $rest />";
}
and use it as (note the double parens, in case somebody reformats a line break into it some day):
Here is the image: $((img basename, align="right"))
The same could be done with gifs and pngs, and the img function could even
look which of these it finds for a given basename. But you need different
utilities. For png, there can be any number of embedded text attributes,
all of which pngtopnm can extract to a file, and you take it from there.
If you version control your files, you can use the timestamp in the footer. Note the trailing empty expansion, which prevents the final dollar from being illegal makepp syntax:
VC = $Id: index.shtml,v 1.2 2006/08/17 07:38:50 pfeiffer Exp pfeiffer $()
The footer can then contain an expression which extracts the date from the
VC variable:
<p>Last changed: $((map $(VC), tr!/!-!; m/([-\d]{10})/; $_ = $1))</p>
If you want more than just a consistent look and feel for your pages, you can
define statement (presumably outputting something with
print) or functions returning some generated HTML. E.g., you can define a
function which gives you an <a> hyperlink tags based on a name you
fetch in a hash or a database. This is left as an excercise for you.
We have a certain number of similar applications, each running in several instances in an account of their own. The conffiles for some programs must be converted to binary format within the run time environment. This led us to set everything up with makepp.