File Coverage

inc/Test/Base.pm
Criterion Covered Total %
statement 227 378 60.0
branch 58 188 30.8
condition 25 83 30.1
subroutine 40 63 63.4
pod 20 29 68.9
total 370 741 49.9


line stmt bran cond sub pod time code
1             #line 1
2             # TODO:
3             #
4 9     9   7238 package Test::Base;
  9         26  
  9         480  
5 9     9   5682 use 5.006001;
  9         333  
  9         66  
6 9     9   102 use Spiffy 0.30 -Base;
  9     9   23  
  9     9   363  
  9         55  
  9         17  
  9         338  
  9         51  
  9         15  
  9         56  
7             use Spiffy ':XXX';
8             our $VERSION = '0.59';
9              
10             my @test_more_exports;
11 9     9   240 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 9     9   7717  
  9         37  
  9         118  
22 9     9   71 use Test::More import => \@test_more_exports;
  9         24  
  9         6151  
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 63     63 1 102  
64 63   66     321 sub default_object {
65 63         116 $default_object ||= $default_class->new;
66             return $default_object;
67             }
68              
69             my $import_called = 0;
70 9     9   84 sub import() {
71 9 50       76 $import_called = 1;
72             my $class = (grep /^-base$/i, @_)
73             ? scalar(caller)
74 9 50       39 : $_[0];
75 9         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 9 50       50  
83 9         19 unless (grep /^-base$/i, @_) {
84 9         48 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 9 50       37 }
92             Test::More->import(import => \@test_more_exports, @args)
93             if @args;
94             }
95 9         37
96 9         208 _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 9     9   59 {
  9         26  
  9         37638  
104             no warnings 'redefine';
105 9     9   30 *Test::Builder::plan = sub {
106 9         61 $Have_Plan = 1;
107             goto &$plan_code;
108             };
109             }
110              
111             my $DIED = 0;
112             $SIG{__DIE__} = sub { $DIED = 1; die @_ };
113 45     45 0 62  
  45         107  
114 270     270 0 353 sub block_class { $self->find_class('Block') }
  270         517  
115             sub filter_class { $self->find_class('Filter') }
116 315     315 0 374  
117 315         382 sub find_class {
118 315         631 my $suffix = shift;
119 315 100       1274 my $class = ref($self) . "::$suffix";
120 9         33 return $class if $class->can('new');
121 9 50       60 $class = __PACKAGE__ . "::$suffix";
122 9         776 return $class if $class->can('new');
123 9 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 63 50   63 0 334 sub find_my_self() {
137             my $self = ref($_[0]) eq $default_class
138             ? splice(@_, 0, 1)
139 63         245 : default_object();
140             return $self, @_;
141             }
142              
143 9     9 1 99 sub blocks() {
144             (my ($self), @_) = find_my_self(@_);
145 9 50       44  
146             croak "Invalid arguments passed to 'blocks'"
147 9 50 33     55 if @_ > 1;
148             croak sprintf("'%s' is invalid argument to blocks()", shift(@_))
149             if @_ && $_[0] !~ /^[a-zA-Z]\w*$/;
150 9         393  
151             my $blocks = $self->block_list;
152 9   50     102
153 0         0 my $section_name = shift || '';
154 9 50       74 my @blocks = $section_name
155             ? (grep { exists $_->{$section_name} } @$blocks)
156             : (@$blocks);
157 9 50       107  
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 0     0 1 0 sub filters() {
226 0 0       0 (my ($self), @_) = find_my_self(@_);
227 0         0 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 0         0 }
234             return $self;
235             }
236              
237 0     0 1 0 sub filter_arguments() {
238             $Test::Base::Filter::arguments;
239             }
240 2     2 0 3  
241 2 50 33     4 sub have_text_diff {
  2         864  
  2         9286  
242             eval { require Text::Diff; 1 } &&
243             $Text::Diff::VERSION >= 0.35 &&
244             $Algorithm::Diff::VERSION >= 1.15;
245             }
246              
247 45     45 1 132 sub is($$;$) {
248 45         103 (my ($self), @_) = find_my_self(@_);
249 45         94 my ($actual, $expected, $name) = @_;
250 45 100 33     655 local $Test::Builder::Level = $Test::Builder::Level + 1;
      33        
      66        
      66        
      100        
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 44         195 ) {
258             Test::More::is($actual, $expected, $name);
259             }
260 1 50       5 else {
261 1         7 $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 9     9   18 my $name_error = "Can't determine section names";
277 9 50       67 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 9     9   20  
289 9 50       45 sub _assert_plan {
290             plan('no_plan') unless $Have_Plan;
291             }
292 9     9   28  
293 9 0 33     83 sub END {
      33        
294             run_compare() unless $Have_Plan or $DIED or not $import_called;
295             }
296              
297 9     9 1 41 sub run_compare() {
298 9         59 (my ($self), @_) = find_my_self(@_);
299 9         60 $self->_assert_plan;
300 9         23 my ($x, $y) = $self->_section_names(@_);
301 9         20 local $Test::Builder::Level = $Test::Builder::Level + 1;
  9         288  
302 45 50 33     330 for my $block (@{$self->block_list}) {
303 45 50       1320 next unless exists($block->{$x}) and exists($block->{$y});
304 45 50       134 $block->run_filters unless $block->is_filtered;
    50          
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 45 50       134 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 9     9   22  
402 9         23 sub _pre_eval {
403 9 50       87 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 9     9   22  
412 9         263 sub _block_list_init {
413 9         51 my $spec = $self->spec;
414 9         305 $spec = $self->_pre_eval($spec);
415 9         1417 my $cd = $self->block_delim;
416 9         58 my @hunks = ($spec =~ /^(\Q${cd}\E.*?(?=^\Q${cd}\E|\z))/msg);
417 9         292 my $blocks = $self->_choose_blocks(@hunks);
418 9         16 $self->block_list($blocks); # Need to set early for possible filter use
419 9         26 my $seq = 1;
420 45         1027 for my $block (@$blocks) {
421 45         1003 $block->blocks_object($self);
422             $block->seq_num($seq++);
423 9         56 }
424             return $blocks;
425             }
426 9     9   26  
427 9         26 sub _choose_blocks {
428 9         40 my $blocks = [];
429 45         232 for my $hunk (@_) {
430 45 50       255 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 45 50       102 }
436 45         74 next if exists $block->{SKIP};
437 45 50       135 push @$blocks, $block;
438 0         0 if (exists $block->{LAST}) {
439             return $blocks;
440             }
441 9         38 }
442             return $blocks;
443             }
444 90     90   246  
445 90         99 sub _check_reserved {
446 90 50 33     478 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 45     45   65  
452 45         72 sub _make_block {
453 45         1160 my $hunk = shift;
454 45         1081 my $cd = $self->block_delim;
455 45         360 my $dd = $self->data_delim;
456 45 50       581 my $block = $self->block_class->new;
457 45         99 $hunk =~ s/\A\Q${cd}\E[ \t]*(.*)\s+// or die;
458 45         728 my $name = $1;
459 45         97 my @parts = split /^\Q${dd}\E +\(?(\w+)\)? *(.*)?\n/m, $hunk;
460 45   50     203 my $description = shift @parts;
461 45 50       115 $description ||= '';
462 45         64 unless ($description =~ /\S/) {
463             $description = $name;
464 45         152 }
465 45         134 $description =~ s/\s*\z//;
466             $block->set_value(description => $description);
467 45         72
468 45         68 my $section_map = {};
469 45         107 my $section_order = [];
470 90         196 while (@parts) {
471 90         203 my ($type, $filters, $value) = splice(@parts, 0, 3);
472 90 50       169 $self->_check_reserved($type);
473 90 50       162 $value = '' unless defined $value;
474 90 50       200 $filters = '' unless defined $filters;
475 0 0       0 if ($filters =~ /:(\s|\z)/) {
476             croak "Extra lines not allowed in '$type' section"
477 0         0 if $value =~ /\S/;
478 0 0       0 ($filters, $value) = split /\s*:(?:\s+|\z)/, $filters, 2;
479 0         0 $value = '' unless defined $value;
480             $value =~ s/^\s*(.*?)\s*$/$1/;
481 90         342 }
482             $section_map->{$type} = {
483             filters => $filters,
484 90         177 };
485 90         192 push @$section_order, $type;
486             $block->set_value($type, $value);
487 45         157 }
488 45         102 $block->set_value(name => $name);
489 45         98 $block->set_value(_section_map => $section_map);
490 45         125 $block->set_value(_section_order => $section_order);
491             return $block;
492             }
493 9     9   20  
494 9 50       266 sub _spec_init {
495             return $self->_spec_string
496 9         39 if $self->_spec_string;
497 9         23 local $/;
498 9 50       260 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 9         20 else {
505             $spec = do {
506 9     9   88 package main;
  9         33  
  9         4501  
507 9         248 no warnings 'once';
508             ;
509             };
510 9         67 }
511             return $spec;
512             }
513              
514 9     9   60 sub _strict_warnings() {
515 9         18 require Filter::Util::Call;
516             my $done = 0;
517             Filter::Util::Call::filter_add(
518 9 50   9   41 sub {
519 9         21 return 0 if $done;
520 9         110 my ($data, $end) = ('', '');
521 117 50       201 while (my $status = Filter::Util::Call::filter_read()) {
522 117 100       260 return $status if $status < 0;
523 9         22 if (/^__(?:END|DATA)__\r?$/) {
524 9         23 $end = $_;
525             last;
526 108         126 }
527 108         316 $data .= $_;
528             $_ = '';
529 9         34 }
530 9         222 $_ = "use strict;use warnings;$data$end";
531             $done = 1;
532 9         78 }
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 54     54   109 sub block_accessor() {
572 9     9   71 my $accessor = shift;
  9         23  
  9         2251  
573 54 50       235 no strict 'refs';
574             return if defined &$accessor;
575 405     405   494 *$accessor = sub {
576 405 50       903 my $self = shift;
577 0         0 if (@_) {
578             Carp::croak "Not allowed to set values for '$accessor'";
579 405 50       405 }
  405         1323  
580             my @list = @{$self->{$accessor} || []};
581 405 100       1454 return wantarray
582             ? (@list)
583 54         525 : $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 585     585   753  
594 9     9   49 sub set_value {
  9         18  
  9         1995  
595 585         769 no strict 'refs';
596 585 100       1694 my $accessor = shift;
597             block_accessor $accessor
598 585         2573 unless defined &$accessor;
599             $self->{$accessor} = [@_];
600             }
601 45     45   63  
602 45         122 sub run_filters {
603 45         130 my $map = $self->_section_map;
604 45 50       1236 my $order = $self->_section_order;
605             Carp::croak "Attempt to filter a block twice"
606 45         98 if $self->is_filtered;
607 90         240 for my $type (@$order) {
608 90         254 my $filters = $map->{$type}{filters};
609 90         2451 my @value = $self->$type;
610 90         280 $self->original_values->{$type} = $value[0];
611 315 50       758 for my $filter ($self->_get_filters($type, $filters)) {
612             $Test::Base::Filter::arguments =
613 315         496 $filter =~ s/=(.*)$// ? $1 : undef;
614 9     9   51 my $function = "main::$filter";
  9         21  
  9         12929  
615 315 100       1314 no strict 'refs';
616 45 50 33     326 if (defined &$function) {
617             local $_ =
618             (@value == 1 and not defined($value[0])) ? undef :
619 45         74 join '', @value;
620 45         173 my $old = $_;
621 45 50 33     39552 @value = &$function(@value);
      33        
      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 270         7078 else {
632 270 50       775 my $filter_object = $self->blocks_object->filter_class->new;
633             die "Can't find a function or method for '$filter' filter\n"
634 270         6712 unless $filter_object->can($filter);
635 270         909 $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 315         818 # introspecting.
640             $self->set_value($type, @value);
641             }
642 45         1140 }
643             $self->is_filtered(1);
644             }
645 90     90   146  
646 90         138 sub _get_filters {
647 90   50     241 my $type = shift;
648 90         384 my $string = shift || '';
649 90         156 $string =~ s/\s*(.*?)\s*/$1/;
650 90   50     2228 my @filters = ();
651 90 50       253 my $map_filters = $self->blocks_object->_filters_map->{$type} || [];
652 90         136 $map_filters = [ $map_filters ] unless ref $map_filters;
653 90         113 my @append = ();
654 90         2122 for (
655             @{$self->blocks_object->_filters},
656             @$map_filters,
657             split(/\s+/, $string),
658 315         400 ) {
659 315 50       562 my $filter = $_;
660 315 50       839 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 315         812 else {
668             push @filters, $filter;
669             }
670 90         403 }
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__