File Coverage

inc/Test/Base.pm
Criterion Covered Total %
statement 249 378 65.8
branch 73 188 38.8
condition 27 83 32.5
subroutine 42 63 66.6
pod 20 29 68.9
total 411 741 55.4


line stmt bran cond sub pod time code
1             #line 1
2             # TODO:
3             #
4 6     6   3826 package Test::Base;
  6         21  
  6         297  
5 6     6   3498 use 5.006001;
  6         194  
  6         44  
6 6     6   63 use Spiffy 0.30 -Base;
  6     6   13  
  6     6   210  
  6         30  
  6         12  
  6         224  
  6         30  
  6         10  
  6         36  
7             use Spiffy ':XXX';
8             our $VERSION = '0.59';
9              
10             my @test_more_exports;
11 6     6   198 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 6     6   5063  
  6         23  
  6         67  
22 6     6   42 use Test::More import => \@test_more_exports;
  6         11  
  6         3142  
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 21     21 1 39  
64 21   66     169 sub default_object {
65 21         44 $default_object ||= $default_class->new;
66             return $default_object;
67             }
68              
69             my $import_called = 0;
70 6     6   52 sub import() {
71 6 50       41 $import_called = 1;
72             my $class = (grep /^-base$/i, @_)
73             ? scalar(caller)
74 6 50       28 : $_[0];
75 6         22 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 6 50       31  
83 6         11 unless (grep /^-base$/i, @_) {
84 6         32 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 6 50       24 }
92             Test::More->import(import => \@test_more_exports, @args)
93             if @args;
94             }
95 6         23
96 6         147 _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 6     6   40 {
  6         17  
  6         25473  
104             no warnings 'redefine';
105 6     6   25 *Test::Builder::plan = sub {
106 6         48 $Have_Plan = 1;
107             goto &$plan_code;
108             };
109             }
110              
111             my $DIED = 0;
112             $SIG{__DIE__} = sub { $DIED = 1; die @_ };
113 55     55 0 85  
  55         111  
114 107     107 0 156 sub block_class { $self->find_class('Block') }
  107         215  
115             sub filter_class { $self->find_class('Filter') }
116 162     162 0 188  
117 162         226 sub find_class {
118 162         361 my $suffix = shift;
119 162 100       670 my $class = ref($self) . "::$suffix";
120 6         20 return $class if $class->can('new');
121 6 50       45 $class = __PACKAGE__ . "::$suffix";
122 6         482 return $class if $class->can('new');
123 6 50       97 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 29 100   29 0 160 sub find_my_self() {
137             my $self = ref($_[0]) eq $default_class
138             ? splice(@_, 0, 1)
139 29         110 : default_object();
140             return $self, @_;
141             }
142              
143 6     6 1 69 sub blocks() {
144             (my ($self), @_) = find_my_self(@_);
145 6 50       36  
146             croak "Invalid arguments passed to 'blocks'"
147 6 50 33     39 if @_ > 1;
148             croak sprintf("'%s' is invalid argument to blocks()", shift(@_))
149             if @_ && $_[0] !~ /^[a-zA-Z]\w*$/;
150 6         320  
151             my $blocks = $self->block_list;
152 6   50     54
153 0         0 my $section_name = shift || '';
154 6 50       39 my @blocks = $section_name
155             ? (grep { exists $_->{$section_name} } @$blocks)
156             : (@$blocks);
157 6 50       91  
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 4     4 1 15 sub next_block() {
171 4         99 (my ($self), @_) = find_my_self(@_);
172 4 50       42 my $list = $self->_next_list;
173 4         8 if (@$list == 0) {
  4         92  
174 4         142 $list = [@{$self->block_list}, undef];
175             $self->_next_list($list);
176 4         10 }
177 4 50 33     123 my $block = shift @$list;
178 4         20 if (defined $block and not $block->is_filtered) {
179             $block->run_filters;
180 1         8 }
181             return $block;
182             }
183              
184 4     4 1 21 sub first_block() {
185 4         118 (my ($self), @_) = find_my_self(@_);
186 4         25 $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 6     6 1 719 sub filters() {
226 6 50       32 (my ($self), @_) = find_my_self(@_);
227 6         206 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 6         22 }
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 3     3 1 15 sub is($$;$) {
248 3         9 (my ($self), @_) = find_my_self(@_);
249 3         7 my ($actual, $expected, $name) = @_;
250 3 50 66     47 local $Test::Builder::Level = $Test::Builder::Level + 1;
      66        
      66        
      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 3         17 ) {
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 0     0 1 0 sub run(&;$) {
268 0         0 (my ($self), @_) = find_my_self(@_);
269 0         0 my $callback = shift;
  0         0  
270 0 0       0 for my $block (@{$self->block_list}) {
271 0         0 $block->run_filters unless $block->is_filtered;
  0         0  
272             &{$callback}($block);
273             }
274             }
275              
276 6     6   11 my $name_error = "Can't determine section names";
277 6 100       37 sub _section_names {
278 4 50       19 return @_ if @_ == 2;
279             my $block = $self->first_block
280 2         9 or croak $name_error;
281 1 50       6 my @names = grep {
282 1         2 $_ !~ /^(ONLY|LAST|SKIP)$/;
283 1 50       4 } @{$block->{_section_order}[0] || []};
284             croak "$name_error. Need two sections in first block"
285 1         4 unless @names == 2;
286             return @names;
287             }
288 6     6   13  
289 6 50       25 sub _assert_plan {
290             plan('no_plan') unless $Have_Plan;
291             }
292 6     6   49  
293 6 0 33     71 sub END {
      33        
294             run_compare() unless $Have_Plan or $DIED or not $import_called;
295             }
296              
297 6     6 1 43 sub run_compare() {
298 6         53 (my ($self), @_) = find_my_self(@_);
299 6         31 $self->_assert_plan;
300 3         8 my ($x, $y) = $self->_section_names(@_);
301 3         6 local $Test::Builder::Level = $Test::Builder::Level + 1;
  3         62  
302 24 50 33     158 for my $block (@{$self->block_list}) {
303 24 100       659 next unless exists($block->{$x}) and exists($block->{$y});
304 23 100       70 $block->run_filters unless $block->is_filtered;
    50          
305 20 50       58 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 3 50       9 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 6     6   15  
402 6         17 sub _pre_eval {
403 6 50       51 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 6     6   13  
412 6         167 sub _block_list_init {
413 6         38 my $spec = $self->spec;
414 6         172 $spec = $self->_pre_eval($spec);
415 6         789 my $cd = $self->block_delim;
416 6         38 my @hunks = ($spec =~ /^(\Q${cd}\E.*?(?=^\Q${cd}\E|\z))/msg);
417 6         188 my $blocks = $self->_choose_blocks(@hunks);
418 6         14 $self->block_list($blocks); # Need to set early for possible filter use
419 6         25 my $seq = 1;
420 50         1122 for my $block (@$blocks) {
421 50         1072 $block->blocks_object($self);
422             $block->seq_num($seq++);
423 6         51 }
424             return $blocks;
425             }
426 6     6   25  
427 6         18 sub _choose_blocks {
428 6         35 my $blocks = [];
429 55         121 for my $hunk (@_) {
430 55 50       148 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 55 100       171 }
436 50         71 next if exists $block->{SKIP};
437 50 50       255 push @$blocks, $block;
438 0         0 if (exists $block->{LAST}) {
439             return $blocks;
440             }
441 6         26 }
442             return $blocks;
443             }
444 86     86   104  
445 86         123 sub _check_reserved {
446 86 50 33     445 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 55     55   67  
452 55         80 sub _make_block {
453 55         1322 my $hunk = shift;
454 55         1197 my $cd = $self->block_delim;
455 55         142 my $dd = $self->data_delim;
456 55 50       600 my $block = $self->block_class->new;
457 55         121 $hunk =~ s/\A\Q${cd}\E[ \t]*(.*)\s+// or die;
458 55         646 my $name = $1;
459 55         99 my @parts = split /^\Q${dd}\E +\(?(\w+)\)? *(.*)?\n/m, $hunk;
460 55   50     232 my $description = shift @parts;
461 55 50       137 $description ||= '';
462 55         83 unless ($description =~ /\S/) {
463             $description = $name;
464 55         488 }
465 55         146 $description =~ s/\s*\z//;
466             $block->set_value(description => $description);
467 55         96
468 55         87 my $section_map = {};
469 55         124 my $section_order = [];
470 86         182 while (@parts) {
471 86         199 my ($type, $filters, $value) = splice(@parts, 0, 3);
472 86 100       192 $self->_check_reserved($type);
473 86 50       160 $value = '' unless defined $value;
474 86 100       236 $filters = '' unless defined $filters;
475 31 50       80 if ($filters =~ /:(\s|\z)/) {
476             croak "Extra lines not allowed in '$type' section"
477 31         157 if $value =~ /\S/;
478 31 50       98 ($filters, $value) = split /\s*:(?:\s+|\z)/, $filters, 2;
479 31         224 $value = '' unless defined $value;
480             $value =~ s/^\s*(.*?)\s*$/$1/;
481 86         318 }
482             $section_map->{$type} = {
483             filters => $filters,
484 86         166 };
485 86         170 push @$section_order, $type;
486             $block->set_value($type, $value);
487 55         128 }
488 55         107 $block->set_value(name => $name);
489 55         111 $block->set_value(_section_map => $section_map);
490 55         155 $block->set_value(_section_order => $section_order);
491             return $block;
492             }
493 6     6   19  
494 6 50       180 sub _spec_init {
495             return $self->_spec_string
496 6         110 if $self->_spec_string;
497 6         18 local $/;
498 6 50       182 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 6         11 else {
505             $spec = do {
506 6     6   62 package main;
  6         13  
  6         3153  
507 6         200 no warnings 'once';
508             ;
509             };
510 6         56 }
511             return $spec;
512             }
513              
514 6     6   36 sub _strict_warnings() {
515 6         12 require Filter::Util::Call;
516             my $done = 0;
517             Filter::Util::Call::filter_add(
518 6 50   6   24 sub {
519 6         13 return 0 if $done;
520 6         67 my ($data, $end) = ('', '');
521 181 50       275 while (my $status = Filter::Util::Call::filter_read()) {
522 181 100       396 return $status if $status < 0;
523 6         11 if (/^__(?:END|DATA)__\r?$/) {
524 6         17 $end = $_;
525             last;
526 175         191 }
527 175         475 $data .= $_;
528             $_ = '';
529 6         29 }
530 6         214 $_ = "use strict;use warnings;$data$end";
531             $done = 1;
532 6         52 }
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 36     36   61 sub block_accessor() {
572 6     6   40 my $accessor = shift;
  6         14  
  6         1258  
573 36 50       152 no strict 'refs';
574             return if defined &$accessor;
575 212     212   248 *$accessor = sub {
576 212 50       394 my $self = shift;
577 0         0 if (@_) {
578             Carp::croak "Not allowed to set values for '$accessor'";
579 212 50       214 }
  212         706  
580             my @list = @{$self->{$accessor} || []};
581 212 100       899 return wantarray
582             ? (@list)
583 36         249 : $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 457     457   539  
594 6     6   35 sub set_value {
  6         15  
  6         1370  
595 457         535 no strict 'refs';
596 457 100       1193 my $accessor = shift;
597             block_accessor $accessor
598 457         1896 unless defined &$accessor;
599             $self->{$accessor} = [@_];
600             }
601 27     27   51  
602 27         74 sub run_filters {
603 27         81 my $map = $self->_section_map;
604 27 50       627 my $order = $self->_section_order;
605             Carp::croak "Attempt to filter a block twice"
606 27         68 if $self->is_filtered;
607 40         126 for my $type (@$order) {
608 40         125 my $filters = $map->{$type}{filters};
609 40         1009 my @value = $self->$type;
610 40         130 $self->original_values->{$type} = $value[0];
611 155 50       373 for my $filter ($self->_get_filters($type, $filters)) {
612             $Test::Base::Filter::arguments =
613 155         289 $filter =~ s/=(.*)$// ? $1 : undef;
614 6     6   45 my $function = "main::$filter";
  6         51  
  6         3757  
615 155 100       665 no strict 'refs';
616 48 100 66     305 if (defined &$function) {
617             local $_ =
618             (@value == 1 and not defined($value[0])) ? undef :
619 48         107 join '', @value;
620 48         178 my $old = $_;
621 48 50 66     2721 @value = &$function(@value);
      66        
      33        
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 107         2336 else {
632 107 50       320 my $filter_object = $self->blocks_object->filter_class->new;
633             die "Can't find a function or method for '$filter' filter\n"
634 107         7650 unless $filter_object->can($filter);
635 107         455 $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 151         450 # introspecting.
640             $self->set_value($type, @value);
641             }
642 23         598 }
643             $self->is_filtered(1);
644             }
645 40     40   56  
646 40         100 sub _get_filters {
647 40   50     161 my $type = shift;
648 40         186 my $string = shift || '';
649 40         68 $string =~ s/\s*(.*?)\s*/$1/;
650 40   50     897 my @filters = ();
651 40 100       145 my $map_filters = $self->blocks_object->_filters_map->{$type} || [];
652 40         69 $map_filters = [ $map_filters ] unless ref $map_filters;
653 40         51 my @append = ();
654 40         860 for (
655             @{$self->blocks_object->_filters},
656             @$map_filters,
657             split(/\s+/, $string),
658 159         193 ) {
659 159 50       281 my $filter = $_;
660 159 50       405 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 159         312 else {
668             push @filters, $filter;
669             }
670 40         193 }
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__