xref: /openbsd-src/gnu/usr.bin/perl/cpan/Test-Harness/lib/TAP/Parser/SourceHandler/Executable.pm (revision 48950c12d106c85f315112191a0228d7b83b9510)
1package TAP::Parser::SourceHandler::Executable;
2
3use strict;
4use vars qw($VERSION @ISA);
5
6use TAP::Parser::SourceHandler     ();
7use TAP::Parser::IteratorFactory   ();
8use TAP::Parser::Iterator::Process ();
9
10@ISA = qw(TAP::Parser::SourceHandler);
11
12TAP::Parser::IteratorFactory->register_handler(__PACKAGE__);
13
14=head1 NAME
15
16TAP::Parser::SourceHandler::Executable - Stream output from an executable TAP source
17
18=head1 VERSION
19
20Version 3.23
21
22=cut
23
24$VERSION = '3.23';
25
26=head1 SYNOPSIS
27
28  use TAP::Parser::Source;
29  use TAP::Parser::SourceHandler::Executable;
30
31  my $source = TAP::Parser::Source->new->raw(['/usr/bin/ruby', 'mytest.rb']);
32  $source->assemble_meta;
33
34  my $class = 'TAP::Parser::SourceHandler::Executable';
35  my $vote  = $class->can_handle( $source );
36  my $iter  = $class->make_iterator( $source );
37
38=head1 DESCRIPTION
39
40This is an I<executable> L<TAP::Parser::SourceHandler> - it has 2 jobs:
41
421. Figure out if the L<TAP::Parser::Source> it's given is an executable
43   command (L</can_handle>).
44
452. Creates an iterator for executable commands (L</make_iterator>).
46
47Unless you're writing a plugin or subclassing L<TAP::Parser>, you
48probably won't need to use this module directly.
49
50=head1 METHODS
51
52=head2 Class Methods
53
54=head3 C<can_handle>
55
56  my $vote = $class->can_handle( $source );
57
58Only votes if $source looks like an executable file. Casts the
59following votes:
60
61  0.9  if it's a hash with an 'exec' key
62  0.8  if it's a .bat file
63  0.75 if it's got an execute bit set
64
65=cut
66
67sub can_handle {
68    my ( $class, $src ) = @_;
69    my $meta = $src->meta;
70
71    if ( $meta->{is_file} ) {
72        my $file = $meta->{file};
73
74        return 0.85 if $file->{execute} && $file->{binary};
75        return 0.8 if $file->{lc_ext} eq '.bat';
76        return 0.25 if $file->{execute};
77    }
78    elsif ( $meta->{is_hash} ) {
79        return 0.9 if $src->raw->{exec};
80    }
81
82    return 0;
83}
84
85=head3 C<make_iterator>
86
87  my $iterator = $class->make_iterator( $source );
88
89Returns a new L<TAP::Parser::Iterator::Process> for the source.
90C<$source-E<gt>raw> must be in one of the following forms:
91
92  { exec => [ @exec ] }
93
94  [ @exec ]
95
96  $file
97
98C<croak>s on error.
99
100=cut
101
102sub make_iterator {
103    my ( $class, $source ) = @_;
104    my $meta = $source->meta;
105
106    my @command;
107    if ( $meta->{is_hash} ) {
108        @command = @{ $source->raw->{exec} || [] };
109    }
110    elsif ( $meta->{is_scalar} ) {
111        @command = ${ $source->raw };
112    }
113    elsif ( $meta->{is_array} ) {
114        @command = @{ $source->raw };
115    }
116
117    $class->_croak('No command found in $source->raw!') unless @command;
118
119    $class->_autoflush( \*STDOUT );
120    $class->_autoflush( \*STDERR );
121
122    push @command, @{ $source->test_args || [] };
123
124    return $class->iterator_class->new(
125        {   command => \@command,
126            merge   => $source->merge
127        }
128    );
129}
130
131=head3 C<iterator_class>
132
133The class of iterator to use, override if you're sub-classing.  Defaults
134to L<TAP::Parser::Iterator::Process>.
135
136=cut
137
138use constant iterator_class => 'TAP::Parser::Iterator::Process';
139
140# Turns on autoflush for the handle passed
141sub _autoflush {
142    my ( $class, $flushed ) = @_;
143    my $old_fh = select $flushed;
144    $| = 1;
145    select $old_fh;
146}
147
1481;
149
150=head1 SUBCLASSING
151
152Please see L<TAP::Parser/SUBCLASSING> for a subclassing overview.
153
154=head2 Example
155
156  package MyRubySourceHandler;
157
158  use strict;
159  use vars '@ISA';
160
161  use Carp qw( croak );
162  use TAP::Parser::SourceHandler::Executable;
163
164  @ISA = qw( TAP::Parser::SourceHandler::Executable );
165
166  # expect $handler->(['mytest.rb', 'cmdline', 'args']);
167  sub make_iterator {
168    my ($self, $source) = @_;
169    my @test_args = @{ $source->test_args };
170    my $rb_file   = $test_args[0];
171    croak("error: Ruby file '$rb_file' not found!") unless (-f $rb_file);
172    return $self->SUPER::raw_source(['/usr/bin/ruby', @test_args]);
173  }
174
175=head1 SEE ALSO
176
177L<TAP::Object>,
178L<TAP::Parser>,
179L<TAP::Parser::IteratorFactory>,
180L<TAP::Parser::SourceHandler>,
181L<TAP::Parser::SourceHandler::Perl>,
182L<TAP::Parser::SourceHandler::File>,
183L<TAP::Parser::SourceHandler::Handle>,
184L<TAP::Parser::SourceHandler::RawTAP>
185
186=cut
187