{
    "content": [
        {
            "type": "text",
            "text": "# TAP::Parser (perldoc)\n\n## NAME\n\nTAP::Parser - Parse TAP output\n\n## SYNOPSIS\n\nuse TAP::Parser;\nmy $parser = TAP::Parser->new( { source => $source } );\nwhile ( my $result = $parser->next ) {\nprint $result->asstring;\n}\n\n## DESCRIPTION\n\n\"TAP::Parser\" is designed to produce a proper parse of TAP output. For an example of how to run\ntests through this module, see the simple harnesses \"examples/\".\n\n## Sections\n\n- **NAME**\n- **VERSION**\n- **SYNOPSIS**\n- **DESCRIPTION**\n- **METHODS** (2 subsections)\n- **INDIVIDUAL RESULTS** (2 subsections)\n- **TOTAL RESULTS** (3 subsections)\n- **CALLBACKS**\n- **TAP GRAMMAR**\n- **BACKWARDS COMPATIBILITY** (1 subsections)\n- **SUBCLASSING** (1 subsections)\n- **ACKNOWLEDGMENTS**\n- **AUTHORS**\n- **BUGS**\n\nUse structuredContent.sections for detailed options, examples, and full documentation.\n"
        }
    ],
    "structuredContent": {
        "command": "TAP::Parser",
        "section": "",
        "mode": "perldoc",
        "summary": "TAP::Parser - Parse TAP output",
        "synopsis": "use TAP::Parser;\nmy $parser = TAP::Parser->new( { source => $source } );\nwhile ( my $result = $parser->next ) {\nprint $result->asstring;\n}",
        "tldr_summary": null,
        "tldr_examples": [],
        "tldr_source": null,
        "flags": [],
        "examples": [],
        "see_also": [],
        "section_outline": [
            {
                "name": "NAME",
                "lines": 2,
                "subsections": []
            },
            {
                "name": "VERSION",
                "lines": 2,
                "subsections": []
            },
            {
                "name": "SYNOPSIS",
                "lines": 8,
                "subsections": []
            },
            {
                "name": "DESCRIPTION",
                "lines": 11,
                "subsections": []
            },
            {
                "name": "METHODS",
                "lines": 1,
                "subsections": [
                    {
                        "name": "Class Methods",
                        "lines": 161
                    },
                    {
                        "name": "Instance Methods",
                        "lines": 38
                    }
                ]
            },
            {
                "name": "INDIVIDUAL RESULTS",
                "lines": 8,
                "subsections": [
                    {
                        "name": "Result types",
                        "lines": 35
                    },
                    {
                        "name": "Common type methods",
                        "lines": 184
                    }
                ]
            },
            {
                "name": "TOTAL RESULTS",
                "lines": 3,
                "subsections": [
                    {
                        "name": "Individual Results",
                        "lines": 67
                    },
                    {
                        "name": "Pragmas",
                        "lines": 16
                    },
                    {
                        "name": "Summary Results",
                        "lines": 142
                    }
                ]
            },
            {
                "name": "CALLBACKS",
                "lines": 107,
                "subsections": []
            },
            {
                "name": "TAP GRAMMAR",
                "lines": 2,
                "subsections": []
            },
            {
                "name": "BACKWARDS COMPATIBILITY",
                "lines": 3,
                "subsections": [
                    {
                        "name": "Differences",
                        "lines": 31
                    }
                ]
            },
            {
                "name": "SUBCLASSING",
                "lines": 25,
                "subsections": [
                    {
                        "name": "Parser Components",
                        "lines": 62
                    }
                ]
            },
            {
                "name": "ACKNOWLEDGMENTS",
                "lines": 45,
                "subsections": []
            },
            {
                "name": "AUTHORS",
                "lines": 18,
                "subsections": []
            },
            {
                "name": "BUGS",
                "lines": 15,
                "subsections": []
            }
        ],
        "sections": {
            "NAME": {
                "content": "TAP::Parser - Parse TAP output\n",
                "subsections": []
            },
            "VERSION": {
                "content": "Version 3.43\n",
                "subsections": []
            },
            "SYNOPSIS": {
                "content": "use TAP::Parser;\n\nmy $parser = TAP::Parser->new( { source => $source } );\n\nwhile ( my $result = $parser->next ) {\nprint $result->asstring;\n}\n",
                "subsections": []
            },
            "DESCRIPTION": {
                "content": "\"TAP::Parser\" is designed to produce a proper parse of TAP output. For an example of how to run\ntests through this module, see the simple harnesses \"examples/\".\n\nThere's a wiki dedicated to the Test Anything Protocol:\n\n<http://testanything.org>\n\nIt includes the TAP::Parser Cookbook:\n\n<http://testanything.org/testing-with-tap/perl/tap::parser-cookbook.html>\n",
                "subsections": []
            },
            "METHODS": {
                "content": "",
                "subsections": [
                    {
                        "name": "Class Methods",
                        "content": "\"new\"\nmy $parser = TAP::Parser->new(\\%args);\n\nReturns a new \"TAP::Parser\" object.\n\nThe arguments should be a hashref with *one* of the following keys:\n\n*   \"source\"\n\n*CHANGED in 3.18*\n\nThis is the preferred method of passing input to the constructor.\n\nThe \"source\" is used to create a TAP::Parser::Source that is passed to the\n\"iteratorfactoryclass\" which in turn figures out how to handle the source and creates a\n<TAP::Parser::Iterator> for it. The iterator is used by the parser to read in the TAP\nstream.\n\nTo configure the *IteratorFactory* use the \"sources\" parameter below.\n\nNote that \"source\", \"tap\" and \"exec\" are *mutually exclusive*.\n\n*   \"tap\"\n\n*CHANGED in 3.18*\n\nThe value should be the complete TAP output.\n\nThe *tap* is used to create a TAP::Parser::Source that is passed to the\n\"iteratorfactoryclass\" which in turn figures out how to handle the source and creates a\n<TAP::Parser::Iterator> for it. The iterator is used by the parser to read in the TAP\nstream.\n\nTo configure the *IteratorFactory* use the \"sources\" parameter below.\n\nNote that \"source\", \"tap\" and \"exec\" are *mutually exclusive*.\n\n*   \"exec\"\n\nMust be passed an array reference.\n\nThe *exec* array ref is used to create a TAP::Parser::Source that is passed to the\n\"iteratorfactoryclass\" which in turn figures out how to handle the source and creates a\n<TAP::Parser::Iterator> for it. The iterator is used by the parser to read in the TAP\nstream.\n\nBy default the TAP::Parser::SourceHandler::Executable class will create a\nTAP::Parser::Iterator::Process object to handle the source. This passes the array reference\nstrings as command arguments to IPC::Open3::open3:\n\nexec => [ '/usr/bin/ruby', 't/mytest.rb' ]\n\nIf any \"testargs\" are given they will be appended to the end of the command argument list.\n\nTo configure the *IteratorFactory* use the \"sources\" parameter below.\n\nNote that \"source\", \"tap\" and \"exec\" are *mutually exclusive*.\n\nThe following keys are optional.\n\n*   \"sources\"\n\n*NEW to 3.18*.\n\nIf set, \"sources\" must be a hashref containing the names of the TAP::Parser::SourceHandlers\nto load and/or configure. The values are a hash of configuration that will be accessible to\nthe source handlers via \"configfor\" in TAP::Parser::Source.\n\nFor example:\n\nsources => {\nPerl => { exec => '/path/to/custom/perl' },\nFile => { extensions => [ '.tap', '.txt' ] },\nMyCustom => { some => 'config' },\n}\n\nThis will cause \"TAP::Parser\" to pass custom configuration to two of the built- in source\nhandlers - TAP::Parser::SourceHandler::Perl, TAP::Parser::SourceHandler::File - and attempt\nto load the \"MyCustom\" class. See \"loadhandlers\" in TAP::Parser::IteratorFactory for more\ndetail.\n\nThe \"sources\" parameter affects how \"source\", \"tap\" and \"exec\" parameters are handled.\n\nSee TAP::Parser::IteratorFactory, TAP::Parser::SourceHandler and subclasses for more\ndetails.\n\n*   \"callback\"\n\nIf present, each callback corresponding to a given result type will be called with the\nresult as the argument if the \"run\" method is used:\n\nmy %callbacks = (\ntest    => \\&testcallback,\nplan    => \\&plancallback,\ncomment => \\&commentcallback,\nbailout => \\&bailoutcallback,\nunknown => \\&unknowncallback,\n);\n\nmy $aggregator = TAP::Parser::Aggregator->new;\nfor my $file ( @testfiles ) {\nmy $parser = TAP::Parser->new(\n{\nsource    => $file,\ncallbacks => \\%callbacks,\n}\n);\n$parser->run;\n$aggregator->add( $file, $parser );\n}\n\n*   \"switches\"\n\nIf using a Perl file as a source, optional switches may be passed which will be used when\ninvoking the perl executable.\n\nmy $parser = TAP::Parser->new( {\nsource   => $testfile,\nswitches => [ '-Ilib' ],\n} );\n\n*   \"testargs\"\n\nUsed in conjunction with the \"source\" and \"exec\" option to supply a reference to an @ARGV\nstyle array of arguments to pass to the test program.\n\n*   \"spool\"\n\nIf passed a filehandle will write a copy of all parsed TAP to that handle.\n\n*   \"merge\"\n\nIf false, STDERR is not captured (though it is 'relayed' to keep it somewhat synchronized\nwith STDOUT.)\n\nIf true, STDERR and STDOUT are the same filehandle. This may cause breakage if STDERR\ncontains anything resembling TAP format, but does allow exact synchronization.\n\nSubtleties of this behavior may be platform-dependent and may change in the future.\n\n*   \"grammarclass\"\n\nThis option was introduced to let you easily customize which *grammar* class the parser\nshould use. It defaults to TAP::Parser::Grammar.\n\nSee also \"makegrammar\".\n\n*   \"resultfactoryclass\"\n\nThis option was introduced to let you easily customize which *result* factory class the\nparser should use. It defaults to TAP::Parser::ResultFactory.\n\nSee also \"makeresult\".\n\n*   \"iteratorfactoryclass\"\n\n*CHANGED in 3.18*\n\nThis option was introduced to let you easily customize which *iterator* factory class the\nparser should use. It defaults to TAP::Parser::IteratorFactory.\n"
                    },
                    {
                        "name": "Instance Methods",
                        "content": "\"next\"\nmy $parser = TAP::Parser->new( { source => $file } );\nwhile ( my $result = $parser->next ) {\nprint $result->asstring, \"\\n\";\n}\n\nThis method returns the results of the parsing, one result at a time. Note that it is\ndestructive. You can't rewind and examine previous results.\n\nIf callbacks are used, they will be issued before this call returns.\n\nEach result returned is a subclass of TAP::Parser::Result. See that module and related classes\nfor more information on how to use them.\n\n\"run\"\n$parser->run;\n\nThis method merely runs the parser and parses all of the TAP.\n\n\"makegrammar\"\nMake a new TAP::Parser::Grammar object and return it. Passes through any arguments given.\n\nThe \"grammarclass\" can be customized, as described in \"new\".\n\n\"makeresult\"\nMake a new TAP::Parser::Result object using the parser's TAP::Parser::ResultFactory, and return\nit. Passes through any arguments given.\n\nThe \"resultfactoryclass\" can be customized, as described in \"new\".\n\n\"makeiteratorfactory\"\n*NEW to 3.18*.\n\nMake a new TAP::Parser::IteratorFactory object and return it. Passes through any arguments\ngiven.\n\n\"iteratorfactoryclass\" can be customized, as described in \"new\".\n"
                    }
                ]
            },
            "INDIVIDUAL RESULTS": {
                "content": "If you've read this far in the docs, you've seen this:\n\nwhile ( my $result = $parser->next ) {\nprint $result->asstring;\n}\n\nEach result returned is a TAP::Parser::Result subclass, referred to as *result types*.\n",
                "subsections": [
                    {
                        "name": "Result types",
                        "content": "Basically, you fetch individual results from the TAP. The six types, with examples of each, are\nas follows:\n\n*   Version\n\nTAP version 12\n\n*   Plan\n\n1..42\n\n*   Pragma\n\npragma +strict\n\n*   Test\n\nok 3 - We should start with some foobar!\n\n*   Comment\n\n# Hope we don't use up the foobar.\n\n*   Bailout\n\nBail out!  We ran out of foobar!\n\n*   Unknown\n\n... yo, this ain't TAP! ...\n\nEach result fetched is a result object of a different type. There are common methods to each\nresult object and different types may have methods unique to their type. Sometimes a type method\nmay be overridden in a subclass, but its use is guaranteed to be identical.\n"
                    },
                    {
                        "name": "Common type methods",
                        "content": "\"type\"\nReturns the type of result, such as \"comment\" or \"test\".\n\n\"asstring\"\nPrints a string representation of the token. This might not be the exact output, however. Tests\nwill have test numbers added if not present, TODO and SKIP directives will be capitalized and,\nin general, things will be cleaned up. If you need the original text for the token, see the\n\"raw\" method.\n\n\"raw\"\nReturns the original line of text which was parsed.\n\n\"isplan\"\nIndicates whether or not this is the test plan line.\n\n\"istest\"\nIndicates whether or not this is a test line.\n\n\"iscomment\"\nIndicates whether or not this is a comment. Comments will generally only appear in the TAP\nstream if STDERR is merged to STDOUT. See the \"merge\" option.\n\n\"isbailout\"\nIndicates whether or not this is bailout line.\n\n\"isyaml\"\nIndicates whether or not the current item is a YAML block.\n\n\"isunknown\"\nIndicates whether or not the current line could be parsed.\n\n\"isok\"\nif ( $result->isok ) { ... }\n\nReports whether or not a given result has passed. Anything which is not a test result returns\ntrue. This is merely provided as a convenient shortcut which allows you to do this:\n\nmy $parser = TAP::Parser->new( { source => $source } );\nwhile ( my $result = $parser->next ) {\n# only print failing results\nprint $result->asstring unless $result->isok;\n}\n\n\"plan\" methods\nif ( $result->isplan ) { ... }\n\nIf the above evaluates as true, the following methods will be available on the $result object.\n\n\"plan\"\nif ( $result->isplan ) {\nprint $result->plan;\n}\n\nThis is merely a synonym for \"asstring\".\n\n\"directive\"\nmy $directive = $result->directive;\n\nIf a SKIP directive is included with the plan, this method will return it.\n\n1..0 # SKIP: why bother?\n\n\"explanation\"\nmy $explanation = $result->explanation;\n\nIf a SKIP directive was included with the plan, this method will return the explanation, if any.\n\n\"pragma\" methods\nif ( $result->ispragma ) { ... }\n\nIf the above evaluates as true, the following methods will be available on the $result object.\n\n\"pragmas\"\nReturns a list of pragmas each of which is a + or - followed by the pragma name.\n\n\"comment\" methods\nif ( $result->iscomment ) { ... }\n\nIf the above evaluates as true, the following methods will be available on the $result object.\n\n\"comment\"\nif ( $result->iscomment ) {\nmy $comment = $result->comment;\nprint \"I have something to say:  $comment\";\n}\n\n\"bailout\" methods\nif ( $result->isbailout ) { ... }\n\nIf the above evaluates as true, the following methods will be available on the $result object.\n\n\"explanation\"\nif ( $result->isbailout ) {\nmy $explanation = $result->explanation;\nprint \"We bailed out because ($explanation)\";\n}\n\nIf, and only if, a token is a bailout token, you can get an \"explanation\" via this method. The\nexplanation is the text after the mystical \"Bail out!\" words which appear in the tap output.\n\n\"unknown\" methods\nif ( $result->isunknown ) { ... }\n\nThere are no unique methods for unknown results.\n\n\"test\" methods\nif ( $result->istest ) { ... }\n\nIf the above evaluates as true, the following methods will be available on the $result object.\n\n\"ok\"\nmy $ok = $result->ok;\n\nReturns the literal text of the \"ok\" or \"not ok\" status.\n\n\"number\"\nmy $testnumber = $result->number;\n\nReturns the number of the test, even if the original TAP output did not supply that number.\n\n\"description\"\nmy $description = $result->description;\n\nReturns the description of the test, if any. This is the portion after the test number but\nbefore the directive.\n\n\"directive\"\nmy $directive = $result->directive;\n\nReturns either \"TODO\" or \"SKIP\" if either directive was present for a test line.\n\n\"explanation\"\nmy $explanation = $result->explanation;\n\nIf a test had either a \"TODO\" or \"SKIP\" directive, this method will return the accompanying\nexplanation, if present.\n\nnot ok 17 - 'Pigs can fly' # TODO not enough acid\n\nFor the above line, the explanation is *not enough acid*.\n\n\"isok\"\nif ( $result->isok ) { ... }\n\nReturns a boolean value indicating whether or not the test passed. Remember that for TODO tests,\nthe test always passes.\n\nNote: this was formerly \"passed\". The latter method is deprecated and will issue a warning.\n\n\"isactualok\"\nif ( $result->isactualok ) { ... }\n\nReturns a boolean value indicating whether or not the test passed, regardless of its TODO\nstatus.\n\nNote: this was formerly \"actualpassed\". The latter method is deprecated and will issue a\nwarning.\n\n\"isunplanned\"\nif ( $test->isunplanned ) { ... }\n\nIf a test number is greater than the number of planned tests, this method will return true.\nUnplanned tests will *always* return false for \"isok\", regardless of whether or not the test\n\"hastodo\" (see TAP::Parser::Result::Test for more information about this).\n\n\"hasskip\"\nif ( $result->hasskip ) { ... }\n\nReturns a boolean value indicating whether or not this test had a SKIP directive.\n\n\"hastodo\"\nif ( $result->hastodo ) { ... }\n\nReturns a boolean value indicating whether or not this test had a TODO directive.\n\nNote that TODO tests *always* pass. If you need to know whether or not they really passed, check\nthe \"isactualok\" method.\n\n\"intodo\"\nif ( $parser->intodo ) { ... }\n\nTrue while the most recent result was a TODO. Becomes true before the TODO result is returned\nand stays true until just before the next non- TODO test is returned.\n"
                    }
                ]
            },
            "TOTAL RESULTS": {
                "content": "After parsing the TAP, there are many methods available to let you dig through the results and\ndetermine what is meaningful to you.\n",
                "subsections": [
                    {
                        "name": "Individual Results",
                        "content": "These results refer to individual tests which are run.\n\n\"passed\"\nmy @passed = $parser->passed; # the test numbers which passed\nmy $passed = $parser->passed; # the number of tests which passed\n\nThis method lets you know which (or how many) tests passed. If a test failed but had a TODO\ndirective, it will be counted as a passed test.\n\n\"failed\"\nmy @failed = $parser->failed; # the test numbers which failed\nmy $failed = $parser->failed; # the number of tests which failed\n\nThis method lets you know which (or how many) tests failed. If a test passed but had a TODO\ndirective, it will NOT be counted as a failed test.\n\n\"actualpassed\"\n# the test numbers which actually passed\nmy @actualpassed = $parser->actualpassed;\n\n# the number of tests which actually passed\nmy $actualpassed = $parser->actualpassed;\n\nThis method lets you know which (or how many) tests actually passed, regardless of whether or\nnot a TODO directive was found.\n\n\"actualok\"\nThis method is a synonym for \"actualpassed\".\n\n\"actualfailed\"\n# the test numbers which actually failed\nmy @actualfailed = $parser->actualfailed;\n\n# the number of tests which actually failed\nmy $actualfailed = $parser->actualfailed;\n\nThis method lets you know which (or how many) tests actually failed, regardless of whether or\nnot a TODO directive was found.\n\n\"todo\"\nmy @todo = $parser->todo; # the test numbers with todo directives\nmy $todo = $parser->todo; # the number of tests with todo directives\n\nThis method lets you know which (or how many) tests had TODO directives.\n\n\"todopassed\"\n# the test numbers which unexpectedly succeeded\nmy @todopassed = $parser->todopassed;\n\n# the number of tests which unexpectedly succeeded\nmy $todopassed = $parser->todopassed;\n\nThis method lets you know which (or how many) tests actually passed but were declared as \"TODO\"\ntests.\n\n\"todofailed\"\n# deprecated in favor of 'todopassed'.  This method was horribly misnamed.\n\nThis was a badly misnamed method. It indicates which TODO tests unexpectedly succeeded. Will now\nissue a warning and call \"todopassed\".\n\n\"skipped\"\nmy @skipped = $parser->skipped; # the test numbers with SKIP directives\nmy $skipped = $parser->skipped; # the number of tests with SKIP directives\n\nThis method lets you know which (or how many) tests had SKIP directives.\n"
                    },
                    {
                        "name": "Pragmas",
                        "content": "\"pragma\"\nGet or set a pragma. To get the state of a pragma:\n\nif ( $p->pragma('strict') ) {\n# be strict\n}\n\nTo set the state of a pragma:\n\n$p->pragma('strict', 1); # enable strict mode\n\n\"pragmas\"\nGet a list of all the currently enabled pragmas:\n\nmy @pragmasenabled = $p->pragmas;\n"
                    },
                    {
                        "name": "Summary Results",
                        "content": "These results are \"meta\" information about the total results of an individual test program.\n\n\"plan\"\nmy $plan = $parser->plan;\n\nReturns the test plan, if found.\n\n\"goodplan\"\nDeprecated. Use \"isgoodplan\" instead.\n\n\"isgoodplan\"\nif ( $parser->isgoodplan ) { ... }\n\nReturns a boolean value indicating whether or not the number of tests planned matches the number\nof tests run.\n\nNote: this was formerly \"goodplan\". The latter method is deprecated and will issue a warning.\n\nAnd since we're on that subject ...\n\n\"testsplanned\"\nprint $parser->testsplanned;\n\nReturns the number of tests planned, according to the plan. For example, a plan of '1..17' will\nmean that 17 tests were planned.\n\n\"testsrun\"\nprint $parser->testsrun;\n\nReturns the number of tests which actually were run. Hopefully this will match the number of\n\"$parser->testsplanned\".\n\n\"skipall\"\nReturns a true value (actually the reason for skipping) if all tests were skipped.\n\n\"starttime\"\nReturns the wall-clock time when the Parser was created.\n\n\"endtime\"\nReturns the wall-clock time when the end of TAP input was seen.\n\n\"starttimes\"\nReturns the CPU times (like \"times\" in perlfunc when the Parser was created.\n\n\"endtimes\"\nReturns the CPU times (like \"times\" in perlfunc when the end of TAP input was seen.\n\n\"hasproblems\"\nif ( $parser->hasproblems ) {\n...\n}\n\nThis is a 'catch-all' method which returns true if any tests have currently failed, any TODO\ntests unexpectedly succeeded, or any parse errors occurred.\n\n\"version\"\n$parser->version;\n\nOnce the parser is done, this will return the version number for the parsed TAP. Version numbers\nwere introduced with TAP version 13 so if no version number is found version 12 is assumed.\n\n\"exit\"\n$parser->exit;\n\nOnce the parser is done, this will return the exit status. If the parser ran an executable, it\nreturns the exit status of the executable.\n\n\"wait\"\n$parser->wait;\n\nOnce the parser is done, this will return the wait status. If the parser ran an executable, it\nreturns the wait status of the executable. Otherwise, this merely returns the \"exit\" status.\n\n\"ignoreexit\"\n$parser->ignoreexit(1);\n\nTell the parser to ignore the exit status from the test when determining whether the test\npassed. Normally tests with non-zero exit status are considered to have failed even if all\nindividual tests passed. In cases where it is not possible to control the exit value of the test\nscript use this option to ignore it.\n\n\"parseerrors\"\nmy @errors = $parser->parseerrors; # the parser errors\nmy $errors = $parser->parseerrors; # the number of parsererrors\n\nFortunately, all TAP output is perfect. In the event that it is not, this method will return\nparser errors. Note that a junk line which the parser does not recognize is \"not\" an error. This\nallows this parser to handle future versions of TAP. The following are all TAP errors reported\nby the parser:\n\n*   Misplaced plan\n\nThe plan (for example, '1..5'), must only come at the beginning or end of the TAP output.\n\n*   No plan\n\nGotta have a plan!\n\n*   More than one plan\n\n1..3\nok 1 - input file opened\nnot ok 2 - first line of the input valid # todo some data\nok 3 read the rest of the file\n1..3\n\nRight. Very funny. Don't do that.\n\n*   Test numbers out of sequence\n\n1..3\nok 1 - input file opened\nnot ok 2 - first line of the input valid # todo some data\nok 2 read the rest of the file\n\nThat last test line above should have the number '3' instead of '2'.\n\nNote that it's perfectly acceptable for some lines to have test numbers and others to not\nhave them. However, when a test number is found, it must be in sequence. The following is\nalso an error:\n\n1..3\nok 1 - input file opened\nnot ok - first line of the input valid # todo some data\nok 2 read the rest of the file\n\nBut this is not:\n\n1..3\nok  - input file opened\nnot ok - first line of the input valid # todo some data\nok 3 read the rest of the file\n\n\"getselecthandles\"\nGet an a list of file handles which can be passed to \"select\" to determine the readiness of this\nparser.\n\n\"deletespool\"\nDelete and return the spool.\n\nmy $fh = $parser->deletespool;\n"
                    }
                ]
            },
            "CALLBACKS": {
                "content": "As mentioned earlier, a \"callback\" key may be added to the \"TAP::Parser\" constructor. If\npresent, each callback corresponding to a given result type will be called with the result as\nthe argument if the \"run\" method is used. The callback is expected to be a subroutine reference\n(or anonymous subroutine) which is invoked with the parser result as its argument.\n\nmy %callbacks = (\ntest    => \\&testcallback,\nplan    => \\&plancallback,\ncomment => \\&commentcallback,\nbailout => \\&bailoutcallback,\nunknown => \\&unknowncallback,\n);\n\nmy $aggregator = TAP::Parser::Aggregator->new;\nfor my $file ( @testfiles ) {\nmy $parser = TAP::Parser->new(\n{\nsource    => $file,\ncallbacks => \\%callbacks,\n}\n);\n$parser->run;\n$aggregator->add( $file, $parser );\n}\n\nCallbacks may also be added like this:\n\n$parser->callback( test => \\&testcallback );\n$parser->callback( plan => \\&plancallback );\n\nThe following keys allowed for callbacks. These keys are case-sensitive.\n\n*   \"test\"\n\nInvoked if \"$result->istest\" returns true.\n\n*   \"version\"\n\nInvoked if \"$result->isversion\" returns true.\n\n*   \"plan\"\n\nInvoked if \"$result->isplan\" returns true.\n\n*   \"comment\"\n\nInvoked if \"$result->iscomment\" returns true.\n\n*   \"bailout\"\n\nInvoked if \"$result->isunknown\" returns true.\n\n*   \"yaml\"\n\nInvoked if \"$result->isyaml\" returns true.\n\n*   \"unknown\"\n\nInvoked if \"$result->isunknown\" returns true.\n\n*   \"ELSE\"\n\nIf a result does not have a callback defined for it, this callback will be invoked. Thus, if\nall of the previous result types are specified as callbacks, this callback will *never* be\ninvoked.\n\n*   \"ALL\"\n\nThis callback will always be invoked and this will happen for each result after one of the\nabove callbacks is invoked. For example, if Term::ANSIColor is loaded, you could use the\nfollowing to color your test output:\n\nmy %callbacks = (\ntest => sub {\nmy $test = shift;\nif ( $test->isok && not $test->directive ) {\n# normal passing test\nprint color 'green';\n}\nelsif ( !$test->isok ) {    # even if it's TODO\nprint color 'white onred';\n}\nelsif ( $test->hasskip ) {\nprint color 'white onblue';\n\n}\nelsif ( $test->hastodo ) {\nprint color 'white';\n}\n},\nELSE => sub {\n# plan, comment, and so on (anything which isn't a test line)\nprint color 'black onwhite';\n},\nALL => sub {\n# now print them\nprint shift->asstring;\nprint color 'reset';\nprint \"\\n\";\n},\n);\n\n*   \"EOF\"\n\nInvoked when there are no more lines to be parsed. Since there is no accompanying\nTAP::Parser::Result object the \"TAP::Parser\" object is passed instead.\n",
                "subsections": []
            },
            "TAP GRAMMAR": {
                "content": "If you're looking for an EBNF grammar, see TAP::Parser::Grammar.\n",
                "subsections": []
            },
            "BACKWARDS COMPATIBILITY": {
                "content": "The Perl-QA list attempted to ensure backwards compatibility with Test::Harness. However, there\nare some minor differences.\n",
                "subsections": [
                    {
                        "name": "Differences",
                        "content": "*   TODO plans\n\nA little-known feature of Test::Harness is that it supported TODO lists in the plan:\n\n1..2 todo 2\nok 1 - We have liftoff\nnot ok 2 - Anti-gravity device activated\n\nUnder Test::Harness, test number 2 would *pass* because it was listed as a TODO test on the\nplan line. However, we are not aware of anyone actually using this feature and hard-coding\ntest numbers is discouraged because it's very easy to add a test and break the test number\nsequence. This makes test suites very fragile. Instead, the following should be used:\n\n1..2\nok 1 - We have liftoff\nnot ok 2 - Anti-gravity device activated # TODO\n\n*   'Missing' tests\n\nIt rarely happens, but sometimes a harness might encounter 'missing tests:\n\nok 1\nok 2\nok 15\nok 16\nok 17\n\nTest::Harness would report tests 3-14 as having failed. For the \"TAP::Parser\", these tests\nare not considered failed because they've never run. They're reported as parse failures\n(tests out of sequence).\n"
                    }
                ]
            },
            "SUBCLASSING": {
                "content": "If you find you need to provide custom functionality (as you would have using\nTest::Harness::Straps), you're in luck: \"TAP::Parser\" and friends are designed to be easily\nplugged-into and/or subclassed.\n\nBefore you start, it's important to know a few things:\n\n1 All \"TAP::*\" objects inherit from TAP::Object.\n\n2 Many \"TAP::*\" classes have a *SUBCLASSING* section to guide you.\n\n3 Note that \"TAP::Parser\" is designed to be the central \"maker\" - ie: it is responsible for\ncreating most new objects in the \"TAP::Parser::*\" namespace.\n\nThis makes it possible for you to have a single point of configuring what subclasses should be\nused, which means that in many cases you'll find you only need to sub-class one of the\nparser's components.\n\nThe exception to this rule are *SourceHandlers* & *Iterators*, but those are both created with\ncustomizable *IteratorFactory*.\n\n4 By subclassing, you may end up overriding undocumented methods. That's not a bad thing per se,\nbut be forewarned that undocumented methods may change without warning from one release to the\nnext - we cannot guarantee backwards compatibility. If any *documented* method needs changing,\nit will be deprecated first, and changed in a later release.\n",
                "subsections": [
                    {
                        "name": "Parser Components",
                        "content": "Sources\nA TAP parser consumes input from a single *raw source* of TAP, which could come from anywhere (a\nfile, an executable, a database, an IO handle, a URI, etc..). The source gets bundled up in a\nTAP::Parser::Source object which gathers some meta data about it. The parser then uses a\nTAP::Parser::IteratorFactory to determine which TAP::Parser::SourceHandler to use to turn the\nraw source into a stream of TAP by way of \"Iterators\".\n\nIf you simply want \"TAP::Parser\" to handle a new source of TAP you probably don't need to\nsubclass \"TAP::Parser\" itself. Rather, you'll need to create a new TAP::Parser::SourceHandler\nclass, and just plug it into the parser using the *sources* param to \"new\". Before you start\nwriting one, read through TAP::Parser::IteratorFactory to get a feel for how the system works\nfirst.\n\nIf you find you really need to use your own iterator factory you can still do so without\nsub-classing \"TAP::Parser\" by setting \"iteratorfactoryclass\".\n\nIf you just need to customize the objects on creation, subclass TAP::Parser and override\n\"makeiteratorfactory\".\n\nNote that \"makesource\" & \"makeperlsource\" have been *DEPRECATED* and are now removed.\n\nIterators\nA TAP parser uses *iterators* to loop through the *stream* of TAP read in from the *source* it\nwas given. There are a few types of Iterators available by default, all sub-classes of\nTAP::Parser::Iterator. Choosing which iterator to use is the responsibility of the *iterator\nfactory*, though it simply delegates to the *Source Handler* it uses.\n\nIf you're writing your own TAP::Parser::SourceHandler, you may need to create your own iterators\ntoo. If so you'll need to subclass TAP::Parser::Iterator.\n\nNote that \"makeiterator\" has been *DEPRECATED* and is now removed.\n\nResults\nA TAP parser creates TAP::Parser::Results as it iterates through the input *stream*. There are\nquite a few result types available; choosing which class to use is the responsibility of the\n*result factory*.\n\nTo create your own result types you have two options:\n\noption 1\nSubclass TAP::Parser::Result and register your new result type/class with the default\nTAP::Parser::ResultFactory.\n\noption 2\nSubclass TAP::Parser::ResultFactory itself and implement your own TAP::Parser::Result creation\nlogic. Then you'll need to customize the class used by your parser by setting the\n\"resultfactoryclass\" parameter. See \"new\" for more details.\n\nIf you need to customize the objects on creation, subclass TAP::Parser and override\n\"makeresult\".\n\nGrammar\nTAP::Parser::Grammar is the heart of the parser. It tokenizes the TAP input *stream* and\nproduces results. If you need to customize its behaviour you should probably familiarize\nyourself with the source first. Enough lecturing.\n\nSubclass TAP::Parser::Grammar and customize your parser by setting the \"grammarclass\"\nparameter. See \"new\" for more details.\n\nIf you need to customize the objects on creation, subclass TAP::Parser and override\n\"makegrammar\"\n"
                    }
                ]
            },
            "ACKNOWLEDGMENTS": {
                "content": "All of the following have helped. Bug reports, patches, (im)moral support, or just words of\nencouragement have all been forthcoming.\n\n*   Michael Schwern\n\n*   Andy Lester\n\n*   chromatic\n\n*   GEOFFR\n\n*   Shlomi Fish\n\n*   Torsten Schoenfeld\n\n*   Jerry Gay\n\n*   Aristotle\n\n*   Adam Kennedy\n\n*   Yves Orton\n\n*   Adrian Howard\n\n*   Sean & Lil\n\n*   Andreas J. Koenig\n\n*   Florian Ragwitz\n\n*   Corion\n\n*   Mark Stosberg\n\n*   Matt Kraai\n\n*   David Wheeler\n\n*   Alex Vandiver\n\n*   Cosimo Streppone\n\n*   Ville Skyttä\n",
                "subsections": []
            },
            "AUTHORS": {
                "content": "Curtis \"Ovid\" Poe <ovid@cpan.org>\n\nAndy Armstong <andy@hexten.net>\n\nEric Wilhelm @ <ewilhelm at cpan dot org>\n\nMichael Peters <mpeters at plusthree dot com>\n\nLeif Eriksen <leif dot eriksen at bigpond dot com>\n\nSteve Purkis <spurkis@cpan.org>\n\nNicholas Clark <nick@ccl4.org>\n\nLee Johnson <notfadeaway at btinternet dot com>\n\nPhilippe Bruhat <book@cpan.org>\n",
                "subsections": []
            },
            "BUGS": {
                "content": "Please report any bugs or feature requests to \"bug-test-harness@rt.cpan.org\", or through the web\ninterface at <http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Test-Harness>. We will be notified,\nand then you'll automatically be notified of progress on your bug as we make changes.\n\nObviously, bugs which include patches are best. If you prefer, you can patch against bleed by\nvia anonymous checkout of the latest version:\n\ngit clone git://github.com/Perl-Toolchain-Gang/Test-Harness.git\n\nCOPYRIGHT & LICENSE\nCopyright 2006-2008 Curtis \"Ovid\" Poe, all rights reserved.\n\nThis program is free software; you can redistribute it and/or modify it under the same terms as\nPerl itself.\n",
                "subsections": []
            }
        }
    }
}