File Coverage

inc/Test/Base.pm
Criterion Covered Total %
statement 218 378 57.6
branch 51 188 27.1
condition 16 83 19.2
subroutine 38 63 60.3
pod 0 29 0.0
total 323 741 43.5


line stmt bran cond sub pod time code
1             #line 1
2             # TODO:
3             #
4 4     4   2926 package Test::Base;
  4         14  
  4         197  
5 4     4   2401 use 5.006001;
  4         114  
  4         26  
6 4     4   41 use Spiffy 0.30 -Base;
  4     4   7  
  4     4   134  
  4         21  
  4         9  
  4         120  
  4         19  
  4         7  
  4         20  
7             use Spiffy ':XXX';
8             our $VERSION = '0.59';
9              
10             my @test_more_exports;
11 4     4   100 BEGIN {
12             @test_more_exports = qw(
13             ok isnt like unlike is_deeply cmp_ok
14             skip todo_skip pass fail
15             eq_array eq_hash eq_set
16             plan can_ok isa_ok diag
17             use_ok
18             $TODO
19             );
20             }
21 4     4   2994  
  4         13  
  4         38  
22 4     4   24 use Test::More import => \@test_more_exports;
  4         6  
  4         1999  
23             use Carp;
24              
25             our @EXPORT = (@test_more_exports, qw(
26             is no_diff
27              
28             blocks next_block first_block
29             delimiters spec_file spec_string
30             filters filters_delay filter_arguments
31             run run_compare run_is run_is_deeply run_like run_unlike
32             skip_all_unless_require is_deep run_is_deep
33             WWW XXX YYY ZZZ
34             tie_output no_diag_on_only
35              
36             find_my_self default_object
37              
38             croak carp cluck confess
39             ));
40              
41             field '_spec_file';
42             field '_spec_string';
43             field _filters => [qw(norm trim)];
44             field _filters_map => {};
45             field spec =>
46             -init => '$self->_spec_init';
47             field block_list =>
48             -init => '$self->_block_list_init';
49             field _next_list => [];
50             field block_delim =>
51             -init => '$self->block_delim_default';
52             field data_delim =>
53             -init => '$self->data_delim_default';
54             field _filters_delay => 0;
55             field _no_diag_on_only => 0;
56              
57             field block_delim_default => '===';
58             field data_delim_default => '---';
59              
60             my $default_class;
61             my $default_object;
62             my $reserved_section_names = {};
63 65     65 0 102  
64 65   66     247 sub default_object {
65 65         134 $default_object ||= $default_class->new;
66             return $default_object;
67             }
68              
69             my $import_called = 0;
70 4     4   46 sub import() {
71 4 50       32 $import_called = 1;
72             my $class = (grep /^-base$/i, @_)
73             ? scalar(caller)
74 4 50       24 : $_[0];
75 4         9 if (not defined $default_class) {
76             $default_class = $class;
77             }
78             # else {
79             # croak "Can't use $class after using $default_class"
80             # unless $default_class->isa($class);
81             # }
82 4 50       20  
83 4         8 unless (grep /^-base$/i, @_) {
84 4         21 my @args;
85 0 0       0 for (my $ii = 1; $ii <= $#_; ++$ii) {
86 0         0 if ($_[$ii] eq '-package') {
87             ++$ii;
88 0         0 } else {
89             push @args, $_[$ii];
90             }
91 4 50       16 }
92             Test::More->import(import => \@test_more_exports, @args)
93             if @args;
94             }
95 4         16
96 4         87 _strict_warnings();
97             goto &Spiffy::import;
98             }
99              
100             # Wrap Test::Builder::plan
101             my $plan_code = \&Test::Builder::plan;
102             my $Have_Plan = 0;
103 4     4   22 {
  4         9  
  4         15402  
104             no warnings 'redefine';
105 4     4   11 *Test::Builder::plan = sub {
106 4         28 $Have_Plan = 1;
107             goto &$plan_code;
108             };
109             }
110              
111             my $DIED = 0;
112             $SIG{__DIE__} = sub { $DIED = 1; die @_ };
113 79     79 0 100  
  79         158  
114 499     499 0 606 sub block_class { $self->find_class('Block') }
  499         1023  
115             sub filter_class { $self->find_class('Filter') }
116 578     578 0 680  
117 578         632 sub find_class {
118 578         1175 my $suffix = shift;
119 578 100       1817 my $class = ref($self) . "::$suffix";
120 4         12 return $class if $class->can('new');
121 4 50       32 $class = __PACKAGE__ . "::$suffix";
122 4         363 return $class if $class->can('new');
123 4 50       51 eval "require $class";
124 0         0 return $class if $class->can('new');
125             die "Can't find a class for $suffix";
126             }
127 0     0 0 0  
128 0 0       0 sub check_late {
129 0         0 if ($self->{block_list}) {
130 0         0 my $caller = (caller(1))[3];
131 0         0 $caller =~ s/.*:://;
132             croak "Too late to call $caller()"
133             }
134             }
135              
136 65 50   65 0 314 sub find_my_self() {
137             my $self = ref($_[0]) eq $default_class
138             ? splice(@_, 0, 1)
139 65         259 : default_object();
140             return $self, @_;
141             }
142              
143 4     4 0 46 sub blocks() {
144             (my ($self), @_) = find_my_self(@_);
145 4 50       21  
146             croak "Invalid arguments passed to 'blocks'"
147 4 50 33     24 if @_ > 1;
148             croak sprintf("'%s' is invalid argument to blocks()", shift(@_))
149             if @_ && $_[0] !~ /^[a-zA-Z]\w*$/;
150 4         230  
151             my $blocks = $self->block_list;
152 4   50     34
153 0         0 my $section_name = shift || '';
154 4 50       28 my @blocks = $section_name
155             ? (grep { exists $_->{$section_name} } @$blocks)
156             : (@$blocks);
157 4 50       66  
158             return scalar(@blocks) unless wantarray;
159 0 0       0
160             return (@blocks) if $self->_filters_delay;
161 0         0  
162 0 0       0 for my $block (@blocks) {
163             $block->run_filters
164             unless $block->is_filtered;
165             }
166 0         0  
167             return (@blocks);
168             }
169              
170 0     0 0 0 sub next_block() {
171 0         0 (my ($self), @_) = find_my_self(@_);
172 0 0       0 my $list = $self->_next_list;
173 0         0 if (@$list == 0) {
  0         0  
174 0         0 $list = [@{$self->block_list}, undef];
175             $self->_next_list($list);
176 0         0 }
177 0 0 0     0 my $block = shift @$list;
178 0         0 if (defined $block and not $block->is_filtered) {
179             $block->run_filters;
180 0         0 }
181             return $block;
182             }
183              
184 0     0 0 0 sub first_block() {
185 0         0 (my ($self), @_) = find_my_self(@_);
186 0         0 $self->_next_list([]);
187             $self->next_block;
188             }
189              
190 0     0 0 0 sub filters_delay() {
191 0 0       0 (my ($self), @_) = find_my_self(@_);
192             $self->_filters_delay(defined $_[0] ? shift : 1);
193             }
194              
195 0     0 0 0 sub no_diag_on_only() {
196 0 0       0 (my ($self), @_) = find_my_self(@_);
197             $self->_no_diag_on_only(defined $_[0] ? shift : 1);
198             }
199              
200 0     0 0 0 sub delimiters() {
201 0         0 (my ($self), @_) = find_my_self(@_);
202 0         0 $self->check_late;
203 0   0     0 my ($block_delimiter, $data_delimiter) = @_;
204 0   0     0 $block_delimiter ||= $self->block_delim_default;
205 0         0 $data_delimiter ||= $self->data_delim_default;
206 0         0 $self->block_delim($block_delimiter);
207 0         0 $self->data_delim($data_delimiter);
208             return $self;
209             }
210              
211 0     0 0 0 sub spec_file() {
212 0         0 (my ($self), @_) = find_my_self(@_);
213 0         0 $self->check_late;
214 0         0 $self->_spec_file(shift);
215             return $self;
216             }
217              
218 0     0 0 0 sub spec_string() {
219 0         0 (my ($self), @_) = find_my_self(@_);
220 0         0 $self->check_late;
221 0         0 $self->_spec_string(shift);
222             return $self;
223             }
224              
225 3     3 0 14 sub filters() {
226 3 50       25 (my ($self), @_) = find_my_self(@_);
227 3         105 if (ref($_[0]) eq 'HASH') {
228             $self->_filters_map(shift);
229             }
230 0         0 else {
231 0         0 my $filters = $self->_filters;
232             push @$filters, @_;
233 3         487 }
234             return $self;
235             }
236              
237 0     0 0 0 sub filter_arguments() {
238             $Test::Base::Filter::arguments;
239             }
240 0     0 0 0  
241 0 0 0     0 sub have_text_diff {
  0         0  
  0         0  
242             eval { require Text::Diff; 1 } &&
243             $Text::Diff::VERSION >= 0.35 &&
244             $Algorithm::Diff::VERSION >= 1.15;
245             }
246              
247 54     54 0 168 sub is($$;$) {
248 54         121 (my ($self), @_) = find_my_self(@_);
249 54         98 my ($actual, $expected, $name) = @_;
250 54 50 33     5758 local $Test::Builder::Level = $Test::Builder::Level + 1;
      33        
      33        
      33        
      33        
251             if ($ENV{TEST_SHOW_NO_DIFFS} or
252             not defined $actual or
253             not defined $expected or
254             $actual eq $expected or
255             not($self->have_text_diff) or
256             $expected !~ /\n./s
257 54         649 ) {
258             Test::More::is($actual, $expected, $name);
259             }
260 0 0       0 else {
261 0         0 $name = '' unless defined $name;
262             ok $actual eq $expected,
263             $name . "\n" . Text::Diff::diff(\$expected, \$actual);
264             }
265             }
266              
267 4     4 0 19 sub run(&;$) {
268 4         12 (my ($self), @_) = find_my_self(@_);
269 4         8 my $callback = shift;
  4         125  
270 79 50       2536 for my $block (@{$self->block_list}) {
271 79         144 $block->run_filters unless $block->is_filtered;
  79         239  
272             &{$callback}($block);
273             }
274             }
275              
276 0     0   0 my $name_error = "Can't determine section names";
277 0 0       0 sub _section_names {
278 0 0       0 return @_ if @_ == 2;
279             my $block = $self->first_block
280 0         0 or croak $name_error;
281 0 0       0 my @names = grep {
282 0         0 $_ !~ /^(ONLY|LAST|SKIP)$/;
283 0 0       0 } @{$block->{_section_order}[0] || []};
284             croak "$name_error. Need two sections in first block"
285 0         0 unless @names == 2;
286             return @names;
287             }
288 0     0   0  
289 0 0       0 sub _assert_plan {
290             plan('no_plan') unless $Have_Plan;
291             }
292 4     4   14  
293 4 0 33     37 sub END {
      33        
294             run_compare() unless $Have_Plan or $DIED or not $import_called;
295             }
296              
297 0     0 0 0 sub run_compare() {
298 0         0 (my ($self), @_) = find_my_self(@_);
299 0         0 $self->_assert_plan;
300 0         0 my ($x, $y) = $self->_section_names(@_);
301 0         0 local $Test::Builder::Level = $Test::Builder::Level + 1;
  0         0  
302 0 0 0     0 for my $block (@{$self->block_list}) {
303 0 0       0 next unless exists($block->{$x}) and exists($block->{$y});
304 0 0       0 $block->run_filters unless $block->is_filtered;
    0          
305 0 0       0 if (ref $block->$x) {
306             is_deeply($block->$x, $block->$y,
307             $block->name ? $block->name : ());
308             }
309 0 0       0 elsif (ref $block->$y eq 'Regexp') {
310 0 0       0 my $regexp = ref $y ? $y : $block->$y;
311             like($block->$x, $regexp, $block->name ? $block->name : ());
312             }
313 0 0       0 else {
314             is($block->$x, $block->$y, $block->name ? $block->name : ());
315             }
316             }
317             }
318              
319 0     0 0 0 sub run_is() {
320 0         0 (my ($self), @_) = find_my_self(@_);
321 0         0 $self->_assert_plan;
322 0         0 my ($x, $y) = $self->_section_names(@_);
323 0         0 local $Test::Builder::Level = $Test::Builder::Level + 1;
  0         0  
324 0 0 0     0 for my $block (@{$self->block_list}) {
325 0 0       0 next unless exists($block->{$x}) and exists($block->{$y});
326 0 0       0 $block->run_filters unless $block->is_filtered;
327             is($block->$x, $block->$y,
328             $block->name ? $block->name : ()
329             );
330             }
331             }
332              
333 0     0 0 0 sub run_is_deeply() {
334 0         0 (my ($self), @_) = find_my_self(@_);
335 0         0 $self->_assert_plan;
336 0         0 my ($x, $y) = $self->_section_names(@_);
  0         0  
337 0 0 0     0 for my $block (@{$self->block_list}) {
338 0 0       0 next unless exists($block->{$x}) and exists($block->{$y});
339 0 0       0 $block->run_filters unless $block->is_filtered;
340             is_deeply($block->$x, $block->$y,
341             $block->name ? $block->name : ()
342             );
343             }
344             }
345              
346 0     0 0 0 sub run_like() {
347 0         0 (my ($self), @_) = find_my_self(@_);
348 0         0 $self->_assert_plan;
349 0         0 my ($x, $y) = $self->_section_names(@_);
  0         0  
350 0 0 0     0 for my $block (@{$self->block_list}) {
351 0 0       0 next unless exists($block->{$x}) and defined($y);
352 0 0       0 $block->run_filters unless $block->is_filtered;
353 0 0       0 my $regexp = ref $y ? $y : $block->$y;
354             like($block->$x, $regexp,
355             $block->name ? $block->name : ()
356             );
357             }
358             }
359              
360 0     0 0 0 sub run_unlike() {
361 0         0 (my ($self), @_) = find_my_self(@_);
362 0         0 $self->_assert_plan;
363 0         0 my ($x, $y) = $self->_section_names(@_);
  0         0  
364 0 0 0     0 for my $block (@{$self->block_list}) {
365 0 0       0 next unless exists($block->{$x}) and defined($y);
366 0 0       0 $block->run_filters unless $block->is_filtered;
367 0 0       0 my $regexp = ref $y ? $y : $block->$y;
368             unlike($block->$x, $regexp,
369             $block->name ? $block->name : ()
370             );
371             }
372             }
373              
374 0     0 0 0 sub skip_all_unless_require() {
375 0         0 (my ($self), @_) = find_my_self(@_);
376 0 0       0 my $module = shift;
377             eval "require $module; 1"
378             or Test::More::plan(
379             skip_all => "$module failed to load"
380             );
381             }
382              
383 0     0 0 0 sub is_deep() {
384 0         0 (my ($self), @_) = find_my_self(@_);
385 0         0 require Test::Deep;
386             Test::Deep::cmp_deeply(@_);
387             }
388              
389 0     0 0 0 sub run_is_deep() {
390 0         0 (my ($self), @_) = find_my_self(@_);
391 0         0 $self->_assert_plan;
392 0         0 my ($x, $y) = $self->_section_names(@_);
  0         0  
393 0 0 0     0 for my $block (@{$self->block_list}) {
394 0 0       0 next unless exists($block->{$x}) and exists($block->{$y});
395 0 0       0 $block->run_filters unless $block->is_filtered;
396             is_deep($block->$x, $block->$y,
397             $block->name ? $block->name : ()
398             );
399             }
400             }
401 4     4   25  
402 4         8 sub _pre_eval {
403 4 50       46 my $spec = shift;
404             return $spec unless $spec =~
405 0         0 s/\A\s*<<<(.*?)>>>\s*$//sm;
406 0         0 my $eval_code = $1;
407 0 0       0 eval "package main; $eval_code";
408 0         0 croak $@ if $@;
409             return $spec;
410             }
411 4     4   10  
412 4         120 sub _block_list_init {
413 4         23 my $spec = $self->spec;
414 4         137 $spec = $self->_pre_eval($spec);
415 4         1448 my $cd = $self->block_delim;
416 4         28 my @hunks = ($spec =~ /^(\Q${cd}\E.*?(?=^\Q${cd}\E|\z))/msg);
417 4         126 my $blocks = $self->_choose_blocks(@hunks);
418 4         7 $self->block_list($blocks); # Need to set early for possible filter use
419 4         12 my $seq = 1;
420 79         1735 for my $block (@$blocks) {
421 79         1769 $block->blocks_object($self);
422             $block->seq_num($seq++);
423 4         44 }
424             return $blocks;
425             }
426 4     4   10  
427 4         21 sub _choose_blocks {
428 4         18 my $blocks = [];
429 79         173 for my $hunk (@_) {
430 79 50       202 my $block = $self->_make_block($hunk);
431 0 0       0 if (exists $block->{ONLY}) {
432             diag "I found ONLY: maybe you're debugging?"
433 0         0 unless $self->_no_diag_on_only;
434             return [$block];
435 79 50       184 }
436 79         152 next if exists $block->{SKIP};
437 79 50       258 push @$blocks, $block;
438 0         0 if (exists $block->{LAST}) {
439             return $blocks;
440             }
441 4         14 }
442             return $blocks;
443             }
444 218     218   251  
445 218         261 sub _check_reserved {
446 218 50 33     1190 my $id = shift;
447             croak "'$id' is a reserved name. Use something else.\n"
448             if $reserved_section_names->{$id} or
449             $id =~ /^_/;
450             }
451 79     79   90  
452 79         112 sub _make_block {
453 79         2130 my $hunk = shift;
454 79         1947 my $cd = $self->block_delim;
455 79         201 my $dd = $self->data_delim;
456 79 50       737 my $block = $self->block_class->new;
457 79         176 $hunk =~ s/\A\Q${cd}\E[ \t]*(.*)\s+// or die;
458 79         1157 my $name = $1;
459 79         158 my @parts = split /^\Q${dd}\E +\(?(\w+)\)? *(.*)?\n/m, $hunk;
460 79   50     292 my $description = shift @parts;
461 79 50       317 $description ||= '';
462 79         114 unless ($description =~ /\S/) {
463             $description = $name;
464 79         443 }
465 79         209 $description =~ s/\s*\z//;
466             $block->set_value(description => $description);
467 79         119
468 79         113 my $section_map = {};
469 79         171 my $section_order = [];
470 218         457 while (@parts) {
471 218         457 my ($type, $filters, $value) = splice(@parts, 0, 3);
472 218 100       437 $self->_check_reserved($type);
473 218 50       363 $value = '' unless defined $value;
474 218 50       861 $filters = '' unless defined $filters;
475 218 50       437 if ($filters =~ /:(\s|\z)/) {
476             croak "Extra lines not allowed in '$type' section"
477 218         961 if $value =~ /\S/;
478 218 50       551 ($filters, $value) = split /\s*:(?:\s+|\z)/, $filters, 2;
479 218         1658 $value = '' unless defined $value;
480             $value =~ s/^\s*(.*?)\s*$/$1/;
481 218         775 }
482             $section_map->{$type} = {
483             filters => $filters,
484 218         393 };
485 218         448 push @$section_order, $type;
486             $block->set_value($type, $value);
487 79         168 }
488 79         157 $block->set_value(name => $name);
489 79         160 $block->set_value(_section_map => $section_map);
490 79         238 $block->set_value(_section_order => $section_order);
491             return $block;
492             }
493 4     4   12  
494 4 50       121 sub _spec_init {
495             return $self->_spec_string
496 4         17 if $self->_spec_string;
497 4         9 local $/;
498 4 50       114 my $spec;
499 0 0       0 if (my $spec_file = $self->_spec_file) {
500 0         0 open FILE, $spec_file or die $!;
501 0         0 $spec = ;
502             close FILE;
503             }
504 4         22 else {
505             $spec = do {
506 4     4   32 package main;
  4         9  
  4         1845  
507 4         167 no warnings 'once';
508             ;
509             };
510 4         34 }
511             return $spec;
512             }
513              
514 4     4   33 sub _strict_warnings() {
515 4         8 require Filter::Util::Call;
516             my $done = 0;
517             Filter::Util::Call::filter_add(
518 4 50   4   19 sub {
519 4         10 return 0 if $done;
520 4         66 my ($data, $end) = ('', '');
521 79 50       163 while (my $status = Filter::Util::Call::filter_read()) {
522 79 100       173 return $status if $status < 0;
523 4         8 if (/^__(?:END|DATA)__\r?$/) {
524 4         10 $end = $_;
525             last;
526 75         97 }
527 75         211 $data .= $_;
528             $_ = '';
529 4         15 }
530 4         142 $_ = "use strict;use warnings;$data$end";
531             $done = 1;
532 4         35 }
533             );
534             }
535              
536 0     0 0 0 sub tie_output() {
537 0 0       0 my $handle = shift;
538 0         0 die "No buffer to tie" unless @_;
539             tie $handle, 'Test::Base::Handle', $_[0];
540             }
541 0     0 0 0  
542 0         0 sub no_diff {
543             $ENV{TEST_SHOW_NO_DIFFS} = 1;
544             }
545              
546             package Test::Base::Handle;
547              
548 0     0   0 sub TIEHANDLE() {
549 0         0 my $class = shift;
550             bless \ $_[0], $class;
551             }
552 0     0   0  
553 0         0 sub PRINT {
554             $$self .= $_ for @_;
555             }
556              
557             #===============================================================================
558             # Test::Base::Block
559             #
560             # This is the default class for accessing a Test::Base block object.
561             #===============================================================================
562             package Test::Base::Block;
563             our @ISA = qw(Spiffy);
564              
565             our @EXPORT = qw(block_accessor);
566 0     0   0  
567 0         0 sub AUTOLOAD {
568             return;
569             }
570              
571 26     26   46 sub block_accessor() {
572 4     4   22 my $accessor = shift;
  4         14  
  4         747  
573 26 50       109 no strict 'refs';
574             return if defined &$accessor;
575 701     701   31198 *$accessor = sub {
576 701 50       1368 my $self = shift;
577 0         0 if (@_) {
578             Carp::croak "Not allowed to set values for '$accessor'";
579 701 100       700 }
  701         2452  
580             my @list = @{$self->{$accessor} || []};
581 701 100       2696 return wantarray
582             ? (@list)
583 26         235 : $list[0];
584             };
585             }
586              
587             block_accessor 'name';
588             block_accessor 'description';
589             Spiffy::field 'seq_num';
590             Spiffy::field 'is_filtered';
591             Spiffy::field 'blocks_object';
592             Spiffy::field 'original_values' => {};
593 1033     1033   1247  
594 4     4   26 sub set_value {
  4         11  
  4         858  
595 1033         1268 no strict 'refs';
596 1033 100       2606 my $accessor = shift;
597             block_accessor $accessor
598 1033         4391 unless defined &$accessor;
599             $self->{$accessor} = [@_];
600             }
601 79     79   136  
602 79         212 sub run_filters {
603 79         215 my $map = $self->_section_map;
604 79 50       1937 my $order = $self->_section_order;
605             Carp::croak "Attempt to filter a block twice"
606 79         176 if $self->is_filtered;
607 218         558 for my $type (@$order) {
608 218         597 my $filters = $map->{$type}{filters};
609 218         14770 my @value = $self->$type;
610 218         610 $self->original_values->{$type} = $value[0];
611 499 50       1029 for my $filter ($self->_get_filters($type, $filters)) {
612             $Test::Base::Filter::arguments =
613 499         734 $filter =~ s/=(.*)$// ? $1 : undef;
614 4     4   21 my $function = "main::$filter";
  4         10  
  4         2353  
615 499 50       2147 no strict 'refs';
616 0 0 0     0 if (defined &$function) {
617             local $_ =
618             (@value == 1 and not defined($value[0])) ? undef :
619 0         0 join '', @value;
620 0         0 my $old = $_;
621 0 0 0     0 @value = &$function(@value);
      0        
      0        
622             if (not(@value) or
623             @value == 1 and defined($value[0]) and $value[0] =~ /\A(\d+|)\z/
624 0 0 0     0 ) {
625 0         0 if ($value[0] && $_ eq $old) {
626             Test::Base::diag("Filters returning numbers are supposed to do munging \$_: your filter '$function' apparently doesn't.");
627 0         0 }
628             @value = ($_);
629             }
630             }
631 499         11527 else {
632 499 50       1464 my $filter_object = $self->blocks_object->filter_class->new;
633             die "Can't find a function or method for '$filter' filter\n"
634 499         12038 unless $filter_object->can($filter);
635 499         1787 $filter_object->current_block($self);
636             @value = $filter_object->$filter(@value);
637             }
638             # Set the value after each filter since other filters may be
639 499         1330 # introspecting.
640             $self->set_value($type, @value);
641             }
642 79         1884 }
643             $self->is_filtered(1);
644             }
645 218     218   351  
646 218         278 sub _get_filters {
647 218   50     774 my $type = shift;
648 218         902 my $string = shift || '';
649 218         352 $string =~ s/\s*(.*?)\s*/$1/;
650 218   100     5256 my @filters = ();
651 218 50       545 my $map_filters = $self->blocks_object->_filters_map->{$type} || [];
652 218         304 $map_filters = [ $map_filters ] unless ref $map_filters;
653 218         261 my @append = ();
654 218         5149 for (
655             @{$self->blocks_object->_filters},
656             @$map_filters,
657             split(/\s+/, $string),
658 499         544 ) {
659 499 50       999 my $filter = $_;
660 499 50       1227 last unless length $filter;
    50          
661 0         0 if ($filter =~ s/^-//) {
  0         0  
662             @filters = grep { $_ ne $filter } @filters;
663             }
664 0         0 elsif ($filter =~ s/^\+//) {
665             push @append, $filter;
666             }
667 499         989 else {
668             push @filters, $filter;
669             }
670 218         849 }
671             return @filters, @append;
672             }
673              
674             {
675             %$reserved_section_names = map {
676             ($_, 1);
677             } keys(%Test::Base::Block::), qw( new DESTROY );
678             }
679              
680             __DATA__