CLI-Framework

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN


        * Documentation improvements
            + refined existing documentation
            + added Tutorial

        * Concept of "session" replaced with the "cache" (which can hold data shared
          between separate components of a CLIF application)

        * Now supporting custom error handling capability (new handle_exception() hook)

        * Built-in command CLI::Framework::Command::Menu improved for better
          formatting

        * New features
            + inline declaration of CLIF subclasses (both Application and
              Command classes) is now supported (one file can contain everything)
            + new built-in command CLI::Framework::Command::Alias

        ***
        *** ATTENTION: interface has changed! Most noteworthy changes follow...
        ***

MANIFEST  view on Meta::CPAN

MANIFEST
README
Changes
Makefile.PL
lib/CLI/Framework/Command/Alias.pm
lib/CLI/Framework/Command/Meta.pm
lib/CLI/Framework/Command/Menu.pm
lib/CLI/Framework/Command/List.pm
lib/CLI/Framework/Command/Console.pm
lib/CLI/Framework/Command/Help.pm
lib/CLI/Framework/Command/Dump.pm
lib/CLI/Framework/Command/Tree.pm
lib/CLI/Framework/Exceptions.pm
lib/CLI/Framework/Tutorial.pod
lib/CLI/Framework/Command.pm
lib/CLI/Framework/Application.pm
lib/CLI/Framework.pm
t/00-load.t
t/bin/perlfunc
t/bin/myjournal
t/config/myjournal.sql
t/session-prod-cons.t
t/db/myjournal.sqlite
t/lib/My/Command/Shared/X.pm
t/lib/My/Journal/Command/Publish.pm
t/lib/My/Journal/Command/Dummy.pm
t/lib/My/Journal/Command/Menu.pm
t/lib/My/Journal/Command/Entry/dummy.txt
t/lib/My/Journal/Command/Entry/Dummy.pm
t/lib/My/Journal/Command/Entry/Modify.pm
t/lib/My/Journal/Command/Entry/Add.pm
t/lib/My/Journal/Command/Entry/Print.pm
t/lib/My/Journal/Command/Entry/Remove.pm
t/lib/My/Journal/Command/Entry.pm
t/lib/My/Journal/Model.pm
t/lib/My/PerlFunctions.pm
t/lib/My/DemoNoUsage.pm

lib/CLI/Framework.pm  view on Meta::CPAN

Application Script - The wrapper program that invokes the CLIF Application's
L<run|CLI::Framework::Application/run()> method.  The file it is defined in may or may not also contain
the definition of Application or Command packages.

=item *

Metacommand - An application-aware command.  Metacommands are subclasses of
L<CLI::Framework::Command::Meta>.  They are identical to regular commands except
they hold a reference to the application within which they are running.  This
means they are able to "know about" and affect the application.  For example,
the built-in command "Menu" is a Metacommand because it needs to produce a
list of the other commands in its application.

In general, your commands should be designed to operate independently of the
application, so they should simply inherit from L<CLI::Framework::Command>.
This encourages looser coupling.  However, in exceptional cases, the use of
Metacommands is warranted (For an example, see the built-in "Menu" command).

=item *

Non-interactive Command - In interactive mode, some commands need to be
disabled.  For instance, the built-in "console" command (which is used to start
interactive mode, presenting a command menu and responding to user selections)
should not be presented as a menu option in interactive mode because it is
already running.  You can designate which commands are non-interactive by
overriding the
L<noninteractive_commands|CLI::Framework::Application/noninteractive_commands()>

lib/CLI/Framework.pm  view on Meta::CPAN

built-in command L<CLI::Framework::Command::Console> to your
L<command_map|CLI::Framework::Application/command_map()>.

=head1 BUILT-IN COMMANDS INCLUDED IN THIS DISTRIBUTION

This distribution comes with some default built-in commands, and more
CLIF built-ins can be installed as they become available on CPAN.

Use of the built-ins is optional in most cases, but certain features require
specific built-in commands (e.g. the Help command is a fundamental feature of
all applications and the Menu command is required in interactive mode).  You can
override any of the built-ins.

A new application that does not override the
L<command_map|CLI::Framework::Application/command_map()> hook will include all
of the built-ins listed below.

The existing built-ins and their corresponding packages are as follows:

=over

lib/CLI/Framework.pm  view on Meta::CPAN

=item alias: Display the command aliases that are in effect for the running application and its commands

L<CLI::Framework::Command::Alias>

=item console: Invoke CLIF's interactive mode

L<CLI::Framework::Command::Console>

=item menu: Show a command menu including the commands that are available to the running application

L<CLI::Framework::Command::Menu>

B<Note>: This command is registered automatically when an application runs in
interactive mode.  This built-in may be replaced by a user-defined "menu"
command, but any command class to be used for the "menu" command MUST be a
subclass of this one.

=back

=head1 CLIF ARCHITECTURE AT A GLANCE

lib/CLI/Framework/Application.pm  view on Meta::CPAN


# Certain built-in commands are required:
use constant REQUIRED_BUILTINS_PKGS => qw(
    CLI::Framework::Command::Help
);
use constant REQUIRED_BUILTINS_NAMES => qw(
    help
);
# Certain built-in commands are required only in interactive mode:
use constant REQUIRED_BUILTINS_PKGS_INTERACTIVE => qw(
    CLI::Framework::Command::Menu
);
use constant REQUIRED_BUILTINS_NAMES_INTERACTIVE => qw(
    menu
);

#FIXME-TODO-CLASS_GENERATION:
#sub import {
#    my ($class, $app_pkg, $app_def) = @_;
#
#    # If caller has supplied import args, CLIF's "inline form" is being used.

lib/CLI/Framework/Application.pm  view on Meta::CPAN

        $app->{_registered_command_objects}->{ref $cmd} = $cmd;
    }
#FIXME:use REQUIRED_BUILTINS_PKGS_INTERACTIVE & REQUIRED_BUILTINS_NAMES_INTERACTIVE
    elsif( $cmd eq 'help' ) {
        # Required built-in is always valid...
        $cmd = CLI::Framework::Command->manufacture( 'CLI::Framework::Command::Help' );
        $app->{_registered_command_objects}->{'CLI::Framework::Command::Help'} = $cmd;
    }
    elsif( $app->get_interactivity_mode() && $cmd eq 'menu' ) {
        # Required built-in for interactive usage is always valid...
        $cmd = CLI::Framework::Command->manufacture( 'CLI::Framework::Command::Menu' );
        $app->{_registered_command_objects}->{'CLI::Framework::Command::Menu'} = $cmd;
    }
    else {
        throw_cmd_registration_exception(
            error => "Error: failed attempt to register invalid command '$cmd'" );
    }
    # Metacommands should be app-aware...
    $cmd->set_app( $app ) if $cmd->isa( 'CLI::Framework::Command::Meta' );

    return $cmd;
}

lib/CLI/Framework/Application.pm  view on Meta::CPAN

    }
    # If initialization indicated, run init() and handle existing input...
    eval { $app->_parse_request( initialize => $param{initialize} )
        if $param{initialize}
    };
    if( catch my $e ) { $app->handle_exception($e); return }

    # Find how many prompts to display in sequence between displaying menu...
    my $menu_cmd = $app->registered_command_object('menu')
        || $app->register_command( 'menu' );
    $menu_cmd->isa( 'CLI::Framework::Command::Menu' )
        or throw_type_exception(
            error => "Menu command must be a subtype of " .
                     "CLI::Framework::Command::Menu" );

    my $invalid_request_threshold = $param{invalid_request_threshold}
        || $menu_cmd->line_count(); # num empty prompts b4 re-displaying menu

    $app->_run_cmd_processing_loop(
        menu_cmd                    => $menu_cmd,
        invalid_request_threshold   => $invalid_request_threshold
    );
    # Restore original default command...
    $app->set_default_command( $orig_default_command );

lib/CLI/Framework/Application.pm  view on Meta::CPAN


sub usage_text { }

sub option_spec { }

sub validate_options { 1 }

sub command_map {
    help        => 'CLI::Framework::Command::Help',
    console     => 'CLI::Framework::Command::Console',
    menu        => 'CLI::Framework::Command::Menu',
    list        => 'CLI::Framework::Command::List',
    'dump'      => 'CLI::Framework::Command::Dump',
    tree        => 'CLI::Framework::Command::Tree',
    alias       => 'CLI::Framework::Command::Alias',
}

sub command_alias { }

sub noninteractive_commands { qw( console menu ) }

lib/CLI/Framework/Application.pm  view on Meta::CPAN

    } }

    sub option_spec {
        [ 'help|h'      => 'show help' ],
        [ 'verbose|v'   => 'be verbose' ],
        [ 'db=s'        => 'path to SQLite database file' ],
    }

    sub command_map {
        help    => 'CLI::Framework::Command::Help',
        menu    => 'My::Journal::Command::Menu',
        entry   => 'My::Journal::Command::Entry',
        publish => 'My::Journal::Command::Publish',
        console => 'CLI::Framework::Command::Console',
    }

    sub command_alias {
        h   => 'help',
        m   => 'menu',
        e   => 'entry',
        p   => 'publish',

lib/CLI/Framework/Application.pm  view on Meta::CPAN


=head2 run_interactive( [%param] )

    MyApp->run_interactive();

    # ...or as an object method:
    $app->run_interactive();

Start an event processing loop to prompt for and run commands in sequence.  The
C<menu> command is used to display available command selections (the built-in
C<menu> command, L<CLI::Framework::Command::Menu>, will be used unless the
application defines its own C<menu> command).

Within this loop, valid input is the same as in non-interactive mode except
that application options are not accepted (any application options should be
handled upon application initialization and before the interactive B<command>
loop is entered -- see the description of the C<initialize> parameter below).

The following parameters are recognized:

C<initialize>: causes any application options that are present in C<@ARGV> to be

lib/CLI/Framework/Application.pm  view on Meta::CPAN

The keys are names that should be used to install the commands in the
application.  The values are the names of the packages that implement the
corresponding commands, as in this example:

    sub command_map {
        # custom commands:
        fly     => 'My::Command::Fly',
        run     => 'My::Command::Run',

        # overridden built-in commands:
        menu    => 'My::Command::Menu',

        # built-in commands:
        help    => 'CLI::Framework::Command::Help',
        list    => 'CLI::Framework::Command::List',
        tree    => 'CLI::Framework::Command::Tree',
        'dump'  => 'CLI::Framework::Command::Dump',
        console => 'CLI::Framework::Command::Console',
        alias   => 'CLI::Framework::Command::Alias',
    }

lib/CLI/Framework/Command/Console.pm  view on Meta::CPAN


=head1 NAME

CLI::Framework::Command::Console - CLIF built-in command supporting
interactive mode

=head1 SEE ALSO

L<run_interactive|CLI::Framework::Application/run_interactive( [%param] )>

L<CLI::Framework::Command::Menu>

L<CLI::Framework::Command>

=cut

lib/CLI/Framework/Command/Menu.pm  view on Meta::CPAN

package CLI::Framework::Command::Menu;
use base qw( CLI::Framework::Command::Meta );

use strict;
use warnings;

our $VERSION = 0.01;

#-------

sub usage_text { 

lib/CLI/Framework/Command/Menu.pm  view on Meta::CPAN


#-------
1;

__END__

=pod

=head1 NAME

CLI::Framework::Command::Menu - CLIF built-in command to show a command menu
including the commands that are available to the running application

=head1 SEE ALSO

L<run_interactive|CLI::Framework::Application/run_interactive( [%param] )>

L<CLI::Framework::Command::Console>

L<CLI::Framework::Command>

t/00-load.t  view on Meta::CPAN


use lib 'lib';
use lib 't/lib';

BEGIN {
    use_ok( 'CLI::Framework' );
    use_ok( 'CLI::Framework::Application' );
    use_ok( 'CLI::Framework::Command' );
    use_ok( 'CLI::Framework::Command::Help' );
    use_ok( 'CLI::Framework::Command::List' );
    use_ok( 'CLI::Framework::Command::Menu' );
}

diag( "Testing CLI::Framework::Application $CLI::Framework::Application::VERSION, Perl $], $^X" );

t/command_registration.t  view on Meta::CPAN

use_ok( 'My::Journal' );

my $app = My::Journal->new();

# Register some commands...
ok( my $cmd = $app->register_command( 'console'   ), "register (built-in) 'console' command" );
ok( $cmd->isa( 'CLI::Framework::Command::Console' ), "built-in 'console' command object returned" );
is( $cmd->name(), 'console', 'command name is as expected' );

ok( $cmd = $app->register_command( 'menu'   ), "register (overridden) 'menu' command" );
ok( $cmd->isa( 'My::Journal::Command::Menu' ),
    "application-specific, overridden command returned instead of the built-in 'menu' command" );
is( $cmd->name(), 'menu', 'command name is as expected' );

# Get and check list of all registered commands...
ok( my @registered_cmd_names = $app->registered_command_names(),
    'CLI::Framework::Application::registered_command_names()' );
my @got_cmd_names = sort @registered_cmd_names;
my @expected_cmd_names = sort qw( console menu );
is_deeply( \@got_cmd_names, \@expected_cmd_names,
    'registered_command_names() returned expected set of commands that were registered' );

# Check that we can get registered commands by name...
ok( my $console_command = $app->registered_command_object('console'), 'retrieve console command by name' );
ok( $console_command->isa('CLI::Framework::Command::Console'), 'command object is ref to proper class' );
ok( my $menu_command = $app->registered_command_object('menu'), 'retrieve menu command by name' );
ok( $menu_command->isa('CLI::Framework::Command::Menu'), 'command object is a ref to proper class');

__END__

=pod

=head1 PURPOSE

To verify basic CLIF features related to registration of commands.

=cut

t/define-classes-inline.t  view on Meta::CPAN


sub option_spec {
    [ 'help|h'      => 'show help' ],
    [ 'verbose|v'   => 'be verbose' ],
    [ 'db=s'        => 'db' ],
}

sub command_map {
    console => 'CLI::Framework::Command::Console',
    list    => 'CLI::Framework::Command::List',
    menu    => 'CLI::Framework::Command::Menu',
    'dump'  => 'CLI::Framework::Command::Dump',
    tree    => 'CLI::Framework::Command::Tree',
    x       => 'My::App::Command::X',
#    x       => 'My::Command::Shared::X',
}

sub command_alias {
    h   => 'help',

    t   => 'tree',

t/lib/My/Journal.pm  view on Meta::CPAN


sub option_spec {
    [ 'help|h'      => 'show help' ],
    [ 'verbose|v'   => 'be verbose' ],
    [ 'db=s'        => 'path to SQLite database file for your journal' ],
}

sub command_map {
    entry   => 'My::Journal::Command::Entry',
    publish => 'My::Journal::Command::Publish',
    menu    => 'My::Journal::Command::Menu',
    help    => 'CLI::Framework::Command::Help',
    list    => 'CLI::Framework::Command::List',
    tree    => 'CLI::Framework::Command::Tree',
    alias   => 'CLI::Framework::Command::Alias',
    'dump'  => 'CLI::Framework::Command::Dump',
    console => 'CLI::Framework::Command::Console',
}

sub command_alias {
    h   => 'help',

t/lib/My/Journal/Command/Menu.pm  view on Meta::CPAN

package My::Journal::Command::Menu;
use base qw( CLI::Framework::Command::Menu );

use strict;
use warnings;

sub usage_text {
    q{
    menu (My::Journal command overriding the built-in): test of overriding a built-in command...'
    }
}

t/lib/My/Journal/Command/Menu.pm  view on Meta::CPAN


#-------
1;

__END__

=pod

=head1 NAME

My::Journal::Command::Menu

=head1 PURPOSE

A demonstration and test of overriding a built-in CLIF Menu command.

=head1 NOTES

This example replaces the built-in command menu.  The particular replacement
is not particularly useful, but shows how such a replacement could be done.

Note that overriding the menu command is a special case of overriding a
built-in command and it is necessary that the overriding command inherit from
the built-in menu class, CLI::Framework::Command::Menu.

This example merely changes the menu format.

=cut

t/lib/My/PerlFunctions.pm  view on Meta::CPAN

        -v --verbose:   running commentary about actions

    COMMANDS
        summary:        show perl functions by name
    }
}

sub command_map {
    summary => 'My::PerlFunctions::Command::Summary',
    console => 'CLI::Framework::Command::Console',
    menu    => 'CLI::Framework::Command::Menu',
}

#-------
1;

__END__

=pod

=head1 PURPOSE



( run in 1.816 second using v1.01-cache-2.11-cpan-49f99fa48dc )