NAME Sub::Spec::Runner::Orderly - Run a set of subs (with dependency ordering, order changing, etc) VERSION version 0.06 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. ATTRIBUTES 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 $runner->get_spec($subname) => SPEC Get spec for sub named $subname. Will be called by add(). Can be overriden to provide your own specs other than from %SPECS package variables. $runner->add($subname) Add subroutine to the set of subroutines to be run. Example: $runner->add('Foo::bar'); Will also automatically add all dependencies. $runner->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. $runner->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. $runner->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. $runner->run(%opts) => [STATUSCODE, ERRMSG, RESULT] Options: ignore_errors => BOOL (default false), order_by_dependencies => BOOL (default true). 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. $runner->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) $runner->success_res($res) => BOOL By default, all responses with 2xx and 3xx are assumed as a success. You can override this. $runner->pre_run() => BOOL See run() for more details. Can be overridden by subclass. $runner->pre_sub() => BOOL See run() for more details. Can be overridden by subclass. $runner->post_sub() => BOOL See run() for more details. Can be overridden by subclass. $runner->post_run() => BOOL See run() for more details. Can be overridden by subclass. $runner->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. $runner->skip(SUBNAME) Alias for done(SUBNAME, 1). $runner->skip_all() Alias for skip(qr/.*/, 1). $runner->repeat(SUBNAME) Alias for done(SUBNAME, 0). $runner->repeat_all() Alias for repeat(qr/.*/, 1). $runner->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. $runner->jump($subname) Jump to another subname. Can be called in pre_sub() or inside subroutine or post_sub(). $runner->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 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.