NAME
    CLI::Framework::Tutorial - "HOWTO" develop CLIF applications using best
    practices

CLIF DOCUMENTATION
    This is a guide to developing CLIF applications. It is a supplement to
    the documentation in CLI::Framework::Application and
    CLI::Framework::Command, which have more thorough coverage of some finer
    points.

    It is suggested that new users start by reading this document, then use
    the other documentation for reference as necessary.

INTRODUCTION
    Developers have been reluctantly writing ad-hoc, disposable scripts for
    too long or struggling to decide how not to do so. There is a better
    alternative.

    CLI::Framework::Application enumerates many advantages to using CLIF
    instead of writing yet-another-getopt-based-script. CLIF comes with a
    lot of documentation, but don't take that to mean that using CLIF is
    complicated. CLIF apps with simple needs are very easy to build. Apps
    with complex needs are a bit more work, but much easier to build (and
    far easier to test and maintain) than doing that work from scratch.

    This document will first demonstrate a very simple CLIF application.
    Next, a complete application will be shown to demonstrate more advanced
    CLIF features.

    Think of a typical command-line script. It needs to parse command-line
    options and arguments, check that any required external resources
    (files, databases, etc.) have been supplied, fail nicely if something is
    missing or inconsistent, then do something that depends on the options,
    arguments, and external resources.

    What happens when new scripts are created to do something similar? All
    too often, they end up with different option names for conceptually the
    same purpose. It is common for functionality needed by several scripts
    to be duplicated in each similar script. This rapidly gets out of hand,
    becoming a maintenance frustration. Your team members are not "on the
    same page" and new people learning your tools have to have lengthy,
    verbal one-on-one code tours.

    Instead, a set of related scripts could be combined into a CLIF
    application. Consistent naming conventions and sharing of common code is
    naturally encouraged. The commands are easy to test. New commands can be
    added with ease.

FROM P.O.S. TO CLIF IN A FEW EASY STEPS
    A "P.O.S." is a "Plain Old Script." This section shows you how to reform
    that old P.O.S., creating a shiny new CLIF application!

    Please see working code for this example included with the
    "CLI::Framework" distribution (examples/demo-simple.pl).

    This example demonstrates the following features:

    *   inline application definition

    *   basics (app, app args, commands, command options and args)

    *   the relationship between plain scripts and CLIF applications
        (including how to convert between them)

    To understand CLIF commands, imagine converting a legacy script to a
    CLIF application. First, create a Perl class that inherits from
    CLI::Framework::Command. Place the main body of the script in a "run()"
    method. Add the functions that the script defines, if any.

        # Your Command Subclass...
        package Converted::Script::Command::LegacyScript;
        use base qw( CLI::Framework::Command );

        sub run { ... }

    Next, create a Perl class (creating a separate package file for the
    class is totally optional) that inherits from
    CLI::Framework::Application and define a method, "command_map()", that
    links command names with command classes that implement the commands:

        # Your Application Class...
        package Converted::Script;
        use base qw( CLI::Framework::Application );

        sub command_map {
            {
                'legacy-script' => 'Converted::Script::Command::LegacyScript',
            }
        }

    The code that provides a friendly usage message (if the legacy script
    provided one) can be replaced by defining the "usage_text" method:

        sub usage_text {
            qq{
            $0 [--verbose|v] [--help|h]: work all manner of mischief devised by long-departed miscreants
            }
        }

    Back in your Command Subclass, the option/argument processing code will
    be replaced with a method defining what options will be recognized (the
    data structure to be returned is exactly as explained in
    Getopt::Long::Descriptive):

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

    ...and that's all it takes to convert a simple script to a CLIF app.
    This contrived example demonstrates the mechanics, but let me point out
    a few advantages (see DESIGN GOALS AND FEATURES in the
    CLI::Framework::Applicaton documentation for the long list):

    Clear division of responsibilities
        Using packages, subroutines, and separate files (if desired), CLIF
        apps follow established convention and provide a new pattern for
        creating tools.

    Easy to test
        Now that functional units of code are subroutines in packages, you
        can unit test each component independently.

    Easy to maintain
        Instead of puzzling over a several-thousand-line script, maintaining
        a CLIF application is like maintaining any other well-engineered
        application code.

    Easy to extend
        Related tools frequently occur in groups. Instead of awkwardly
        forcing loosely-related behaviors into the same script, CLIF makes
        it easy to add additional commands.

WHEN NOT TO USE CLIF
    CLIF could be used for the simplest of needs, but it may be overkill in
    very simple situations.

    You may want to avoid CLIF for very basic scripts that have a single
    behavior and are completely independent from other such tools. However,
    if there's a chance that the scripts might grow to become more complex
    or if you would simply like a pattern to follow, it may still be worth
    considering.

CONCEPTS AND DEFINITIONS
    See CONCEPTS AND DEFINITIONS in the CLI::Framework::Application
    documentation.

UNDERSTANDING THE APPLICATION RUN SEQUENCE
    See APPLICATION RUN SEQUENCE in the CLI::Framework::Application
    documentation.

    Understanding this is important to building more complex apps. You need,
    at the least, to understand how CLIF differentiates between options/args
    that are meant for the application itself and those options/args that
    are meant for individual commands.

    The following examples demonstrate the alternative command request
    forms. Note that in all cases, any number of (sub)command options and
    arguments can be passed (these examples show only one of each for
    brevity).

    FORM #1 (without subcommands) -- command requests that involve NO
    subcommands take the following form:

        <app> [--app-opt] <cmd> [--cmd-opt] [cmd-arg] ...

    (notice how the position of options and arguments determines whether
    they are meant for the application as a whole or for the specific
    command).

    FORM #2 (with subcommands) -- Command requests that involve A SINGLE
    subcommand take this form:

        <app> [--app-opt] <cmd> [--cmd-opt] <subcmd> [--subcmd-opt] [subcmd-arg] ...

    Command requests that involve MULTIPLE subcommands follow the same form:

        <app> [--app-opt] <cmd> [--cmd-opt] <subcmd1> [--subcmd1-opt] <subcmd2> [--subcmd2-opt] [subcmd2-arg] ...

    (notice that the final arguments apply to the final subcommand. In this
    form, the only command that can receive arguments is the final
    subcommand).

A MORE INVOLVED EXAMPLE
    Please see working code for this example included with the
    "CLI::Framework" distribution (examples/queue).

    The next example demonstrates the following features:

    *   inline application definition

    *   basics (app, app args, commands, command options and args)

    *   subcommands

    *   validation of application and command arguments

    *   interactive mode

    *   non-interactive mode

    Suppose we need to write a command-line app that provides an interface
    to a queue. Strings can be added to or removed from the queue, queue
    contents can be displayed, and queue "properties" can be set to restrict
    the contents added to the queue. The interface should work
    interactively.

    The following usage demonstrates the desired behavior:

        # ---- interactive mode ----
        1) dequeue
        2) cmd-list
        3) enqueue
        4) print
        5) alias
        6) property

        > help enqueue

        enqueue [--tag=<tag1> [--tag=<tag2> [...] ] ] <item1> [<item2> ...  <itemN>]: add item(s) to queue

        > enqueue --tag=x "something"

        > property set --evens

        > e 1 21 514 937 18

    The working example in examples/queue accomplishes this goal in a single
    inline application containing the Application Class and multiple Command
    Classes.

    This application is created in fundamentally the same way as the simple
    one presented earlier. It uses more commands, more Application
    Class/Command Class hooks, and subcommands. The code is much longer but
    almost all of it is for business logic -- little additional
    CLIF-specific code is needed.

    The example code shows how various commands can be managed by an
    Application subclass. The code is commented thoroughly to explain the
    various hooks that are available for Application Class and Command
    Classes.

    Of course, CLIF applications can always be used in non-interactive mode:

        # ---- non-interactive mode ----
        $ examples/queue --qout=/tmp/qfile enqueue 'first'
        $ examples/queue --qin=/tmp/qfile --qout=/tmp/qfile enqueue --tag=x --tag=y 'second'
        $ examples/queue --qin=/tmp/qfile --qout=/tmp/qfile property list
        $ examples/queue --qin=/tmp/qfile --qout=/tmp/qfile property set --evens
        $ examples/queue --qin=/tmp/qfile --qout=/tmp/qfile property list
        $ examples/queue --qin=/tmp/qfile --qout=/tmp/qfile enqueue 17
        $ examples/queue --qin=/tmp/qfile --qout=/tmp/qfile enqueue 4
        $ examples/queue --qin=/tmp/qfile --qout=/tmp/qfile enqueue 2
        $ examples/queue --qin=/tmp/qfile --qout=/tmp/qfile dequeue
        $ examples/queue --qin=/tmp/qfile --qout=/tmp/qfile dequeue
        $ examples/queue --qin=/tmp/qfile --qout=/tmp/qfile dequeue
        $ examples/queue --qin=/tmp/qfile --qout=/tmp/qfile enqueue 3
        $ examples/queue --qin=/tmp/qfile print

PLANNING A COMPLEX CLIF APPLICATION
    Little additional thought (beyond that needed for business logic) is
    required to create a basic CLIF app -- the strategy explained in "FROM
    P.O.S. TO CLIF IN A FEW EASY STEPS" demonstrates how CLIF differs from a
    "Plain Old Script".

    A more complicated command line application will benefit from a wider
    variety of the features CLIF provides. The extra features are easy to
    use, but the additional complexity warrants some planning.

    Here are some considerations:

    Basic interface
        What commands and subcommands should be available? What options and
        arguments will they support? What kind of validation should be done
        on the provided command requests? Which built-in commands will be
        used? Will an interactive mode be provided? If so, will a custom
        menu be created? Do any commands need to directly access or modify
        the application itself or the other commands (these will be
        metacommands)?

    High-level code layout
        Which components of the application will be defined in their own
        package files? Which will be defined inline?

    Separation of concerns using MVC strategy
        How will the model be separated from the rest of the application?
        What about the view?

    Data sharing between application and commands
        What data will data be shared between the application and the
        commands? Will this be arranged by using the cache, using a Command
        superclass (a generic command class that all of your commands
        inherit from), or by some other means?

    Read on for possible answers to some of these questions.

HOW CAN I ...?
    This section explains how CLIF could be used to support various common
    goals. Even if your particular situation does not appear here, reading
    this section will give you an understanding of how CLIF could be set up
    to support novel cases.

  How can I quickly create a very simple application?
    For a demonstration of how to create a very simple CLIF app, see "FROM
    P.O.S. TO CLIF IN A FEW EASY STEPS". CLIF applications require, at the
    minimum:

    *   An Application Class that inherits from CLI::Framework::Application.
        For anything useful to happen, it should override the
        "command_map()" hook and include a new command.

    *   A Command Class that inherits from CLI::Framework::Command. It
        should override the "run()" hook (or have a subcommand that
        overrides "run()").

    *   An Application Script that calls the "run()" method in your
        application.

    These can all be defined in one file or each class can be placed in a
    separate file. Do whatever works best for your particular needs.

  How can I include logging in my application?
    In your Application Class, define "init()" to initialize your logging
    object and save the resulting object in the cache, where the object will
    be available to your application and command objects.

  How can I include database connectivity in my application?
    In your Application Class, define "init()" to connect to your database
    and save the resulting object or database handle in the cache, where the
    object/handle will be available to your application and command objects.

    Of course, for proper Separation of Concerns, you should not simply
    store a connected database handle in the cache and use it directly in
    your Command classes. You should instead store an object of another
    class that encapsulates your data model layer code. An example of this
    is the model class for the demo journal application included with CLIF
    tests: t/lib/My/Journal/Model.pm.

  How can I support an application configuration file?
    In your Application Class, define "init()" to load your configuration
    file and save the resulting configuration object in the cache using the
    cache(), where the object will be available to your application and
    command objects.

  How can I use templates for more flexible output?
    In your Application Class, override the "render()" method.

    For instance, you could write an application where all commands return a
    data structure to be used in processing a template. Your "render()"
    method could determine which template file to process (e.g. based on
    which command is being run) and then process it using the received data
    structure.

  How can I use alternative CLI prompting techniques and terminal I/O convenience functions?
    You may, for example, want to present a menu of options from a variety
    of choices based on content from a database. Or perhaps you want to
    prompt the user for a list of numbers and you want to support a
    comma-separated list with ranges, etc.

    Create a CLI::Framework::Command subclass (say, "Your::Command") that
    implements your convenience functions or uses a CPAN module such as
    Term::Prompt. Then all of your commands can inherit from "Your::Command"
    and will all have access to the functions.

    You may also want to override read_cmd().

  How can I create an app without a 'help' command?
    The 'help' command is fundamental to most applications. If you really
    want to build an application without a 'help' command, simply create a
    custom Help command with an empty "run" method.

TROUBLESHOOTING
    The following problems and solutions may be helpful when working with
    CLIF.

    *   Don't forget to inherit from CLI::Framework::Application in your
        Application class and CLI::Framework::Command in your command class

    *   Don't forget to define (override) command_map() in your Application
        class

    *   Don't forget to define (override) run() in your Command class

    *   If in doubt, run "perl -wc <your command class file>"

        If a user-defined command class does not compile, your CLIF
        application will fail silently. Running "perl -wc Class.pm" will
        report compilation problems for Class.pm.

LICENSE AND COPYRIGHT
    Copyright (c) 2009 Karl Erisman (karl.erisman@icainformatics.com),
    Informatics Corporation of America. All rights reserved.

    This is free software; you can redistribute it and/or modify it under
    the same terms as Perl itself. See perlartistic.

AUTHOR
    Karl Erisman (karl.erisman@icainformatics.com)

