App-Dapper

 view release on metacpan or  search on metacpan

bin/dapper  view on Meta::CPAN

#!/usr/bin/perl 

=head1 NAME

dapper - A publishing tool for static websites.

=cut

#use utf8;
use open ':std', ':encoding(UTF-8)';
use 5.010;

use strict;
use warnings;

use FindBin;
use lib "$FindBin::Bin/../lib";

use Pod::Usage;
use Getopt::Mixed;
use App::Dapper;
use File::Monitor;
use File::Find;

use Data::Dumper;

my $COMMAND = undef;
my $SOURCE  = "_source";
my $OUTPUT  = "_output";
my $LAYOUT  = "_layout";
my $CONFIG  = "_config.yml";
my $PORT    = 8000;
my $HELP    = undef;
my $VERSION = undef;

=head1 SYNOPSIS

B<Dapper> allows you to transform simple text files into static websites. By installing the App::Dapper Perl module, an executable named C<dapper> will be available to you in your terminal window. You can use this executable in a number of ways:

    # Initialize the current directory with a fresh skeleton of a site
    $ dapper init

    # Build the site
    $ dapper build

    # Serve the site locally at http://localhost:8000
    $ dapper serve

    # Rebuild the site if anything (source, layout dirs; config file) changes
    $ dapper watch

    # Get help on usage and switches
    $ dapper -h

    # Print the version
    $ dapper -v

Additionally, B<Dapper> may be used as a perl module directly from a script. Examples:

    use App::Dapper;

    # Create a Dapper object
    my $d = App::Dapper->new();

    # Initialize a new website in the current directory
    $d->init();

    # Build the site
    $d->build();

    # Serve the site locally at http://localhost:8000
    $d->serve();

=head1 DESCRIPTION

Dapper helps you build static websites. To get you started, you can use the
C<dapper init> command to initialize a directory. After running this command,
the following directory structure will be created:

    _config.yml
    _layout/
        index.html
    _source/
        index.md

In that same directory, you may then build the site using the C<dapper build>
command, which will combine the source files and the layout files and place
the results in the output directory (default: C<_output>). After you build
the default site, you'll then have the following directory structure:

bin/dapper  view on Meta::CPAN


The output file that is created is a mix of the input file and the layout that
is specified by the input file. For the default site, the following output
file is created:

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    <head>
      <title>Welcome</title>
      <meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
    </head>

    <body>

    <p>Hello world.</p>

    </body>
    </html>

=back

B<Dapper> provides a number of optional command line switches:

=head2 Options

=over 4

=item B<-s>, B<--source>=I<source directory>

Specify the directory containing source files to process. If this command line option is not present, it defaults to "_source".

=item B<-o>, B<--output>=I<output directory>

Specify the directory to place the output files in. If this command line option is not present, it defaults to "_output".

=item B<-l>, B<--layout>=I<layout directory>

Specify the directory containing source files to process. If this command line option is not present, it defaults to "_layout".

=item B<-c>, B<--config>=I<config file>

Specify the config file name to use. If this command line option is not present, it defaults to "_config.yml".

=item B<-p>, B<--port>=I<port>

Specify the port to use for the serve command. This option is only used for the serve command. If this command line option is not present, it defaults to "8000".

=item B<-h>

Get help on available commands and options.

=item B<-v>

Print the version and exit.

=back

=cut

sub init {
    my $d = new App::Dapper($SOURCE, $OUTPUT, $LAYOUT, $CONFIG);
    $d->init();
    undef $d;
}

sub build {
    my $d = new App::Dapper($SOURCE, $OUTPUT, $LAYOUT, $CONFIG);
    $d->build();
    undef $d;
}

sub serve {
    my $pid = fork();
    if ($pid == 0) { watch(); exit(0); }
    my $d = new App::Dapper($SOURCE, $OUTPUT, $LAYOUT, $CONFIG);
    $d->serve($PORT);
    undef $d;
}

sub watch {
    build();
    my $monitor = File::Monitor->new();

    # Find files to watch that are not in the _output directory
    find({ wanted => sub {
        my $filename = $_;
        my $fullpath = $File::Find::name;

        # Ignore directories
        return if -d $filename;

        # Ignore files that start with a period (.) or underscore (_)
        return if $filename =~ /^[_\.].*/;

        # Ignore the output directory and everything in it
        return if $fullpath =~ /$OUTPUT/;

        #print "WATCH $filename\n";

        $monitor->watch( { name => $filename } );
    }}, ".");

    # First scan just finds out about the monitored files. No changes will be reported
    $monitor->scan;

    # Monitor for changes
    while ( 1 ) { for my $change ($monitor->scan) { if ($change->is_change) { build(); last; } } sleep 1; }
}

sub help() {
    pod2usage({-sections => [ qw(USAGE) ] });
    exit(0);
}

sub version() {
    print "Dapper version $App::Dapper::VERSION\n";
    exit(0);
}

Getopt::Mixed::init(q{h
    v   version>v
    s=s source>s
    o=s output>o
    l=s layout>l
    c=s config>c
    p=s port>p
});

while( my( $option, $value, $pretty ) = Getopt::Mixed::nextOption() ) {
    $SOURCE = $value if $option eq 's';
    $OUTPUT = $value if $option eq 'o';
    $LAYOUT = $value if $option eq 'l';
    $CONFIG = $value if $option eq 'c';
    $PORT   = $value if $option eq 'p';
    help()           if $option eq 'h';
    version()        if $option eq 'v';
}

Getopt::Mixed::cleanup();

$COMMAND = $ARGV[0];
$COMMAND = "help" if not $COMMAND;

my $switch = {
  'init'    => sub { init() },
  'build'   => sub { build() },
  'serve'   => sub { serve() },
  'watch'   => sub { watch() },
  'default' => sub { help(); }
};
$switch->{$COMMAND} ? $switch->{$COMMAND}->() : $switch->{'default'}->();

=head1 AUTHOR

Mark Benson, C<< <markbenson at vanilladraft.com> >>

=head1 BUGS

Please report any bugs or feature requests to C<bug-text-dapper at rt.cpan.org>, or through
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=App-Dapper>.  I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.

=head1 SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc App::Dapper

You can also look for information at:

=over 4

=item * RT: CPAN's request tracker (report bugs here)

L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=App-Dapper>

=item * AnnoCPAN: Annotated CPAN documentation

L<http://annocpan.org/dist/App-Dapper>

=item * CPAN Ratings

L<http://cpanratings.perl.org/d/App-Dapper>

=item * Search CPAN

L<http://search.cpan.org/dist/App-Dapper/>

=back

=head1 LICENSE AND COPYRIGHT



( run in 1.128 second using v1.01-cache-2.11-cpan-39bf76dae61 )