File Coverage

blib/lib/Data/Transform/Grep.pm
Criterion Covered Total %
statement 37 37 100.0
branch 28 28 100.0
condition 12 17 70.5
subroutine 9 9 100.0
pod 3 3 100.0
total 89 94 94.6


line stmt bran cond sub pod time code
1             # vim: ts=3 sw=3 expandtab
2             # 2001/01/25 shizukesa@pobox.com
3             package Data::Transform::Grep;
4 2     2   3159 use strict;
  2         4  
  2         73  
5 2     2   588 use Data::Transform;
  2         5  
  2         53  
6              
7 2     2   12 use vars qw($VERSION @ISA);
  2         3  
  2         150  
8             $VERSION = '0.01';
9             @ISA = qw(Data::Transform);
10              
11 2     2   11 use Carp qw(croak carp);
  2         22  
  2         1785  
12              
13             sub BUFFER () { 0 }
14             sub CODEGET () { 1 }
15             sub CODEPUT () { 2 }
16              
17             =head1 NAME
18              
19             Data::Transform::Grep - select or remove items based on simple rules
20              
21             =head1 SYNOPSIS
22              
23             my $filter = Data::Transform::Grep->new(
24             Put => sub { 1 },
25             Get => sub { $_[0] =~ /ba/ },
26             );
27            
28             my $out = $filter->get([qw(foo bar baz)]);
29             # is($out, [qw(bar baz)], "only stuff with 'ba' in it");
30              
31             =head1 DESCRIPTION
32              
33             Data::Transform::Grep selects or removes items based on simple tests. It
34             may be used to filter input, output, or both. This filter is named
35             and modeled after Perl's built-in grep() function.
36              
37             =head1 PUBLIC FILTER METHODS
38              
39             Data::Transform::Grep implements the L API. Only
40             differences and additions to the API are documented here.
41              
42             =cut
43              
44             =head2 new
45              
46             new() constructs a new Data::Transform::Grep object. It must either be
47             called with a single Code parameter, or both a Put and a Get
48             parameter. The values for Code, Put, and Get are code references
49             that, when invoked, return true to select an item or false to reject
50             it. A Code function will be used for both input and output, while Get
51             and Put functions allow input and output to be filtered in different
52             ways. The item in question will be passed as the function's sole
53             parameter.
54              
55             sub reject_bidoofs {
56             my $pokemon = shift;
57             return 1 if $pokemon ne "bidoof";
58             return;
59             }
60              
61             my $gotta_catch_nearly_all = Data::Transform::Grep->new(
62             Code => \&reject_bidoofs,
63             );
64              
65             Enforce read-only behavior:
66              
67             my $read_only = Data::Transform::Grep->new(
68             Get => sub { 1 },
69             Put => sub { 0 },
70             );
71              
72             =cut
73              
74             sub new {
75 12     12 1 9958 my $type = shift;
76 12 100       183 croak "$type must be given an even number of parameters" if @_ & 1;
77 11         28 my %params = @_;
78              
79 11 100 100     549 croak "$type requires a Code or both Get and Put parameters" unless (
      66        
80             defined($params{Code}) or
81             (defined($params{Get}) and defined($params{Put}))
82             );
83 8 100       181 croak "Code element is not a subref"
    100          
84             unless (defined $params{Code} ? ref $params{Code} eq 'CODE' : 1);
85 7 100 66     364 croak "Get or Put element is not a subref"
    100          
    100          
86             unless ((defined $params{Get} ? (ref $params{Get} eq 'CODE') : 1)
87             and (defined $params{Put} ? (ref $params{Put} eq 'CODE') : 1));
88              
89 5   66     67 my $self = bless [
      66        
90             [ ], # BUFFER
91             $params{Code} || $params{Get}, # CODEGET
92             $params{Code} || $params{Put}, # CODEPUT
93             ], $type;
94             }
95              
96             sub clone {
97 3     3 1 1351 my $self = shift;
98              
99 3         10 my $new = [
100             [],
101             $self->[CODEGET],
102             $self->[CODEPUT],
103             ];
104              
105 3         17 return bless $new, ref $self;
106             }
107              
108             # get() is inherited from Data::Transform.
109             # get_one_start() is inherited from Data::Transform.
110             # get_one() is inherited from Data::Transform.
111              
112             sub _handle_get_data {
113 125     125   162 my ($self, $data) = @_;
114              
115             # Must be a loop so that the buffer will be altered as items are
116             # tested.
117 125 100       383 return unless (defined $data);
118 64 100       168 return $data if ($self->[CODEGET]->($data));
119 22         128 return;
120             }
121              
122             sub _handle_put_data {
123 40     40   66 my ($self, $data) = @_;
124 40 100       101 return $data if $self->[CODEPUT]->($data);
125 13         88 return;
126             }
127              
128             =head2 modify
129              
130             modify() changes a Data::Transform::Grep object's behavior at runtime. It
131             accepts the same parameters as new(), and it replaces the existing
132             tests with new ones.
133              
134             # Don't give away our Dialgas.
135             $gotta_catch_nearly_all->modify(
136             Get => sub { 1 },
137             Put => sub { return shift() ne "dialga" },
138             );
139              
140             =cut
141              
142             sub modify {
143 7     7 1 3982 my ($self, %params) = @_;
144              
145 7         18 for (keys %params) {
146 7 100 50     511 (carp("Modify $_ element must be given a coderef") and next) unless (ref $params{$_} eq 'CODE');
147 4 100       24 if (lc eq 'code') {
    100          
    100          
148 1         3 $self->[CODEGET] = $params{$_};
149 1         7 $self->[CODEPUT] = $params{$_};
150             }
151             elsif (lc eq 'put') {
152 1         9 $self->[CODEPUT] = $params{$_};
153             }
154             elsif (lc eq 'get') {
155 1         7 $self->[CODEGET] = $params{$_};
156             }
157             }
158             }
159              
160             1;
161              
162             __END__