GithubHelp home page GithubHelp logo

templer's Introduction

Templer

Templer is yet another static site generator, written in Perl.

It makes use of the HTML::Template module for performing variable expansion within pages and layouts, along with looping and conditional-statement handling.

Templer has evolved over time for my own personal use, but I believe it is sufficiently generic it could be useful to others.

My motivation for putting it together came from the desire to change several hand-made, HTML-coded, sites to something more maintainable such that I could easily change the layout in one place.

The design evolved over time but the key reason for keeping it around is that it differs from many other simple static-generators in several ways:

  • You may define global variables for use in your pages/layouts.
  • A page may define and use page-specific variables.
  • You may change the layout on a per-page basis if you so wish.
    • This was something that is missing from a lot of competing tools.
  • Conditional variable expansion is supported, via HTML::Template.
  • File contents, shell commands, and file-globs may be used in the templates
    • This allows the trivial creation of galleries, for example.
    • These are implemented via plugins.
    • Plugins are documented in the file PLUGINS.md.
  • You may also embed perl code in your pages.

Another key point is that the layouts allow for more than a single simple "content" block to be placed into them - you can add arbitrary numbers of optional side-menus, for example.

Although this tool was written and used with the intent you'd write your site-content in HTML you can write your input pages in Textile or Markdown if you prefer (these inputs are supported via plugins).

Concepts

A templer site comprises of three things:

  • A global configuration file.
    • This defines the paths to search for input pages, layout templates, plugins, etc.
    • This may contain global variable declarations.
    • Please see the example configuration file: templer.cfg.
  • A layout.
    • This is used to format the output pages, defining the common look and feel.
  • A series of pages & assets.
    • Pages have their content processed and inserted into the layout to produce output HTML.
    • Assets are not processed, but are copied into the output directory literally.

In general we assume there is a tree like so:

├── input
│   ├── index.wgn
│   ├── ...
│   ├── ...
│   ├── favicon.ico
│   └── robots.txt
├── layouts
│   └── default.layout
├── output
└── templer.cfg

Every file in the input directory is either considered to be a page which is converted into HTML, or an asset which is copied into the output-tree with no changes made.

In the example above input/index.wgn would become output/index.html.

NOTE The .wgn suffix is an example. You can define which suffix is considered a page via the configuration file.

There is also an "in-place" mode. When working in-place there is no distinct output directory, instead output is written to the same directory in which is encountered. Given an input directory you might see this kind of transformation:

index.wgn           -> index.html
about.wgn           -> about.html
favicon.ico         [Ignored and left un-modified.]
robots.txt          [Ignored and left un-modified.]
..

There is also a synchronized mode. When working synchronized any file in the output directory which do not have a source file in input directory (page or asset) is removed each time the site is rebuild.

Pages

Your site will be made of pages, which are snippets of HTML you write. These snippets will be processed and inserted into the layout file before being output to disk.

A page is a simple file which contains a header and some content. This is a sample page:

Title:  This is the title page.
----
<p>This is the body of the page</p>

The header of the page is delimited from the body by four dashes (----) and can contain an arbitrary number of variable definitions.

Special Page Variables

In your page you can define, and refer to, an arbitrary number of variables but some names are reserved - and any variable with one of those names will be treated specially:

The special variable layout may be used to specify a different layout template for the current page. If there is no per-page layout specified then the global layout declared in the templer.cfg file will be used.

The special variable template-filter may be used to specify some filters to apply on the used layout in order to transform it into valid HTML::Template file. If there is no per-page layout filter specified then the global layout declared in the templer.cfg file will be used.

The special variable output may be used to specify an alternative output file. For example the input file index.wgn would normally become index.html, but you could make it become something else.

The special variable format may be given a value of textile, markdown, or perl to enable processing the page body with the appropriate filter. These formatters are implemented as plugins, and will be available assuming their dependencies are installed.

Textile and markdown are well-known, and allow you to write your page content naturally. The perl-formatter is used to allow you to write dynamic content in Perl in your page-body, via the Text::Template module. Perl code to be executed is wrapped in { and } characters. Here is a sample page:

Title: This page has code in it
format: perl
----

<p>This page has some code in it.</p>
<p>I am running on { `hostname` }...</p>
<p>I am {
       my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
                                                           localtime(time);
       $year += 1900;
       $year - 1976;
   } years old.</p>

NOTE: Formatters may be chained. For example "format: perl, markdown".

Variable Definitions

Within the header of each page you may declare an arbitrary number of per-page variables. These variable declarations are then available for use within the page-body, using the standard HTML::Template expansion facilities:

Title:  Page title
Name: Steve Kemp
----
<p>Hello, my name is <!-- tmpl_var name='name' -->.</p>

NOTE: All variable-names are transformed to lower-case for consistency, which is why we refer to the variable name rather than the defined Name.

As well as simple "name: value" pairs there are also additional options implemented in plugins;

  • A variable may refer to the contents of a given file.
    • Using read_file.
  • A variable may refer to a list of filenames, matching a pattern.
    • Using file_glob.
  • A variable may contain the output of running a command.
    • Using run_command.
  • A variable may be based on the timestamp of the input page.
    • Using timestamp.
  • A variable may contain the contents of a remote RSS feed.
    • Using rss(count, URL).
  • A variable may contain the result of a key-lookup from a Redis server.
    • Using redis_get('foo').

In addition to declaring variables in a page-header you may also declare global variables in your templer.cfg file, or upon the command-line via --define foo=bar.

Defining global variables is demonstrated in the sample templer.cfg file.

File Globbing Variables

We've already seen simple variables declared by key: value in the page header, in addition to this you may define a variable that refers to a number of files by pattern.

Here is a simple example of creating a gallery which will include files matching the pattern img/*.jpg:

Title: My gallery
Images: file_glob( "img/*.jpg" )
---
<!-- tmpl_if name='images' -->
  <!-- tmpl_loop name='images' -->
   <p><img src="<!-- tmpl_var name='file' -->"
           height="<!-- tmpl_var name='height' -->"
           width="<!-- tmpl_var name='width' -->" /> </p>
  <!-- /tmpl_loop -->
<!-- tmpl_else -->
  <p>No images were found.</p>
<!-- /tmpl_if -->

TIP: If your images are numbered numerically you can ensure their correct order by doing this:

Title:  This is my title
images: file_glob( img/[0-9].jpg img/1[0-9].jpg )
----
<p>My gallery is now included in ascending numerical order:</p>

This facility is implemented in the Templer::Plugin::FileGlob plugin.

The file glob is primarily designed for handling image-galleries, which is why it will set the height and width attributes if your glob matches *.jpg, *.png, etc. However it can also be used for non-images.

If your glob matches files which are not images it will populate the member content, being the text-content of the matching files. This allows you to include files easily. For example:

Title: This is my news-page
news: file_glob( news-*.txt )
----
<p>Here are the recent events:</p>
<!-- tmpl_loop name='news' -->
<p><!-- tmpl_var name='content' --></p>
<!-- /tmpl_loop -->

This assumes you have files such as news-20130912.txt, etc, and will show the contents of each file in (glob)order.

If matching files are templer input files then all templer variables are populated instead of the text-content of the matching files.

In all cases it will populate dirname, basename and extension, being parts of each matching files name.

File Inclusion

The HTML::Template module supports file inclusion natively, via the following construct:

<p>This is some text.</p>
<!-- tmpl_include name='/etc/passwd' -->
<p>That was my password file.</p>

In addition to this you may define a variable to contain the contents of a specified file. For example:

Title: This file has my passwords!
Passwd: read_file( "/etc/passwd" )
----
<p>Please see my passwords:</p>
<pre><!-- tmpl_var name='passwd' -->
</pre>

This facility is implemented in the Templer::Plugin::FileContents plugin.

Include files, whether included via the read_file method, or via the native HTML::Template faclity, are searched for in the same fashion:

  • If the filename is fully-qualified, then the absolute path-name will be used.
  • Otherwise the include-path will be searched.
  • After the include-path has been searched the file will be looked for in the location relative to the input page location.

This allows you to place all your include-files in a single directory which is outside your web-root.

TIP: The advantage of choosing to use read_file over the native HTML::Template support is that with the former the output page will be automatically rebuilt if you modify the include file.

Shell Command Execution

Pages may also define variables which receive the value of the output of shell commands. This is done via definitions like this:

Title: This file is dynamic
Host: run_command( "hostname" )
----
<p>This page was built upon <!-- tmpl_var name='host' -->.</p>

This facility is implemented in the Templer::Plugin::ShellCommand plugin.

Remote RSS Feeds

Pages may use snippets of RSS feeds, limiting them to the given number of entries. For example:

title: About my site
feed: rss(4, http://blog.steve.org.uk/index.rss )
----
<p>This page is about my site, here are my recent blog posts:</p>
<ul>
<!-- tmpl_loop name='feed' -->
    <li><a href="<!-- tmpl_var name='link' -->"><!-- tmpl_var name='title' --></a></li>
<!-- /tmpl_loop -->
</ul>

Redis Lookups

If you have a redis-server running upon the local system you may configure page-variables to retrieve their values via lookups against it.

For example:

title: Site Statistics
count: redis_get( "global_count" )
----
<p>There are <!-- tmpL-var name='count' --> entries.</p>

Installation

Templer is developed in a public fashion, here on github, but stable releases are also uploaded to CPAN:

Installation should be as simple as any other CPAN-based module:

$ git clone https://github.com/skx/templer.git
$ cd templer
$ perl Makefile.PL
$ make test
$ sudo make install

(If you ever wish to remove the software you may run sudo make uninstall.)

The code makes use of a reasonably large number of modules for its implementation, and you can see a brief overview of the logical structure later.)

If you want to get a standalone templer executable which includes all those Templer modules, you can use the standalone target of the generated Makefile:

$ make standalone

This will produce a script called templer in the base directory so that you should be able to use it alone without copying these used modules anywhere in perl library directories.

The dependencies are minimal, to ease installation:

  • Perl
  • The Module::Pluggable module for loading plugins.
  • The HTML::Template module.
    • This may be installed, on a Debian system, with apt-get install libhtml-template-perl.
  • The following are optional modules:
    • The Image::Size module is used if available whenever you create file_glob-using loops of image files.
      • This will set the attributes width and height any images added via file_glob.
    • The Text::Markdown module is required if you wish to write your page bodies in Markdown.
      • This may be installed, on a Debian system, with apt-get install libtext-markdown-perl.
    • The Text::Textile module is required if you wish to write your page bodies in Textile.
      • This may be installed, on a Debian system, with apt-get install libtext-textile-perl.
    • The Text::Template module is required if you wish to include dynamic perl in your input pages.
      • This may be installed, on a Debian system, with apt-get install libtext-template-perl.
    • The Redis module is required if you wish to use the Redis plugin.
      • This may be installed, on a Debian system, with apt-get install libredis-perl.
    • The XML::Feed module is required if you wish to use the RSS plugin.
      • This may be installed, on a Debian system, with apt-get install libxml-feed-perl.

If you prefer you can install Debian binary packages from my personal repository:

Creating a new site

There is a supplied script templer-generate which will create a new site-structure if you give in the name of a directory to create & write to:

~$ templer-generate my-site
~$ tree my-site/
my-site/
├── include
├── input
│   ├── about.wgn
│   ├── index.wgn
│   └── robots.txt
├── layouts
│   └── default.layout
├── output
└── templer.cfg

If you prefer you may go through the process manually creating a directory, adding the templer.cfg to it, and then creating the input tree and layout directory.

There are several examples provided with the distribution to illustrate the software. These example sites are built automatically every evening and uploaded online - so you may easily compare the input and the generated output:

Rebuilding a site

If you're beneath the directory containing your templer.cfg file simply run templer with no arguments. You may optionally add flags to control what happens:

  • templer --verbose
    • To see more details of what is happening.
  • templer --force
    • To force a rebuild of the site.
  • templer --define foo=bar
    • Define the variable foo for use in your templates. This will over-ride any setting of foo in the configuration file you've loaded.

In the general case templer should rebuild only the files which are needed to be built. A page will be rebuilt if:

  • The page source is edited.
  • The layout the page uses is edited.
  • Any include-file the page includes is edited.
    • This applies to those includes read via read_file rather than via HTML::Template includes

Previously it was required that you run templer from the top-level of your site, this has now changed. templer will walk upwards from the current working directory and attempt to find the site-root by itself.

Object Hierarchy

Although templer is distributed and used as a single script it is written using a series of objects. Bundling into a single binary allows for easier distribution, installation and usage.

In brief the control flow goes like this:

  • templer runs, parses the command line, etc.
  • A Templer::Global object is created to read the templer.cfg file, or the file passed via --config=foo.
  • The options from the command-line and the config file are merged.
  • From this point onwards Templer::Global is ignored.
  • A Templer::Site object is created, using the merged config values.
  • A Templer::Timer object is created to record the build-time.
  • The build process is contained in Templer::Site::build():
    • A Templer::Plugin::Factory object is created to load plugins.
    • A Templer::Site::Page object is created for each appropriate input.
    • Each page is output.
    • The plugins are unloaded.
  • The assets are copied via Templer::Site::copyAssets().
  • The output directory is cleaned via Templer::Site::sync().
  • The build-time/build-count is reported and the process is complete.

Each of the modules has a simple test-case associated with it. To test functionality, especially after making changes, please run the test-suite:

$ make test
prove --shuffle t/
t/style-no-tabs.t ........................... ok
t/test-dependencies.t ....................... ok
..
..
t/test-templer-plugin-filecontents.t ........ ok
t/test-templer-site.t ....................... ok
t/test-templer-plugin-timestamp.t ........... ok
All tests successful.
Files=15, Tests=286,  1 wallclock secs ( 0.11 usr  0.01 sys +  0.88 cusr  0.14 csys =  1.14 CPU)
Result: PASS

Any test-case failure is a bug, and should be reported as such.

Problems

Please report any issue via the github repository:

Author

Steve Kemp [email protected]

templer's People

Contributors

b3 avatar coudot avatar skx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

templer's Issues

It isn't possible to auto-generate pages / create virtual pages.

At the moment input pages are processed, correctly, into output pages. We have plugin support that could be used to generate new pages - but we don't have the ability to do that.

Consider a plugin that you might desire to generate an automatic sitemap. You could write that as a standard variable-expanding plugin:

sub expand_variables{
   my( $self, $page, $data ) = ( @_);

   # record the input path.
   push( $self->{'pages'}, $page->source();

   # return the data unmodified
   return( $data )
}

sub cleanup
{
    # here we can iterate over the page-sources we've recorded in the
    # expand_variables method
}

That's the core of a plugin that can read every input-page, and record their filenames. The missing step is obviously the generation of the /output/sitemap.html file. Now we can read the configuration variables of the site and output pure HTML but that must be done without the access to the site layout.

The solution has to be a Templer::Site method to inject a virtual page into the build process. Something like:

  $site->addPage( { title => "Test title", random  => "bob", content => "This is my generated page", source => "sitemap.wgn" } );

Details need to be considered because the input page will be generated despite not living on disk.

When using include files we don't rebuild if they change.

Consider the following page:

   Title: This is my page.
   menu: read_file( "menu.inc" )
    ---
   <p>This is my page</p>

The output should be rebuilt if:

  • The page is edited.
  • The layout is edited.
  • The templer.cfg file is edited.
  • The include file is edited.

Currently only the first two conditions will trigger a rebuild. If you carry out one of the other two actions the page will only be built if you run:

  • rm -rf output && temper
  • templer --force

We should store the mtime of each Templer::Site::Page and query that. This would allow the Templer::Plugin::FileContents plugin to update the mtime of the parent-page based on the filenames it examines.

NOTE: The plugin must be the thing that does the mtime updating, as that is the only location where we know what is included as a dependency.

NOTE: We should make sure shell commands always trigger a rebuild too. That's the safest way.

Update our plugin-handlers.

I've just added the ability for plugins to have an init-method called, which is useful for my personal website. The reason for this is that you can now define a plugin which has two methods:

sub init {
    my( $self, $site ) = ( @_);
    $self->{ 'site' } ||= $site;
 }

 sub cleanup
 {     my ($self) = (@_);
     my $out   = $self->{ 'site' }->{ 'output' };
     my $pages = $self->{ 'site' }->{ 'output-files' };
      ..
  }

 Templer::Plugin::Factory->new()->register_plugin("Templer::Plugin::sitemap");

This plugin doesn't do anything during the build, but post-build the cleanup method is called and that generates $output/sitemap.xml. Lovely.

The problem is that the register_plugin method assumes there will be an expand_variables method in our plugin - wrap that with a UNIVERSAL->can test.

Pod::Find dependency not listed

cpanm App::Templer

lead to

Can't locate Pod/Find.pm in @INC (you may need to install the Pod::Find module) (@INC contains: /root/.cpanm/work/1641919760.17441/App-Templer-1.2/blib/lib /root/.cpanm/work/1641919760.17441/App-Templer-1.2/blib/arch /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.32.1 /usr/local/share/perl/5.32.1 /usr/lib/x86_64-linux-gnu/perl5/5.32 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl-base /usr/lib/x86_64-linux-gnu/perl/5.32 /usr/share/perl/5.32 /usr/local/lib/site_perl . /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.32.1 /usr/local/share/perl/5.32.1 /usr/lib/x86_64-linux-gnu/perl5/5.32 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl-base /usr/lib/x86_64-linux-gnu/perl/5.32 /usr/share/perl/5.32 /usr/local/lib/site_perl .) at /root/.cpanm/work/1641919760.17441/App-Templer-1.2/t/../bin/templer line 9

It worked after installing Pod-Parser-1.63 with cpanm.

OS: Debian v11.2

Release signature invalid

I attempted to follow the instructions at https://packages.steve.org.uk/templer/ but -

# apt-key list steve
pub   dsa1024 2006-02-23 [SC]
      3661 9DAA B8E8 3147 1BB1  A3EF F3E8 C641 DC26 98A1
uid           [ unknown] steve.org.uk APT key (This key is only used to sign the APT repository at http://www.steve.org.uk/apt/) <[email protected]>
sub   elg2048 2006-02-23 [E]

# cat /etc/apt/sources.list.d/steve-kemp.list 
deb     http://packages.steve.org.uk/templer/jessie/ ./
# 
# apt -q update
Hit:1 http://security.debian.org/debian-security stretch/updates InRelease
Ign:2 http://packages.steve.org.uk/templer/jessie ./ InRelease
Get:3 http://packages.steve.org.uk/templer/jessie ./ Release [347 B]
Get:4 http://packages.steve.org.uk/templer/jessie ./ Release.gpg [181 B]
Ign:4 http://packages.steve.org.uk/templer/jessie ./ Release.gpg
Ign:5 http://mirror.bytemark.co.uk/debian stretch InRelease
Hit:6 http://mirror.bytemark.co.uk/debian stretch-updates InRelease
Hit:7 http://mirror.bytemark.co.uk/debian stretch Release
Reading package lists...
W: GPG error: http://packages.steve.org.uk/templer/jessie ./ Release: The following signatures were invalid: 36619DAAB8E831471BB1A3EFF3E8C641DC2698A1
E: The repository 'http://packages.steve.org.uk/templer/jessie ./ Release' is not signed.

I'm generally on stretch, is that the trouble? Could you release for stretch, pretty please?
Thanks

`templer --manual` is broken.

Because we use Pod::Usage we can embed the man-page inside the script itself, neat.

Unfortunately the main script is comprised of several modules concatenated together, and Pod::Usage shows all of them.

Variables not replaced with correct value

I have installed templer:

$ g clone https://github.com/skx/templer.git
$ cd templer
$ make
$ sudo make install

... and tested

$ make test
...
All tests successful.
Files=15, Tests=332,  1 wallclock secs ( 0.07 usr  0.02 sys +  0.98 cusr  0.05 csys =  1.12 CPU)
Result: PASS

So, when I build examples:

$ cd examples
$ make rebuild
$ cat simple/output/index.html

output is

$ cat simple/output/index.html
<html>
 <head>
  <title></title> <--- empty title variabile!
 </head>
...

My environment:

$ uname -a
Linux boe 3.12.6-1-ARCH #1 SMP PREEMPT Fri Dec 20 19:39:00 CET 2013 x86_64 GNU/Linux

$ perl -v
This is perl 5, version 18, subversion 1 (v5.18.1) built for x86_64-linux-thread-multi

Installation from CPAN fails

If I install App::Templer through CPAN one of the test programs seems to fail, which means I can't install the module (other modules work fine).

I'm running Ubuntu 15.04 and Perl 5.20.2 and using local::lib. Happy to try other distros if that would help narrow down the problem, though there seem to be a lot of failures on CPAN Testers too.

Full error log:

perl -MCPAN -Mlocal::lib -e 'CPAN::install(App::Templer)
Reading '/home/paul/.local/share/.cpan/Metadata'
  Database was generated on Wed, 19 Aug 2015 13:53:35 GMT
Running install for module 'App::Templer'
Checksum for /home/paul/.local/share/.cpan/sources/authors/id/S/SK/SKX/App-Templer-0.9.9.1.tar.gz ok
Configuring S/SK/SKX/App-Templer-0.9.9.1.tar.gz with Makefile.PL
Checking if your kit is complete...
Looks good
Generating a Unix-style Makefile
Writing Makefile for App::Templer
Writing MYMETA.yml and MYMETA.json
  SKX/App-Templer-0.9.9.1.tar.gz
  /usr/bin/perl Makefile.PL INSTALLDIRS=site -- OK
Running make for S/SK/SKX/App-Templer-0.9.9.1.tar.gz
cp lib/Templer/Timer.pm blib/lib/Templer/Timer.pm
cp lib/Templer/Site/Asset.pm blib/lib/Templer/Site/Asset.pm
cp lib/Templer/Plugin/Redis.pm blib/lib/Templer/Plugin/Redis.pm
cp lib/Templer/Plugin/Hash.pm blib/lib/Templer/Plugin/Hash.pm
cp lib/Templer/Plugin/FileContents.pm blib/lib/Templer/Plugin/FileContents.pm
cp lib/Templer/Plugin/FileGlob.pm blib/lib/Templer/Plugin/FileGlob.pm
cp lib/Templer/Plugin/Strict.pm blib/lib/Templer/Plugin/Strict.pm
cp lib/App/Templer.pm blib/lib/App/Templer.pm
cp lib/Templer/Plugin/Markdown.pm blib/lib/Templer/Plugin/Markdown.pm
cp lib/Templer/Plugin/Factory.pm blib/lib/Templer/Plugin/Factory.pm
cp lib/Templer/Plugin/Breadcrumbs.pm blib/lib/Templer/Plugin/Breadcrumbs.pm
cp lib/Templer/Plugin/Dollar.pm blib/lib/Templer/Plugin/Dollar.pm
cp lib/Templer/Plugin/TimeStamp.pm blib/lib/Templer/Plugin/TimeStamp.pm
cp lib/Templer/Plugin/RootPath.pm blib/lib/Templer/Plugin/RootPath.pm
cp lib/Templer/Plugin/RSS.pm blib/lib/Templer/Plugin/RSS.pm
cp lib/Templer/Plugin/ShellCommand.pm blib/lib/Templer/Plugin/ShellCommand.pm
cp lib/Templer/Site/Page.pm blib/lib/Templer/Site/Page.pm
cp lib/Templer/Site.pm blib/lib/Templer/Site.pm
cp lib/Templer/Global.pm blib/lib/Templer/Global.pm
cp lib/Templer/Site/New.pm blib/lib/Templer/Site/New.pm
cp lib/Templer/Plugin/Textile.pm blib/lib/Templer/Plugin/Textile.pm
cp lib/Templer/Plugin/HTML.pm blib/lib/Templer/Plugin/HTML.pm
cp lib/Templer/Plugin/Perl.pm blib/lib/Templer/Plugin/Perl.pm
cp bin/templer-generate blib/script/templer-generate
"/usr/bin/perl" -MExtUtils::MY -e 'MY->fixin(shift)' -- blib/script/templer-generate
cp bin/templer blib/script/templer
"/usr/bin/perl" -MExtUtils::MY -e 'MY->fixin(shift)' -- blib/script/templer
Manifying 2 pod documents
Manifying 23 pod documents
  SKX/App-Templer-0.9.9.1.tar.gz
  /usr/bin/make -- OK
Running make test
PERL_DL_NONLAZY=1 "/usr/bin/perl" "-MExtUtils::Command::MM" "-MTest::Harness" "-e" "undef *Test::Harness::Switches; test_harness(0, 'blib/lib', 'blib/arch')" t/*.t
t/style-no-tabs.t ........................... ok
t/style-no-trailing-whitespace.t ............ ok
t/test-dependencies.t ....................... ok
t/test-pod-syntax.t ......................... ok
t/test-strict.t ............................. ok
t/test-templer-asset-copying.t .............. ok
t/test-templer-page-expansion.t ............. ok
t/test-templer-plugin-factory-formatters.t .. ok
t/test-templer-plugin-factory.t ............. ok
t/test-templer-plugin-filecontents.t ........ ok
t/test-templer-plugin-fileglob.t ............ ok
t/test-templer-plugin-filters.t ............. ok
Use of uninitialized value in string eq at /home/paul/perl5/lib/perl5/Test/More.pm line 1298.
skip() needs to know $how_many tests are in the block at t/test-templer-plugin-redis.t line 60
# Tests were run but no plan was declared and done_testing() was not seen.
t/test-templer-plugin-redis.t ............... 
Dubious, test returned 254 (wstat 65024, 0xfe00)
All 9 subtests passed 
    (less 1 skipped subtest: 8 okay)
t/test-templer-plugin-rootpath.t ............ ok
t/test-templer-plugin-shellcommand.t ........ ok
t/test-templer-plugin-timestamp.t ........... ok
t/test-templer-site-new.t ................... ok
t/test-templer-site.t ....................... ok
t/test-templer-synchronization.t ............ ok

Test Summary Report
-------------------
t/test-templer-plugin-redis.t             (Wstat: 65024 Tests: 9 Failed: 0)
  Non-zero exit status: 254
  Parse errors: No plan found in TAP output
Files=19, Tests=670,  5 wallclock secs ( 0.16 usr  0.00 sys +  3.98 cusr  0.33 csys =  4.47 CPU)
Result: FAIL
Failed 1/19 test programs. 0/670 subtests failed.
Makefile:1042: recipe for target 'test_dynamic' failed
make: *** [test_dynamic] Error 255
  SKX/App-Templer-0.9.9.1.tar.gz
  /usr/bin/make test -- NOT OK
//hint// to see the cpan-testers results for installing this module, try:
  reports SKX/App-Templer-0.9.9.1.tar.gz

`make standalone` is broken.

I've just realized version 1.1 and, too late, I see that this doesn't work any more.

Fix this for 1.2 as a matter of some priority.

The file-hash plugin is bogus.

The documentation doesn't match the code, and the use of Digest::SHA1 is a problem.

Suggestion:

  • Audit the code for behaviour.
  • Attempt to load both Digest::SHA1 and Digest::SHA.

Changes required:

  • If running with --verbose ensure we output the name of the file we're digesting.
  • Fail hard if both module(s) aren't present.

As Bruno said the code structure is confusing at times.

Specifically we want to allow defaults to be read from a configuration file, and then overridden by the command line.

To do that we parse the config file - via Templer::Global - and then parse the cmd line flags. These two sets of options (hashes, internally) are merged and then passed to Templer::Site where all the magic happens.

The Templer::Site object thus has all the values it needs for the generation - input path, output path, & etc.

Unfortunately the Templer::Site module continues to refer to the `Templer::Global object, for things like the include-path and passing state to plugins.

We want the plugins to refer to the site-object not the cfg-object, and we want to otherwise remove Templer::Global from Templer::Site.

Conclusion: This will have lots of code-churn, but no functional/visible change - except to the plugin-api. (Move the API to a hash? Instead of named params?)

.htaccess files are not processed

I've added a .htaccess file to the input directory of one of my Templer sites, but when I run the templer command it's not copied across in the same way as *.pdf files or robots.txt. Is this intentional, or is Templer using something like *.* to get the files under input and therefore missing dotfiles?

File inclusion should have a search path.

There are two forms of file inclusion:

  • Inclusion via the HTML::Template facility to use
  • Inclusion via the meta-data: foo: read_file( "path/here" );

Both forms should allow a search-path to be defined. When expanding file-inclusions we should search the directory tree, relative to the source file, as we do now. If that fails search the global-include path(s).

Suggest we allow --include-path=includes/:/home/includes or similar.

Output filename should come from the page.

At the moment templer is responsible for converting the input file to the output filename.

We do this by stripping the prefix, and changing the suffix to .html, unconditionally.

If we moved the output-path handling into Templer::Page we'd have the easy ability to allow the output to be changed:

Title: This is my page title
Output: foo.html
----
<p>This is my page content.</p>

This would write to foo.html rather than the expected file.

We shouldn't only run from the top-level directory.

Although this simplified the initial migration and coding it is now painful when I'm working in:

   ~/hg/websites/steve.org.uk/input/Software/templer

I have to keep going back to ~/hg/websites/steve.org.uk to run the rebuild-command.

Suggestion: We keep running "cd .." until we hit a filesystem boundary, before aborting. Exactly like git/mercurial do things.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.