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   2237 use strict;
  38         45  
  38         905  
4 38     38   126 use warnings;
  38         41  
  38         808  
5              
6 38     38   492 use TAP::Parser::IteratorFactory ();
  38         40  
  38         406  
7 38     38   10033 use TAP::Parser::Iterator::Process ();
  38         69  
  38         856  
8              
9 38     38   175 use base 'TAP::Parser::SourceHandler';
  38         42  
  38         14172  
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.39
20              
21             =cut
22              
23             our $VERSION = '3.39';
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 545 my ( $class, $src ) = @_;
68 307         684 my $meta = $src->meta;
69              
70 307 100       877 if ( $meta->{is_file} ) {
    100          
71 221         364 my $file = $meta->{file};
72              
73 221 50 66     566 return 0.85 if $file->{execute} && $file->{binary};
74 221 100       655 return 0.8 if $file->{lc_ext} eq '.bat';
75 219 100       548 return 0.25 if $file->{execute};
76             }
77             elsif ( $meta->{is_hash} ) {
78 12 50       39 return 0.9 if $src->raw->{exec};
79             }
80              
81 289         667 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 76 my ( $class, $source ) = @_;
103 15         38 my $meta = $source->meta;
104              
105 15         21 my @command;
106 15 100       48 if ( $meta->{is_hash} ) {
    100          
    100          
107 11 50       14 @command = @{ $source->raw->{exec} || [] };
  11         28  
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       56 $class->_croak('No command found in $source->raw!') unless @command;
117              
118 13         63 $class->_autoflush( \*STDOUT );
119 13         30 $class->_autoflush( \*STDERR );
120              
121 13 100       19 push @command, @{ $source->test_args || [] };
  13         30  
122              
123 13         85 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   174 use constant iterator_class => 'TAP::Parser::Iterator::Process';
  38         45  
  38         4524  
138              
139             # Turns on autoflush for the handle passed
140             sub _autoflush {
141 446     446   504 my ( $class, $flushed ) = @_;
142 446         1024 my $old_fh = select $flushed;
143 446         814 $| = 1;
144 446         1240 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