The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Data::RunningTotal - Module that allow you to keep track of running totals within a multi-dimensional space. Allows the access of the total at a point or volume at any specified time.

SYNOPSIS

  use Data::RunningTotal;

  # Create a running total across 3 dimensions: owner, priority and product
  my $rt = Data::RunningTotal->new(dimensions => ["owner", "priority", "product"]);

  ## Simple interface
  my $time = 1;

  # increment the specified point by weight
  $rt->inc($time++, 
           weight => $weight, 
           coords => ["bob", "P1", "infinite improbablity generator"]);

  # decrement the specified point by weight
  $rt->dec($time++, 
           weight => $weight, 
           coords => ["sam", "P2", "genuine people personalities"]);

  ## Item based interface

  # Create a new event
  my $item = $rt->newItem(weight => $weight);

  # Shuffle this item around within the specified coordinates
  $item->moveTo($time++, coords => ["bob", "P1", "infinite improbability generator"]);
  $item->moveTo($time++, coords => ["sam", "P1", "infinite improbability generator"]);
  $item->moveTo($time++, coords => ["sam", "P2", "infinite improbability generator"]);
    
  # Get the number of bugs for "sam", "P1", "infinite improbability generator"
  # at time 4
  my $count = $rt->getValue(4, 
                            coords => ["sam", 
                                       "P2", 
                                       "infinite improbability generator"]);

  # Get the number of bugs for "sam" at time 10 (undef is a wildcard)
  $count = $rt->getValue(10, coords => ["sam", undef, undef]);

  # Get the list of count changes over time for priorities 1 and 2, between
  # time 0 and 100, inclusive, but only on 10 time-unit intervals
  my $list = $rt->getChangeList(start => 0,
                                end   => 100,
                                period => 10,
                                coords => [undef, sub {$_[0] =~ /^P[12]$/}, undef]);

  # Get all P3 and P4 priorities across all time at max granularity
  my $list2 = $rt->getChangeList(coords => [undef, sub {$_[0] =~ /^P[34]$/}, undef]);

  # Put the two preceding lists into a single list - note that they
  # don't need to have the same time contraints
  my $comblist = $rt->getChangeList($list, $list2);

DESCRIPTION

This module is used to make it easy to get a running total of items within a multi-dimensional space. It was originally written to keep track of counts of open bugs across users, products and a bunch of other attributes so that it was possible to extract historical information from a bug database to produce graphs of open bugs for various attributes over time. While that was its original purpose, it is completely generic and can be used for lots of other purposes.

The typical way of doing this is to create a new item for each thing being counted (in my example, this is a bug) and then just move it around in the multi-dimensional space using the 'moveTo' method. When an item is created, the weight of that item can be specified or it defaults to 1. This weight will be added to the point the item is moved to in the multi-dimensional space and subtracted from the point that it left.

After all the data has been stored in the RunningTotal db, the data can be walked over for a specified volume (or point) or query a specific time for a specified volume (or point). For example, daily counts for priority 1 bugs of a period of a few months can be extracted in order to generate a bug graph.

The following statement would get a list of changes to the volume that contains all bugs owned by all users, with priority P2 for all products. If it wasn't clear, undef means all values in that dimension.

my @levelChanges = $rt->getChangeList(coords = [undef, "P2", undef]); >

Each entry in the returned list is an array ref that contains [time, value], with the time being the time that the total of all items in that volume changed and value being the new sum of all weights of those items.

Methods

new

new(%options)

Create at new running total with the specified dimensions. Returns a RunningTotal object reference.

The list of options are:

dimensions (required)

A list of dimension names for the multi-dimensional space. For example, if you were counting within normal 3-d space, you might specify: dimensions => ['x', 'y', 'z']

inc

$rt->inc($time, %options);

Increment the point specified by coords by value weight. Weight defaults to 1 if not specified.

The list of options are:

coords

Required parameter specifying the location that is being incremented.

coords => ["loc1", "loc2", ...]

weight

Optional parameter to specify the value of the increment

weight => <weight>

dec

$rt->dec($time, %options);

Same as inc, except that the value is decremented at the specified point and time.

getValue

my $value = $rt->getValue($time, %options);

Get a list of all changes over a range of time for the specified point or volume.

The method will return a list of array refs, with each containing a time and value pair ([$time, $value]).

The options may be:

coords

Required parameter specifying an array ref pointing to a list of coordinate selectors. Each item my be an exact coordinate, undef (for all coords in this dimension) or an anonymous sub that will be called within each possible coordidate in that dimension.

getChangeList

my @changes = $rt->getChangeList(%options);

Get a list of all changes over a range of time for the specified point or volume.

The method will return a list of array refs, with each containing a time and value pair ([$time, $value]).

The options may be:

coords

Required parameter specifying an array ref pointing to a list of coordinate selectors. Each item my be an exact coordinate, undef (for all coords in this dimension) or an anonymous sub that will be called within each possible coordidate in that dimension.

coords => [>coord|undef|sub{...}<, ...]

start

Specifies the starting time for the list. If not specified the list will start with the earliest relevent event.

end

Specifies the ending time for the list. If not specified the list will continue to the last relevent event.

period

Specifies a time interval for how often changed values should be returned. For example, if you enter events using seconds, you could set period to 3600*24 to get a value for each day.

combineChangeList

my $combList = $rt->combineChangeList($list1, $list2, ...);

This method takes a many lists in the form that are returned from getChangeList and merges them into a single list. That single list will have an entry for each distinct time from all the specified lists. The entry will have the form: [time, list1Val, list2Val, ...].

A convenient was to use it is (using the bug example again):

   my $combList = 
     $rt->combineChangeList(
       $rt->getChangeList(undef, "P1", undef),
       $rt->getChangeList(undef, "P2", undef),
       $rt->getChangeList(undef, "P3", undef),
       $rt->getChangeList(undef, "P4", undef),
       $rt->getChangeList(undef, "P5", undef));

The preceding example would give a single list in which each entry has a count for a different priority.

newItem

$item = $rt->newItem(%options)

Create a new item that will be moved within the multi-dimensional space. The weight will be used when adding to the new point it is moved to and subtracting from the point it is leaving.

Options:

weight

Optional parameter to specify the weight of an item. If not specified, it defaults to 1.

moveTo

$item->moveTo($time, %options);

Subtract the item's weight from its current location and move it to the specified new point, where its weight will be added.

A MAJOR limitation of this command is that movements must occur in ascending time order. In other words, you can't move to a point in the past.

Options:

coords

Required parameter to specify the coordidates to move to

coords => ["loc1", "loc2", ...]

SEE ALSO

AUTHOR

Edward Funnekotter, <efunneko+cpan@gmail.com>

COPYRIGHT AND LICENSE

Copyright (C) 2009 by Edward Funnekotter

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.6 or, at your option, any later version of Perl 5 you may have available.