From 65a54c00d8083a96c18f02b7f43a4822e3f1fd9a Mon Sep 17 00:00:00 2001 From: Tom Ryder Date: Tue, 3 Oct 2017 15:13:57 +1300 Subject: First commit of List::Filters I'll add more Perl distribution infrastructure and tests as I learn more about how that all works. The README.markdown is just a manually converted README for now. --- lib/List/Filters.pm | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 lib/List/Filters.pm (limited to 'lib') diff --git a/lib/List/Filters.pm b/lib/List/Filters.pm new file mode 100644 index 0000000..aa59a49 --- /dev/null +++ b/lib/List/Filters.pm @@ -0,0 +1,220 @@ +package List::Filters; + +# Force me to write this properly +use strict; +use warnings; +use utf8; + +# Target reasonably old Perls +use 5.006; + +# Import required modules +use Carp; +use Exporter 'import'; + +# Specify package version +our $VERSION = 0.01; + +# Specify functions available for export +our @EXPORT_OK = 'filter'; + +# Dispatch table of functions to handle different ref types for the spec +# hashref's values +my %types = ( + + # If it's a hash, apply filter() again as if it were another root-level + # spec + HASH => sub { + my $spec = shift; + return { filter( $spec, @_ ) }; + }, + + # If it's a subroutine, return a arrayref of all elements for which it + # returns true + CODE => sub { + my $sub = shift; + return [ grep { $sub->() } @_ ]; + }, + + # If it's a regular expression, return an arrayref of all elements it + # matches + Regexp => sub { + my $re = shift; + return [ grep { $_ =~ $re } @_ ]; + }, +); + +# Given a spec and a list of items, filter them into a hash of the same +# structure +sub filter { + my ( $spec, @items ) = @_; + + # Check the spec is a hashref + ref $spec eq 'HASH' + or croak 'HASH reference expected for first argument'; + + # Start building a results hash + my %results; + for my $key ( keys %{$spec} ) { + + # Check that the value for this key is a reference + my $ref = ref $spec->{$key} + or croak "Reference expected for '$key'"; + + # Check it's a reference we understand + exists $types{$ref} + or croak "Unhandled ref type $ref for '$key'"; + + # Apply the appropriate subroutine for this reference type to the list + # of items + $results{$key} = $types{$ref}->( $spec->{$key}, @items ); + } + + # Return the constructed result set + return %results; +} + +1; + +__END__ + +=pod + +=for stopwords +sublists Unhandled tradename licensable MERCHANTABILITY + +=head1 NAME + +List::Filters - Build list sublists matching conditions + +=head1 VERSION + +Version 0.01 + +=head1 DESCRIPTION + +This module filters elements from a list non-uniquely into a specified hash +structure, which can be nested. It may be useful in situations where you have a +big list of things to generate reports on or to otherwise filter into several +sublists. + +It differs from the excellent C in that it does not require +only one final category for any given item; an item can be in more than one +filter. + +You could maybe think of it as a multi-C that returns named results. + +=head1 SYNOPSIS + + my @words = qw(foo bar baz quux wibble florb); + my $cats = { + all => sub { 1 }, + has_b => sub { m/ b /msx }, + has_w => sub { m/ w /msx }, + length => { + 3 => sub { length == 3 }, + 4 => sub { length == 4 }, + long => sub { length > 4 }, + }, + has_ba => qr/ba/msx, + }; + my %filterd = filter $cats, @words; + +=head1 SUBROUTINES/METHODS + +=head2 B + +Given a hash reference structure and a list of items, apply each of the +subroutines or regular expressions given as values of the hash reference, +returning a new hash in the same structure with the tests replaced with the +items that for which the subroutine was true or the regular expression matched. + +=head1 AUTHOR + +Tom Ryder C<< >> + +=head1 DIAGNOSTICS + +=over 4 + +=item HASH reference expected for first argument + +The first argument that B saw wasn't the hash reference it expects. +That's the only format a spec is allowed to have. + +=item Reference expected for '%s' + +The value for the named key in the spec was not a reference, and one was +expected. + +=item Unhandled ref type %s for '%s' + +The value for the named key in the spec is of a type that makes no sense to +this module. Legal reference types are C, C, and C. + +=back + +=head1 DEPENDENCIES + +Perl 5.6 and the core modules C and C. + +=head1 CONFIGURATION AND ENVIRONMENT + +None required. + +=head1 INCOMPATIBILITIES + +None known. + +=head1 BUGS AND LIMITATIONS + +Definitely. This is a very early release. Please report any bugs or feature +requests to C. + +=head1 SUPPORT + +You can find documentation for this module with the C command. + + perldoc List::Filters + +=head1 LICENSE AND COPYRIGHT + +Copyright (C) 2017 Tom Ryder + +This program is free software; you can redistribute it and/or modify it under +the terms of the the Artistic License (2.0). You may obtain a copy of the full +license at: + + + +Any use, modification, and distribution of the Standard or Modified Versions is +governed by this Artistic License. By using, modifying or distributing the +Package, you accept this license. Do not use, modify, or distribute the +Package, if you do not accept this license. + +If your Modified Version has been derived from a Modified Version made by +someone other than you, you are nevertheless required to ensure that your +Modified Version complies with the requirements of this license. + +This license does not grant you the right to use any trademark, service mark, +tradename, or logo of the Copyright Holder. + +This license includes the non-exclusive, worldwide, free-of-charge patent +license to make, have made, use, offer to sell, sell, import and otherwise +transfer the Package with respect to any patent claims licensable by the +Copyright Holder that are necessarily infringed by the Package. If you +institute patent litigation (including a cross-claim or counterclaim) against +any party alleging that the Package constitutes direct or contributory patent +infringement, then this Artistic License to you shall terminate on the date +that such litigation is filed. + +Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND +CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. +UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY +OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +=cut -- cgit v1.2.3