File Coverage

inc/Test/Base.pm
Criterion Covered Total %
statement 219 378 57.9
branch 53 188 28.1
condition 13 83 15.6
subroutine 39 63 61.9
pod 20 29 68.9
total 344 741 46.4


line stmt bran cond sub pod time code
1             #line 1
2 17     17   13392 package Test::Base;
  17         63  
  17         844  
3 17     17   10282 use 5.006001;
  17         491  
  17         130  
4 17     17   163 use Spiffy 0.30 -Base;
  17     17   32  
  17     17   559  
  17         87  
  17         32  
  17         504  
  17         450  
  17         36  
  17         91  
5             use Spiffy ':XXX';
6             our $VERSION = '0.60';
7              
8             my @test_more_exports;
9 17     17   447 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 17     17   96  
  17         31  
  17         220  
20 17     17   94 use Test::More import => \@test_more_exports;
  17         31  
  17         11172  
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 50     50 1 92  
62 50   66     588 sub default_object {
63 50         113 $default_object ||= $default_class->new;
64             return $default_object;
65             }
66              
67             my $import_called = 0;
68 34     34   681 sub import() {
69 34 100       286 $import_called = 1;
70             my $class = (grep /^-base$/i, @_)
71             ? scalar(caller)
72 34 100       164 : $_[0];
73 17         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 34 100       214  
81 17         41 unless (grep /^-base$/i, @_) {
82 17         89 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 17 50       78 }
90             Test::More->import(import => \@test_more_exports, @args)
91             if @args;
92             }
93 34         131
94 34         826 _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 17     17   118 {
  17         41  
  17         64132  
102             no warnings 'redefine';
103 15     15   42 *Test::Builder::plan = sub {
104 15         98 $Have_Plan = 1;
105             goto &$plan_code;
106             };
107             }
108              
109             my $DIED = 0;
110             $SIG{__DIE__} = sub { $DIED = 1; die @_ };
111 87     87 0 114  
  87         246  
112 522     522 0 701 sub block_class { $self->find_class('Block') }
  522         1228  
113             sub filter_class { $self->find_class('Filter') }
114 609     609 0 745  
115 609         677 sub find_class {
116 609         1282 my $suffix = shift;
117 609 50       5482 my $class = ref($self) . "::$suffix";
118 609         888 return $class if $class->can('new');
119 609 100       2170 $class = __PACKAGE__ . "::$suffix";
120 14         1267 return $class if $class->can('new');
121 14 50       165 eval "require $class";
122 0         0 return $class if $class->can('new');
123             die "Can't find a class for $suffix";
124             }
125 3     3 0 8  
126 3 50       19 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 50 50   50 0 348 sub find_my_self() {
135             my $self = ref($_[0]) eq $default_class
136             ? splice(@_, 0, 1)
137 50         193 : default_object();
138             return $self, @_;
139             }
140              
141 14     14 1 142 sub blocks() {
142             (my ($self), @_) = find_my_self(@_);
143 14 50       75  
144             croak "Invalid arguments passed to 'blocks'"
145 14 50 33     92 if @_ > 1;
146             croak sprintf("'%s' is invalid argument to blocks()", shift(@_))
147             if @_ && $_[0] !~ /^[a-zA-Z]\w*$/;
148 14         637  
149             my $blocks = $self->block_list;
150 14   50     286
151 0         0 my $section_name = shift || '';
152 14 50       87 my @blocks = $section_name
153             ? (grep { exists $_->{$section_name} } @$blocks)
154             : (@$blocks);
155 14 50       168  
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 3     3 1 37 sub delimiters() {
199 3         30 (my ($self), @_) = find_my_self(@_);
200 3         8 $self->check_late;
201 3   33     12 my ($block_delimiter, $data_delimiter) = @_;
202 3   33     20 $block_delimiter ||= $self->block_delim_default;
203 3         140 $data_delimiter ||= $self->data_delim_default;
204 3         84 $self->block_delim($block_delimiter);
205 3         9 $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 17     17 1 244 sub filters() {
224 17 50       137 (my ($self), @_) = find_my_self(@_);
225 17         742 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 17         54 }
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 0     0 1 0 sub is($$;$) {
246 0         0 (my ($self), @_) = find_my_self(@_);
247 0         0 my ($actual, $expected, $name) = @_;
248 0 0 0     0 local $Test::Builder::Level = $Test::Builder::Level + 1;
      0        
      0        
      0        
      0        
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 0         0 ) {
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 16     16 1 272 sub run(&;$) {
266 16         44 (my ($self), @_) = find_my_self(@_);
267 16         46 my $callback = shift;
  16         476  
268 93 100       4468 for my $block (@{$self->block_list}) {
269 93         165 $block->run_filters unless $block->is_filtered;
  93         330  
270             &{$callback}($block);
271             }
272             }
273              
274 0     0   0 my $name_error = "Can't determine section names";
275 0 0       0 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 0     0   0  
287 0 0       0 sub _assert_plan {
288             plan('no_plan') unless $Have_Plan;
289             }
290 17     17   2313  
291 17 50 66     580 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 0     0 1 0 sub run_is() {
318 0         0 (my ($self), @_) = find_my_self(@_);
319 0         0 $self->_assert_plan;
320 0         0 my ($x, $y) = $self->_section_names(@_);
321 0         0 local $Test::Builder::Level = $Test::Builder::Level + 1;
  0         0  
322 0 0 0     0 for my $block (@{$self->block_list}) {
323 0 0       0 next unless exists($block->{$x}) and exists($block->{$y});
324 0 0       0 $block->run_filters unless $block->is_filtered;
325             is($block->$x, $block->$y,
326             $block->name ? $block->name : ()
327             );
328             }
329             }
330              
331 0     0 1 0 sub run_is_deeply() {
332 0         0 (my ($self), @_) = find_my_self(@_);
333 0         0 $self->_assert_plan;
334 0         0 my ($x, $y) = $self->_section_names(@_);
  0         0  
335 0 0 0     0 for my $block (@{$self->block_list}) {
336 0 0       0 next unless exists($block->{$x}) and exists($block->{$y});
337 0 0       0 $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         37 sub _pre_eval {
401 14 50       124 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   34  
410 14         399 sub _block_list_init {
411 14         121 my $spec = $self->spec;
412 14         388 $spec = $self->_pre_eval($spec);
413 14         2172 my $cd = $self->block_delim;
414 14         2970 my @hunks = ($spec =~ /^(\Q${cd}\E.*?(?=^\Q${cd}\E|\z))/msg);
415 14         395 my $blocks = $self->_choose_blocks(@hunks);
416 14         35 $self->block_list($blocks); # Need to set early for possible filter use
417 14         52 my $seq = 1;
418 87         1783 for my $block (@$blocks) {
419 87         1784 $block->blocks_object($self);
420             $block->seq_num($seq++);
421 14         107 }
422             return $blocks;
423             }
424 14     14   36  
425 14         43 sub _choose_blocks {
426 14         53 my $blocks = [];
427 87         269 for my $hunk (@_) {
428 87 50       221 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 87 50       193 }
434 87         161 next if exists $block->{SKIP};
435 87 50       255 push @$blocks, $block;
436 0         0 if (exists $block->{LAST}) {
437             return $blocks;
438             }
439 14         66 }
440             return $blocks;
441             }
442 174     174   204  
443 174         204 sub _check_reserved {
444 174 50 33     953 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 87     87   112  
450 87         144 sub _make_block {
451 87         2047 my $hunk = shift;
452 87         1939 my $cd = $self->block_delim;
453 87         291 my $dd = $self->data_delim;
454 87 50       959 my $block = $self->block_class->new;
455 87         198 $hunk =~ s/\A\Q${cd}\E[ \t]*(.*)\s+// or die;
456 87         1250 my $name = $1;
457 87         160 my @parts = split /^\Q${dd}\E +\(?(\w+)\)? *(.*)?\n/m, $hunk;
458 87   50     358 my $description = shift @parts;
459 87 50       185 $description ||= '';
460 87         189 unless ($description =~ /\S/) {
461             $description = $name;
462 87         367 }
463 87         246 $description =~ s/\s*\z//;
464             $block->set_value(description => $description);
465 87         160
466 87         138 my $section_map = {};
467 87         444 my $section_order = [];
468 174         361 while (@parts) {
469 174         444 my ($type, $filters, $value) = splice(@parts, 0, 3);
470 174 50       329 $self->_check_reserved($type);
471 174 50       318 $value = '' unless defined $value;
472 174 50       324 $filters = '' unless defined $filters;
473 0 0       0 if ($filters =~ /:(\s|\z)/) {
474             croak "Extra lines not allowed in '$type' section"
475 0         0 if $value =~ /\S/;
476 0 0       0 ($filters, $value) = split /\s*:(?:\s+|\z)/, $filters, 2;
477 0         0 $value = '' unless defined $value;
478             $value =~ s/^\s*(.*?)\s*$/$1/;
479 174         608 }
480             $section_map->{$type} = {
481             filters => $filters,
482 174         332 };
483 174         359 push @$section_order, $type;
484             $block->set_value($type, $value);
485 87         189 }
486 87         196 $block->set_value(name => $name);
487 87         188 $block->set_value(_section_map => $section_map);
488 87         255 $block->set_value(_section_order => $section_order);
489             return $block;
490             }
491 14     14   34  
492 14 50       416 sub _spec_init {
493             return $self->_spec_string
494 14         64 if $self->_spec_string;
495 14         34 local $/;
496 14 50       427 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         62 else {
503             $spec = do {
504 17     17   141 package main;
  17         33  
  17         8450  
505 14         473 no warnings 'once';
506             ;
507             };
508 14         126 }
509             return $spec;
510             }
511              
512 34     34   218 sub _strict_warnings() {
513 34         81 require Filter::Util::Call;
514             my $done = 0;
515             Filter::Util::Call::filter_add(
516 52 100   52   2374 sub {
517 34         129 return 0 if $done;
518 34         363 my ($data, $end) = ('', '');
519 1097 50       1689 while (my $status = Filter::Util::Call::filter_read()) {
520 1097 100       1877 return $status if $status < 0;
521 16         40 if (/^__(?:END|DATA)__\r?$/) {
522 16         43 $end = $_;
523             last;
524 1081         1344 }
525 1081         3031 $data .= $_;
526             $_ = '';
527 34         147 }
528 34         580 $_ = "use strict;use warnings;$data$end";
529             $done = 1;
530 34         347 }
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 90     90   155 sub block_accessor() {
570 17     17   124 my $accessor = shift;
  17         39  
  17         3913  
571 90 50       421 no strict 'refs';
572             return if defined &$accessor;
573 627     627   4748 *$accessor = sub {
574 627 50       1621 my $self = shift;
575 0         0 if (@_) {
576             Carp::croak "Not allowed to set values for '$accessor'";
577 627 50       739 }
  627         2426  
578             my @list = @{$self->{$accessor} || []};
579 627 100       2203 return wantarray
580             ? (@list)
581 90         628 : $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 1044     1044   1232  
592 17     17   92 sub set_value {
  17         43  
  17         4111  
593 1044         1275 no strict 'refs';
594 1044 100       2703 my $accessor = shift;
595             block_accessor $accessor
596 1044         5993 unless defined &$accessor;
597             $self->{$accessor} = [@_];
598             }
599 87     87   159  
600 87         286 sub run_filters {
601 87         262 my $map = $self->_section_map;
602 87 50       1906 my $order = $self->_section_order;
603             Carp::croak "Attempt to filter a block twice"
604 87         223 if $self->is_filtered;
605 174         581 for my $type (@$order) {
606 174         512 my $filters = $map->{$type}{filters};
607 174         3906 my @value = $self->$type;
608 174         550 $self->original_values->{$type} = $value[0];
609 522 50       1262 for my $filter ($self->_get_filters($type, $filters)) {
610             $Test::Base::Filter::arguments =
611 522         902 $filter =~ s/=(.*)$// ? $1 : undef;
612 17     17   95 my $function = "main::$filter";
  17         34  
  17         11774  
613 522 50       2615 no strict 'refs';
614 0 0 0     0 if (defined &$function) {
615             local $_ =
616             (@value == 1 and not defined($value[0])) ? undef :
617 0         0 join '', @value;
618 0         0 my $old = $_;
619 0 0 0     0 @value = &$function(@value);
      0        
      0        
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 522         11982 else {
630 522 50       1575 my $filter_object = $self->blocks_object->filter_class->new;
631             die "Can't find a function or method for '$filter' filter\n"
632 522         11429 unless $filter_object->can($filter);
633 522         1655 $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 522         1338 # introspecting.
638             $self->set_value($type, @value);
639             }
640 87         1916 }
641             $self->is_filtered(1);
642             }
643 174     174   257  
644 174         263 sub _get_filters {
645 174   50     2917 my $type = shift;
646 174         782 my $string = shift || '';
647 174         322 $string =~ s/\s*(.*?)\s*/$1/;
648 174   50     3908 my @filters = ();
649 174 50       528 my $map_filters = $self->blocks_object->_filters_map->{$type} || [];
650 174         274 $map_filters = [ $map_filters ] unless ref $map_filters;
651 174         215 my @append = ();
652 174         3531 for (
653             @{$self->blocks_object->_filters},
654             @$map_filters,
655             split(/\s+/, $string),
656 522         662 ) {
657 522 50       987 my $filter = $_;
658 522 50       1261 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 522         1052 else {
666             push @filters, $filter;
667             }
668 174         638 }
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__