NAME¶
MooseX::App::Tutorial - getting started with MooseX::App
GETTING STARTED¶
To create a simple command-line application with MooseX::App you need
- •
- A base class
- •
- Multiple command classes (unless you use MooseX::App::Simple)
- •
- and an invocation script
BASE CLASS¶
The simplest possible base class just contains a single use statement which
loads all roles and metaclasses you need to get started as well as Moose.
package MyApp;
use MooseX::App;
1;
The base class can be customized by
- •
- adding MooseX-App plugins
- •
- Changing the command-class namespace
- •
- defining global attributes used by all command classes (if they inherit
from the base class)
- •
- add documentation (either POD or via the app_usage and app_description
functions)
- •
- and changing MooseX-App flags (eg. turn fuzzy matching off)
It is also possible to add global options and parameters to your base class and
inherit your command classes from the base class (inheriting your command
classes from your base class is purely optional).
package MyApp;
use MooseX::App qw(Config Color); # Loads the Config and Color plugin
# This attribute will be available at the command line
option 'some_global_option' => (
is => 'rw',
isa => 'Str',
documentation => q[Some important global option],
);
# This attribute will not be exposed
has 'private_option' => (
is => 'rw',
isa => 'Str',
);
1;
When adding attributes make sure to include a documentation and possibly a type
constraint. MooseX-App will use this information to build a user documentation
for each attribute and command. The attribute documentation can be customized
by providing additional options (see
MooseX::App::Meta::Role::Attribute::Option)
COMMAND CLASSES¶
After you have created a base class it is time to create one class for each
command you want to provide (unless you are using MooseX::App::Simple). The
command classes must reside in the namespace of the base class (eg.
'MyApp::SomeCommand'). The namespace for the command classes however can be
changed via the 'app_namespace' function in the base class.
All command classes must use MooseX::App::Command.
package MyApp::SomeCommand;
use MooseX::App::Command;
If you want to use global options defined in the base class you can optionally
extend the base class with your command class.
package MyApp::SomeCommand;
use MooseX::App::Command;
extends qw(MyApp);
To provide a description for each command you need to set the
"command_short_description", "command_long_description"
and optionally "command_usage" information. The command descriptions
may contain linebreaks.
command_short_description q[This command is awesome];
command_long_description q[This command is so awesome, yadda yadda yadda];
If not provided, MooseX-App will try to parse the command description from the
POD. The NAME or ABSTRACT section will become the short description and the
DESCRIPTION or OVERVIEW section the long description.
The usage header can either be set by adding "command_usage"
command_usage q[script some_command --some_option NUMBER];
or by adding a SYNOPSIS or USAGE section to the module' POD. If neither
command_usage nor SYNOPSIS/USAGE are set, then the usage header will be
autogenerated.
Attributes can be documented using the Moose built-in "documentation"
option as well as "cmd_tags", "cmd_flag" and
"cmd_aliases" which are defined by MooseX-App (see
MooseX::App::Meta::Role::Attribute::Option)
option 'some_option' => (
is => 'rw',
isa => 'Integer',
required => 1,
documentation => q[Some important option],
cmd_tags => [qw(Important!)], # Extra tags. Displayed in square brackets
cmd_aliases => [qw(s)], # Alternative option name
cmd_flag => 'some', # Option should be called 'some' instead of 'some_option'
);
It is also possible to define positional parameters with the 'parameter' keyword
# This attribute will become a positional parameter
parameter 'id' => (
is => 'rw',
isa => 'Int',
documentation => q[Some ID],
required => 1,
);
The help for this command would look something like this (with autogenerated
usage header):
usage:
my_app some_command <ID> [long options...]
my_app help
my_app some_command --help
description:
This command is awesome, yadda yadda yadda
parameter:
ID Some ID [Integer; Required]
options:
--config Path to command config file
--some -s Some important option [Required; Integer; Important!]
--help --usage -? Prints this usage information. [Flag]
In case you want to include an attribute not defined with the 'option' or
'parameter' keyword you can use the 'AppOption' trait and 'cmd_type'
attribute. (see MooseX::App::Meta::Attribute::Option).
has 'myoption' => (
is => 'rw',
traits => ['AppOption'], # only required if not definded in base or command class
cmd_type => 'option', # or 'parameter'
);
Finally your command classes will need a method which should be called if the
command is invoked by the user.
sub run {
my ($self) = @_;
# do something
}
If you need to implement only a single command you should use
MooseX::App::Simple instead of MooseX::App, and omit command classes. In this
case of course you have to declare all options and implement the application
logic in the base class:
package MyApp;
use MooseX::App::Simple qw(Config); # Loads the Config plugin
option 'some_global_option' => (
is => 'rw',
isa => 'Str',
documentation => q[Some important global option],
);
sub run {
my ($self) = @_;
# do something
}
1;
INVOCATION SCRIPT¶
Once you have the base and command classes ready, you need to write a small
invocation script:
#!/usr/bin/env perl
use MyApp;
MyApp->new_with_command->run();
"MyApp->new_with_command" will try to instantiate a command class.
If it fails it will return a MooseX::App::Message::Envelope object possibly
containing an error message and a usage message. Since
MooseX::App::Message::Envelope follows the Null object pattern you can call
any method on it without checking the object type.
You can also pass default/fallback values to the constructor
#!/usr/bin/env perl
use MyApp;
MyApp->new_with_command( some_global_option => 'something' )->run();
If using MooseX::App::Simple your invocation script needs some modification.
#!/usr/bin/env perl
use MyApp;
MyApp->new_with_options->run();
HOW TO CONTINUE¶
Once you have a basic working application you can make it more user friendly by
adding documentation (either by using the app_description, app_usage,
command_short_description, ... functions or by writing POD) and Moose type
constraints and additional plugins (eg. colorise the output).