NAME
    Sub::Spec::Runner::Orderly - Run a set of subs (with dependency
    ordering, order changing, etc)

VERSION
    version 0.05

SYNOPSIS
    In YourModule.pm:

     package YourModule;

     use 5.010;
     our %SPEC;

     $SPEC{a} = { depends => {sub=>'b'}, ... };
     sub a { my %args = @_; say "a"; [200, "OK"] }

     $SPEC{b} = { depends => {sub=>'c'}, ... };
     sub b { my %args = @_; say "b"; [200, "OK"] }

     $SPEC{c} = { depends => {and=>[{sub=>'d'}, {sub=>'e'}]}, ... };
     sub c { my %args = @_; say "c"; [200, "OK"] }

     $SPEC{d} = { depends => {sub=>'e'}, ... };
     sub d { my %args = @_; say "d"; [200, "OK"] }

     $SPEC{e} = { ... };
     sub e { my %args = @_; say "e"; [200, "OK"] }

    In main module:

     use Sub::Spec::Runner::Orderly;

     my $runner = Sub::Spec::Runner::Orderly->new(load_modules=>0);
     $runner->add('YourModule::a');
     $runner->run;

    Will output:

     e
     d
     c
     b
     a

DESCRIPTION
    This class can run a set of subroutines along with their dependencies
    (read from sub spec's 'depends' clause) according to the dependency tree
    order. During the run, subroutines can instruct the runner to
    skip/repeat some subroutines, jump to another subroutine, or even add
    more subroutines and reorder the execution. The runner will finish after
    all subroutines have been run (or skipped).

    This module uses Log::Any logging framework. Use something like
    Log::Any::App, etc to see more logging statements for debugging.

    This module uses Moo for object system.

  args => HASHREF
    Arguments to pass to each subroutine. Note that each argument will only
    be passed if the 'args' clause in subroutine spec specifies that the sub
    accepts that argument, or if subroutine doesn't have an 'args' clause.
    Example:

     package Foo;

     our %SPEC;
     $SPEC{sub0} = {};
     sub sub0 { ... }

     $SPEC{sub1} = {args=>{}};
     sub sub1 { ... }

     $SPEC{sub2} = {args=>{foo=>"str"}};
     sub sub2 { ... }

     $SPEC{sub3} = {args=>{bar=>"str"}};
     sub sub2 { ... }

     $SPEC{sub4} = {args=>{foo=>"str", bar=>"str"}};
     sub sub4 { ... }

     package main;
     use Sub::Spec::Runner::Orderly;

     my $runner = Sub::Spec::Runner::Orderly->new(sub_args => {foo=>1, foo=>2});
     $runner->add("Foo::sub$_") for (1 2 3 4);
     $runner->run;

    Then only sub0 and sub4 will receive 'foo' and 'bar' args. sub1 won't
    receive any arguments, sub2 will only receive 'foo', sub3 will only
    receive 'bar'.

  load_modules => BOOL
    Whether to load (require()) modules when required, default is yes.

METHODS
  add($subname[, $spec])
    Add subroutine to the set of subroutines to be run. Example:

     $runner->add('Foo::bar');

    Sub spec will be retrieved from $Foo::SPEC{bar}, except when $spec is
    specified.

    Will also automatically add all dependencies.

  order_by_dependencies
    Reorder set of subroutines by dependencies. Normally need not be called
    manually since it will be caled by run() prior to running subroutines,
    but might be useful if you want to add more subroutines in the middle of
    a run and then reorder.

  todo_subs => ARRAYREF
    Return the current list of subroutine names not yet runned, in order.
    Previously run subroutines can belong to this list again if repeat()-ed.

  done_subs => ARRAYREF
    Return the current list of subroutine names already run, in order.
    Never-run subroutines can belong to this list too if skip()-ed.

  run(%opts) => [STATUSCODE, ERRMSG, RESULT]
    Options: ignore_errors => BOOL (default false).

    Run the set of subroutines previously added by add(). Will return status
    code 400 if there are no subroutines to run.

    Prior to running, 'depends' clause in each subroutine's spec will be
    read and resolved first to add depended subroutines and change the order
    of execution according to dependency tree. Will return 412 if dependency
    cannot be resolved.

    Then it will call pre_run(), which you can override. pre_run() must
    return true, or run() will immediately return with 412 error.

    Then it will run each subroutine successively and store its result. Each
    subroutine will be called with arguments specified in 'args', with one
    extra special argument, '-runner' which is the runner object. Prior to
    running a subroutine, pre_sub() will be called. It must return true, or
    run() will immediately return with 500 error.

    The subroutine being run can see the status/result of other subroutines
    by calling $runner->done(), $runner->result(). It can share data by
    using $runner->stash(). It can also change the ordering or repeat/skip
    some subroutines by calling $runner->done(), skip(), skip_all(),
    repeat(), repeat_all(). It can jump to other subroutines using
    $runner->jump(). See the respective method documentation for more
    detail.

    After running a subroutine, post_sub() will be called. It must return
    true, or run() will immediately return with 500 error.

    If ignore_errors is not set to true, then if the subroutine a
    non-success result, run() will immediately exit with that result. The
    meaning of subroutine's success can be changed by overriding
    success_res() (by default, all 2xx and 3xx are considered success).

    After all subroutines have been run (or skipped), run() will call
    post_run() which must return true or otherwise run() will immediately
    exit with 500 status.

    After that, run() will return the summary. It will return status 200 if
    there are at least one subroutine returning success, or 500 otherwise.

  format_subname($subname) => STR
    Can be used to format info log message: "Running XXX ..." when about to
    run a subroutine inside run(). Default is "Running Package::bar ..."
    (just the subname)

  success_res($res) => BOOL
    By default, all responses with 2xx and 3xx are assumed as a success. You
    can override this.

  pre_run() => BOOL
    See run() for more details. Can be overridden by subclass.

  pre_sub() => BOOL
    See run() for more details. Can be overridden by subclass.

  post_sub() => BOOL
    See run() for more details. Can be overridden by subclass.

  post_run() => BOOL
    See run() for more details. Can be overridden by subclass.

  done(SUBNAME[, VALUE]) => OLDVAL
    If VALUE is set, set a subroutine to be done/not done. Otherwise will
    return the current done status of SUBNAME.

    SUBNAME can also be a regex, which means all subroutines matching the
    regex. The last SUBNAME's current done status will be returned.

  skip(SUBNAME)
    Alias for done(SUBNAME, 1).

  skip_all()
    Alias for skip(qr/.*/, 1).

  repeat(SUBNAME)
    Alias for done(SUBNAME, 0).

  repeat_all()
    Alias for repeat(qr/.*/, 1).

  branch_done(SUBNAME, VALUE)
    Just like done(), except that will set SUBNAME *and all its dependants*.
    Example: if a depends on b and b depends on c, then doing branch_done(c,
    1) will also set a & b as done.

    SUBNAME must be a string and not regex.

  jump($subname)
    Jump to another subname. Can be called in pre_sub() or inside subroutine
    or post_sub().

  stash(NAME[, VALUE]) => OLDVAL
    Get/set stash data. This is a generic place to share data between
    subroutines being run.

SEE ALSO
    Sub::Spec

    Sub::Spec::Clause::depends

AUTHOR
    Steven Haryanto <stevenharyanto@gmail.com>

COPYRIGHT AND LICENSE
    This software is copyright (c) 2011 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.

