I'm sick of writing HTML by hand. Fortunately, Perl
comes to the rescue. A simple combination of make,
HTML::Template, HTML::FromText, and an
almost stupidly trivial "markup" format of my own have
automated the generation of pages on http://infernus.net
to a satisfying degree. The makefile especially is still
in flux, but here's the Perl code that I call to generate
each page:
#! /usr/bin/perl -w
=head1 NAME
to_html: Translate an atxt document to HTML
=head1 SYNOPSIS
to_html [-t template -o output] document.atxt
=head1 DESCRIPTION
to_html translates an augmented text (atxt) document to HTML using
HTML::Template and HTML::FromText.
to_html tries to use C<./template.tmpl> or a file specified by the
C<-t> option as an HTML::Template template, and writes to
C<./document.html> or a file specified by the C<-o> flag.
=head1 ATXT FORMAT
The atxt format is simple: a top block of headers (in key: value
form), an empty line, and the rest of the document, just like an
email.
=cut
use strict;
use vars qw($opt_t $opt_o);
use HTML::FromText;
use HTML::Template;
use Data::Dumper;
# symbolic constants
my $WEBROOT = "/var/www/infernus.net/";
my $doc = shift @ARGV
or die "Usage: to_html [-t template -o output] document\n";
my $template = HTML::Template->new
(
'filename' => $opt_t || "template.tmpl"
)
or die "Cannot create HTML::Template object: $!\n";
my $output = $opt_o || $doc;
$output =~ s/\.\w+$/\.html/ unless $opt_o;
my ($headers, $body) = &grab_doc($doc);
my $html_body = &text2html
($body,
'bold' => 1,
'underline' => 1,
'urls' => 1,
'paras' => 1,
'blockparas' => 1,
'bullets' => 1,
'numbers' => 1,
'tables' => 1,
);
my $lastmod = (-M $doc) * 86400 + time;
# default template variables
$template->param('lastmod_date' => &make_time_str($lastmod));
$template->param('content' => $html_body);
$template->param('sitenav' => &make_sitenav());
# page-specific template variables
$template->param('dirnav' => &make_dirnav())
unless ((defined $headers->{'dirnav'}) and
(! $headers->{'dirnav'}));
# set template variables based on headers
$template->param(%$headers);
&write_html($output, $template->output());
# make_sitenav
# Make a site navigation link bar (top level)
# Links to /main.html and each dir in $WEBROOT
sub make_sitenav
{
my @links = (qq(<a href="/main.html">main</a>));
opendir WEBROOT, $WEBROOT
or die "Can't opendir $WEBROOT: $!\n";
my @dirs = grep { -d $_ } readdir WEBROOT;
foreach (@dirs) {
next if /^\.{1,2}$/;
push @links, qq(<a href="/$_/">$_</a>);
}
closedir WEBROOT
or die "Can't closedir $WEBROOT: $!\n";
return join " | ", @links;
}
# make_dirnav
# Make links to the HTML versions of any files in the current director
+y.
# Pretty up the filenames a bit for the link text -- this should chang
+e
# to document titles in later versions
sub make_dirnav
{
my @links = ();
opendir CURRENT, '.'
or die "Can't opendir .: $!\n";
my @files = grep /\.atxt$/, readdir CURRENT;
foreach (@files) {
my ($file) = /^(.+)\.atxt$/;
my $name = $file; $name =~ s/_/ /g;
push @links, qq(<a href="$file.html">$name</a>);
}
closedir CURRENT
or die "Can't closedir .: $!\n";
return join " | ", @links;
}
# grab_doc(doc)
# Read in an atxt document, extract the headers, and grab the rest.
# Returns a ref to a headers hash and a scalar of the body text.
# Dies on file open error.
sub grab_doc
{
my ($doc) = @_;
open DOC, "<$doc"
or die "Cannot open $doc: $!\n";
my $headers = {};
my $body = "";
# get headers
while(<DOC>) {
last if /^\s*$/;
# would use split here, but only want to break on the first :
my ($key, $value) = /^([^:]+):\s*(.*)$/;
$headers->{$key} = $value;
}
# rest is body
local $/ = undef;
$body = <DOC>;
close DOC
or die "Cannot close $doc: $!\n";
return ($headers, $body);
}
# make_time_str(time)
# Makes a pretty date string from an epoch time.
# Probably horribly redundant.
sub make_time_str
{
my ($time) = @_;
my ($sec,
$min,
$hour,
$day,
$mth,
$year,
$wday,
$yearday,
$isdst
) = localtime($time);
# CHANGE if you're in a different time zone
my $timezone = $isdst ? "MDT" : "MST";
my @weekdays =
qw(Sunday Monday Tuesday Wednesday Thursday Friday Saturday);
my $weekday = $weekdays[$wday];
my @months =
qw(Jan. Feb. Mar. Apr. May June July Aug. Sep. Oct. Nov. Dec.);
my $month = $months[$mth];
# bah to all of these.
$year += 1900;
$sec = "0$sec" if $sec < 10;
$min = "0$min" if $min < 10;
$hour = "0$hour" if $hour < 10;
return "$weekday $day-$month-$year at $hour:$min:$sec $timezone";
}
# write_html(outfile, content)
# Writes content to a file named "outfile". Simple.
sub write_html
{
my ($outfile, $content) = @_;
open OUT, ">$outfile"
or die "Cannot open output file $outfile: $!\n";
print OUT $content;
close OUT
or die "Cannot close output file $outfile: $!\n";
}
The make_time_str function is probably
redundant, and all of the code is incredibly hackish, but
for the hour or so that this took me (in total), it's
well worth it.
--
The hell with paco, vote for Erudil!
:wq
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.