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

NAME

Data::Remember - remember complex information without giving yourself a headache

SYNOPSIS

  use Data::Remember 'Memory';

  remember foo => 1;
  remember [ bar => 7 ], [ 'spaz', 'w00t', 'doof', 'flibble' ];
  remember [ 'xyz', 'abc', 'mno' ] => { some => 'thing' };

  my $foo     = recall 'foo';        # retrieve a simple key
  my $wibbler = recall [ bar => 7 ]; # retrieve a complex key
  my $alpha   = recall 'xyz';        # retrieve a subkey

  forget 'foo';

DESCRIPTION

While designing some IRC bots and such I got really tired of statements that looked like:

  $heap->{job}{$job} = {
      source  => $source,
      dest    => $destination,
      options => $options,
  };

and later:

  if ($heap->{job}{$job}{options}{wibble} eq $something_else) {
      # do something...
  }

I could simplify things with intermediate variables, but then I inevitably end up with 4 or 5 lines of init at the start or middle of each subroutine. Yech.

So, I decided that it would be nice to simplify the above to:

  remember [ job => $job ], {
      source  => $source,
      dest    => $destination,
      options => $options,
  };

and later:

  if (recall [ job => $job, options => 'wibble' ] eq $something_else) {
      # do something...
  }

Which I consider to far more readable.

The second aspect that this deals with is long-term storage. I started using DBM::Deep to remember the important bits of state across bot restarts. This package will store your information persistently for you too if you want:

  use Data::Remember DBM => 'state.db';

By using that command, the Data::Remember::DBM "brain" is used instead of the usual Data::Remember::Memory brain, which just stores things in a Perl data structure.

SUBROUTINES

By using this module you will automatically import (I know, how rude) four subroutines into the calling package: "remember", "recall", "forget", and "brain".

QUE

Each take a $que argument. The que is a memory que to store the information with. This que may be a scalar, an array, or a hash, depending on what suits your needs. However, you will want to be aware of how these are translated into memory locations in the brain plugin.

Any que argument is passed to the brain as an array. A scalar que is just wrapped in an array reference:

  remember foo => 1;

is the same as:

  remember [ 'foo' ] => 1;

An array que is passed exactly as it is to the brain plugin.

A hash que is converted to an array by sorting the keys in lexicographic order and keeping the pairs together. For example:

  remember { foo => 3, bar => 2, baz => 1 } => 'xyz';

is the same as:

  remember [ bar => 2, baz => 1, foo => 3 ] => 'xyz';

Once the array is built the brains are required to treat these in the same way as hash keys for a hash of hashes. For example, you can think of:

  remember [ foo => 3, bar => 2, baz => 1 ] => 'xyz';

as being similar to storing:

  $memory->{foo}{3}{bar}{2}{baz}{1} = 'xyz';

This means that you could later recall a subset of the previous key:

  my $bar = recall [ foo => 3, 'bar' ];

which would return a hash reference similar to:

  my $bar = { 2 => { baz => { 1 => 'xyz' } } };

(assuming you hadn't stored anything else under [ foo => 3, 'bar' ]).

Clear as mud? Good!

import $brain, @options;

Called automagically when you use this package. Do NOT try

  use Data::Remember ();

This will keep import from being called, which will keep you from using any of the nice features of this package. Since it uses deep magic in the import process, attempting to call Data::Remember::remember() and such won't work correctly.

If you can't import these three methods, sorry. Send me a bug report and a patch and I'll consider it.

The $brain argument lets you select a brain plugin to use. The brain plugins available with this distribution currently include:

Data::Remember::Memory

A brain that stores everything in plain Perl data structures. Data in this brain is not persistent.

Data::Remember::DBM

A brain that stores everything via DBM::Deep. Data stored here will be persistent. This brain also requires additional arguments (see the module documentation for details).

Data::Remember::YAML

A brain that stores everything via YAML. This is great for storing configuration data.

Data::Remember::Hybrid

A brain that doesn't store anything, but lets you use mix storage mechanisms.

You can specify $brain as a short name if it exists under "Data::Remember::". (For example, "DBM" will load "Data::Remember::DBM".) if $brain contains a "::", then it will be treated as a fully qualified name, in case you want to create your own brain. See "CREATING A BRAIN".

The @options are whatever options described in the brain's module documentation.

remember $que, $fact

Remember the given $fact at memory que $que. See "QUE" for an in depth discussion of $que. The $fact can be anything your brain can store. This will generally include, at least, scalars, hash references, and array references.

recall $que

Recalls a previously stored fact located at the memory location described by $que. See "QUE" for an in depth discussion of that argument.

If no fact is found at that que, undef will be returned.

forget $que

Tells the brain to forget a previously remembered fact stored at $que. See "QUE" for an in depth discussion of the argument. If no fact is stored at the given $que, this subroutine does nothing.

brain

Returns the inner object used to store data. This can be used in case the brain plugin provides additional methods or features that need manual access. For example, if you want to use DBM::Deeps locking features, you could:

  brain->dbm->begin_work;

  my $balance = recall 'balance';
  remember balance => $balance + 150;

  brain->dbm->commit;

CREATING A BRAIN

If you would like to create a custom brain plugin, you need to create a package that implements four methods: new, remember, recall, and forget.

The new method will take the list of options passed to "import" for your brain in addition to the class name. It should return a blessed reference that will be used for all further method calls.

The remember method will be passed a normalized reference to a que array and the fact the user has asked to store. You should read through "QUE" and handle the first argument as described there. Then, store the second argument at the memory location described.

The recall method will be passed a normalized reference to a que array, which should be treated as described in "QUE". Your implementation should return the fact stored at that location or undef. It's important that your implementation avoid the pit-falls caused by auto-vivifying keys. The recall method should never modify the memory of your brain.

The forget method will be passed a normalized reference to a que array, which should be treated as described in "QUE". Your implementation should then delete any fact stored there. Other than deleting this key, the forget method should not modify any other aspect of the memory of your brain.

To build a brain, I highly recommend extending Data::Remember::Memory, which performs (or should perform) all the work of safely storing and fetching records from a Perl data structure according to the interface described here. It stores everything under $self->{brain}. At the very least, you should read through that code before building your brain.

The Data::Remember::DBM or other included brains may also be a good place to look. They extend Data::Remember::Memory so that I didn't have to repeat myself.

SEE ALSO

Data::Remember::Memory, Data::Remember::DBM, Data::Remember::YAML, Data::Remember::Hybrid

AUTHOR

Andrew Sterling Hanenkamp <hanenkamp@cpan.org>

COPYRIGHT AND LICENSE

Copyright 2007 Boomer Consulting, Inc. All Rights Reserved.

This program is free software and may be modified and distributed under the same terms as Perl itself.