NAME¶
App::Rad - Rapid (and easy!) creation of command line applications
VERSION¶
Version 1.04
SYNOPSIS¶
This is your smallest working application (let's call it 
myapp.pl)
    use App::Rad;
    App::Rad->run();
That's it, your program already works and you can use it directly via the
  command line (try it!)
    [user@host]$ ./myapp.pl
    Usage: myapp.pl command [arguments]
    
    Available Commands:
        help    show syntax and available commands
Next, start creating your own functions (e.g.) inside 
myapp.pl:
    sub hello {
        return "Hello, World!";
    }
And now your simple command line program 
myapp.pl has a 'hello' command!
    [user@host]$ ./myapp.pl
    Usage: myapp.pl command [arguments]
    
    Available Commands:
        hello
        help    show syntax and available commands
   [user@host]$ ./myapp.pl hello
   Hello, World!
You could easily add a customized help message for your command through the '
  
Help()' attribute:
    sub hello 
    :Help(give a nice compliment)
    {
        return "Hello, World!";
    }
And then, as expected:
    [user@host]$ ./myapp.pl
    Usage: myapp.pl command [arguments]
    
    Available Commands:
        hello   give a nice compliment
        help    show syntax and available commands
App::Rad also lets you expand your applications, providing a lot of flexibility
  for every command, with embedded help, argument and options parsing,
  configuration file, default behavior, and much more:
    use App::Rad;
    App::Rad->run();
    sub setup {
        my $c = shift;
        $c->register_commands( {
                foo => 'expand your foo!',
                bar => 'have a drink! arguments: --drink=DRINK',
            });
    }
    sub foo {
        my $c = shift;
        $c->load_config('myapp.conf');
        return 'foo expanded to ' . baz() * $c->config->{'myfoo'};
    }
    # note that 'baz' was not registered as a command,
    # so it can't be called from the outside.
    sub baz { rand(10) }
    sub bar {
        my $c = shift;
        if ( $c->options->{'drink'} ) {
            return 'you asked for a ' . $c->options->{'drink'};
        }
        else {
            return 'you need to ask for a drink';
        }
    }
You can try on the command line:
   [user@host]$ ./myapp.pl
    Usage: myapp.pl command [arguments]
    
    Available Commands:
        bar     have a drink! arguments: --drink=DRINK
        foo     expand your foo!
        help    show syntax and available commands
   [user@host]$ ./myapp.pl bar --drink=martini
    you asked for a martini
WARNING¶
This module is very young, likely to change in strange ways and to have some
  bugs (please report if you find any!). I will try to keep the API stable, but
  even that is subject to change (let me know if you find anything annoying or
  have a wishlist). You have been warned!
DESCRIPTION¶
App::Rad aims to be a simple yet powerful framework for developing your
  command-line applications. It can easily transform your Perl 
one-liners
  into reusable subroutines than can be called directly by the user of your
  program.
It also tries to provide a handy interface for your common command-line tasks.
  
If you have a feature request to easen out your tasks even more, please
  drop me an email or a RT feature request.
Extending App::Rad - Plugins!¶
App::Rad plugins can be loaded by naming them as arguments to the "use
  App::Rad" statement. Just ommit the "App::Rad::Plugin" prefix
  from the plugin name. For example:
   use App::Rad  qw(My::Module);
will load the "App::Rad::Plugin::My::Module" plugin for you!
Developers are 
strongly encouraged to publish their App::Rad plugins
  under the "App::Rad::Plugin" namespace. But, if your plugin start
  with a name other than that, you can fully qualify the name by using an unary
  plus sign:
  use App::Rad  qw(
          My::Module
          +Fully::Qualified::Plugin::Name
  );
Note that plugins are loaded in the order in which they appear.
Please refer to the actual plugin documentation for specific usage. And
  check out App::Rad::Plugin if you want to create your own plugins.
INSTANTIATION¶
These are the main execution calls for the application. In your App::Rad
  programs, the 
*ONLY* thing your script needs to actually (and actively)
  call is one of the instantiation (or dispatcher) methods. Leave all the rest
  to your subs. Currently, the only available dispatcher is 
run():
run()¶
You'll be able to access all of your program's commands directly through the
  command line, as shown in the synopsis.
BUILT-IN COMMANDS¶
This module comes with the following default commands. You are free to override
  them as you see fit.
help¶
Shows help information for your program. This built-in function displays the
  program name and all available commands (including the ones you added
  yourself) if a user types the 'help' command, or no command at all, or any
  command that does not exist (as they'd fall into the 'default' control
  function which (by default) calls 'help').
You can also display specific embedded help for your commands, either explicitly
  registering them with "$c->register()" or
  "$c->register_commands()" inside "$c->setup()" (see
  respective sections below) or with the 
Help() attribute:
    use App::Rad;
    App::Rad->run();
    
    sub mycmd 
    :Help(display a nice welcome message) 
    {
        return "Welcome!";
    }
the associated help text would go like this:
    [user@host]$ ./myapp.pl
    Usage: myapp.pl command [arguments]
    Available Commands:
        help    show syntax and available commands
        mycmd   display a nice welcome message
OTHER BUILT IN COMMANDS (OPT-IN)¶
The 'include' and 'exclude' commands below let the user include and exclude
  commands to your program and, as this might be dangerous when the user is not
  yourself, you have to opt-in on them:
   use App::Rad qw(include);  # add the 'include' command
   use App::Rad qw(exclude);  # add the 'exclude' command
though you'll probably want to set them both:
   use App::Rad qw(include exclude);
include [command_name] -perl_params 'your
  subroutine code'¶
Includes the given subroutine into your program on-the-fly, just as you would
  writing it directly into your program.
Let's say you have your simple 
'myapp.pl' program that uses App::Rad
  sitting on your system quietly. One day, perhaps during your sysadmin's tasks,
  you create a really amazing one-liner to solve a really hairy problem, and
  want to keep it for posterity (reusability is always a good thing!).
For instance, to change a CSV file in place, adding a column on position #2
  containing the line number, you might do something like this (this is merely
  illustrative, it's not actually the best way to do it):
    $ perl -i -paF, -le 'splice @F,1,0,$.; $_=join ",",@F' somesheet.csv
And you just found out that you might use this other times. What do you do?
  App::Rad to the rescue!
In the one-liner above, just switch 
'perl' to 
'myapp.pl include
  SUBNAME' and remove the trailing parameters ( 
somesheet.csv):
    $ myapp.pl include addcsvcol -i -paF, -le 'splice @F,1,0,$.; $_=join ",",@F'
That's it! Now myapp.pl has the 'addcsvcol' command (granted, not the best name)
  and you can call it directly whenever you want:
    $ myapp.pl addcsvcol somesheet.csv
App::Rad not only transforms and adjusts your one-liner so it can be used inside
  your program, but also automatically formats it with Perl::Tidy (if you have
  it). This is what the one-liner above would look like inside your program:
    sub addcsvcol {
        my $c = shift;
    
        local ($^I) = "";
        local ($/)  = "\n";
        local ($\)  = "\n";
      LINE: while ( defined( $_ = <ARGV> ) ) {
            chomp $_;
            our (@F) = split( /,/, $_, 0 );
            splice @F, 1, 0, $.;
            $_ = join( ',', @F );
        }
        continue {
            die "-p destination: $!\n" unless print $_;
        }
    }
With so many arguments (-i, -p, -a -F,, -l -e), this is about as bad as it gets.
  And still one might find this way easier to document and mantain than a crude
  one-liner stored in your ~/.bash_history or similar.
Note: If you don't supply a name for your command, App::Rad will make one
  up for you (cmd1, cmd2, ...). But don't do that, as you'll have a hard time
  figuring out what that specific command does.
Another Note: App::Rad tries to adjust the command to its interface, but
  please keep in mind this module is still in its early stages so it's not
  guaranteed to work every time. *PLEASE* let me know via email or RT bug
  request if your one-liner was not correctly translated into an App::Rad
  command. Thanks!
exclude command_name¶
Removes the requested function from your program. Note that this will delete the
  actual code from your program, so be *extra* careful. It is strongly
  recommended that you do not use this command and either remove the subroutine
  yourself or add the function to your excluded list inside
  
setup() .
Note that built-in commands such as 'help' cannot be removed via 
exclude.
  They have to be added to your excluded list inside
  
setup().
ROLLING YOUR OWN COMMANDS¶
Creating a new command is as easy as writing any sub inside your program. Some
  names ("setup", "default", "invalid",
  "pre_process", "post_process" and "teardown")
  are reserved for special purposes (see the 
Control Functions section of
  this document). App::Rad provides a nice interface for reading command line
  input and writing formatted output:
The Controller¶
Every command (sub) you create receives the controller object "$c"
  (sometimes referred as "$self" in other projects) as an argument.
  The controller is the main interface to App::Rad and has several methods to
  easen your command manipulation and execution tasks.
Reading arguments¶
When someone types in a command, she may pass some arguments to it. Those
  arguments can be accessed in four different ways, depending on what you want.
  This way it's up to you to control which and how many arguments (if at all)
  you want to receive and/or use. They are:
@ARGV
Perl's @ARGV array has all the arguments passed to your command, without the
  command name (use "$c->cmd" for this) and without any processing
  (even if you explicitly use "$c->getopt", which will change
  $c->argv instead, see below). Since the command itself won't be in the
  @ARGV parameters, you can use it in each command as if they were stand-alone
  programs.
$c->options
App::Rad lets you automatically retrieve any POSIX syntax command line options (
  
getopt-style) passed to your command via the $c->options method.
  This method returns a hash reference with keys as given parameters and values
  as... well... values. The 'options' method automatically supports two simple
  argument structures:
Extended (long) option. Translates "--parameter or --parameter=value"
  into "$c->options->{parameter}". If no value is supplied, it
  will be set to 1.
Single-letter option. Translates "-p" into
  "$c->options->{p}".
Single-letter options can be nested together, so "-abc" will be parsed
  into "$c->options->{a}", "$c->options->{b}"
  and "$c->options{c}", while "--abc" will be parsed into
  "$c->options->{abc}". We could, for instance, create a
  dice-rolling command like this:
    sub roll {
        my $c = shift;
        my $value = 0;
        for ( 1..$c->options->{'times'} ) {
            $value += ( int(rand ($c->options->{'faces'}) + 1));
        }
        return $value;
    }
And now you can call your 'roll' command like:
    [user@host]$ ./myapp.pl roll --faces=6 --times=2
Note that App::Rad does not control which arguments can or cannot be passed:
  they are all parsed into "$c->options" and it's up to you to use
  whichever you want. For a more advanced use and control, see the
  "$c->getopt" method below.
Also note that single-letter options will be set to 1. However, if a user types
  them more than once, the value will be incremented accordingly. For example,
  if a user calls your program like so:
   [user@host]$ ./myapp.pl some_command -vvv
or
   [user@host]$ ./myapp.pl some_command -v -v -v
then, in both cases, "$c->options->{v}" will be set to 3. This
  will let you easily keep track of how many times any given option was chosen,
  and still let you just check for definedness if you don't care about that.
$c->argv
The array reference "$c->argv" contains every argument passed to
  your command that have 
not been parsed into "$c->options".
  This is usually a list of every provided argument that didn't start with a
  dash (-), unless you've called "$c->getopt" and used something
  like 'param=s' (again, see below).
$c->getopt (Advanced Getopt usage)
App::Rad is also smoothly integrated with Getopt::Long, so you can have even
  more flexibility and power while parsing your command's arguments, such as
  aliases and types. Call the "$c->getopt()" method anytime inside
  your commands (or just once in your "pre_process" function to always
  have the same interface) passing a simple array with your options, and refer
  back to $c->options to see them. For instance:
    sub roll {
        my $c = shift;
        $c->getopt( 'faces|f=i', 'times|t=i' )
            or $c->execute('usage') and return undef;
        # and now you have $c->options->{'faces'} 
        # and $c->options->{'times'} just like above.
    }
This becomes very handy for complex or feature-rich commands. Please refer to
  the Getopt::Long module for more usage examples.
So, in order to manipulate and use any arguments, remember:
  - •
 
  - The given command name does not appear in the argument
      list;
 
  - •
 
  - All given arguments are in @ARGV
 
  - •
 
  - Automatically processed arguments are in
      "$c->options"
 
  - •
 
  - Non-processed arguments (the ones
      "$c->options" didn't catch) are in $c->argv
 
  - •
 
  - You can use "$c->getopt" to have
      "Getopt::Long" parse your arguments (it will not change
      @ARGV)
 
Sharing Data: "$c->stash"¶
The "stash" is a universal hash for storing data among your Commands:
    $c->stash->{foo} = 'bar';
    $c->stash->{herculoids} = [ qw(igoo tundro zok gloop gleep) ];
    $c->stash->{application} = { name => 'My Application' };
You can use it for more granularity and control over your program. For instance,
  you can email the output of a command if (and only if) something happened:
    sub command {
        my $c = shift;
        my $ret = do_something();
        if ( $ret =~ /critical error/ ) {
            $c->stash->{mail} = 1;
        }
        return $ret;
    }
    sub post_process {
        my $c = shift;
        if ( $c->stash->{mail} ) {
            # send email alert...
        }
        else {
            print $c->output . "\n";
        }
    }
Returning output¶
Once you're through, return whatever you want to give as output for your
  command:
    my $ret = "Here's the list: ";
    $ret .= join ', ', 1..5;
    return $ret;
    
    # this prints "Here's the list: 1, 2, 3, 4, 5"
App::Rad lets you post-process the returned value of every command, so refrain
  from printing to STDOUT directly whenever possible as it will give much more
  power to your programs. See the 
post_process() control
  function further below in this document.
HELPER METHODS¶
App::Rad's controller comes with several methods to help you manage your
  application easily. 
If you can think of any other useful command that is
  not here, please drop me a line or RT request.
$c->execute( COMMAND_NAME )¶
Runs the given command. If no command is given, runs the one stored in
  "$c->cmd". If the command does not exist, the 'default' command
  is ran instead. Each 
execute() call also invokes
  pre_process and post_process, so you can easily manipulate income and outcome
  of every command.
$c->cmd¶
Returns a string containing the name of the command (that is, the first argument
  of your program), that will be called right after pre_process.
$c->command
Alias for "$c->cmd". This longer form is discouraged and may be
  removed in future versions, as one may confuse it with the
  "$c->commands()" method, explained below. You have been warned.
$c->commands()¶
Returns a list of available commands ( 
functions) inside your program
$c->is_command ( COMMAND_NAME )¶
Returns 1 (true) if the given 
COMMAND_NAME is available, 0 (false)
  otherwise.
$c->create_command_name()¶
Returns a valid name for a command (i.e. a name slot that's not been used by
  your program). This goes in the form of 'cmd1', 'cmd2', etc., so don't use
  unless you absolutely have to. App::Rad, for instance, uses this whenever you
  try to 
include (see below) a new command but do not supply a name for
  it.
$c->load_config( FILE (FILE2, FILE3, ...) )¶
This method lets you easily load into your program one or more configuration
  files written like this:
    # comments and blank lines are discarded
    key1 value1
    key2:value2
    key3=value3
    key5           # stand-alone attribute (and inline-comment)
$c->config¶
Returns a hash reference with any loaded config values (see
  "$c->load_config()" above).
$c->register ( NAME, CODEREF [,
  INLINE_HELP ])¶
Registers a coderef as a callable command. Note that you don't have to call this
  in order to register a sub inside your program as a command, 
run() will
  already do this for you - and if you don't want some subroutines to be issued
  as commands you can always use "$c->register_commands()" (note
  the plural) inside 
setup(). This is just an interface to dinamically
  include commands in your programs. The function returns the command name in
  case of success, undef otherwise.
It is also very useful for creating aliases for your commands:
    sub setup {
        my $c = shift;
        $c->register_commands();
        $c->register('myalias', \&command);
    }
    sub command { return "Hi!" }
and, on the command line:
    [user@host]$ ./myapp.pl command
    Hi!
    [user@host]@ ./myapp.pl myalias
    Hi!
The last parameter is optional and lets you add inline help to your command:
    $c->register('cmd_name', \&cmd_func, 'display secret of life');
$c->register_command ( NAME,
  CODEREF  [, INLINE_HELP ] )
Longer alias for "$c->register()". It's use is disencouraged as one
  may confuse it with "register_commands" (note the plural) below.
  Plus you type more :) As such, this method may be removed in future versions.
  You have been warned!
$c->register_commands()¶
This method, usually called during 
setup(), tells App::Rad to register
  subroutines as valid commands. If called without any parameters, it will
  register 
all subroutines in your main program as valid commands (note
  that the default behavior of App::Rad is to ignore subroutines starting with
  an underscore '_'). You can easily change this behavior using some of the
  options below:
Adding single commands
    $c->register_commands( qw/foo bar baz/ );
The code above will register 
only the subs "foo",
  "bar" and "baz" as commands. Other subroutines will
  
not be valid commands, so they can be used as internal subs for your
  program. You can change this behavior with the bundled options - see 'Adding
  several commands' and 'Putting it all together' below.
Adding single commands (with inline help)
    $c->register_commands(
            {
                dos2unix => 'convert text files from DOS to Unix format',
                unix2dos => 'convert text files from Unix to DOS format',
            }
    );
You can pass a hash reference containing commands as keys and a small help
  string as their values. The code above will register 
only the subs
  "dos2unix" and "unix2dos", and the default help for your
  program will become something like this:
    [user@host]$ ./myapp.pl
    Usage: myapp.pl command [arguments]
    
    Available Commands:
        dos2unix    convert text files from DOS to Unix format
        help        show syntax and available commands
        unix2dos    convert text files from Unix to DOS format
Adding several commands
You can pass a hash reference as an argument, letting you choose which
  subroutines to add as commands. The following keys may be used (note the dash
  preceding each key):
  - •
 
  - "-ignore_prefix": subroutine names starting with
      the given string won't be added as commands
 
  - •
 
  - "-ignore_suffix": subroutine names ending with
      the given string won't be added as commands
 
  - •
 
  - "-ignore_regexp": subroutine names matching the
      given regular expression (as a string) won't be added as commands
 
For example:
    use App::Rad;
    App::Rad->run();
    sub setup { 
        my $c = shift; 
        $c->register_commands( { -ignore_prefix => '_' } );
    }
    sub foo  {}  # will become a command
    sub bar  {}  # will become a command
    sub _baz {}  # will *NOT* become a command
This way you can easily segregate between commands and helper functions, making
  your code even more reusable without jeopardizing the command line interface
  (As of version 1.04, ignoring commands with underscore '_' prefixes is also
  the default App::Rad behavior).
Putting it all together
You can combine some of the options above to have even more flexibility:
    $c->register_commands(
            'foo',
            { -ignore_suffix => 'foo' },
            { bar => 'all your command line are belong to us' },
    );
The code above will register as commands all subs with names 
not ending
  in 'foo', but it 
will register the 'foo' sub as well. It will also give
  the 'bar' command the help string. This behavior is handy for registering
  several commands and having a few exceptions, or to add your commands and only
  have inline help for a few of them (as you see fit).
You don't have to worry about the order of your elements passed, App::Rad will
  figure them out for you in a DWIM fashion.
    # this does the same as the code above
    $c->register_commands(
            { bar => 'all your command line are belong to us' },
            'foo',
            { -ignore_suffix => 'foo' },
    );
You can even bundle the hash reference to include your "cmd =>
  help" and special keys:
    # this behaves the same way as the code above:
    $c->register_commands(
        'foo',
        { 
            -ignore_suffix => 'foo',
            bar => 'all your command line are belong to us',
        }
    );
$c->unregister_command ( NAME )¶
Longer alias for "$c->unregister()". The use of the shorter form is
  encouraged, and this alias may be removed in future versions. You have been
  warned.
$c->unregister ( NAME )
Unregisters a given command name so it's not available anymore. Note that the
  subroutine will still be there to be called from inside your program - it just
  won't be accessible via command line anymore.
$c->debug( MESSAGE )¶
Will print the given message on screen only if the debug flag is enabled:
    use App::Rad  qw( debug );
Note that, if debug is enabled, App::Rad itself will print several debug
  messages stating its current flow, so you can easily find out where everything
  is happening.
$c->plugins()¶
Returns a list of all loaded plugins, in the order in which they were loaded.
$c->load_plugin( PLUGIN NAME )¶
This method will dinamically load the given plugin. The plugin needs to be under
  the "App::Rad::Plugin" namespace, and the name should be relative to
  this path (i.e. $c->load_plugin('MyPlugin') will try to load
  'App::Rad::Plugin::MyPlugin'). If you want to load a plugin by its fully
  qualified name, you need to prepend a plus sign to the name
  ('+Fully::Qualified::Plugin::Name'). 
This is an internal method and you
  really should refrain from using it. Instead, plugins should be loaded as
  parameters to the "use App::Rad" statement, as explained above.
CONTROL FUNCTIONS (to possibly override)¶
App::Rad implements some control functions which are expected to be overridden
  by implementing them in your program. They are as follows:
setup()¶
This function is responsible for setting up what your program can and cannot do,
  plus everything you need to set before actually running any command
  (connecting to a database or host, check and validate things, download a
  document, whatever). Note that, if you override 
setup(), you
  
*must* call "$c->register_commands()" or at least
  "$c->register()" so your subs are classified as valid commands
  (check $c-> 
register_commands() above for more information).
Another interesting thing you can do with setup is to manipulate the command
  list. For instance, you may want to be able to use the "include" and
  "exclude" commands, but not let them available for all users. So
  instead of writing:
    use App::Rad qw(include exclude);
    App::Rad->run();
you can write something like this:
    use App::Rad;
    App::Rad->run();
    sub setup {
        my $c = shift;
        $c->register_commands();
        # EUID is 'root'
        if ( $> == 0 ) {
            $c->register('include', \&App::Rad::include);
            $c->register('exclude', \&App::Rad::exclude);
        }
    }
to get something like this:
    [user@host]$ myapp.pl help
    Usage: myapp.pl command [arguments]
    Available Commands:
       help
    [user@host]$ sudo myapp.pl help
    Usage: myapp.pl command [arguments]
    Available Commands:
       exclude
       help
       include
default()¶
If no command is given to your application, it will fall in here. Please note
  that invalid (non-existant) command will fall here too, but you can change
  this behavior with the 
invalid() function below (although usually you
  don't want to).
Default's default (grin) is just an alias for the help command.
    sub default {
        my $c = shift;
        # will fall here if the given
        # command isn't valid.
    }
You are free (and encouraged) to change the default behavior to whatever you
  want. This is rather useful for when your program will only do one thing, and
  as such it receives only parameters instead of command names. In those cases,
  use the ""default()"" sub as your main program's sub and
  parse the parameters with "$c->argv" and
  "$c->getopt" as you would in any other command.
invalid()¶
This is a special function to provide even more flexibility while creating your
  command line applications. This is called when the user requests a command
  that does not exist. The built-in "invalid()" will simply redirect
  itself to "default()" (see above), so usually you just have to worry
  about this when you want to differentiate between "no command given"
  (with or without getopt-like arguments) and "invalid command given"
  (with or without getopt-like arguments).
teardown()¶
If implemented, this function is called automatically after your application
  runs. It can be used to clean up after your operations, removing temporary
  files, disconnecting a database connection established in the setup function,
  logging, sending data over a network, or even storing state information via
  Storable or whatever.
pre_process()¶
If implemented, this function is called automatically right before the actual
  wanted command is called. This way you have an optional pre-run hook, which
  permits functionality to be added, such as preventing some commands to be run
  from a specific uid (e.g. 
root):
    sub pre_process {
        my $c = shift;
        if ( $c->cmd eq 'some_command' and $> != 0 ) {
            $c->cmd = 'default'; # or some standard error message
        }
    }
post_process()¶
If implemented, this function is called automatically right after the requested
  function returned. It receives the Controller object right after a given
  command has been executed (and hopefully with some output returned), so you
  can manipulate it at will. In fact, the default "post_process"
  function is as goes:
    sub post_process {
        my $c = shift;
        if ( $c->output() ) {
            print $c->output() . "\n";
        }
    }
You can override this function to include a default header/footer for your
  programs (either a label or perhaps a "Content-type: " string),
  parse the output in any ways you see fit (CPAN is your friend, as usual), etc.
IMPORTANT NOTE ON PRINTING INSIDE YOUR COMMANDS¶
The post_process() function above is why your
  application should *NEVER* print to STDOUT. Using 
print (or
  
say, in 5.10) to send output to STDOUT is exclusively the domain of the
  
post_process() function. Breaking this rule is a common source of
  errors. If you want your functions to be interactive (for instance) and print
  everything themselves, you should disable post-processing in 
setup(),
  or create an empty post_process function or make your functions return
  
undef (so 
post_process() will only add a blank
  line to the output).
DIAGNOSTICS¶
If you see a '1' printed on the screen after a command is issued, it's probably
  because that command is returning a "true" value instead of an
  output string. If you don't want to return the command output for post
  processing(you'll loose some nice features, though) you can return undef or
  make 
post_process() empty.
CONFIGURATION AND ENVIRONMENT¶
App::Rad requires no configuration files or environment variables.
DEPENDENCIES¶
App::Rad depends only on 5.8 core modules (Carp for errors, Getopt::Long for
  "$c->getopt", Attribute::Handlers for "help" and
  O/B::Deparse for the "include" command).
If you have Perl::Tidy installed, the "include" command will tidy up
  your code before inclusion.
The test suite depends on Test::More, FindBin and File::Temp, also core modules.
INCOMPATIBILITIES¶
None reported.
BUGS AND LIMITATIONS¶
Please report any bugs or feature requests to "bug-app-easy at
  rt.cpan.org", or through the web interface at
  <
http://rt.cpan.org/garu/ReportBug.html?Queue=App-Rad>. I will be
  notified, and then you'll automatically be notified of progress on your bug as
  I make changes.
SUPPORT¶
You can find documentation for this module with the perldoc command.
    perldoc App::Rad
Although this Module comes without any warraties whatsoever (see DISCLAIMER
  below), I try really hard to provide some quality assurance for the users.
  This means I not only try to close all reported bugs in the minimum amount of
  time but I also try to find some on my own.
This version of App::Rad comes with 183 tests and I keep my eye constantly on
  CPAN Testers <
http://www.cpantesters.org/show/App-Rad.html> to ensure it
  passes all of them, in all platforms. You can send me your own App::Rad tests
  if you feel I'm missing something and I'll hapilly add them to the
  distribution.
Since I take user's feedback very seriously, I really hope you send me any
  wishlist/TODO you'd like App::Rad to have (please try to send them via RT so
  other people can give their own suggestions).
You can also look for information at:
  - •
 
  - RT: CPAN's request tracker
    
 
    <http://rt.cpan.org/garu/Bugs.html?Dist=App-Rad> 
  - •
 
  - AnnoCPAN: Annotated CPAN documentation
    
 
    <http://annocpan.org/dist/App-Rad> 
  - •
 
  - CPAN Ratings
    
 
    <http://cpanratings.perl.org/d/App-Rad> 
  - •
 
  - Search CPAN
    
 
    <http://search.cpan.org/dist/App-Rad> 
IRC¶
   #app-rad  on irc.perl.org
TODO¶
This is a small list of features I plan to add in the near future (in no
  particular order). Feel free to contribute with your wishlist and comentaries!
  - •
 
  - Shell-like environment
 
  - •
 
  - Loadable commands (in an external container file)
 
  - •
 
  - Modularized commands (similar to App::Cmd::Commands ?)
 
  - •
 
  - app-starter
 
  - •
 
  - command inclusion by prefix, suffix and regexp (feature
      request by fco)
 
  - •
 
  - command inclusion and exclusion also by attributes
 
  - •
 
  - some extra integration, maybe IPC::Cmd and IO::Prompt
 
AUTHOR¶
Breno G. de Oliveira, "<garu at cpan.org>"
CONTRIBUTORS¶
(in alphabetical order)
Ben Hengst
Fernando Correa
Flavio Glock
Thanks to everyone for contributing! Please let me know if I've skipped your
  name by accident.
ACKNOWLEDGEMENTS¶
This module was inspired by Kenichi Ishigaki's presentation 
"Web is not
  the only one that requires frameworks" during YAPC::Asia::2008 and
  the modules it exposed (mainly App::Cmd and App::CLI).
Also, many thanks to CGI::App(now Titanium)'s Mark Stosberg and all the Catalyst
  developers, as some of App::Rad's functionality was taken from those (web)
  frameworks.
LICENSE AND COPYRIGHT¶
Copyright 2008 Breno G. de Oliveira "<garu at cpan.org>". All
  rights reserved.
This module is free software; you can redistribute it and/or modify it under the
  same terms as Perl itself. See perlartistic.
DISCLAIMER OF WARRANTY¶
BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE
  SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
  STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE
  SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR
  IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO
  THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE
  PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR
  CORRECTION.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY
  COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE
  SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE LIABLE TO YOU FOR DAMAGES,
  INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING
  OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING BUT NOT LIMITED TO
  LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR
  THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER
  SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
  POSSIBILITY OF SUCH DAMAGES.