NAME
   CHI::Cascade - a cache dependencies (cache and like 'make' utility
   concept)

SYNOPSIS
       use CHI;
       use CHI::Cascade;

       $cascade = CHI::Cascade->new(chi => CHI->new(...));

       $cascade->rule(
           target  => 'unique_name',
           depends => ['unique_name_other1', 'unique_name_other2'],
           code    => sub {
               my ($rule, $target_name, $values_of_depends) = @_;

               # $values_of_depends == {
               #     unique_name_other1 => $value_1,
               #     unique_name_other2 => $value_2
               # }
               # $rule->target     eq      $target_name
               # $rule->depends    ===     ['unique_name_other1', 'unique_name_other2']
               # $rule->dep_values ==      $values_of_depends
               # $rule->params     ==      { a => 1, b => 2 }

               # Now we can calcualte $value
               return $value;
           },
           params  => { a => 1, b => 2 }
       );

       $cascade->rule(
           target  => 'unique_name_other1',
           depends => 'unique_name_other3',
           code    => sub {
               my ($rule, $target_name, $values_of_depends) = @_;

               # $values_of_depends == {
               #     unique_name_other3 => $value_3
               # }

               # computing here
               return $value;
           }
       );

       $value_of_this_target = $cascade->run('unique_name');

DESCRIPTION
   This module is the attempt to use a benefits of caching and 'make'
   concept. If we have many an expensive tasks and want to cache it we can
   split its to small expsnsive tasks and to describe dependencies for
   cache items.

   This module is experimental yet. I plan to improve it near time but some
   things already work. You can take a look for t/* tests as examples.

CONSTRUCTOR
   $cascade = CHI::Cascade->new( %options )

   This method constructs a new "CHI::Cascade" object and returns it.
   Key/value pair arguments may be provided to set up the initial state.
   Options are:

   chi Required. Instance of CHI object. The CHI::Cascade doesn't construct
       this object for you. Please create instance of "CHI" yourself.

   busy_lock
       Optional. Default is *never*. *This is not "busy_lock" option of
       CHI!* This is amount of time (to see "DURATION EXPRESSIONS" in CHI)
       until all target locks expire. When a target is recomputed it is
       locked. If process is to be recomputing target and it will die or OS
       will be hangs up we can dead locks and locked target will never
       recomputed again. This option helps to avoid it. You can set up a
       special busy_lock for rules too.

   target_chi
       Optional. This is CHI cache for target markers. Default value is
       value of "chi" option. It can be useful if you use a "l1_cache" in
       CHI option. So you can separate data of targets from target markers
       - data will be kept in a file cache and a marker in memory cache for
       example.

METHODS
   rule( %options )
       To add new rule to "CHI::Cascade" object. All rules should be added
       before first "run" method

       The keys of %options are:

       target
           Required. A target for "run" and for searching of "depends". It
           can be as scalar text or "Regexp" object created through "qr//"

       depends
           Optional. The scalar, arrayref or coderef values of
           dependencies. This is the definition of target(s) from which
           this current rule is dependent. If *depends* is:

           scalar
               It should be plain text of single dependence of this target.

           arrayref
               An each item of list can be scalar value (exactly matched
               target) or code reference. If item is coderef it will be
               executed as $coderef->( $rule, $rule->qr_params ) and should
               return a scalar value as current dependence for this target
               at runtime (the API for coderef parameters was changed since
               v0.16)

           coderef
               This subroutine will be executed every time inside *run*
               method if necessary and with parameters as: $coderef->(
               $rule, $rule->qr_params ) (API was changed since v0.16). It
               should return scalar or arrayref. The returned value is
               *scalar* it will be considered as single dependence of this
               target and the behavior will be exactly as described for
               *scalar* in this paragraph. If the returned value is
               *arrayref* it will be considered as list of dependencies for
               this target and the behavior will be exactly as described
               for *arrayref* in this paragraph.

       depends_catch
           Optional. This is coderef for dependence exceptions. If any
           dependence from list of "depends"'s option throws an exception
           of type CHI::Cascade::Value by "die" (for example like this
           code: "die CHI::Cascade::Value->new->value( { i_have_problem =>
           1 } )" ) then the $cascade will execute this code as
           "$rule->{depends_catch}->( $this_rule_obj,
           $exception_of_dependence, $rule_obj_of_dependence,
           $plain_text_target_of_dependence )" and you can do into inside a
           following:

           re-"die" new exception of any type
               If your new exception will be type of CHI::Cascade::Value
               you will get the value of this object from "run" method
               immediately (please to see "code" below) without saving in
               cache.

               If exception will be other type this will be propogated
               onward beyond the "run" method

           to do something
               You can make something in this code. After execution of your
               code the cascade re-throws original exception of dependence
               like described above in "re-"die"" section.

               But please notice that original exception has a status of
               "thrown from code" so it can be catched later by other
               "depends_catch" callback from other rule located closer to
               the call hierarchy of "run".

           Please notice that there no way to continue a "code" of current
           rule if any dependence throws an exception!. It because that the
           main concept of execution code of rules is to have all valid
           values (cached or recomputed) of all dependencies before
           execution of dependent code.

       code
           Required. The code reference for computing a value of this
           target (a recompute code). Will be executed if no value in cache
           for this target or any dependence or dependences of dependences
           and so on will be recomputed. Will be executed as "$code->(
           $rule, $target, $hashref_to_value_of_dependencies )" *(The API
           of running this code was changed since v0.10)*

           If you want to terminate a code and to return immediately from
           "run" method and don't want to save a value in cache you can
           throw an exception from "code" of type CHI::Cascade::Value. Your
           instance of CHI::Cascade::Value can have a value or cannot (a
           valid value can be even "undef"!). A "run" method returns either
           a value is set by you (through "value" in CHI::Cascade::Value
           method) or value from cache or "undef" in other cases. Please to
           see CHI::Cascade::Value

           $rule
               An instance of CHI::Cascade::Rule object. You can use it
               object as accessor for some current executed target data
               (plain text of target, for getting of parameters and so on).
               Please to see CHI::Cascade::Rule

           $target
               The current executed target as plain text for this "code"

           $hashref_to_value_of_dependencies
               A hash reference of values (values are cleaned values not
               CHI::Cascade::Value objects!) of all dependencies for
               current target. Keys in this hash are flat strings of
               dependecies and values are computed or cached ones.

               This module should guarantee that values of dependencies
               will be valid values even if value is "undef". This code can
               return "undef" value as a valid code return but author
               doesn't recommend it. If "CHI::Cascade" could not get a
               valid values of all dependencies of current target before
               execution of this code the last will not be executed (The
               "run" will return "undef").

       params
           You can pass in your code any additional parameters by this
           option. These parameters are accessed in your code through
           "params" in CHI::Cascade::Rule method of CHI::Cascade::Rule
           instance object.

       busy_lock
           Optional. Default is "busy_lock" of constructor or *never* if
           first is not defined. *This is not "busy_lock" option of CHI!*
           This is amount of time (to see "DURATION EXPRESSIONS" in CHI)
           until target lock expires. When a target is recomputed it is
           locked. If process is to be recomputing target and it will die
           or OS will be hangs up we can dead locks and locked target will
           never recomputed again. This option helps to avoid it.

       recomputed
           Optional. This is a recomputed callback (coderef). If target of
           this rule was recomputed this callback will be executed right
           away after recomputed value has been saved in cache. The
           callback will be executed as $coderef->( $rule, $target, $value
           ) where are:

           $rule
               An instance of CHI::Cascade::Rule class. This instance is
               recreated for every target searching and recomputing if
               need.

           $target
               A current target as string

           $value
               The instance of CHI::Cascade::Value class. You can use a
               recomputed value as $value->value

           For example you can use this callback for notifying of other
           sites that your target's value has been changed and is already
           in cache.

   run( $target )
       This method makes a cascade computing if need and returns value
       (value is cleaned value not CHI::Cascade::Value object!) for this
       target If any dependence of this target of any dependencies of
       dependencies were recomputed this target will be recomputed too.

   touch( $target )
       This method refreshes the time of this target. Here is analogy with
       touch utility of Unix and behaviour as make(1) after it. After
       "touch" all targets are dependent from this target will be
       recomputed at next "run" with an appropriate ones.

   target_remove ( $target )
       It's like a removing of target file in make. You can force to
       recompute target by this method. It will remove target marker if one
       exists and once when cascade will need target value it will be
       recomputed. In a during recomputing of course cascade will return an
       old value if one exists in cache.

STATUS
   This module is experimental and not finished for new features ;-) Please
   send me issues through <https://github.com/Perlover/CHI-Cascade> page

ANALOGIES WITH make
   Here simple example how it works. Here is a direct analogy to Unix make
   utility:

       In CHI::Cascade:            In make:

       rule                        rule
       depends                     prerequisites
       code                        commands
       run( rule_name )            make target_name

FEATURES
   The features of this module are following:

   Computing inside process
       If module needs to compute item for cache we compute inside process
       (no forks) For web applications it means that one process for one
       request could take a some time for computing. But other processes
       will not wait and will get either old previous computed value or
       *undef* value.

   Non-blocking computing for concurrent processes
       If other process want to get data from cache we should not block it.
       So concurrent process can get an old data if new computing is run or
       can get *undef* value. A concurrent process should decide itself
       what it should do after it - try again after few time or print some
       message like 'Please wait and try again' to user.

   Each target is splitted is two items in cache
       For optimization this module keeps target's info by separately from
       value item. A target item has lock & timestamp fields. A value item
       has a computed value.

EXAMPLE
   For example please to see the SYNOPSIS

   When we prepared a rules and a depends we can:

   If unique_name_other1 and/or unique_name_other2 are(is) more newer than
   unique_name the unique_name will be recomputed. If in this example
   unique_name_other1 and unique_name_other2 are older than unique_name but
   the unique_name_other3 is newer than unique_name_other1 then
   unique_name_other1 will be recomputed and after the unique_name will be
   recomputed.

   And even we can have a same rule:

       $cascade->rule(
           target  => qr/^unique_name_(.*)$/,
           depends => sub { 'unique_name_other_' . $_[1] },
           code    => sub {
               my ($rule, $target_name, $values_of_depends) = @_;

               # $rule->qr_params          === ( 3 )
               # $target_name              == 'unique_name_3' if $cascade->run('unique_name_3') was
               # $values_of_depends        == {
               #     unique_name_other_3   => $value_ref_3
               # }
           }
       );

       $cascade->rule(
           target  => qr/unique_name_other_(.*)/,
           code    => sub {
               my ($rule, $target_name, $values_of_depends) = @_;
               ...
           }
       );

   When we will do:

       $cascade->run('unique_name_52');

   $cascade will find rule with qr/^unique_name_(.*)$/, will make =~ and
   will find a depend as unique_name_other_52

AUTHOR
   This module has been written by Perlover <[email protected]>

LICENSE
   This module is free software and is published under the same terms as
   Perl itself.

SEE ALSO
   CHI::Cascade::Rule
       An instance of this object can be used in your target codes.

   CHI This object is used for cache.

   CHI::Driver::Memcached::Fast
       Recommended if you have the Memcached

   CHI::Driver::File
       Recommended if you want to use the file caching instead the
       Memcached for example