File Coverage

inc/Test/Base.pm
Criterion Covered Total %
statement 236 378 62.4
branch 63 188 33.5
condition 22 83 26.5
subroutine 41 63 65.0
pod 20 29 68.9
total 382 741 51.5


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