File Coverage

lib/Badger/Filter.pm
Criterion Covered Total %
statement 73 91 80.2
branch 31 48 64.5
condition 12 19 63.1
subroutine 13 13 100.0
pod 7 10 70.0
total 136 181 75.1


line stmt bran cond sub pod time code
1             package Badger::Filter;
2              
3             use Badger::Class
4 2         15 version => 0.01,
5             debug => 0,
6             import => 'class',
7             base => 'Badger::Base',
8             utils => 'is_object',
9             constants => 'NONE ALL TRUE FALSE CODE REGEX ARRAY HASH',
10             constant => {
11             FILTER => 'Badger::Filter',
12             },
13             exports => {
14             any => 'FILTER Filter',
15 2     2   469 };
  2         4  
16              
17              
18             sub Filter {
19 4 50   4 0 35 return FILTER unless @_;
20 4 50 33     18 return @_ == 1 && is_object(FILTER, $_[0])
21             ? $_[0] # return existing Filter object
22             : FILTER->new(@_); # or construct a new one
23             }
24              
25             #-----------------------------------------------------------------------------
26             # Initialisation methods
27             #-----------------------------------------------------------------------------
28              
29             sub init {
30 5     5 1 9 my ($self, $config) = @_;
31 5         14 my $class = $self->class;
32 5         12 my $accept = $config->{ accept };
33 5         6 my ($include, $exclude);
34              
35 5 100       11 if ($accept) {
36 2 100       23 if ($accept eq ALL) {
    50          
37             # default behaviour - no include, no exclude
38             }
39             elsif ($accept eq NONE) {
40 1         3 $exclude = '*';
41             }
42             else {
43             # list of "item" (include), "-item" (exclude) or "+item" (include)
44 0         0 my @items = split(/[^\w\-\+]+/, $accept);
45 0         0 my (@inc, @exc);
46              
47 0         0 foreach my $item (@items) {
48 0 0       0 if ($item =~ s/^\-//) { push(@exc, $item); }
  0 0       0  
49 0         0 elsif ($item =~ s/^\+//) { push(@inc, $item); }
50 0         0 else { push(@inc, $item); }
51             }
52 0 0       0 $include = \@inc if @inc;
53 0 0       0 $exclude = \@exc if @exc;
54             }
55             }
56             else {
57             $include = $class->list_vars(
58             INCLUDE => $config->{ include }
59 3         12 );
60             $exclude = $class->list_vars(
61             EXCLUDE => $config->{ exclude }
62 3         13 );
63             }
64              
65 5 100       18 $self->{ include } = $self->init_filter_set(
66             include => $include
67             ) if $include;
68              
69 5 100       13 $self->{ exclude } = $self->init_filter_set(
70             exclude => $exclude
71             ) if $exclude;
72              
73 5         13 return $self;
74             }
75              
76             sub init_filter_set {
77 7     7 0 16 my ($self, $name, @items) = @_;
78 7         10 my $static = { };
79 7         9 my $dynamic = [ ];
80 7         9 my $n = 0;
81              
82 7         6 $self->debug(
83             "init_filter_set($name) : ",
84             $self->dump_data(\@items)
85             ) if DEBUG;
86              
87 7         20 while (@items) {
88 18         27 my $item = shift @items;
89              
90 18 100       61 if (! ref $item) {
    100          
    50          
    100          
    50          
91 7 100       19 if ((my $copy = $item) =~ s/\*/.*/g) {
92 2     10   12 push(@$dynamic, sub { $_[0] =~ /^$copy$/ });
  10         92  
93 2         4 $self->debug("$name: set wildcard item: $item") if DEBUG;
94             }
95             else {
96 5         10 $static->{ $item } = 1;
97 5         4 $self->debug("$name: set static item: $item") if DEBUG;
98             }
99 7         13 $n++;
100             }
101             elsif (ref $item eq ARRAY) {
102 6         13 unshift(@items, @$item);
103 6         10 $self->debug("$name: expanded array: ", $self->dump_data($item)) if DEBUG;
104             }
105             elsif (ref $item eq HASH) {
106             my $truly = {
107 0         0 map { @$_ } # unpack key and value
108 0         0 grep { $_[1] } # only accept true value
109 0         0 map { [$_, $item->{ $_ }] } # pack key and value
  0         0  
110             keys %$item
111             };
112 0         0 @$static{ keys %$truly } = map { 1 } values %$truly;
  0         0  
113 0         0 $n += scalar keys %$truly;
114 0         0 $self->debug("$name: set hash of true items: ", $self->dump_data($truly)) if DEBUG;
115             }
116             elsif (ref $item eq CODE) {
117 2         15 push(@$dynamic, $item);
118 2         1 $n++;
119 2         13 $self->debug("$name: added code ref: $item") if DEBUG;
120             }
121             elsif (ref $item eq REGEX) {
122 3         3 my $regex = $item;
123 3     75   23 push(@$dynamic, sub { $_[0] =~ $regex });
  75         332  
124 3         3 $n++;
125 3         6 $self->debug("$name: added regex: $item") if DEBUG;
126             }
127             else {
128 0         0 return $self->error_msg( invalid => $name => $item );
129             }
130             }
131              
132 7 100       24 return undef unless $n;
133              
134 5         23 my $set = {
135             static => $static,
136             dynamic => $dynamic,
137             };
138              
139 5         6 $self->debug(
140             "init_filter_set($name) $n items: ",
141             $self->dump_data($set)
142             ) if DEBUG;
143              
144 5         15 return $set;
145             }
146              
147              
148             #-----------------------------------------------------------------------------
149             # List filtering methods
150             #-----------------------------------------------------------------------------
151              
152             sub accept {
153 5     5 1 55 my $self = shift;
154 5 50 33     22 my $items = (@_ == 1 && ref $_[0] eq ARRAY) ? shift : [@_];
155 5         11 my @accept = grep { $self->item_accepted($_) } @$items;
  56         91  
156             return wantarray
157             ? @accept
158 5 50       39 : \@accept;
159             }
160              
161             sub reject {
162 1     1 1 24 my $self = shift;
163 1 50 33     19 my $items = (@_ == 1 && ref $_[0] eq ARRAY) ? shift : [@_];
164 1         7 my @reject = grep { $self->item_rejected($_) } @$items;
  21         31  
165             return wantarray
166             ? @reject
167 1 50       12 : \@reject;
168             }
169              
170              
171             #-----------------------------------------------------------------------------
172             # Item filtering methods
173             #-----------------------------------------------------------------------------
174              
175             sub item_accepted {
176 77     77 1 105 my ($self, $item) = @_;
177 77   100     98 return $self->item_included($item)
178             && !$self->item_excluded($item);
179             }
180              
181             sub item_rejected {
182 21     21 1 28 ! shift->item_accepted(@_);
183             }
184              
185             sub item_included {
186 77     77 1 77 my $self = shift;
187 77   100     134 my $include = $self->{ include } || return TRUE;
188 69         96 return $self->check_item($include, @_);
189             }
190              
191             sub item_excluded {
192 37     37 1 53 my $self = shift;
193 37   100     80 my $exclude = $self->{ exclude } || return FALSE;
194 26         48 return $self->check_item($exclude, @_);
195             }
196              
197             sub check_item {
198 95     95 0 111 my ($self, $checks, $item) = @_;
199              
200 95         88 $self->debug(
201             "check [$item] via ",
202             $self->dump_data($checks)
203             ) if DEBUG;
204              
205             return TRUE
206             if $checks->{ static }->{ $item }
207 95 100 66     272 || $checks->{ static }->{"*"};
208              
209 85         95 foreach my $check (@{ $checks->{ dynamic } }) {
  85         127  
210 123         127 $self->debug("check: $check") if DEBUG;
211 123 100       148 return TRUE
212             if $check->($item);
213             }
214              
215 56         265 return FALSE;
216             }
217              
218              
219             1;
220              
221             __END__