File Coverage

blib/lib/ifdef.pm
Criterion Covered Total %
statement 50 58 86.2
branch 32 42 76.1
condition 6 11 54.5
subroutine 8 9 88.8
pod 3 3 100.0
total 99 123 80.4


line stmt bran cond sub pod time code
1             package ifdef;
2              
3             $VERSION= '0.09';
4              
5             # be strict from now on
6 4     4   3496 use strict;
  4         9  
  4         326  
7              
8             # take all =begin CAPITALS pod sections
9             my $ALL;
10              
11             # output all source to be output as diff to STDERR
12             BEGIN {
13 4   50 4   38 my $diff= $ENV{'IFDEF_DIFF'} || 0;
14 4         316 eval "sub DIFF () { $diff }";
15             } #BEGIN
16              
17             # get the necessary modules
18 4     4   3933 use IO::File ();
  4         47759  
  4         106  
19              
20             # set up source filter for the initial script
21 4     4   242737 use Filter::Util::Call ();
  4         4829  
  4         5084  
22              
23             # initializations
24             my $STATUS; # status as returned by source filter
25             my $ACTIVATING; # whether we're inside a =begin section being activated
26             my $INPOD; # whether we're inside any =pod section
27             my $DEPTH; # depth of conditionals
28             my @STATE; # state of each level
29             my %IFDEF; # filename conversion hash
30              
31             # install an @INC handler
32             unshift( @INC, sub {
33             my ( $ref, $filename, $path )= @_;
34              
35             # return what we know of this module
36             if ( !ref $ref ) {
37             $ref =~ s#/#::#;
38             return $IFDEF{$ref};
39             }
40              
41             # check all directories and handlers
42             foreach (@INC) {
43              
44             # let that INC handle do it if it is an INC handle and it's not us
45             if (ref) {
46             goto &$_ unless $_ eq $ref;
47             }
48              
49             # we found the file
50             elsif ( -f ( $path= "$_/$filename" ) ) {
51              
52             # create temp file
53             open( my $in, $path ) or next;
54             my $out= IO::File->new_tmpfile
55             or die "Failed to create temporary file for '$path': $!\n";
56             $filename =~ s#/#::#;
57             $IFDEF{$filename}= $path;
58              
59             # process all lines
60             local $_= \my $foo; # current state of localizing $_ ?
61             while ( readline $in ) {
62             &oneline;
63             print $out $_;
64             }
65             close $in;
66             &reset;
67              
68             # make sure we start reading from start again
69             $out->seek( 0, 0 ) or die "Failed to seek: $!\n";
70              
71             return $out;
72             }
73             }
74              
75             # indicate that the rest should be searched (which will fail)
76             return;
77             } );
78              
79             # satisfy require
80             1;
81              
82             #---------------------------------------------------------------------------
83             # process
84             #
85             # Process a string (consisting of many lines)
86             #
87             # IN: 1 string to process
88             # OUT: 1 processed string (in place change if called in void context)
89              
90             sub process {
91              
92             # process all lines
93 7     7 1 3311 my @line= split m#(?<=$/)#, $_[0];
94 7         24 &reset;
95 7         11 local $_= \my $foo;
96 7         21 &oneline foreach @line;
97              
98             # close of activating section (e.g. when called by "load")
99 7 100       23 push @line,"}$/" if $ACTIVATING;
100              
101             # return if not in void context
102 7 50       81 return join( '', @line ) if defined wantarray;
103              
104             # change in place
105 0         0 $_[0]= join( '',@line );
106              
107 0         0 return undef;
108             } #process
109              
110             #---------------------------------------------------------------------------
111             # reset
112             #
113             # Reset all internal variables to a known state
114              
115 22     22 1 44 sub reset { $ACTIVATING= $INPOD= $DEPTH= 0 } #reset
116              
117             #---------------------------------------------------------------------------
118             # oneline
119             #
120             # Process one line in $_ in place
121              
122             sub oneline {
123              
124             # let the world know if we should
125 157     157 1 143 print STDERR "<$_" if DIFF;
126              
127             # it's a pod marker
128 157 100       404 if ( m#^=(\w+)# ){
    100          
    100          
129              
130             # going back to source
131 35 100       113 if ( $1 eq 'cut' ) {
    100          
    100          
132 9 100       23 $_= $ACTIVATING ? "}$/" : $/;
133 9         16 &reset;
134             }
135              
136             # beginning potentially special pod section
137             elsif ( $1 eq 'begin' ) {
138 16 100       55 if ( m#^=begin\s+([A-Z_0-9]+)\b# ) {
139              
140             # activating
141 14 100 100     60 if ( $ALL or $ENV{$1} ) {
142 9 100       29 $_= $ACTIVATING ? "}{$/" : "{;$/";
143 9         13 $ACTIVATING= 1;
144 9         15 $INPOD= 0;
145             }
146              
147             # not activating now
148             else {
149 5 100       13 $_= $ACTIVATING ? "}$/" : $/;
150 5         7 $ACTIVATING= 0;
151 5         7 $INPOD= 1;
152             }
153             }
154              
155             # normal begin of pod
156             else {
157 2         5 $_= $/;
158 2         3 $INPOD= 1;
159             }
160             }
161              
162             # at the end of a possibly activated section
163             elsif ( $1 eq 'end' ) {
164 5 100       12 $_ = $ACTIVATING ? "}$/" : $/;
165 5         7 $ACTIVATING= 0;
166 5         6 $INPOD= 1;
167             }
168              
169             # it's another pod directive
170             else {
171 5         9 $_= $/;
172 5         7 $INPOD= 1;
173             }
174             }
175              
176             # already inside pod
177             elsif ($INPOD) {
178 52         75 $_= $/;
179             }
180              
181             # looks like comment, make it normal line if so indicated
182             elsif ( m/^#\s+([A-Z_0-9]+)\b/ ) {
183 7 100       34 s/^#\s+(?:[A-Z_0-9]+)\b// if $ENV{$1};
184             }
185              
186             # let the world know if we should
187 157         269 print STDERR ">$_" if DIFF;
188             } #oneline
189              
190             #---------------------------------------------------------------------------
191              
192             # Perl specific subroutines
193              
194             #---------------------------------------------------------------------------
195             # IN: 1 class (ignored)
196             # 2..N keys to watch for
197              
198             sub import {
199              
200             # being called from source (unless it's from the test-suite)
201 6 50 33 6   3748 warn "The '".
      33        
202             __PACKAGE__.
203             "' pragma is not supposed to be called from source\n"
204             if ( (caller)[2] ) and ( $_[0] ne '_testing_' and !shift );
205              
206             # lose the class
207 6         14 shift;
208              
209             # check all parameters
210 6         9 my @ignored;
211 6         22 foreach (@_) {
212             # it's all
213 2 50       13 if ( m#^:?all$# ) {
    0          
    0          
214 2         6 $ALL= 1;
215             }
216              
217             # not all
218             elsif ( m#^:?selected$# ) {
219 0         0 $ALL= 0;
220             }
221              
222             # looks like an environment var reference
223             elsif ( m#^[A-Z_0-9]+$# ) {
224 0         0 $ENV{$_}= 1;
225             }
226              
227             # huh?
228             else {
229 0         0 push @ignored, $_;
230             }
231             }
232              
233             # huh?
234 6 50       19 warn "Ignored parameters: @ignored\n" if @ignored;
235              
236             # make sure we start with a clean slate
237 6         16 &reset;
238              
239             # set up source filter
240             return Filter::Util::Call::filter_add( sub {
241 0 0   0     if ( ( $STATUS= Filter::Util::Call::filter_read() ) > 0 ) {
242 0           &oneline;
243             }
244 0           $STATUS;
245 6         43 } );
246             } #import
247              
248             #---------------------------------------------------------------------------
249              
250             __END__