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

NAME

List::Filter - named, persistent, shared lists of patterns

SYNOPSIS

   use List::Filter;

   my $filter = List::Filter->new(
     { name         => 'skip_boring_stuff',
       terms        => ['-\.vb$', '\-.js$'],
       method       => 'skip_boring_stuff',
       description  => "Skip the really boring stuff",
       modifiers    => "xi",
     } );

   # If non-standard behavior is desired in locating the methods via plugins
   my $filter = List::Filter->new(
     { name         => 'skip_boring_stuff',
       terms        => ['-\.vb$', '\-.js$'],
       method       => 'skip_boring_stuff',
       description  => "Skip the really boring stuff",
       modifiers    => "xi",
       plugin_root  => 'List::Filter::Filters',
       plugin_exceptions => ["List::Filter::Transforms::NotThisOne"],

     } );


   # Alternately:
   my $filter = List::Filter->new();  # creates an *empty* filter

   my @terms = ['-\.vb$', '-\.js$'];
   $filter->set_name('skip_dull');
   $filter->set_terms( \@terms );
   $filter->set_method('skip_boring_stuff');
   $filter->set_description(
             "Skip the really boring stuff");
   $filter->set_modifiers( "xi" );


   # using a filter (using it's internally defined "method")
   my $output_items = $filter->apply( \@input_items );

   # using a filter, specifying an alternate "method"
   my $output_items = $filter->apply( \@input_items, "do_it_like_this" );

DESCRIPTION

The List::Filter system is a generalized, extensible way of filtering a list of items by apply a stack of perl regular expressions, with a persistant storage mechanism to allow the sharing of filters between different applications.

A List::Filter filter would just be a container object (a hashref with some accessor code), except that it also has an internally generated "dispatcher" object, so that it knows how to "apply" itself.

The "method" attribute of a filter object is indeed the name of a method, but not one defined inside this module. Instead there's a "plug-in" system that allows the definition of new methods without modification of the existing code.

See List::Filter::Project for documentation of the system.

OBJECT ATTRIBUTES

filter attributes (stored associated with the given name)

name

The name of the search filter.

terms

A list of filter items, e.g. search terms (essentially regexps).

method

The default method used to apply the search terms.

modifiers

Default modifiers to be applied to the search terms (essentially, regexp modifiers, e.g. "i").

description

A short description of the search filter.

dispatcher

Internally used field that stores the dispatcher object, a handle used to apply the filter according to it's "method".

storage_handler

### TODO weirdly enough, I can't figure out where this gets set. ### if it isn't set, then the save method can't work. ### but if the following flag is set, the apply method calls ### the save method... do I ever set this flag at this level?

save_filters_when_used

### TODO

METHODS

new

Instantiates a new List::Filter object.

Takes an optional hashref as an argument, with named fields identical to the names of the object attributes:

  name
  description
  terms
  method
  modifiers

With no arguments, the newly created filter will be empty.

There is also the attribute:

  storage_handler

which is intended to point to the storage handler set-up so that the filter has the capbility of saving itself to storage later. See "MOTIVATION" below.

There's a related flag (typically set by the storage handler):

   save_filters_when_used

There are two additional optional arguments,

 plugin_root
 plugin_exceptions

That are used in creating the dispatcher object which locates the code used to apply the filter (typically as specified by the "method" attribute):

List::Filter::Dispatcher

init

Initialize object attributes and then lock them down to prevent accidental creation of new ones.

Note: there is no leading underscore on name "init", though it's arguably an "internal" routine (i.e. not likely to be of use to client code).

generate_dispatcher

Generate the dispatcher object, used to apply a filter's method

the stuff that does the Real Work

apply

Apply applies the filter object, typically acting as a filter.

Inputs: (1) aref of input items to be operated on (2) method to use to apply filter to input items (optional) defaults to method specified inside the filter

Return: aref of output items

save

Saves a copy of the filter to the using the storage_handler stored inside the object.

basic setters and getters

name

Getter for object attribute name

set_name

Setter for object attribute set_name

method

Getter for object attribute method

set_method

Setter for object attribute set_method

description

Getter for object attribute description

set_description

Setter for object attribute set_description

terms

Getter for object attribute terms

set_terms

Setter for object attribute set_terms

modifiers

Getter for object attribute modifiers

set_modifiers

Setter for object attribute set_modifiers

dispatcher

Getter for object attribute dispatcher

set_dispatcher

Setter for object attribute set_dispatcher

storage_handler

Getter for object attribute storage_handler

set_storage_handler

Setter for object attribute set_storage_handler

save_filters_when_used

Getter for object attribute save_filters_when_used

set_save_filters_when_used

Setter for object attribute set_save_filters_when_used

MOTIVATION

Why not just an href?

Why do we have List::Filter objects instead of just filter hash references? There's the usual reasoning of using abstraction to preserve flexibility (later, implementation can be changed from href to aref, qualification code might be added to the accessors, and so on).

It also makes a convenient place to ensure that a "lock_keys" has been done before the href is used (to help catch typos during development).

Why not a fixed method?

A more interesting question is why is there a "method" attribute for each filter? A more standard OOP approach to this kind of polymorphism (each filter is supposed to know it should be used) would be to simply have a class for each type of filter.

This would be inelegant for a few reasons:

(1) it would make the use of the filters more rigid. the internally specified "method" name is only the default way the filter should be applied, there are cases where you might like to deviate from it (e.g. you might invert an "omit" filter to do a "select" to check just what it is you've been skipping).

(2) it would multiply classes for no good reason, and I think it would make it a little clumsier to add new Filter "methods".

the storage handler framework (lookup/save)

Each filter can hold a pointer to it's "storage handler", which is intended to be set by the "lookup" method of that handler as the filter is returned. This gives the filter the capability to save itself later, and that's not as crazy as it sounds (not quite) because there's a path of storage locations, and the place it's read from need not be where it's saved to).

The way it works normally (?) is that the storage handler instructs the filter that when it is applied it will save a copy of itself. The storage write location is most likely going to be a yaml file that the user has access to, but the storage read location can be somewhere else (e.g. a "standard" filter, which is defined in the code, and hence not writeable). The idea here is that any filter that you've used, you get an accessible copy of, suitable for editing if you'd like to make changes.

SEE ALSO

List::Filter::Project List::Filter::Dispatcher

AUTHOR

Joseph Brenner, <doom@kzsu.stanford.edu>

COPYRIGHT AND LICENSE

Copyright (C) 2007 by Joseph Brenner

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.2 or, at your option, any later version of Perl 5 you may have available.

BUGS

None reported... yet.

1 POD Error

The following errors were encountered while parsing the POD:

Around line 551:

You forgot a '=back' before '=head1'