File Coverage

inc/Test/Base.pm
Criterion Covered Total %
statement 218 378 57.6
branch 53 188 28.1
condition 17 83 20.4
subroutine 38 63 60.3
pod 20 29 68.9
total 346 741 46.6


line stmt bran cond sub pod time code
1             #line 1
2             # TODO:
3             #
4 4     4   4576 package Test::Base;
  4         15  
  4         217  
5 4     4   3068 use 5.006001;
  4         142  
  4         32  
6 4     4   140 use Spiffy 0.30 -Base;
  4     4   11  
  4     4   185  
  4         23  
  4         8  
  4         328  
  4         23  
  4         10  
  4         28  
7             use Spiffy ':XXX';
8             our $VERSION = '0.59';
9              
10             my @test_more_exports;
11 4     4   109 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   3658  
  4         17  
  4         50  
22 4     4   116 use Test::More import => \@test_more_exports;
  4         8  
  4         1979  
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 22     22 1 52  
64 22   66     144 sub default_object {
65 22         55 $default_object ||= $default_class->new;
66             return $default_object;
67             }
68              
69             my $import_called = 0;
70 4     4   45 sub import() {
71 4 50       35 $import_called = 1;
72             my $class = (grep /^-base$/i, @_)
73             ? scalar(caller)
74 4 50       20 : $_[0];
75 4         10 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       24  
83 4         8 unless (grep /^-base$/i, @_) {
84 4         26 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         19
96 4         93 _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   27 {
  4         9  
  4         32913  
104             no warnings 'redefine';
105 4     4   12 *Test::Builder::plan = sub {
106 4         25 $Have_Plan = 1;
107             goto &$plan_code;
108             };
109             }
110              
111             my $DIED = 0;
112             $SIG{__DIE__} = sub { $DIED = 1; die @_ };
113 27     27 0 39  
  27         66  
114 268     268 0 412 sub block_class { $self->find_class('Block') }
  268         543  
115             sub filter_class { $self->find_class('Filter') }
116 295     295 0 1090  
117 295         531 sub find_class {
118 295         756 my $suffix = shift;
119 295 100       1995 my $class = ref($self) . "::$suffix";
120 4         13 return $class if $class->can('new');
121 4 50       29 $class = __PACKAGE__ . "::$suffix";
122 4         934 return $class if $class->can('new');
123 4 50       55 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 22 50   22 0 153 sub find_my_self() {
137             my $self = ref($_[0]) eq $default_class
138             ? splice(@_, 0, 1)
139 22         101 : default_object();
140             return $self, @_;
141             }
142              
143 4     4 1 46 sub blocks() {
144             (my ($self), @_) = find_my_self(@_);
145 4 50       22  
146             croak "Invalid arguments passed to 'blocks'"
147 4 50 33     20 if @_ > 1;
148             croak sprintf("'%s' is invalid argument to blocks()", shift(@_))
149             if @_ && $_[0] !~ /^[a-zA-Z]\w*$/;
150 4         145  
151             my $blocks = $self->block_list;
152 4   50     36
153 0         0 my $section_name = shift || '';
154 4 50       23 my @blocks = $section_name
155             ? (grep { exists $_->{$section_name} } @$blocks)
156             : (@$blocks);
157 4 50       48  
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 1 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 1 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 1 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 1 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 1 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 1 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 2     2 1 8 sub filters() {
226 2 50       11 (my ($self), @_) = find_my_self(@_);
227 2         68 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 2         8 }
234             return $self;
235             }
236              
237 0     0 1 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 12     12 1 23751 sub is($$;$) {
248 12         37 (my ($self), @_) = find_my_self(@_);
249 12         34 my ($actual, $expected, $name) = @_;
250 12 50 33     186 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 12         48 ) {
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 1 21 sub run(&;$) {
268 4         14 (my ($self), @_) = find_my_self(@_);
269 4         10 my $callback = shift;
  4         126  
270 27 50       106212 for my $block (@{$self->block_list}) {
271 27         63 $block->run_filters unless $block->is_filtered;
  27         158  
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   12660  
293 4 0 33     50 sub END {
      33        
294             run_compare() unless $Have_Plan or $DIED or not $import_called;
295             }
296              
297 0     0 1 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 1 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 1 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 1 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 1 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 1 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   11  
402 4         13 sub _pre_eval {
403 4 50       34 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         138 sub _block_list_init {
413 4         22 my $spec = $self->spec;
414 4         121 $spec = $self->_pre_eval($spec);
415 4         445 my $cd = $self->block_delim;
416 4         26 my @hunks = ($spec =~ /^(\Q${cd}\E.*?(?=^\Q${cd}\E|\z))/msg);
417 4         127 my $blocks = $self->_choose_blocks(@hunks);
418 4         9 $self->block_list($blocks); # Need to set early for possible filter use
419 4         15 my $seq = 1;
420 27         650 for my $block (@$blocks) {
421 27         667 $block->blocks_object($self);
422             $block->seq_num($seq++);
423 4         34 }
424             return $blocks;
425             }
426 4     4   9  
427 4         13 sub _choose_blocks {
428 4         13 my $blocks = [];
429 27         73 for my $hunk (@_) {
430 27 50       82 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 27 50       102 }
436 27         48 next if exists $block->{SKIP};
437 27 50       87 push @$blocks, $block;
438 0         0 if (exists $block->{LAST}) {
439             return $blocks;
440             }
441 4         17 }
442             return $blocks;
443             }
444 89     89   106  
445 89         115 sub _check_reserved {
446 89 50 33     493 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 27     27   39  
452 27         41 sub _make_block {
453 27         734 my $hunk = shift;
454 27         758 my $cd = $self->block_delim;
455 27         80 my $dd = $self->data_delim;
456 27 50       299 my $block = $self->block_class->new;
457 27         64 $hunk =~ s/\A\Q${cd}\E[ \t]*(.*)\s+// or die;
458 27         463 my $name = $1;
459 27         65 my @parts = split /^\Q${dd}\E +\(?(\w+)\)? *(.*)?\n/m, $hunk;
460 27   50     154 my $description = shift @parts;
461 27 50       67 $description ||= '';
462 27         41 unless ($description =~ /\S/) {
463             $description = $name;
464 27         107 }
465 27         82 $description =~ s/\s*\z//;
466             $block->set_value(description => $description);
467 27         50
468 27         44 my $section_map = {};
469 27         69 my $section_order = [];
470 89         204 while (@parts) {
471 89         206 my ($type, $filters, $value) = splice(@parts, 0, 3);
472 89 100       179 $self->_check_reserved($type);
473 89 50       166 $value = '' unless defined $value;
474 89 100       313 $filters = '' unless defined $filters;
475 38 50       86 if ($filters =~ /:(\s|\z)/) {
476             croak "Extra lines not allowed in '$type' section"
477 38         176 if $value =~ /\S/;
478 38 50       98 ($filters, $value) = split /\s*:(?:\s+|\z)/, $filters, 2;
479 38         362 $value = '' unless defined $value;
480             $value =~ s/^\s*(.*?)\s*$/$1/;
481 89         295 }
482             $section_map->{$type} = {
483             filters => $filters,
484 89         163 };
485 89         194 push @$section_order, $type;
486             $block->set_value($type, $value);
487 27         70 }
488 27         70 $block->set_value(name => $name);
489 27         60 $block->set_value(_section_map => $section_map);
490 27         101 $block->set_value(_section_order => $section_order);
491             return $block;
492             }
493 4     4   13  
494 4 50       130 sub _spec_init {
495             return $self->_spec_string
496 4         16 if $self->_spec_string;
497 4         9 local $/;
498 4 50       116 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         10 else {
505             $spec = do {
506 4     4   42 package main;
  4         8  
  4         2074  
507 4         87 no warnings 'once';
508             ;
509             };
510 4         35 }
511             return $spec;
512             }
513              
514 4     4   29 sub _strict_warnings() {
515 4         9 require Filter::Util::Call;
516             my $done = 0;
517             Filter::Util::Call::filter_add(
518 4 50   4   19 sub {
519 4         9 return 0 if $done;
520 4         108 my ($data, $end) = ('', '');
521 111 50       203 while (my $status = Filter::Util::Call::filter_read()) {
522 111 100       228 return $status if $status < 0;
523 4         10 if (/^__(?:END|DATA)__\r?$/) {
524 4         12 $end = $_;
525             last;
526 107         137 }
527 107         332 $data .= $_;
528             $_ = '';
529 4         21 }
530 4         121 $_ = "use strict;use warnings;$data$end";
531             $done = 1;
532 4         37 }
533             );
534             }
535              
536 0     0 1 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 1 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 32     32   76 sub block_accessor() {
572 4     4   32 my $accessor = shift;
  4         9  
  4         839  
573 32 50       138 no strict 'refs';
574             return if defined &$accessor;
575 308     308   19939 *$accessor = sub {
576 308 50       810 my $self = shift;
577 0         0 if (@_) {
578             Carp::croak "Not allowed to set values for '$accessor'";
579 308 100       373 }
  308         1421  
580             my @list = @{$self->{$accessor} || []};
581 308 100       1755 return wantarray
582             ? (@list)
583 32         208 : $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 465     465   622  
594 4     4   22 sub set_value {
  4         8  
  4         880  
595 465         625 no strict 'refs';
596 465 100       1379 my $accessor = shift;
597             block_accessor $accessor
598 465         2398 unless defined &$accessor;
599             $self->{$accessor} = [@_];
600             }
601 27     27   54  
602 27         129 sub run_filters {
603 27         101 my $map = $self->_section_map;
604 27 50       1098 my $order = $self->_section_order;
605             Carp::croak "Attempt to filter a block twice"
606 27         91 if $self->is_filtered;
607 89         375 for my $type (@$order) {
608 89         474 my $filters = $map->{$type}{filters};
609 89         2551 my @value = $self->$type;
610 89         344 $self->original_values->{$type} = $value[0];
611 268 50       2238 for my $filter ($self->_get_filters($type, $filters)) {
612             $Test::Base::Filter::arguments =
613 268         520 $filter =~ s/=(.*)$// ? $1 : undef;
614 4     4   24 my $function = "main::$filter";
  4         10  
  4         2777  
615 268 50       1897 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 268         13292 else {
632 268 50       1061 my $filter_object = $self->blocks_object->filter_class->new;
633             die "Can't find a function or method for '$filter' filter\n"
634 268         7666 unless $filter_object->can($filter);
635 268         1027 $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 268         85490 # introspecting.
640             $self->set_value($type, @value);
641             }
642 27         985 }
643             $self->is_filtered(1);
644             }
645 89     89   155  
646 89         137 sub _get_filters {
647 89   100     467 my $type = shift;
648 89         432 my $string = shift || '';
649 89         423 $string =~ s/\s*(.*?)\s*/$1/;
650 89   100     3335 my @filters = ();
651 89 100       264 my $map_filters = $self->blocks_object->_filters_map->{$type} || [];
652 89         180 $map_filters = [ $map_filters ] unless ref $map_filters;
653 89         281 my @append = ();
654 89         2197 for (
655             @{$self->blocks_object->_filters},
656             @$map_filters,
657             split(/\s+/, $string),
658 268         373 ) {
659 268 50       530 my $filter = $_;
660 268 50       711 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 268         578 else {
668             push @filters, $filter;
669             }
670 89         529 }
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__