NAME
    Perinci::Sub::Gen::Undoable - Generate undoable (transactional,
    dry-runnable, idempotent) function

VERSION
    version 0.20

SYNOPSIS
     # See an example, like in Setup::File::Symlink

DESCRIPTION
    This module helps you write undoable/transactional functions (as well as
    functions that support dry-run and are idempotent).

FUNCTIONS
  get_step_spec($name, \%steps) => HASHREF
    %steps is optional. Step $name will first be searched in %steps's keys.
    If found and value is a hashref, that stepspec is returned. If found but
    value is a string, it is assumed to be the new step name (an alias) and
    the new step name is searched. If not found in %steps (or %steps if not
    provided), then an attempt is made to load module
    Perinci::Sub::Step::<$name>; the module should contain "spec()" which if
    called returns the stepspec.

SEE ALSO
    Rinci::function::Undo, Rinci::function::Transaction, Rinci

    Setup.

DESCRIPTION
    This module has Rinci metadata.

FUNCTIONS
    None are exported by default, but they are exportable.

  gen_undoable_func(%args) -> [status, msg, result, meta]
    Generate undoable (transactional, dry-runnable, idempotent) function.

    This function is basically a helper for writing undoable (as well as
    transactional, dry-runnable, and idempotent) function. This function
    will generate a function with the basic structure, and you supply the
    'business-logic' bits through the 'build_steps' and 'steps' arguments.

    This generator helps because writing an undoable and transactional
    function is a bit tricky. This helper shields function writer from
    having to interact with the transaction manager, or writing the steps
    loop, or writing the rollback mechanism on his/her own, and just focus
    on writing the actual steps.

    Some notes:

    *   Though it generally should not die(), generated function might still
        die, there is no big eval{} loop inside. But this is usually OK
        since a function wrapper (like Perinci::Sub::Wrapper) has this loop.

    For examples, see Setup::* Perl modules.

    Control flow:

    1.  "check_args" hook is executed, if supplied. It should return
        enveloped result. If response is not success, exit with this
        response.

    1.  If "-undo_action" argument is "do", "build_steps" hook is executed
        to get list of steps (an arrayref). If "-undo_action" is "undo" or
        "redo", steps is retrieved either from transaction manager
        ("-tx_manager" argument) or passed undo data ("-undo_data"
        argument).

    1.  Execute the steps. First, step's "check" hook is executed. If it
        returns undef, it means nothing needs to be done and we move on to
        the next step. If it returns an arrayref (undo step), it means we
        need to record the undo step first to transaction manager (if we are
        using transaction) or just collect the step in an array (if not
        using transaction), and then execute the step's "fix" hook. The hook
        should return an enveloped result. If response if not success, we
        trigger the rollback mechanism (see point 4). Otherwise we move on
        to the next step. After all the steps are executed successfully, we
        return 200 response.

    1.  To rollback: if we are not using transaction, we get out of the loop
        in point 3) and enter a loop to execute the undo steps in backward
        order (which is basically the same as point 3). If we are using
        transaction, we call transaction manager's rollback() (which will
        also essentially do the same kind of loop). If there is failure in
        the rollback steps, we just exit with the last step's response.

    Additional notes:

    *   Generated function returns result as well as result metadata (3rd
        and 4th element of envelope array). Currently each step's "fix" hook
        is passed these two thus given the opportunity to fill/change them.
        Result is initially {} like result metadata. If result is still {}
        at the end of executing steps, "undef" is used instead.

    Arguments ('*' denotes required arguments):

    *   args => *hash* (default: {})

        Specification for generated function's arguments.

        This is just like the metadata property 'args'.

    *   build_steps* => *array|code*

        Code to build steps.

        This is the code that should build the steps. Code will be given
        (\%args) and should return an enveloped response. If response is not
        a success one, function will exit with that response. Steps must be
        an array of steps, where each step is like this: [NAME, ...] (an
        array with step name as the first element and step argument(s) name,
        if any, in the rest of the elements).

        Each step must be defined in the "steps" argument.

    *   check_args => *code*

        Code to check function's arguments.

        This is a hook to allow the generated function to check its
        arguments. This should later be mostly unnecessary when
        Perinci::Sub::Wrapper already integrates with Data::Sah to generate
        argument-checking code from schema.

        Code is given (\%args), where you can modify the args (e.g. set
        defaults, etc) and it will be carried on to the other steps like
        'build_steps'. Code should return enveloped result. If response is
        not a success one, it will be used as the function's response.

    *   description => *str*

        Generated function's description.

    *   install => *bool* (default: 1)

        Whether to install generated function (and metadata).

        By default, generated function will be installed to the specified
        (or caller's) package, as well as its generated metadata into %SPEC.
        Set this argument to false to skip installing.

    *   log_level_fix_step => *str* (default: "info")

        At what level to show log messages when performing step.

        By default, it is at "info" (can be turned on using --verbose or
        VERBOSE=1 in command-line scripts). For example:

            % VERBOSE=1 u-trash --dry-run *.bak
            [info] (DRY) Trashing file1.bak ...
            [info] (DRY) Trashing file2.bak ...
            [info] (DRY) Trashing file3.bak ...

        However, if you feel it is too chatty, you can lower it to 'trace',
        for example.

    *   name* => *str*

        Generated function's name, e.g. `myfunc`.

    *   package => *str*

        Generated function's package, e.g. `My::Package`.

        This is needed mostly for installing the function. You usually don't
        need to supply this if you set "install" to false.

        If not specified, caller's package will be used by default.

    *   steps* => *hash*

        Steps specification.

        A hash of step name and step specification ("stepspec"). Stepspec is
        a hash. Stepspec must at least have "check" and "fix" routines (or a
        single combined "check_and_fix" routine).

        Instead of stepspec hash, a string can also be provided and it is
        assumed to be an alias to another step name.

        If a step is not found in this "steps" argument, it will be searched
        in Perinci::Sub::Step:: module. A step module should contain spec()
        which returns the stepspec. If the module is not found, an 'unknown
        step' error is returned.

    *   summary => *str*

        Generated function's summary.

    *   trash_dir => *bool* (default: 0)

        Whether function needs undo trash directory.

    *   tx => *hash* (default: {})

        Whether function is transactional.

        Valid values include {use=>1} (meaning function can use transaction
        and will utilize it if given '-tx' special argument), {req=>1}
        (meaning function always require '-tx' and will return error
        response if not given it). Otherwise function will not use
        transaction, undo data will be passed to function via '-undo*data'
        special argument and returned by function in 'undo*data' result
        metadata.

    Return value:

    Returns an enveloped result (an array). First element (status) is an
    integer containing HTTP status code (200 means OK, 4xx caller error, 5xx
    function error). Second element (msg) is a string containing error
    message, or 'OK' if status is 200. Third element (result) is optional,
    the actual result. Fourth element (meta) is called result metadata and
    is optional, a hash that contains extra information.

AUTHOR
    Steven Haryanto <stevenharyanto@gmail.com>

COPYRIGHT AND LICENSE
    This software is copyright (c) 2012 by Steven Haryanto.

    This is free software; you can redistribute it and/or modify it under
    the same terms as the Perl 5 programming language system itself.

POD ERRORS
    Hey! The above document had some coding errors, which are explained
    below:

    Around line 671:
        You have '=item 1' instead of the expected '=item 2'

    Around line 680:
        You have '=item 1' instead of the expected '=item 3'

    Around line 694:
        You have '=item 1' instead of the expected '=item 4'

