App-WRT
view release on metacpan or search on metacpan
lib/App/WRT.pm view on Meta::CPAN
$ cd wrt
$ perl Build.PL
$ ./Build installdeps
$ ./Build test
$ ./Build install
To install the latest version released on CPAN:
$ cpanm App::WRT
Or:
$ cpan -i App::WRT
You will likely need to use C<sudo> or C<su> to get a systemwide install.
=head1 DESCRIPTION
This started life somewhere around 2001 as C<display.pl>, a CGI script to
concatenate fragments of handwritten HTML by date. It has since accumulated
several of the usual weblog features (lightweight markup, feed generation,
embedded Perl, poetry tools, image galleries, and ill-advised dependencies),
but the basic idea hasn't changed that much.
The C<wrt> utility now generates static HTML files, instead of expecting to
run as a CGI script. This is a better idea, for the most part.
By default, entries are stored in a simple directory tree under C<entry_dir>.
Like:
archives/2001/1/1
archives/2001/1/2/index
archives/2001/1/2/sub_entry
Which will publish files like so:
public/index.html
public/all/index.html
public/2001/index.html
public/2001/1/index.html
public/2001/1/1/index.html
public/2001/1/2/index.html
public/2001/1/2/sub_entry/index.html
Contents will be generated for each year and for the entire collection of dated
entries. Month indices will consist of all entries for that month. A
top-level index file will consist of the most recent month's entries.
An entry may be either a plain UTF-8 text file, or a directory containing
several such files. If it's a directory, a file named "index" will be treated
as the text of the entry, and all other lower-case filenames without extensions
will be treated as sub-entries or documents within that entry, and displayed
accordingly. Links to certain other filetypes will be displayed as well.
Directories may be nested to an arbitrary depth, although it's probably not a
good idea to go very deep with the current display logic.
A PNG or JPEG file with a name like
2001/1/1.icon.png
2001/1/1/index.icon.png
2001/1/1/whatever.icon.png
2001/1/1/whatever/index.icon.png
will be treated as an icon for the corresponding entry file.
=head2 MARKUP
Entries may consist of hand-written HTML (to be passed along without further
mangling), a supported form of lightweight markup, or some combination thereof.
Header tags (<h1>, <h2>, etc.) will be used to display titles in feeds,
navigation, and other places.
Other special markup is indicated by a variety of HTML-like container tags.
B<Embedded Perl> - evaluated and replaced by whatever value you return
(evaluated in a scalar context):
<perl>my $dog = "Ralph."; return $dog;</perl>
This code is evaluated before any other processing is done, so you can return
any other markup understood by the script and have it handled appropriately.
B<Interpolated variables> - actually keys to the hash underlying the App::WRT
object, for the moment:
<perl>$self->{title} = "About Ralph, My Dog"; return '';</perl>
<p>The title is <em>${title}</em>.</p>
This is likely to change at some point, so don't build anything too elaborate
on it.
Embedded code and variables are intended only for use in the F<template> file,
where it's handy to drop in titles or conditionalize aspects of a layout. You
want to be careful with this sort of thing - it's useful in small doses, but
it's also a maintainability nightmare waiting to happen.
B<Includes> - replaced by the contents of the enclosed file path, from the
root of the current wrt project:
<include>path/to/file</include>
This is a bit constraining, since it doesn't currently allow for files outside
of the current project, but is useful for including HTML generated by some
external script in a page.
B<Several forms of lightweight markup>:
<markdown>John Gruber's Markdown, by way of
Text::Markdown::Discount</markdown>
<textile>Dean Allen's Textile, via Brad Choate's
Text::Textile.</textile>
<freeverse>An easy way to
get properly broken lines
plus -- em dashes --
for poetry and such.</freeverse>
B<And a couple of shortcuts>:
lib/App/WRT.pm view on Meta::CPAN
);
if (scalar @filter_list) {
return $self->{filters}->dispatch($entry, $html, @filter_list);
}
return $html;
}
return '';
}
=item list_contents($entry, @entries)
Returns links (maybe with icons) for a set of sub-entries within an entry.
=cut
sub list_contents {
my $self = shift;
my ($entry) = shift;
my (@entries) = @_;
my $contents;
foreach my $se (@entries) {
my $linktext = $self->icon_markup("$entry/$se", $se);
$linktext ||= $se;
$contents .= q{ }
. a({ href => $self->{url_root} . "$entry/$se",
title => $se },
$linktext);
}
return p( em('more:') . " $contents" ) . "\n";
}
=item get_title($entry)
Returns a title for the entry - potentially a cached one extracted earlier from
the entry's HTML; otherwise just reuse the entry path itself.
=cut
sub get_title {
my ($self, $entry) = @_;
# Base title - just the entry path:
my $title = $entry;
# Do we have anything in the cache?
if (defined $self->{title_cache}{$entry}) {
$title = $self->{title_cache}{$entry};
}
return $title;
}
=item icon_markup($entry, $alt)
Check if an icon exists for a given entry if so, return markup to include it.
Icons are PNG or JPEG image files following a specific naming convention:
index.icon.[png|jp(e)g] for directories
[filename].icon.[png|jp(e)g] for flat text files
Calls image_size, uses filename to determine type.
=cut
{ my %cache;
sub icon_markup {
my ($self, $entry, $alt) = @_;
return $cache{$entry . $alt}
if defined $cache{$entry . $alt};
my $icon_basepath;
if ($self->{entries}->is_file($entry)) {
$icon_basepath = "$entry.icon";
}
elsif ($self->{entries}->is_dir($entry)) {
$icon_basepath = "$entry/index.icon";
} else {
# XXX there are bugs lurking here for virtual entries probably
return;
}
# First suffix found will be used:
my $suffix;
for (qw(png jpg gif jpeg)) {
if ($self->{entries}->is_extant( "$icon_basepath.$_")) {
$suffix = $_;
last;
}
}
# Fail unless there's a file with one of the above suffixes:
return 0 unless $suffix;
my ($icon_loc, $icon_url) = $self->root_locations($icon_basepath);
# Slurp width & height from the image file:
my ($width, $height) = image_size(
$self->{root_dir_abs} . '/' . "$icon_loc.$suffix"
);
return $cache{$entry . $alt} =
qq{<img src="$icon_url.$suffix"\n width="$width" }
. qq{height="$height"\n alt="$alt" />};
}
}
=item datestamp($entry)
Returns a nice html datestamp / breadcrumbs for a given entry.
=cut
sub datestamp {
my $self = shift;
my ($entry) = @_;
my @fragment_stack;
my @fragment_stamps = (
a({ href => $self->{url_root} }, $self->{title_prefix}),
);
# Chop up by directory separator:
my @pieces = split '/', $entry;
foreach my $fragment (@pieces) {
push @fragment_stack, $fragment;
push @fragment_stamps,
a({ href => $self->{url_root} . (join '/', @fragment_stack) . '/',
title => $fragment }, $fragment);
}
my $stamp = p({class => 'datestamp'}, join(" /\n", @fragment_stamps));
my $tag_list = $self->entry_tag_list($entry);
if ($tag_list) {
$stamp = "\n" . p({class => 'tags'}, $tag_list) . $stamp;
}
return "\n$stamp\n";
}
=item root_locations($file)
Given an entry, return the appropriate concatenations with entry_dir and
url_root.
( run in 0.471 second using v1.01-cache-2.11-cpan-744e820c463 )