File Coverage

inc/Test/Base.pm
Criterion Covered Total %
statement 215 378 56.8
branch 57 188 30.3
condition 17 83 20.4
subroutine 38 63 60.3
pod 0 29 0.0
total 327 741 44.1


line stmt bran cond sub pod time code
1             #line 1
2 3     3   4404 package Test::Base;
  3         10  
  3         146  
3 3     3   1839 use 5.006001;
  3         106  
  3         21  
4 3     3   34 use Spiffy 0.30 -Base;
  3     3   5  
  3     3   112  
  3         17  
  3         5  
  3         105  
  3         16  
  3         7  
  3         17  
5             use Spiffy ':XXX';
6             our $VERSION = '0.60';
7              
8             my @test_more_exports;
9 3     3   81 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 3     3   2584  
  3         12  
  3         33  
20 3     3   19 use Test::More import => \@test_more_exports;
  3         6  
  3         1717  
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 179     179 0 643  
62 179   66     11953 sub default_object {
63 179         383 $default_object ||= $default_class->new;
64             return $default_object;
65             }
66              
67             my $import_called = 0;
68 6     6   249 sub import() {
69 6 100       46 $import_called = 1;
70             my $class = (grep /^-base$/i, @_)
71             ? scalar(caller)
72 6 100       27 : $_[0];
73 3         5 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 6 100       34  
81 3         9 unless (grep /^-base$/i, @_) {
82 3         18 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 3 50       14 }
90             Test::More->import(import => \@test_more_exports, @args)
91             if @args;
92             }
93 6         22
94 6         136 _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 3     3   18 {
  3         5  
  3         17775  
102             no warnings 'redefine';
103 3     3   8 *Test::Builder::plan = sub {
104 3         25 $Have_Plan = 1;
105             goto &$plan_code;
106             };
107             }
108              
109             my $DIED = 0;
110             $SIG{__DIE__} = sub { $DIED = 1; die @_ };
111 67     67 0 83  
  67         131  
112 556     556 0 662 sub block_class { $self->find_class('Block') }
  556         966  
113             sub filter_class { $self->find_class('Filter') }
114 623     623 0 633  
115 623         670 sub find_class {
116 623         1318 my $suffix = shift;
117 623 50       4109 my $class = ref($self) . "::$suffix";
118 623         1047 return $class if $class->can('new');
119 623 100       1766 $class = __PACKAGE__ . "::$suffix";
120 3         260 return $class if $class->can('new');
121 3 50       34 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 179 50   179 0 1532 sub find_my_self() {
135             my $self = ref($_[0]) eq $default_class
136             ? splice(@_, 0, 1)
137 179         1019 : default_object();
138             return $self, @_;
139             }
140              
141 6     6 0 53 sub blocks() {
142             (my ($self), @_) = find_my_self(@_);
143 6 50       21  
144             croak "Invalid arguments passed to 'blocks'"
145 6 50 33     26 if @_ > 1;
146             croak sprintf("'%s' is invalid argument to blocks()", shift(@_))
147             if @_ && $_[0] !~ /^[a-zA-Z]\w*$/;
148 6         277  
149             my $blocks = $self->block_list;
150 6   50     34
151 0         0 my $section_name = shift || '';
152 6 50       36 my @blocks = $section_name
153             ? (grep { exists $_->{$section_name} } @$blocks)
154             : (@$blocks);
155 6 100       60  
156             return scalar(@blocks) unless wantarray;
157 3 50       100
158             return (@blocks) if $self->_filters_delay;
159 3         8  
160 64 50       1350 for my $block (@blocks) {
161             $block->run_filters
162             unless $block->is_filtered;
163             }
164 3         37  
165             return (@blocks);
166             }
167              
168 0     0 0 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 0 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 0 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 0 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 0 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 0 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 0     0 0 0 sub filters() {
224 0 0       0 (my ($self), @_) = find_my_self(@_);
225 0         0 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 0         0 }
232             return $self;
233             }
234              
235 0     0 0 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 173     173 0 1590 sub is($$;$) {
246 173         865 (my ($self), @_) = find_my_self(@_);
247 173         743 my ($actual, $expected, $name) = @_;
248 173 50 66     2500 local $Test::Builder::Level = $Test::Builder::Level + 1;
      66        
      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 173         1250 ) {
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 0 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 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 3     3   835  
291 3 0 33     56 sub END {
      33        
292             run_compare() unless $Have_Plan or $DIED or not $import_called;
293             }
294              
295 0     0 0 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 0 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 0 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 0 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 0 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 0 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 3     3   6  
400 3         9 sub _pre_eval {
401 3 50       39 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 3     3   6  
410 3         83 sub _block_list_init {
411 3         26 my $spec = $self->spec;
412 3         88 $spec = $self->_pre_eval($spec);
413 3         1869 my $cd = $self->block_delim;
414 3         33 my @hunks = ($spec =~ /^(\Q${cd}\E.*?(?=^\Q${cd}\E|\z))/msg);
415 3         89 my $blocks = $self->_choose_blocks(@hunks);
416 3         6 $self->block_list($blocks); # Need to set early for possible filter use
417 3         10 my $seq = 1;
418 64         1212 for my $block (@$blocks) {
419 64         1202 $block->blocks_object($self);
420             $block->seq_num($seq++);
421 3         34 }
422             return $blocks;
423             }
424 3     3   9  
425 3         8 sub _choose_blocks {
426 3         10 my $blocks = [];
427 67         174 for my $hunk (@_) {
428 67 50       145 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 67 100       168 }
434 64         110 next if exists $block->{SKIP};
435 64 50       171 push @$blocks, $block;
436 0         0 if (exists $block->{LAST}) {
437             return $blocks;
438             }
439 3         10 }
440             return $blocks;
441             }
442 295     295   308  
443 295         325 sub _check_reserved {
444 295 50 33     1363 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 67     67   77  
450 67         93 sub _make_block {
451 67         1649 my $hunk = shift;
452 67         1483 my $cd = $self->block_delim;
453 67         161 my $dd = $self->data_delim;
454 67 50       569 my $block = $self->block_class->new;
455 67         141 $hunk =~ s/\A\Q${cd}\E[ \t]*(.*)\s+// or die;
456 67         1142 my $name = $1;
457 67         127 my @parts = split /^\Q${dd}\E +\(?(\w+)\)? *(.*)?\n/m, $hunk;
458 67   50     245 my $description = shift @parts;
459 67 50       135 $description ||= '';
460 67         99 unless ($description =~ /\S/) {
461             $description = $name;
462 67         432 }
463 67         163 $description =~ s/\s*\z//;
464             $block->set_value(description => $description);
465 67         100
466 67         96 my $section_map = {};
467 67         146 my $section_order = [];
468 295         581 while (@parts) {
469 295         585 my ($type, $filters, $value) = splice(@parts, 0, 3);
470 295 50       512 $self->_check_reserved($type);
471 295 50       503 $value = '' unless defined $value;
472 295 100       756 $filters = '' unless defined $filters;
473 137 50       278 if ($filters =~ /:(\s|\z)/) {
474             croak "Extra lines not allowed in '$type' section"
475 137         559 if $value =~ /\S/;
476 137 50       307 ($filters, $value) = split /\s*:(?:\s+|\z)/, $filters, 2;
477 137         693 $value = '' unless defined $value;
478             $value =~ s/^\s*(.*?)\s*$/$1/;
479 295         915 }
480             $section_map->{$type} = {
481             filters => $filters,
482 295         529 };
483 295         565 push @$section_order, $type;
484             $block->set_value($type, $value);
485 67         127 }
486 67         134 $block->set_value(name => $name);
487 67         129 $block->set_value(_section_map => $section_map);
488 67         195 $block->set_value(_section_order => $section_order);
489             return $block;
490             }
491 3     3   6  
492 3 50       93 sub _spec_init {
493             return $self->_spec_string
494 3         11 if $self->_spec_string;
495 3         7 local $/;
496 3 50       92 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 3         8 else {
503             $spec = do {
504 3     3   34 package main;
  3         8  
  3         1681  
505 3         123 no warnings 'once';
506             ;
507             };
508 3         19 }
509             return $spec;
510             }
511              
512 6     6   49 sub _strict_warnings() {
513 6         12 require Filter::Util::Call;
514             my $done = 0;
515             Filter::Util::Call::filter_add(
516 9 100   9   60 sub {
517 6         15 return 0 if $done;
518 6         68 my ($data, $end) = ('', '');
519 290 50       506 while (my $status = Filter::Util::Call::filter_read()) {
520 290 100       530 return $status if $status < 0;
521 3         7 if (/^__(?:END|DATA)__\r?$/) {
522 3         8 $end = $_;
523             last;
524 287         313 }
525 287         934 $data .= $_;
526             $_ = '';
527 6         51 }
528 6         90 $_ = "use strict;use warnings;$data$end";
529             $done = 1;
530 6         58 }
531             );
532             }
533              
534 0     0 0 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 1     1 0 4  
540 1         12 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 64     64   1393  
565 64         201 sub AUTOLOAD {
566             return;
567             }
568              
569 37     37   63 sub block_accessor() {
570 3     3   19 my $accessor = shift;
  3         7  
  3         942  
571 37 50       149 no strict 'refs';
572             return if defined &$accessor;
573 1266     1266   8278734 *$accessor = sub {
574 1266 50       3223 my $self = shift;
575 0         0 if (@_) {
576             Carp::croak "Not allowed to set values for '$accessor'";
577 1266 100       1438 }
  1266         8311  
578             my @list = @{$self->{$accessor} || []};
579 1266 100       7109 return wantarray
580             ? (@list)
581 37         262 : $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 1119     1119   1258  
592 3     3   21 sub set_value {
  3         7  
  3         793  
593 1119         1249 no strict 'refs';
594 1119 100       2785 my $accessor = shift;
595             block_accessor $accessor
596 1119         4689 unless defined &$accessor;
597             $self->{$accessor} = [@_];
598             }
599 64     64   83  
600 64         114 sub run_filters {
601 64         139 my $map = $self->_section_map;
602 64 50       1339 my $order = $self->_section_order;
603             Carp::croak "Attempt to filter a block twice"
604 64         123 if $self->is_filtered;
605 278         586 for my $type (@$order) {
606 278         632 my $filters = $map->{$type}{filters};
607 278         5959 my @value = $self->$type;
608 278         679 $self->original_values->{$type} = $value[0];
609 556 50       1057 for my $filter ($self->_get_filters($type, $filters)) {
610             $Test::Base::Filter::arguments =
611 556         1455 $filter =~ s/=(.*)$// ? $1 : undef;
612 3     3   25 my $function = "main::$filter";
  3         12  
  3         2104  
613 556 50       2561 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 556         13487 else {
630 556 50       1749 my $filter_object = $self->blocks_object->filter_class->new;
631             die "Can't find a function or method for '$filter' filter\n"
632 556         12492 unless $filter_object->can($filter);
633 556         1553 $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 556         1322 # introspecting.
638             $self->set_value($type, @value);
639             }
640 64         1353 }
641             $self->is_filtered(1);
642             }
643 278     278   300  
644 278         363 sub _get_filters {
645 278   50     879 my $type = shift;
646 278         1025 my $string = shift || '';
647 278         423 $string =~ s/\s*(.*?)\s*/$1/;
648 278   50     5664 my @filters = ();
649 278 50       655 my $map_filters = $self->blocks_object->_filters_map->{$type} || [];
650 278         374 $map_filters = [ $map_filters ] unless ref $map_filters;
651 278         265 my @append = ();
652 278         5550 for (
653             @{$self->blocks_object->_filters},
654             @$map_filters,
655             split(/\s+/, $string),
656 556         581 ) {
657 556 50       2622 my $filter = $_;
658 556 50       1189 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 556         1162 else {
666             push @filters, $filter;
667             }
668 278         894 }
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__