Toby Inkster > P5U > P5U::Tutorial::Development

Download:
P5U-0.100.tar.gz

Annotate this POD

Website

View/Report Bugs
Source  

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.

syntax highlighting: