1 package TAP::Parser::Source::Perl;
5 use vars qw($VERSION @ISA);
7 use constant IS_WIN32 => ( $^O =~ /^(MS)?Win32$/ );
8 use constant IS_VMS => ( $^O eq 'VMS' );
10 use TAP::Parser::Source;
11 @ISA = 'TAP::Parser::Source';
15 TAP::Parser::Source::Perl - Stream Perl output
27 use TAP::Parser::Source::Perl;
28 my $perl = TAP::Parser::Source::Perl->new({ parser => $parser });
29 my $stream = $perl->source( [ $filename, @args ] )->get_stream;
33 Takes a filename and hopefully returns a stream from it. The filename should
34 be the name of a Perl program.
36 Note that this is a subclass of L<TAP::Parser::Source>. See that module for
45 my $perl = TAP::Parser::Source::Perl->new({ parser => $parser });
47 Returns a new C<TAP::Parser::Source::Perl> object.
49 =head2 Instance Methods
53 Getter/setter the name of the test program and any arguments it requires.
55 my ($filename, @args) = @{ $perl->source };
56 $perl->source( [ $filename, @args ] );
58 C<croak>s if C<$filename> could not be found.
64 $self->_croak("Cannot find ($_[0][0])")
65 if @_ && !-f $_[0][0];
66 return $self->SUPER::source(@_);
71 my $switches = $perl->switches;
72 my @switches = $perl->switches;
73 $perl->switches( \@switches );
75 Getter/setter for the additional switches to pass to the perl executable. One
76 common switch would be to set an include directory:
78 $perl->switches( ['-Ilib'] );
85 return wantarray ? @{ $self->{switches} } : $self->{switches};
88 $self->{switches} = [@$switches]; # force a copy
92 ##############################################################################
96 my $stream = $source->get_stream;
98 Returns a stream of the output generated by executing C<source>.
107 my @switches = $self->_switches;
108 my $path_sep = $Config{path_sep};
109 my $path_pat = qr{$path_sep};
111 # Nasty kludge. It might be nicer if we got the libs separately
112 # although at least this way we find any -I switches that were
113 # supplied other then as explicit libs.
114 # We filter out any names containing colons because they will break
117 for ( grep { $_ !~ $path_pat } @switches ) {
118 push @libs, $1 if / ^ ['"]? -I (.*?) ['"]? $ /x;
121 my $previous = $ENV{PERL5LIB};
123 push @libs, split( $path_pat, $previous );
128 $ENV{PERL5LIB} = join( $path_sep, @libs );
132 # Cargo culted from comments seen elsewhere about VMS / environment
133 # variables. I don't know if this is actually necessary.
136 $ENV{PERL5LIB} = $previous;
139 delete $ENV{PERL5LIB};
143 # Taint mode ignores environment variables so we must retranslate
144 # PERL5LIB as -I switches and place PERL5OPT on the command line
145 # in order that it be seen.
146 if ( grep { $_ eq "-T" } @switches ) {
148 $self->_libs2switches(
150 $ENV{PERL5LIB} || $ENV{PERLLIB} || ''
153 push @switches, $ENV{PERL5OPT} || ();
156 my @command = $self->_get_command_for_switches(@switches)
157 or $self->_croak("No command found!");
159 return $self->{parser}->make_iterator(
160 { command => \@command,
161 merge => $self->merge,
163 teardown => $teardown,
168 sub _get_command_for_switches {
171 my ( $file, @args ) = @{ $self->source };
172 my $command = $self->_get_perl;
174 # XXX we never need to quote if we treat the parts as atoms (except maybe vms)
175 #$file = qq["$file"] if ( $file =~ /\s/ ) && ( $file !~ /^".*"$/ );
176 my @command = ( $command, @switches, $file, @args );
182 return $self->_get_command_for_switches( $self->_switches );
187 return map {"-I$_"} grep {$_} @_;
192 Get the shebang line for a script file.
194 my $shebang = TAP::Parser::Source::Perl->shebang( $some_script );
196 May be called as a class method
202 # Global shebang cache.
209 if ( open( TEST, $file ) ) {
211 close(TEST) or print "Can't close $file. $!\n";
214 print "Can't open $file. $!\n";
220 my ( $class, $file ) = @_;
221 unless ( exists $shebang_for{$file} ) {
222 $shebang_for{$file} = _read_shebang($file);
224 return $shebang_for{$file};
230 Decode any taint switches from a Perl shebang line.
233 my $taint = TAP::Parser::Source::Perl->get_taint( '#!/usr/bin/perl -t' );
235 # $untaint will be undefined
236 my $untaint = TAP::Parser::Source::Perl->get_taint( '#!/usr/bin/perl' );
241 my ( $class, $shebang ) = @_;
243 unless defined $shebang
244 && $shebang =~ /^#!.*\bperl.*\s-\w*([Tt]+)/;
250 my ( $file, @args ) = @{ $self->source };
255 my $shebang = $self->shebang($file);
256 return unless defined $shebang;
258 my $taint = $self->get_taint($shebang);
259 push @switches, "-$taint" if defined $taint;
261 # Quote the argument if there's any whitespace in it, or if
262 # we're VMS, since VMS requires all parms quoted. Also, don't quote
263 # it if it's already quoted.
265 $_ = qq["$_"] if ( ( /\s/ || IS_VMS ) && !/^".*"$/ );
273 return $ENV{HARNESS_PERL} if defined $ENV{HARNESS_PERL};
274 return Win32::GetShortPathName($^X) if IS_WIN32;
283 Please see L<TAP::Parser/SUBCLASSING> for a subclassing overview.
287 package MyPerlSource;
292 use Carp qw( croak );
293 use TAP::Parser::Source::Perl;
295 @ISA = qw( TAP::Parser::Source::Perl );
298 my ($self, $args) = @_;
300 $self->{file} = $args->[0];
301 return $self->SUPER::source($args);
303 return $self->SUPER::source;
306 # use the version of perl from the shebang line in the test file
309 if (my $shebang = $self->shebang( $self->{file} )) {
310 $shebang =~ /^#!(.*\bperl.*?)(?:(?:\s)|(?:$))/;
313 return $self->SUPER::_get_perl(@_);
320 L<TAP::Parser::Source>,