NAME
P5U::Tutorial::Development - so, you want to write your own p5u command...
GENERAL DESIGN PRINCIPLES
Keep command modules (P5U::Command::Foo) lean. Each time p5u is executed, every command module is loaded; not just the one being used. One technique is to split your code into two modules, a workhorse (typically called something like P5U::Lib::Foo), and the command module. The command module only loads the workhorse when it's actually needed.
There are some modules that you can use without worrying about performance (because App::Cmd or P5U has already loaded them). These include Class::Load, JSON and Path::Tiny.
If you need OO, then use Moo (but do it in a workhorse module that's loaded on demand), Types::Standard and namespace::clean. If you need the web, then use LWP::UserAgent or LWP::Simple. If you need to do stuff with the file system, use Path::Tiny and Path::Iterator::Rule. These are good modules, and they're already listed as P5U dependencies, so there's no reason to avoid them.
TEMPLATE
package P5U::Command::Foo;
use 5.010;
use strict;
use utf8;
use P5U-command; # important!
# Metadata
BEGIN {
$P5U::Command::Foo::AUTHORITY = 'cpan:JOEBLOGGS';
$P5U::Command::Foo::VERSION = '0.001';
};
# These are used when generating help information
use constant {
abstract => q[do some foo],
usage_desc => q[%c foo %o],
};
# The first command name is the preferred name.
# Subsequent ones are aliases.
sub command_names
{
qw( foo fu );
}
# See Getopt::Long::Descriptive
sub opt_spec
{
return (
[ "bar|b" => "foobar" ],
[ "baz" => "foobaz" ],
);
}
# This is where the magic happens!
sub execute
{
require P5U::Lib::Foo; # load workhorse
my ($self, $opt, $args) = @_;
# $opt is a hashref of options
# $args is an arrayref of non-option arguments
# do stuff
}
1;
Note that P5U is based on App::Cmd, so all P5U command modules are subclasses of App::Cmd::Command. Thus there are a bunch of other useful methods available for your subclassing pleasure. One in particular that you should be aware of is $self->usage_error($msg)
to die with an error message. (But not all errors are usage errors. For example, an error communicating with a server is not a usage error, but a failure for the user to specify which server to communicate with is.)
UTILITY METHODS
P5U command modules are also subclasses of P5U::Command which provides some utility methods for loading and saving config files, and so on. These are:
$self->get_tempdir
-
Each time this is called returns a new empty directory as a Path::Tiny object. When this object goes out of scope, the directory and its contents will be deleted.
$self->get_cachedir
-
Returns a Path::Tiny object representing a directory where the command can cache data. In the current version, this cache is not automatically purged, but in future versions it will be.
$self->get_datadir
-
Returns a Path::Tiny object representing a directory where the command can keep long-lived data.
$self->get_config
-
Returns a hashref of configuration data.
$self->save_config($hashref)
-
Save a hashref of configuration data.
BUGS
Please report any bugs to http://rt.cpan.org/Dist/Display.html?Queue=P5U.
SEE ALSO
P5U, App::Cmd, Getopt::Long::Descriptive.
AUTHOR
Toby Inkster <tobyink@cpan.org>.
COPYRIGHT AND LICENCE
This software is copyright (c) 2012-2013 by Toby Inkster.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.