=pod

=for vim
   vim: tw=72 ts=3 sts=3 sw=3 et ai :

=encoding utf8

=head1 NAME

Command::Template - A template to build command line arrays, and run them

=head1 VERSION

This document describes Command::Template version 0.001.

=begin html

<a href="https://travis-ci.org/polettix/Command-Template">
<img alt="Build Status" src="https://travis-ci.org/polettix/Command-Template.svg?branch=master">
</a>
<a href="https://www.perl.org/">
<img alt="Perl Version" src="https://img.shields.io/badge/perl-5.24+-brightgreen.svg">
</a>
<a href="https://badge.fury.io/pl/Command-Template">
<img alt="Current CPAN version" src="https://badge.fury.io/pl/Command-Template.svg">
</a>
<a href="http://cpants.cpanauthors.org/dist/Command-Template">
<img alt="Kwalitee" src="http://cpants.cpanauthors.org/dist/Command-Template.png">
</a>
<a href="http://www.cpantesters.org/distro/O/Command-Template.html?distmat=1">
<img alt="CPAN Testers" src="https://img.shields.io/badge/cpan-testers-blue.svg">
</a>
<a href="http://matrix.cpantesters.org/?dist=Command-Template">
<img alt="CPAN Testers Matrix" src="https://img.shields.io/badge/matrix-@testers-blue.svg">
</a>

=end html

=head1 SYNOPSIS

   use Command::Template qw< command_runner command_template cr ct >;

   #### COMMAND EXPANSION GENERATION (NO EXECUTION) ####
   # command_template is aliased to ct
   my $ct = command_template(qw{ ls [options=-l] <dir> });

   # @c1 = qw< ls -l / >
   my @c1 = $ct->generate(dir => '/');

   # @c2 = qw< ls -la / >
   my @c2 = $ct->generate(dir => '/etc', options => '-la');

   # @c3 = @c4 = qw< ls /usr/bin >
   my @c3 = $ct->generate(dir => '/usr/bin', options => undef);
   my @c4 = $ct->generate(dir => '/usr/bin', options => []);

   # @c5 = qw< ls -l -a /usr/bin >
   my @c5 = $ct->generate(dir => '/usr/bin', options => [qw< -l -a >]);


   #### COMMAND RUNNING (VIA IPC::Run) ####
   # command_runner is aliased to cr
   my $runner = command_runner(qw{ ls [options=-l] <dir> });

   # run command qw< ls -l / >, returns a Command::Template::RunRecord
   my $r = $runner->run(dir => '/');
   my $run_successful  = $r->success;
   my $exit_code       = $r->exit_code; # 0 is OK as usual in UNIX
   my $received_signal = $r->signal;    # e.g. if killed, ...
   my $stdout          = $r->stdout;
   my $stderr          = $r->stderr;
   my $merged          = $r->merged; # stderr then stdout, no newlines
                                     # added

   # command_runner is aliased to cr
   my $other_runner = cr(qw< cat >); # gives stdin as stdout
   my $message = "blah\nblah";
   $r = $other_runner->run(-stdin => $message);
   my $equal = $r->stdout eq $message; # true


=head1 DESCRIPTION

C<Command::Template> eases the creation of objects that help building up
command-lines and/or to run them.

As an example, it might be needed to generate multiple commands
according to the following template:

   ls [options=-l] <dir>

i.e. the C<ls> command, where there might be some C<options> (defaulting
to option C<-l>) and there MUST be a directory C<dir> (which in this
case has no default).

The following possible expansions adhere to the template above:

   ls -l /
   ls -la /usr
   ls -l -a /etc
   ls /run

while the following does not (because there is no directory, which we
want because we used the C<< <...> >> form):

   ls -l

The module provides two different interfaces:

=over

=item *

L</command_template> allows generating the commands as lists, which are
then supposed to be used somehow (e.g. provided to C<system>);

=item *

L</command_runner> allows running the commands via L<IPC::Run>.

=back

Both adhere to the same L</Expansion Rules> explained below and
implemented in L<Command::Template::Instance>.

=head2 Expansion Rules

A template in C<Command::Template> resembles the way commands are
explained in documentation:

=over

=item *

required parameters are enclosed by C<< <...> >> delimiters;

=item *

optional parameters are enclosed by C<< [...] >> delimiters.

=back

Parameters name can only start with a letter or an underscore, then can
be followed by any sequence of underscores, letters, and digits. The
following names are valid:

   foo
   bar
   dir
   baz1
   baz_2
   name_or_surname

Any parameter can be optionally set with a default value, which can be
set with the C<=> sign, like in the following examples:

   <foo=this is FOO>
   <bar=  BAR  >

Spaces are preserved starting immediately after the C<=> sign.

When L<Template::Command::Instance> expands a template, it uses a hash
that maps each name to the value it should take:

=over

=item *

if C<undef>, then the corresponding item is I<removed> from the command.
This allows getting rid of a default value set for an optional
parameter; it is an error (leading to an exception) if the parameter is
required;

=item *

if any other plain scalar, it is set as the value in the specific
command line parameter location;

=item *

if an array reference, all items inside are put in the specific command
line parameter location.

=back

The last possibility provides the flexibility to e.g. set options that
require a parameter (e.g. it would be the case of option C<-name> for
command C<find>).

=head2 Running Commands

While L<Command::Template::Instance> only allows generating command
lines as lists of strings, L<Command::Template::Runner> allows running
them by means of L<IPC::Run>.

All the heavy work for expanding is provided by
L<Command::Template::Instance> behind the scenes; the L</SYNOPSIS>
contains examples of actual running of commands.

=head1 INTERFACE

=head2 B<< command_runner >>

   # parse a command line template and use it for running commands
   my $cr = command_runner(qw{ ls [options=-l] <dir> });

Returns a L<Command::Template::Runner> object with a C<run> method that
allows actually running generated commands via L<IPC::Run>.

Each run returns a L<Command::Template::Runner::Record> object that allows
peeking into the actual result of the run.

   my $r = $cr->run(options => '-la', '/etc');
   say $r->stdout if $r->success;

=head2 B<< cr >>

Alias for L</command_runner>.

=head2 B<< command_template >>

   my $ct = command_template(qw{ galook <foo> <bar=N> [baz] [sil=Y] })

Returns a L<Command::Template::Instance> object with a C<generate>
method that performs the actual expansion, returning a list of strings
representing the command line.

=head2 B<< ct >>

Alias for L</command_template>.

=head1 EXTENDING

If extending C<Command::Template> is of interest, here are a few hints:

=over

=item *

class L<Command::Template::Instance> encapsulates parsing a command
template and expanding it for generating command lists, based on a hash
with values binding;

=item *

class L<Command::Template::Runner> provides a simple running facility
around L<Command::Template::Instance> that uses L<IPC::Run> to run
expanded commands, returning the result as a
L<Command::Template::Runner::Record> object.

=item *

class L<Command::Template::Runner::Record> provides accessors into the
outcome of a single run from L<Command::Template::Runner>.

=back

Possible reasons for expanding might be:

=over

=item *

different or additional rules for expansions are needed. If this is the
case, the alternative to L<Command::Template::Instance> must provide a
C<generate> method; L<Comman::Template::Runner> can still be used, as
long as a reference to the alternative object for the instance is passed
to the constructor.

=item *

a different running facility is needed. In this case, it suffices to
impelement a new runner class, leveraging L<Command::Template::Instance>
for the command expansion.

=back


=head1 BUGS AND LIMITATIONS

Minimum perl version 5.24.

Report bugs through GitHub (patches welcome) at
L<https://github.com/polettix/Command-Template>.

=head1 AUTHOR

Flavio Poletti <flavio@polettix.it>

=head1 COPYRIGHT AND LICENSE

Copyright 2021 by Flavio Poletti <flavio@polettix.it>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.


=cut
