1 package TAP::Parser::Multiplexer;
4 use vars qw($VERSION @ISA);
9 use constant IS_WIN32 => $^O =~ /^(MS)?Win32$/;
10 use constant IS_VMS => $^O eq 'VMS';
11 use constant SELECT_OK => !( IS_VMS || IS_WIN32 );
17 TAP::Parser::Multiplexer - Multiplex multiple TAP::Parsers
29 use TAP::Parser::Multiplexer;
31 my $mux = TAP::Parser::Multiplexer->new;
32 $mux->add( $parser1, $stash1 );
33 $mux->add( $parser2, $stash2 );
34 while ( my ( $parser, $stash, $result ) = $mux->next ) {
40 C<TAP::Parser::Multiplexer> gathers input from multiple TAP::Parsers.
41 Internally it calls select on the input file handles for those parsers
42 to wait for one or more of them to have input available.
44 See L<TAP::Harness> for an example of its use.
52 my $mux = TAP::Parser::Multiplexer->new;
54 Returns a new C<TAP::Parser::Multiplexer> object.
58 # new() implementation supplied by TAP::Object
62 $self->{select} = IO::Select->new;
63 $self->{avid} = []; # Parsers that can't select
68 ##############################################################################
70 =head2 Instance Methods
74 $mux->add( $parser, $stash );
76 Add a TAP::Parser to the multiplexer. C<$stash> is an optional opaque
77 reference that will be returned from C<next> along with the parser and
83 my ( $self, $parser, $stash ) = @_;
85 if ( SELECT_OK && ( my @handles = $parser->get_select_handles ) ) {
86 my $sel = $self->{select};
88 # We have to turn handles into file numbers here because by
89 # the time we want to remove them from our IO::Select they
90 # will already have been closed by the iterator.
91 my @filenos = map { fileno $_ } @handles;
92 for my $h (@handles) {
93 $sel->add( [ $h, $parser, $stash, @filenos ] );
99 push @{ $self->{avid} }, [ $parser, $stash ];
105 my $count = $mux->parsers;
107 Returns the number of parsers. Parsers are removed from the multiplexer
108 when their input is exhausted.
114 return $self->{count} + scalar @{ $self->{avid} };
120 my $sel = $self->{select};
121 my $avid = $self->{avid};
126 # Drain all the non-selectable parsers first
128 my ( $parser, $stash ) = @{ $avid->[0] };
129 my $result = $parser->next;
130 shift @$avid unless defined $result;
131 return ( $parser, $stash, $result );
135 return unless $sel->count;
136 @ready = $sel->can_read;
139 my ( $h, $parser, $stash, @handles ) = @{ shift @ready };
140 my $result = $parser->next;
142 unless ( defined $result ) {
143 $sel->remove(@handles);
146 # Force another can_read - we may now have removed a handle
147 # thought to have been ready.
151 return ( $parser, $stash, $result );
157 Return a result from the next available parser. Returns a list
158 containing the parser from which the result came, the stash that
159 corresponds with that parser and the result.
161 my ( $parser, $stash, $result ) = $mux->next;
163 If C<$result> is undefined the corresponding parser has reached the end
164 of its input (and will automatically be removed from the multiplexer).
166 When all parsers are exhausted an empty list will be returned.
168 if ( my ( $parser, $stash, $result ) = $mux->next ) {
169 if ( ! defined $result ) {
177 # All parsers finished
184 return ( $self->{_iter} ||= $self->_iter )->();