summaryrefslogtreecommitdiffstats
path: root/upstream/mageia-cauldron/man3pm/TAP::Parser.3pm
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 19:43:11 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 19:43:11 +0000
commitfc22b3d6507c6745911b9dfcc68f1e665ae13dbc (patch)
treece1e3bce06471410239a6f41282e328770aa404a /upstream/mageia-cauldron/man3pm/TAP::Parser.3pm
parentInitial commit. (diff)
downloadmanpages-l10n-fc22b3d6507c6745911b9dfcc68f1e665ae13dbc.tar.xz
manpages-l10n-fc22b3d6507c6745911b9dfcc68f1e665ae13dbc.zip
Adding upstream version 4.22.0.upstream/4.22.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'upstream/mageia-cauldron/man3pm/TAP::Parser.3pm')
-rw-r--r--upstream/mageia-cauldron/man3pm/TAP::Parser.3pm1412
1 files changed, 1412 insertions, 0 deletions
diff --git a/upstream/mageia-cauldron/man3pm/TAP::Parser.3pm b/upstream/mageia-cauldron/man3pm/TAP::Parser.3pm
new file mode 100644
index 00000000..91fa32b8
--- /dev/null
+++ b/upstream/mageia-cauldron/man3pm/TAP::Parser.3pm
@@ -0,0 +1,1412 @@
+.\" -*- mode: troff; coding: utf-8 -*-
+.\" Automatically generated by Pod::Man 5.01 (Pod::Simple 3.43)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>.
+.ie n \{\
+. ds C` ""
+. ds C' ""
+'br\}
+.el\{\
+. ds C`
+. ds C'
+'br\}
+.\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\"
+.\" If the F register is >0, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
+.\" entries marked with X<> in POD. Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.\"
+.\" Avoid warning from groff about undefined register 'F'.
+.de IX
+..
+.nr rF 0
+.if \n(.g .if rF .nr rF 1
+.if (\n(rF:(\n(.g==0)) \{\
+. if \nF \{\
+. de IX
+. tm Index:\\$1\t\\n%\t"\\$2"
+..
+. if !\nF==2 \{\
+. nr % 0
+. nr F 2
+. \}
+. \}
+.\}
+.rr rF
+.\" ========================================================================
+.\"
+.IX Title "TAP::Parser 3pm"
+.TH TAP::Parser 3pm 2023-11-28 "perl v5.38.2" "Perl Programmers Reference Guide"
+.\" For nroff, turn off justification. Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.if n .ad l
+.nh
+.SH NAME
+TAP::Parser \- Parse TAP output
+.SH VERSION
+.IX Header "VERSION"
+Version 3.44
+.SH SYNOPSIS
+.IX Header "SYNOPSIS"
+.Vb 1
+\& use TAP::Parser;
+\&
+\& my $parser = TAP::Parser\->new( { source => $source } );
+\&
+\& while ( my $result = $parser\->next ) {
+\& print $result\->as_string;
+\& }
+.Ve
+.SH DESCRIPTION
+.IX Header "DESCRIPTION"
+\&\f(CW\*(C`TAP::Parser\*(C'\fR is designed to produce a proper parse of TAP output. For
+an example of how to run tests through this module, see the simple
+harnesses \f(CW\*(C`examples/\*(C'\fR.
+.PP
+There's a wiki dedicated to the Test Anything Protocol:
+.PP
+<http://testanything.org>
+.PP
+It includes the TAP::Parser Cookbook:
+.PP
+<http://testanything.org/testing\-with\-tap/perl/tap::parser\-cookbook.html>
+.SH METHODS
+.IX Header "METHODS"
+.SS "Class Methods"
+.IX Subsection "Class Methods"
+\fR\f(CI\*(C`new\*(C'\fR\fI\fR
+.IX Subsection "new"
+.PP
+.Vb 1
+\& my $parser = TAP::Parser\->new(\e%args);
+.Ve
+.PP
+Returns a new \f(CW\*(C`TAP::Parser\*(C'\fR object.
+.PP
+The arguments should be a hashref with \fIone\fR of the following keys:
+.IP \(bu 4
+\&\f(CW\*(C`source\*(C'\fR
+.Sp
+\&\fICHANGED in 3.18\fR
+.Sp
+This is the preferred method of passing input to the constructor.
+.Sp
+The \f(CW\*(C`source\*(C'\fR is used to create a TAP::Parser::Source that is passed to the
+"iterator_factory_class" which in turn figures out how to handle the source and
+creates a <TAP::Parser::Iterator> for it. The iterator is used by the parser to
+read in the TAP stream.
+.Sp
+To configure the \fIIteratorFactory\fR use the \f(CW\*(C`sources\*(C'\fR parameter below.
+.Sp
+Note that \f(CW\*(C`source\*(C'\fR, \f(CW\*(C`tap\*(C'\fR and \f(CW\*(C`exec\*(C'\fR are \fImutually exclusive\fR.
+.IP \(bu 4
+\&\f(CW\*(C`tap\*(C'\fR
+.Sp
+\&\fICHANGED in 3.18\fR
+.Sp
+The value should be the complete TAP output.
+.Sp
+The \fItap\fR is used to create a TAP::Parser::Source that is passed to the
+"iterator_factory_class" which in turn figures out how to handle the source and
+creates a <TAP::Parser::Iterator> for it. The iterator is used by the parser to
+read in the TAP stream.
+.Sp
+To configure the \fIIteratorFactory\fR use the \f(CW\*(C`sources\*(C'\fR parameter below.
+.Sp
+Note that \f(CW\*(C`source\*(C'\fR, \f(CW\*(C`tap\*(C'\fR and \f(CW\*(C`exec\*(C'\fR are \fImutually exclusive\fR.
+.IP \(bu 4
+\&\f(CW\*(C`exec\*(C'\fR
+.Sp
+Must be passed an array reference.
+.Sp
+The \fIexec\fR array ref is used to create a TAP::Parser::Source that is passed
+to the "iterator_factory_class" which in turn figures out how to handle the
+source and creates a <TAP::Parser::Iterator> for it. The iterator is used by
+the parser to read in the TAP stream.
+.Sp
+By default the TAP::Parser::SourceHandler::Executable class will create a
+TAP::Parser::Iterator::Process object to handle the source. This passes the
+array reference strings as command arguments to IPC::Open3::open3:
+.Sp
+.Vb 1
+\& exec => [ \*(Aq/usr/bin/ruby\*(Aq, \*(Aqt/my_test.rb\*(Aq ]
+.Ve
+.Sp
+If any \f(CW\*(C`test_args\*(C'\fR are given they will be appended to the end of the command
+argument list.
+.Sp
+To configure the \fIIteratorFactory\fR use the \f(CW\*(C`sources\*(C'\fR parameter below.
+.Sp
+Note that \f(CW\*(C`source\*(C'\fR, \f(CW\*(C`tap\*(C'\fR and \f(CW\*(C`exec\*(C'\fR are \fImutually exclusive\fR.
+.PP
+The following keys are optional.
+.IP \(bu 4
+\&\f(CW\*(C`sources\*(C'\fR
+.Sp
+\&\fINEW to 3.18\fR.
+.Sp
+If set, \f(CW\*(C`sources\*(C'\fR must be a hashref containing the names of the
+TAP::Parser::SourceHandlers to load and/or configure. The values are a
+hash of configuration that will be accessible to the source handlers via
+"config_for" in TAP::Parser::Source.
+.Sp
+For example:
+.Sp
+.Vb 5
+\& sources => {
+\& Perl => { exec => \*(Aq/path/to/custom/perl\*(Aq },
+\& File => { extensions => [ \*(Aq.tap\*(Aq, \*(Aq.txt\*(Aq ] },
+\& MyCustom => { some => \*(Aqconfig\*(Aq },
+\& }
+.Ve
+.Sp
+This will cause \f(CW\*(C`TAP::Parser\*(C'\fR to pass custom configuration to two of the built\-
+in source handlers \- TAP::Parser::SourceHandler::Perl,
+TAP::Parser::SourceHandler::File \- and attempt to load the \f(CW\*(C`MyCustom\*(C'\fR
+class. See "load_handlers" in TAP::Parser::IteratorFactory for more detail.
+.Sp
+The \f(CW\*(C`sources\*(C'\fR parameter affects how \f(CW\*(C`source\*(C'\fR, \f(CW\*(C`tap\*(C'\fR and \f(CW\*(C`exec\*(C'\fR parameters
+are handled.
+.Sp
+See TAP::Parser::IteratorFactory, TAP::Parser::SourceHandler and subclasses for
+more details.
+.IP \(bu 4
+\&\f(CW\*(C`callback\*(C'\fR
+.Sp
+If present, each callback corresponding to a given result type will be called
+with the result as the argument if the \f(CW\*(C`run\*(C'\fR method is used:
+.Sp
+.Vb 7
+\& my %callbacks = (
+\& test => \e&test_callback,
+\& plan => \e&plan_callback,
+\& comment => \e&comment_callback,
+\& bailout => \e&bailout_callback,
+\& unknown => \e&unknown_callback,
+\& );
+\&
+\& my $aggregator = TAP::Parser::Aggregator\->new;
+\& for my $file ( @test_files ) {
+\& my $parser = TAP::Parser\->new(
+\& {
+\& source => $file,
+\& callbacks => \e%callbacks,
+\& }
+\& );
+\& $parser\->run;
+\& $aggregator\->add( $file, $parser );
+\& }
+.Ve
+.IP \(bu 4
+\&\f(CW\*(C`switches\*(C'\fR
+.Sp
+If using a Perl file as a source, optional switches may be passed which will
+be used when invoking the perl executable.
+.Sp
+.Vb 4
+\& my $parser = TAP::Parser\->new( {
+\& source => $test_file,
+\& switches => [ \*(Aq\-Ilib\*(Aq ],
+\& } );
+.Ve
+.IP \(bu 4
+\&\f(CW\*(C`test_args\*(C'\fR
+.Sp
+Used in conjunction with the \f(CW\*(C`source\*(C'\fR and \f(CW\*(C`exec\*(C'\fR option to supply a reference
+to an \f(CW@ARGV\fR style array of arguments to pass to the test program.
+.IP \(bu 4
+\&\f(CW\*(C`spool\*(C'\fR
+.Sp
+If passed a filehandle will write a copy of all parsed TAP to that handle.
+.IP \(bu 4
+\&\f(CW\*(C`merge\*(C'\fR
+.Sp
+If false, STDERR is not captured (though it is 'relayed' to keep it
+somewhat synchronized with STDOUT.)
+.Sp
+If true, STDERR and STDOUT are the same filehandle. This may cause
+breakage if STDERR contains anything resembling TAP format, but does
+allow exact synchronization.
+.Sp
+Subtleties of this behavior may be platform-dependent and may change in
+the future.
+.IP \(bu 4
+\&\f(CW\*(C`grammar_class\*(C'\fR
+.Sp
+This option was introduced to let you easily customize which \fIgrammar\fR class
+the parser should use. It defaults to TAP::Parser::Grammar.
+.Sp
+See also "make_grammar".
+.IP \(bu 4
+\&\f(CW\*(C`result_factory_class\*(C'\fR
+.Sp
+This option was introduced to let you easily customize which \fIresult\fR
+factory class the parser should use. It defaults to
+TAP::Parser::ResultFactory.
+.Sp
+See also "make_result".
+.IP \(bu 4
+\&\f(CW\*(C`iterator_factory_class\*(C'\fR
+.Sp
+\&\fICHANGED in 3.18\fR
+.Sp
+This option was introduced to let you easily customize which \fIiterator\fR
+factory class the parser should use. It defaults to
+TAP::Parser::IteratorFactory.
+.SS "Instance Methods"
+.IX Subsection "Instance Methods"
+\fR\f(CI\*(C`next\*(C'\fR\fI\fR
+.IX Subsection "next"
+.PP
+.Vb 4
+\& my $parser = TAP::Parser\->new( { source => $file } );
+\& while ( my $result = $parser\->next ) {
+\& print $result\->as_string, "\en";
+\& }
+.Ve
+.PP
+This method returns the results of the parsing, one result at a time. Note
+that it is destructive. You can't rewind and examine previous results.
+.PP
+If callbacks are used, they will be issued before this call returns.
+.PP
+Each result returned is a subclass of TAP::Parser::Result. See that
+module and related classes for more information on how to use them.
+.PP
+\fR\f(CI\*(C`run\*(C'\fR\fI\fR
+.IX Subsection "run"
+.PP
+.Vb 1
+\& $parser\->run;
+.Ve
+.PP
+This method merely runs the parser and parses all of the TAP.
+.PP
+\fR\f(CI\*(C`make_grammar\*(C'\fR\fI\fR
+.IX Subsection "make_grammar"
+.PP
+Make a new TAP::Parser::Grammar object and return it. Passes through any
+arguments given.
+.PP
+The \f(CW\*(C`grammar_class\*(C'\fR can be customized, as described in "new".
+.PP
+\fR\f(CI\*(C`make_result\*(C'\fR\fI\fR
+.IX Subsection "make_result"
+.PP
+Make a new TAP::Parser::Result object using the parser's
+TAP::Parser::ResultFactory, and return it. Passes through any arguments
+given.
+.PP
+The \f(CW\*(C`result_factory_class\*(C'\fR can be customized, as described in "new".
+.PP
+\fR\f(CI\*(C`make_iterator_factory\*(C'\fR\fI\fR
+.IX Subsection "make_iterator_factory"
+.PP
+\&\fINEW to 3.18\fR.
+.PP
+Make a new TAP::Parser::IteratorFactory object and return it. Passes through
+any arguments given.
+.PP
+\&\f(CW\*(C`iterator_factory_class\*(C'\fR can be customized, as described in "new".
+.SH "INDIVIDUAL RESULTS"
+.IX Header "INDIVIDUAL RESULTS"
+If you've read this far in the docs, you've seen this:
+.PP
+.Vb 3
+\& while ( my $result = $parser\->next ) {
+\& print $result\->as_string;
+\& }
+.Ve
+.PP
+Each result returned is a TAP::Parser::Result subclass, referred to as
+\&\fIresult types\fR.
+.SS "Result types"
+.IX Subsection "Result types"
+Basically, you fetch individual results from the TAP. The six types, with
+examples of each, are as follows:
+.IP \(bu 4
+Version
+.Sp
+.Vb 1
+\& TAP version 12
+.Ve
+.IP \(bu 4
+Plan
+.Sp
+.Vb 1
+\& 1..42
+.Ve
+.IP \(bu 4
+Pragma
+.Sp
+.Vb 1
+\& pragma +strict
+.Ve
+.IP \(bu 4
+Test
+.Sp
+.Vb 1
+\& ok 3 \- We should start with some foobar!
+.Ve
+.IP \(bu 4
+Comment
+.Sp
+.Vb 1
+\& # Hope we don\*(Aqt use up the foobar.
+.Ve
+.IP \(bu 4
+Bailout
+.Sp
+.Vb 1
+\& Bail out! We ran out of foobar!
+.Ve
+.IP \(bu 4
+Unknown
+.Sp
+.Vb 1
+\& ... yo, this ain\*(Aqt TAP! ...
+.Ve
+.PP
+Each result fetched is a result object of a different type. There are common
+methods to each result object and different types may have methods unique to
+their type. Sometimes a type method may be overridden in a subclass, but its
+use is guaranteed to be identical.
+.SS "Common type methods"
+.IX Subsection "Common type methods"
+\fR\f(CI\*(C`type\*(C'\fR\fI\fR
+.IX Subsection "type"
+.PP
+Returns the type of result, such as \f(CW\*(C`comment\*(C'\fR or \f(CW\*(C`test\*(C'\fR.
+.PP
+\fR\f(CI\*(C`as_string\*(C'\fR\fI\fR
+.IX Subsection "as_string"
+.PP
+Prints a string representation of the token. This might not be the exact
+output, however. Tests will have test numbers added if not present, TODO and
+SKIP directives will be capitalized and, in general, things will be cleaned
+up. If you need the original text for the token, see the \f(CW\*(C`raw\*(C'\fR method.
+.PP
+\fR\f(CI\*(C`raw\*(C'\fR\fI\fR
+.IX Subsection "raw"
+.PP
+Returns the original line of text which was parsed.
+.PP
+\fR\f(CI\*(C`is_plan\*(C'\fR\fI\fR
+.IX Subsection "is_plan"
+.PP
+Indicates whether or not this is the test plan line.
+.PP
+\fR\f(CI\*(C`is_test\*(C'\fR\fI\fR
+.IX Subsection "is_test"
+.PP
+Indicates whether or not this is a test line.
+.PP
+\fR\f(CI\*(C`is_comment\*(C'\fR\fI\fR
+.IX Subsection "is_comment"
+.PP
+Indicates whether or not this is a comment. Comments will generally only
+appear in the TAP stream if STDERR is merged to STDOUT. See the
+\&\f(CW\*(C`merge\*(C'\fR option.
+.PP
+\fR\f(CI\*(C`is_bailout\*(C'\fR\fI\fR
+.IX Subsection "is_bailout"
+.PP
+Indicates whether or not this is bailout line.
+.PP
+\fR\f(CI\*(C`is_yaml\*(C'\fR\fI\fR
+.IX Subsection "is_yaml"
+.PP
+Indicates whether or not the current item is a YAML block.
+.PP
+\fR\f(CI\*(C`is_unknown\*(C'\fR\fI\fR
+.IX Subsection "is_unknown"
+.PP
+Indicates whether or not the current line could be parsed.
+.PP
+\fR\f(CI\*(C`is_ok\*(C'\fR\fI\fR
+.IX Subsection "is_ok"
+.PP
+.Vb 1
+\& if ( $result\->is_ok ) { ... }
+.Ve
+.PP
+Reports whether or not a given result has passed. Anything which is \fBnot\fR a
+test result returns true. This is merely provided as a convenient shortcut
+which allows you to do this:
+.PP
+.Vb 5
+\& my $parser = TAP::Parser\->new( { source => $source } );
+\& while ( my $result = $parser\->next ) {
+\& # only print failing results
+\& print $result\->as_string unless $result\->is_ok;
+\& }
+.Ve
+.ie n .SS """plan"" methods"
+.el .SS "\f(CWplan\fP methods"
+.IX Subsection "plan methods"
+.Vb 1
+\& if ( $result\->is_plan ) { ... }
+.Ve
+.PP
+If the above evaluates as true, the following methods will be available on the
+\&\f(CW$result\fR object.
+.PP
+\fR\f(CI\*(C`plan\*(C'\fR\fI\fR
+.IX Subsection "plan"
+.PP
+.Vb 3
+\& if ( $result\->is_plan ) {
+\& print $result\->plan;
+\& }
+.Ve
+.PP
+This is merely a synonym for \f(CW\*(C`as_string\*(C'\fR.
+.PP
+\fR\f(CI\*(C`directive\*(C'\fR\fI\fR
+.IX Subsection "directive"
+.PP
+.Vb 1
+\& my $directive = $result\->directive;
+.Ve
+.PP
+If a SKIP directive is included with the plan, this method will return it.
+.PP
+.Vb 1
+\& 1..0 # SKIP: why bother?
+.Ve
+.PP
+\fR\f(CI\*(C`explanation\*(C'\fR\fI\fR
+.IX Subsection "explanation"
+.PP
+.Vb 1
+\& my $explanation = $result\->explanation;
+.Ve
+.PP
+If a SKIP directive was included with the plan, this method will return the
+explanation, if any.
+.ie n .SS """pragma"" methods"
+.el .SS "\f(CWpragma\fP methods"
+.IX Subsection "pragma methods"
+.Vb 1
+\& if ( $result\->is_pragma ) { ... }
+.Ve
+.PP
+If the above evaluates as true, the following methods will be available on the
+\&\f(CW$result\fR object.
+.PP
+\fR\f(CI\*(C`pragmas\*(C'\fR\fI\fR
+.IX Subsection "pragmas"
+.PP
+Returns a list of pragmas each of which is a + or \- followed by the
+pragma name.
+.ie n .SS """comment"" methods"
+.el .SS "\f(CWcomment\fP methods"
+.IX Subsection "comment methods"
+.Vb 1
+\& if ( $result\->is_comment ) { ... }
+.Ve
+.PP
+If the above evaluates as true, the following methods will be available on the
+\&\f(CW$result\fR object.
+.PP
+\fR\f(CI\*(C`comment\*(C'\fR\fI\fR
+.IX Subsection "comment"
+.PP
+.Vb 4
+\& if ( $result\->is_comment ) {
+\& my $comment = $result\->comment;
+\& print "I have something to say: $comment";
+\& }
+.Ve
+.ie n .SS """bailout"" methods"
+.el .SS "\f(CWbailout\fP methods"
+.IX Subsection "bailout methods"
+.Vb 1
+\& if ( $result\->is_bailout ) { ... }
+.Ve
+.PP
+If the above evaluates as true, the following methods will be available on the
+\&\f(CW$result\fR object.
+.PP
+\fR\f(CI\*(C`explanation\*(C'\fR\fI\fR
+.IX Subsection "explanation"
+.PP
+.Vb 4
+\& if ( $result\->is_bailout ) {
+\& my $explanation = $result\->explanation;
+\& print "We bailed out because ($explanation)";
+\& }
+.Ve
+.PP
+If, and only if, a token is a bailout token, you can get an "explanation" via
+this method. The explanation is the text after the mystical "Bail out!" words
+which appear in the tap output.
+.ie n .SS """unknown"" methods"
+.el .SS "\f(CWunknown\fP methods"
+.IX Subsection "unknown methods"
+.Vb 1
+\& if ( $result\->is_unknown ) { ... }
+.Ve
+.PP
+There are no unique methods for unknown results.
+.ie n .SS """test"" methods"
+.el .SS "\f(CWtest\fP methods"
+.IX Subsection "test methods"
+.Vb 1
+\& if ( $result\->is_test ) { ... }
+.Ve
+.PP
+If the above evaluates as true, the following methods will be available on the
+\&\f(CW$result\fR object.
+.PP
+\fR\f(CI\*(C`ok\*(C'\fR\fI\fR
+.IX Subsection "ok"
+.PP
+.Vb 1
+\& my $ok = $result\->ok;
+.Ve
+.PP
+Returns the literal text of the \f(CW\*(C`ok\*(C'\fR or \f(CW\*(C`not ok\*(C'\fR status.
+.PP
+\fR\f(CI\*(C`number\*(C'\fR\fI\fR
+.IX Subsection "number"
+.PP
+.Vb 1
+\& my $test_number = $result\->number;
+.Ve
+.PP
+Returns the number of the test, even if the original TAP output did not supply
+that number.
+.PP
+\fR\f(CI\*(C`description\*(C'\fR\fI\fR
+.IX Subsection "description"
+.PP
+.Vb 1
+\& my $description = $result\->description;
+.Ve
+.PP
+Returns the description of the test, if any. This is the portion after the
+test number but before the directive.
+.PP
+\fR\f(CI\*(C`directive\*(C'\fR\fI\fR
+.IX Subsection "directive"
+.PP
+.Vb 1
+\& my $directive = $result\->directive;
+.Ve
+.PP
+Returns either \f(CW\*(C`TODO\*(C'\fR or \f(CW\*(C`SKIP\*(C'\fR if either directive was present for a test
+line.
+.PP
+\fR\f(CI\*(C`explanation\*(C'\fR\fI\fR
+.IX Subsection "explanation"
+.PP
+.Vb 1
+\& my $explanation = $result\->explanation;
+.Ve
+.PP
+If a test had either a \f(CW\*(C`TODO\*(C'\fR or \f(CW\*(C`SKIP\*(C'\fR directive, this method will return
+the accompanying explanation, if present.
+.PP
+.Vb 1
+\& not ok 17 \- \*(AqPigs can fly\*(Aq # TODO not enough acid
+.Ve
+.PP
+For the above line, the explanation is \fInot enough acid\fR.
+.PP
+\fR\f(CI\*(C`is_ok\*(C'\fR\fI\fR
+.IX Subsection "is_ok"
+.PP
+.Vb 1
+\& if ( $result\->is_ok ) { ... }
+.Ve
+.PP
+Returns a boolean value indicating whether or not the test passed. Remember
+that for TODO tests, the test always passes.
+.PP
+\&\fBNote:\fR this was formerly \f(CW\*(C`passed\*(C'\fR. The latter method is deprecated and
+will issue a warning.
+.PP
+\fR\f(CI\*(C`is_actual_ok\*(C'\fR\fI\fR
+.IX Subsection "is_actual_ok"
+.PP
+.Vb 1
+\& if ( $result\->is_actual_ok ) { ... }
+.Ve
+.PP
+Returns a boolean value indicating whether or not the test passed, regardless
+of its TODO status.
+.PP
+\&\fBNote:\fR this was formerly \f(CW\*(C`actual_passed\*(C'\fR. The latter method is deprecated
+and will issue a warning.
+.PP
+\fR\f(CI\*(C`is_unplanned\*(C'\fR\fI\fR
+.IX Subsection "is_unplanned"
+.PP
+.Vb 1
+\& if ( $test\->is_unplanned ) { ... }
+.Ve
+.PP
+If a test number is greater than the number of planned tests, this method will
+return true. Unplanned tests will \fIalways\fR return false for \f(CW\*(C`is_ok\*(C'\fR,
+regardless of whether or not the test \f(CW\*(C`has_todo\*(C'\fR (see
+TAP::Parser::Result::Test for more information about this).
+.PP
+\fR\f(CI\*(C`has_skip\*(C'\fR\fI\fR
+.IX Subsection "has_skip"
+.PP
+.Vb 1
+\& if ( $result\->has_skip ) { ... }
+.Ve
+.PP
+Returns a boolean value indicating whether or not this test had a SKIP
+directive.
+.PP
+\fR\f(CI\*(C`has_todo\*(C'\fR\fI\fR
+.IX Subsection "has_todo"
+.PP
+.Vb 1
+\& if ( $result\->has_todo ) { ... }
+.Ve
+.PP
+Returns a boolean value indicating whether or not this test had a TODO
+directive.
+.PP
+Note that TODO tests \fIalways\fR pass. If you need to know whether or not
+they really passed, check the \f(CW\*(C`is_actual_ok\*(C'\fR method.
+.PP
+\fR\f(CI\*(C`in_todo\*(C'\fR\fI\fR
+.IX Subsection "in_todo"
+.PP
+.Vb 1
+\& if ( $parser\->in_todo ) { ... }
+.Ve
+.PP
+True while the most recent result was a TODO. Becomes true before the
+TODO result is returned and stays true until just before the next non\-
+TODO test is returned.
+.SH "TOTAL RESULTS"
+.IX Header "TOTAL RESULTS"
+After parsing the TAP, there are many methods available to let you dig through
+the results and determine what is meaningful to you.
+.SS "Individual Results"
+.IX Subsection "Individual Results"
+These results refer to individual tests which are run.
+.PP
+\fR\f(CI\*(C`passed\*(C'\fR\fI\fR
+.IX Subsection "passed"
+.PP
+.Vb 2
+\& my @passed = $parser\->passed; # the test numbers which passed
+\& my $passed = $parser\->passed; # the number of tests which passed
+.Ve
+.PP
+This method lets you know which (or how many) tests passed. If a test failed
+but had a TODO directive, it will be counted as a passed test.
+.PP
+\fR\f(CI\*(C`failed\*(C'\fR\fI\fR
+.IX Subsection "failed"
+.PP
+.Vb 2
+\& my @failed = $parser\->failed; # the test numbers which failed
+\& my $failed = $parser\->failed; # the number of tests which failed
+.Ve
+.PP
+This method lets you know which (or how many) tests failed. If a test passed
+but had a TODO directive, it will \fBNOT\fR be counted as a failed test.
+.PP
+\fR\f(CI\*(C`actual_passed\*(C'\fR\fI\fR
+.IX Subsection "actual_passed"
+.PP
+.Vb 2
+\& # the test numbers which actually passed
+\& my @actual_passed = $parser\->actual_passed;
+\&
+\& # the number of tests which actually passed
+\& my $actual_passed = $parser\->actual_passed;
+.Ve
+.PP
+This method lets you know which (or how many) tests actually passed,
+regardless of whether or not a TODO directive was found.
+.PP
+\fR\f(CI\*(C`actual_ok\*(C'\fR\fI\fR
+.IX Subsection "actual_ok"
+.PP
+This method is a synonym for \f(CW\*(C`actual_passed\*(C'\fR.
+.PP
+\fR\f(CI\*(C`actual_failed\*(C'\fR\fI\fR
+.IX Subsection "actual_failed"
+.PP
+.Vb 2
+\& # the test numbers which actually failed
+\& my @actual_failed = $parser\->actual_failed;
+\&
+\& # the number of tests which actually failed
+\& my $actual_failed = $parser\->actual_failed;
+.Ve
+.PP
+This method lets you know which (or how many) tests actually failed,
+regardless of whether or not a TODO directive was found.
+.PP
+\fR\f(CI\*(C`todo\*(C'\fR\fI\fR
+.IX Subsection "todo"
+.PP
+.Vb 2
+\& my @todo = $parser\->todo; # the test numbers with todo directives
+\& my $todo = $parser\->todo; # the number of tests with todo directives
+.Ve
+.PP
+This method lets you know which (or how many) tests had TODO directives.
+.PP
+\fR\f(CI\*(C`todo_passed\*(C'\fR\fI\fR
+.IX Subsection "todo_passed"
+.PP
+.Vb 2
+\& # the test numbers which unexpectedly succeeded
+\& my @todo_passed = $parser\->todo_passed;
+\&
+\& # the number of tests which unexpectedly succeeded
+\& my $todo_passed = $parser\->todo_passed;
+.Ve
+.PP
+This method lets you know which (or how many) tests actually passed but were
+declared as "TODO" tests.
+.PP
+\fR\f(CI\*(C`todo_failed\*(C'\fR\fI\fR
+.IX Subsection "todo_failed"
+.PP
+.Vb 1
+\& # deprecated in favor of \*(Aqtodo_passed\*(Aq. This method was horribly misnamed.
+.Ve
+.PP
+This was a badly misnamed method. It indicates which TODO tests unexpectedly
+succeeded. Will now issue a warning and call \f(CW\*(C`todo_passed\*(C'\fR.
+.PP
+\fR\f(CI\*(C`skipped\*(C'\fR\fI\fR
+.IX Subsection "skipped"
+.PP
+.Vb 2
+\& my @skipped = $parser\->skipped; # the test numbers with SKIP directives
+\& my $skipped = $parser\->skipped; # the number of tests with SKIP directives
+.Ve
+.PP
+This method lets you know which (or how many) tests had SKIP directives.
+.SS Pragmas
+.IX Subsection "Pragmas"
+\fR\f(CI\*(C`pragma\*(C'\fR\fI\fR
+.IX Subsection "pragma"
+.PP
+Get or set a pragma. To get the state of a pragma:
+.PP
+.Vb 3
+\& if ( $p\->pragma(\*(Aqstrict\*(Aq) ) {
+\& # be strict
+\& }
+.Ve
+.PP
+To set the state of a pragma:
+.PP
+.Vb 1
+\& $p\->pragma(\*(Aqstrict\*(Aq, 1); # enable strict mode
+.Ve
+.PP
+\fR\f(CI\*(C`pragmas\*(C'\fR\fI\fR
+.IX Subsection "pragmas"
+.PP
+Get a list of all the currently enabled pragmas:
+.PP
+.Vb 1
+\& my @pragmas_enabled = $p\->pragmas;
+.Ve
+.SS "Summary Results"
+.IX Subsection "Summary Results"
+These results are "meta" information about the total results of an individual
+test program.
+.PP
+\fR\f(CI\*(C`plan\*(C'\fR\fI\fR
+.IX Subsection "plan"
+.PP
+.Vb 1
+\& my $plan = $parser\->plan;
+.Ve
+.PP
+Returns the test plan, if found.
+.PP
+\fR\f(CI\*(C`good_plan\*(C'\fR\fI\fR
+.IX Subsection "good_plan"
+.PP
+Deprecated. Use \f(CW\*(C`is_good_plan\*(C'\fR instead.
+.PP
+\fR\f(CI\*(C`is_good_plan\*(C'\fR\fI\fR
+.IX Subsection "is_good_plan"
+.PP
+.Vb 1
+\& if ( $parser\->is_good_plan ) { ... }
+.Ve
+.PP
+Returns a boolean value indicating whether or not the number of tests planned
+matches the number of tests run.
+.PP
+\&\fBNote:\fR this was formerly \f(CW\*(C`good_plan\*(C'\fR. The latter method is deprecated and
+will issue a warning.
+.PP
+And since we're on that subject ...
+.PP
+\fR\f(CI\*(C`tests_planned\*(C'\fR\fI\fR
+.IX Subsection "tests_planned"
+.PP
+.Vb 1
+\& print $parser\->tests_planned;
+.Ve
+.PP
+Returns the number of tests planned, according to the plan. For example, a
+plan of '1..17' will mean that 17 tests were planned.
+.PP
+\fR\f(CI\*(C`tests_run\*(C'\fR\fI\fR
+.IX Subsection "tests_run"
+.PP
+.Vb 1
+\& print $parser\->tests_run;
+.Ve
+.PP
+Returns the number of tests which actually were run. Hopefully this will
+match the number of \f(CW\*(C`$parser\->tests_planned\*(C'\fR.
+.PP
+\fR\f(CI\*(C`skip_all\*(C'\fR\fI\fR
+.IX Subsection "skip_all"
+.PP
+Returns a true value (actually the reason for skipping) if all tests
+were skipped.
+.PP
+\fR\f(CI\*(C`start_time\*(C'\fR\fI\fR
+.IX Subsection "start_time"
+.PP
+Returns the wall-clock time when the Parser was created.
+.PP
+\fR\f(CI\*(C`end_time\*(C'\fR\fI\fR
+.IX Subsection "end_time"
+.PP
+Returns the wall-clock time when the end of TAP input was seen.
+.PP
+\fR\f(CI\*(C`start_times\*(C'\fR\fI\fR
+.IX Subsection "start_times"
+.PP
+Returns the CPU times (like "times" in perlfunc when the Parser was created.
+.PP
+\fR\f(CI\*(C`end_times\*(C'\fR\fI\fR
+.IX Subsection "end_times"
+.PP
+Returns the CPU times (like "times" in perlfunc when the end of TAP
+input was seen.
+.PP
+\fR\f(CI\*(C`has_problems\*(C'\fR\fI\fR
+.IX Subsection "has_problems"
+.PP
+.Vb 3
+\& if ( $parser\->has_problems ) {
+\& ...
+\& }
+.Ve
+.PP
+This is a 'catch\-all' method which returns true if any tests have currently
+failed, any TODO tests unexpectedly succeeded, or any parse errors occurred.
+.PP
+\fR\f(CI\*(C`version\*(C'\fR\fI\fR
+.IX Subsection "version"
+.PP
+.Vb 1
+\& $parser\->version;
+.Ve
+.PP
+Once the parser is done, this will return the version number for the
+parsed TAP. Version numbers were introduced with TAP version 13 so if no
+version number is found version 12 is assumed.
+.PP
+\fR\f(CI\*(C`exit\*(C'\fR\fI\fR
+.IX Subsection "exit"
+.PP
+.Vb 1
+\& $parser\->exit;
+.Ve
+.PP
+Once the parser is done, this will return the exit status. If the parser ran
+an executable, it returns the exit status of the executable.
+.PP
+\fR\f(CI\*(C`wait\*(C'\fR\fI\fR
+.IX Subsection "wait"
+.PP
+.Vb 1
+\& $parser\->wait;
+.Ve
+.PP
+Once the parser is done, this will return the wait status. If the parser ran
+an executable, it returns the wait status of the executable. Otherwise, this
+merely returns the \f(CW\*(C`exit\*(C'\fR status.
+.ie n .SS """ignore_exit"""
+.el .SS \f(CWignore_exit\fP
+.IX Subsection "ignore_exit"
+.Vb 1
+\& $parser\->ignore_exit(1);
+.Ve
+.PP
+Tell the parser to ignore the exit status from the test when determining
+whether the test passed. Normally tests with non-zero exit status are
+considered to have failed even if all individual tests passed. In cases
+where it is not possible to control the exit value of the test script
+use this option to ignore it.
+.PP
+\fR\f(CI\*(C`parse_errors\*(C'\fR\fI\fR
+.IX Subsection "parse_errors"
+.PP
+.Vb 2
+\& my @errors = $parser\->parse_errors; # the parser errors
+\& my $errors = $parser\->parse_errors; # the number of parser_errors
+.Ve
+.PP
+Fortunately, all TAP output is perfect. In the event that it is not, this
+method will return parser errors. Note that a junk line which the parser does
+not recognize is \f(CW\*(C`not\*(C'\fR an error. This allows this parser to handle future
+versions of TAP. The following are all TAP errors reported by the parser:
+.IP \(bu 4
+Misplaced plan
+.Sp
+The plan (for example, '1..5'), must only come at the beginning or end of the
+TAP output.
+.IP \(bu 4
+No plan
+.Sp
+Gotta have a plan!
+.IP \(bu 4
+More than one plan
+.Sp
+.Vb 5
+\& 1..3
+\& ok 1 \- input file opened
+\& not ok 2 \- first line of the input valid # todo some data
+\& ok 3 read the rest of the file
+\& 1..3
+.Ve
+.Sp
+Right. Very funny. Don't do that.
+.IP \(bu 4
+Test numbers out of sequence
+.Sp
+.Vb 4
+\& 1..3
+\& ok 1 \- input file opened
+\& not ok 2 \- first line of the input valid # todo some data
+\& ok 2 read the rest of the file
+.Ve
+.Sp
+That last test line above should have the number '3' instead of '2'.
+.Sp
+Note that it's perfectly acceptable for some lines to have test numbers and
+others to not have them. However, when a test number is found, it must be in
+sequence. The following is also an error:
+.Sp
+.Vb 4
+\& 1..3
+\& ok 1 \- input file opened
+\& not ok \- first line of the input valid # todo some data
+\& ok 2 read the rest of the file
+.Ve
+.Sp
+But this is not:
+.Sp
+.Vb 4
+\& 1..3
+\& ok \- input file opened
+\& not ok \- first line of the input valid # todo some data
+\& ok 3 read the rest of the file
+.Ve
+.PP
+\fR\f(CI\*(C`get_select_handles\*(C'\fR\fI\fR
+.IX Subsection "get_select_handles"
+.PP
+Get an a list of file handles which can be passed to \f(CW\*(C`select\*(C'\fR to
+determine the readiness of this parser.
+.PP
+\fR\f(CI\*(C`delete_spool\*(C'\fR\fI\fR
+.IX Subsection "delete_spool"
+.PP
+Delete and return the spool.
+.PP
+.Vb 1
+\& my $fh = $parser\->delete_spool;
+.Ve
+.SH CALLBACKS
+.IX Header "CALLBACKS"
+As mentioned earlier, a "callback" key may be added to the
+\&\f(CW\*(C`TAP::Parser\*(C'\fR constructor. If present, each callback corresponding to a
+given result type will be called with the result as the argument if the
+\&\f(CW\*(C`run\*(C'\fR method is used. The callback is expected to be a subroutine
+reference (or anonymous subroutine) which is invoked with the parser
+result as its argument.
+.PP
+.Vb 7
+\& my %callbacks = (
+\& test => \e&test_callback,
+\& plan => \e&plan_callback,
+\& comment => \e&comment_callback,
+\& bailout => \e&bailout_callback,
+\& unknown => \e&unknown_callback,
+\& );
+\&
+\& my $aggregator = TAP::Parser::Aggregator\->new;
+\& for my $file ( @test_files ) {
+\& my $parser = TAP::Parser\->new(
+\& {
+\& source => $file,
+\& callbacks => \e%callbacks,
+\& }
+\& );
+\& $parser\->run;
+\& $aggregator\->add( $file, $parser );
+\& }
+.Ve
+.PP
+Callbacks may also be added like this:
+.PP
+.Vb 2
+\& $parser\->callback( test => \e&test_callback );
+\& $parser\->callback( plan => \e&plan_callback );
+.Ve
+.PP
+The following keys allowed for callbacks. These keys are case-sensitive.
+.IP \(bu 4
+\&\f(CW\*(C`test\*(C'\fR
+.Sp
+Invoked if \f(CW\*(C`$result\->is_test\*(C'\fR returns true.
+.IP \(bu 4
+\&\f(CW\*(C`version\*(C'\fR
+.Sp
+Invoked if \f(CW\*(C`$result\->is_version\*(C'\fR returns true.
+.IP \(bu 4
+\&\f(CW\*(C`plan\*(C'\fR
+.Sp
+Invoked if \f(CW\*(C`$result\->is_plan\*(C'\fR returns true.
+.IP \(bu 4
+\&\f(CW\*(C`comment\*(C'\fR
+.Sp
+Invoked if \f(CW\*(C`$result\->is_comment\*(C'\fR returns true.
+.IP \(bu 4
+\&\f(CW\*(C`bailout\*(C'\fR
+.Sp
+Invoked if \f(CW\*(C`$result\->is_unknown\*(C'\fR returns true.
+.IP \(bu 4
+\&\f(CW\*(C`yaml\*(C'\fR
+.Sp
+Invoked if \f(CW\*(C`$result\->is_yaml\*(C'\fR returns true.
+.IP \(bu 4
+\&\f(CW\*(C`unknown\*(C'\fR
+.Sp
+Invoked if \f(CW\*(C`$result\->is_unknown\*(C'\fR returns true.
+.IP \(bu 4
+\&\f(CW\*(C`ELSE\*(C'\fR
+.Sp
+If a result does not have a callback defined for it, this callback will
+be invoked. Thus, if all of the previous result types are specified as
+callbacks, this callback will \fInever\fR be invoked.
+.IP \(bu 4
+\&\f(CW\*(C`ALL\*(C'\fR
+.Sp
+This callback will always be invoked and this will happen for each
+result after one of the above callbacks is invoked. For example, if
+Term::ANSIColor is loaded, you could use the following to color your
+test output:
+.Sp
+.Vb 12
+\& my %callbacks = (
+\& test => sub {
+\& my $test = shift;
+\& if ( $test\->is_ok && not $test\->directive ) {
+\& # normal passing test
+\& print color \*(Aqgreen\*(Aq;
+\& }
+\& elsif ( !$test\->is_ok ) { # even if it\*(Aqs TODO
+\& print color \*(Aqwhite on_red\*(Aq;
+\& }
+\& elsif ( $test\->has_skip ) {
+\& print color \*(Aqwhite on_blue\*(Aq;
+\&
+\& }
+\& elsif ( $test\->has_todo ) {
+\& print color \*(Aqwhite\*(Aq;
+\& }
+\& },
+\& ELSE => sub {
+\& # plan, comment, and so on (anything which isn\*(Aqt a test line)
+\& print color \*(Aqblack on_white\*(Aq;
+\& },
+\& ALL => sub {
+\& # now print them
+\& print shift\->as_string;
+\& print color \*(Aqreset\*(Aq;
+\& print "\en";
+\& },
+\& );
+.Ve
+.IP \(bu 4
+\&\f(CW\*(C`EOF\*(C'\fR
+.Sp
+Invoked when there are no more lines to be parsed. Since there is no
+accompanying TAP::Parser::Result object the \f(CW\*(C`TAP::Parser\*(C'\fR object is
+passed instead.
+.SH "TAP GRAMMAR"
+.IX Header "TAP GRAMMAR"
+If you're looking for an EBNF grammar, see TAP::Parser::Grammar.
+.SH "BACKWARDS COMPATIBILITY"
+.IX Header "BACKWARDS COMPATIBILITY"
+The Perl-QA list attempted to ensure backwards compatibility with
+Test::Harness. However, there are some minor differences.
+.SS Differences
+.IX Subsection "Differences"
+.IP \(bu 4
+TODO plans
+.Sp
+A little-known feature of Test::Harness is that it supported TODO
+lists in the plan:
+.Sp
+.Vb 3
+\& 1..2 todo 2
+\& ok 1 \- We have liftoff
+\& not ok 2 \- Anti\-gravity device activated
+.Ve
+.Sp
+Under Test::Harness, test number 2 would \fIpass\fR because it was
+listed as a TODO test on the plan line. However, we are not aware of
+anyone actually using this feature and hard-coding test numbers is
+discouraged because it's very easy to add a test and break the test
+number sequence. This makes test suites very fragile. Instead, the
+following should be used:
+.Sp
+.Vb 3
+\& 1..2
+\& ok 1 \- We have liftoff
+\& not ok 2 \- Anti\-gravity device activated # TODO
+.Ve
+.IP \(bu 4
+\&'Missing' tests
+.Sp
+It rarely happens, but sometimes a harness might encounter
+\&'missing tests:
+.Sp
+.Vb 5
+\& ok 1
+\& ok 2
+\& ok 15
+\& ok 16
+\& ok 17
+.Ve
+.Sp
+Test::Harness would report tests 3\-14 as having failed. For the
+\&\f(CW\*(C`TAP::Parser\*(C'\fR, these tests are not considered failed because they've
+never run. They're reported as parse failures (tests out of sequence).
+.SH SUBCLASSING
+.IX Header "SUBCLASSING"
+If you find you need to provide custom functionality (as you would have using
+Test::Harness::Straps), you're in luck: \f(CW\*(C`TAP::Parser\*(C'\fR and friends are
+designed to be easily plugged-into and/or subclassed.
+.PP
+Before you start, it's important to know a few things:
+.IP 1. 2
+All \f(CW\*(C`TAP::*\*(C'\fR objects inherit from TAP::Object.
+.IP 2. 2
+Many \f(CW\*(C`TAP::*\*(C'\fR classes have a \fISUBCLASSING\fR section to guide you.
+.IP 3. 2
+Note that \f(CW\*(C`TAP::Parser\*(C'\fR is designed to be the central "maker" \- ie: it is
+responsible for creating most new objects in the \f(CW\*(C`TAP::Parser::*\*(C'\fR namespace.
+.Sp
+This makes it possible for you to have a single point of configuring what
+subclasses should be used, which means that in many cases you'll find
+you only need to sub-class one of the parser's components.
+.Sp
+The exception to this rule are \fISourceHandlers\fR & \fIIterators\fR, but those are
+both created with customizable \fIIteratorFactory\fR.
+.IP 4. 2
+By subclassing, you may end up overriding undocumented methods. That's not
+a bad thing per se, but be forewarned that undocumented methods may change
+without warning from one release to the next \- we cannot guarantee backwards
+compatibility. If any \fIdocumented\fR method needs changing, it will be
+deprecated first, and changed in a later release.
+.SS "Parser Components"
+.IX Subsection "Parser Components"
+\fISources\fR
+.IX Subsection "Sources"
+.PP
+A TAP parser consumes input from a single \fIraw source\fR of TAP, which could come
+from anywhere (a file, an executable, a database, an IO handle, a URI, etc..).
+The source gets bundled up in a TAP::Parser::Source object which gathers some
+meta data about it. The parser then uses a TAP::Parser::IteratorFactory to
+determine which TAP::Parser::SourceHandler to use to turn the raw source
+into a stream of TAP by way of "Iterators".
+.PP
+If you simply want \f(CW\*(C`TAP::Parser\*(C'\fR to handle a new source of TAP you probably
+don't need to subclass \f(CW\*(C`TAP::Parser\*(C'\fR itself. Rather, you'll need to create a
+new TAP::Parser::SourceHandler class, and just plug it into the parser using
+the \fIsources\fR param to "new". Before you start writing one, read through
+TAP::Parser::IteratorFactory to get a feel for how the system works first.
+.PP
+If you find you really need to use your own iterator factory you can still do
+so without sub-classing \f(CW\*(C`TAP::Parser\*(C'\fR by setting "iterator_factory_class".
+.PP
+If you just need to customize the objects on creation, subclass TAP::Parser
+and override "make_iterator_factory".
+.PP
+Note that \f(CW\*(C`make_source\*(C'\fR & \f(CW\*(C`make_perl_source\*(C'\fR have been \fIDEPRECATED\fR and
+are now removed.
+.PP
+\fIIterators\fR
+.IX Subsection "Iterators"
+.PP
+A TAP parser uses \fIiterators\fR to loop through the \fIstream\fR of TAP read in
+from the \fIsource\fR it was given. There are a few types of Iterators available
+by default, all sub-classes of TAP::Parser::Iterator. Choosing which
+iterator to use is the responsibility of the \fIiterator factory\fR, though it
+simply delegates to the \fISource Handler\fR it uses.
+.PP
+If you're writing your own TAP::Parser::SourceHandler, you may need to
+create your own iterators too. If so you'll need to subclass
+TAP::Parser::Iterator.
+.PP
+Note that "make_iterator" has been \fIDEPRECATED\fR and is now removed.
+.PP
+\fIResults\fR
+.IX Subsection "Results"
+.PP
+A TAP parser creates TAP::Parser::Results as it iterates through the
+input \fIstream\fR. There are quite a few result types available; choosing
+which class to use is the responsibility of the \fIresult factory\fR.
+.PP
+To create your own result types you have two options:
+.IP "option 1" 2
+.IX Item "option 1"
+Subclass TAP::Parser::Result and register your new result type/class with
+the default TAP::Parser::ResultFactory.
+.IP "option 2" 2
+.IX Item "option 2"
+Subclass TAP::Parser::ResultFactory itself and implement your own
+TAP::Parser::Result creation logic. Then you'll need to customize the
+class used by your parser by setting the \f(CW\*(C`result_factory_class\*(C'\fR parameter.
+See "new" for more details.
+.PP
+If you need to customize the objects on creation, subclass TAP::Parser and
+override "make_result".
+.PP
+\fIGrammar\fR
+.IX Subsection "Grammar"
+.PP
+TAP::Parser::Grammar is the heart of the parser. It tokenizes the TAP
+input \fIstream\fR and produces results. If you need to customize its behaviour
+you should probably familiarize yourself with the source first. Enough
+lecturing.
+.PP
+Subclass TAP::Parser::Grammar and customize your parser by setting the
+\&\f(CW\*(C`grammar_class\*(C'\fR parameter. See "new" for more details.
+.PP
+If you need to customize the objects on creation, subclass TAP::Parser and
+override "make_grammar"
+.SH ACKNOWLEDGMENTS
+.IX Header "ACKNOWLEDGMENTS"
+All of the following have helped. Bug reports, patches, (im)moral
+support, or just words of encouragement have all been forthcoming.
+.IP \(bu 4
+Michael Schwern
+.IP \(bu 4
+Andy Lester
+.IP \(bu 4
+chromatic
+.IP \(bu 4
+GEOFFR
+.IP \(bu 4
+Shlomi Fish
+.IP \(bu 4
+Torsten Schoenfeld
+.IP \(bu 4
+Jerry Gay
+.IP \(bu 4
+Aristotle
+.IP \(bu 4
+Adam Kennedy
+.IP \(bu 4
+Yves Orton
+.IP \(bu 4
+Adrian Howard
+.IP \(bu 4
+Sean & Lil
+.IP \(bu 4
+Andreas J. Koenig
+.IP \(bu 4
+Florian Ragwitz
+.IP \(bu 4
+Corion
+.IP \(bu 4
+Mark Stosberg
+.IP \(bu 4
+Matt Kraai
+.IP \(bu 4
+David Wheeler
+.IP \(bu 4
+Alex Vandiver
+.IP \(bu 4
+Cosimo Streppone
+.IP \(bu 4
+Ville Skyttä
+.SH AUTHORS
+.IX Header "AUTHORS"
+Curtis "Ovid" Poe <ovid@cpan.org>
+.PP
+Andy Armstong <andy@hexten.net>
+.PP
+Eric Wilhelm @ <ewilhelm at cpan dot org>
+.PP
+Michael Peters <mpeters at plusthree dot com>
+.PP
+Leif Eriksen <leif dot eriksen at bigpond dot com>
+.PP
+Steve Purkis <spurkis@cpan.org>
+.PP
+Nicholas Clark <nick@ccl4.org>
+.PP
+Lee Johnson <notfadeaway at btinternet dot com>
+.PP
+Philippe Bruhat <book@cpan.org>
+.SH BUGS
+.IX Header "BUGS"
+Please report any bugs or feature requests to
+\&\f(CW\*(C`bug\-test\-harness@rt.cpan.org\*(C'\fR, or through the web interface at
+<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Test\-Harness>.
+We will be notified, and then you'll automatically be notified of
+progress on your bug as we make changes.
+.PP
+Obviously, bugs which include patches are best. If you prefer, you can
+patch against bleed by via anonymous checkout of the latest version:
+.PP
+.Vb 1
+\& git clone git://github.com/Perl\-Toolchain\-Gang/Test\-Harness.git
+.Ve
+.SH "COPYRIGHT & LICENSE"
+.IX Header "COPYRIGHT & LICENSE"
+Copyright 2006\-2008 Curtis "Ovid" Poe, all rights reserved.
+.PP
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl itself.