File Coverage

blib/lib/TAP/Parser/SourceHandler/Executable.pm
Criterion Covered Total %
statement 47 47 100.0
branch 21 24 87.5
condition 2 3 66.6
subroutine 9 9 100.0
pod 2 2 100.0
total 81 85 95.2


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