Perl's not the only TAP source

Steve Purkis steve at purkis.ca
Thu Jun 11 21:43:17 GMT 2009


(yes, I'm replying in reverse-order)

On 10 Jun 2009, at 20:37, David E. Wheeler wrote:

> On Jun 10, 2009, at 12:19 PM, David E. Wheeler wrote:
>
>>> 4. think of ways we can make any of this easier for people.
>>
>> It needs more documentation. It took me quite a while to figure out
>> that I could get at source-specific configuration data in `$args-
>>> {config}`. Data::Dumper helped me out here. I'll likely write up
>> detailed docs as I figure how how to write a proper pgTAP source.
>
> Reflecting on this, and realizing that the vast majority of sources
> will want to execute a program, the easiest way to create sources
> would be to require that source authors implement just two functions:
>
> 1. can_handle()
> 2. command()
>
> The former is the same as in source (though with one argument instead
> of three), and the second just puts together the command to be
> executed. With something like this, it'd be easy to write a PHP source
> like this:
>
>
>     package TAP::Parser::Source::PHP;
>
>     use strict;
>     our $VERSION = '3.18';
>
>     sub can_handle {
>         my $meta = shift;
>         return 0 unless $meta->{is_file};
>         return 1 if     $meta->{file}{lc_ext} eq '.php';
>         return 0;
>     }
>
>     sub command {
>         my $params = shift;
>         return [ 'php', $params->{file}{name} @{ $params->{config} ||
> [] }];
>     }
>
> Note how there is no registration to be made; the `sources` parameter
> in Build.PL tells it to load. The source class (or perhaps an exec
> subclass) then loads this module and calls the two functions as
> appropriate, passing in the appropriate data. That's it. This will
> make it as easy as possible for source authors to write sources: all
> they have to do is implement the above two functions and document the
> configuration keys they support (such as "dbname" and "username" in
> the pgTAP example).
>
>>
>
> This also eliminates all of the subclassing stuff that the current
> implementation requires. Just trying to make it as simple as humanly
> possible.
>
> Thoughts?

I like the simplicity, and I think it'll work with Executable sources.

But I don't think it'll work in all cases: while it's true, I  
currently expect most sources to be Execution based, we still need to  
make sure we don't limit people to it.  As mentioned in my last email,  
there are valid sources that are not Execution based, including 2  
internal sources.  Having a method called 'command' doesn't make sense  
there.

I'm also not so convinced about removing the sub-classing, mainly  
because it would complicate the internal sources that aren't command- 
based, and it would take away the benefits of being able to sub-class  
(like re-using parent methods).

Coming back to Executable sources - the reason I like your idea is  
because plugin writers really won't care about cases where the  
$raw_source_ref is not a file, so the fact that it's a ref, and a raw  
source is irrelevant noise.  Having extra params on the method calls  
is also annoying if you don't need them...  So if the super-class was  
to set them all up as instance attrs then they're there for the  
taking, but won't get in the way otherwise.  Tricky with can_handle,  
as the object's not instantiated yet, but would work for command.

I'd say: make it possible to create a plugin by writing 2 simple  
methods, as above.  Gear up all the docs that way.  But still allow  
people to do more if they need to.


Finally, while I can see it's nice not to have to register stuff, I  
think we may have to keep the registration in, otherwise I don't know  
how we'll be able to load plugins from App::Prove.  Maybe I'm missing  
something - this is what I had in mind:

	% ls t
	load.t
	test.foo
	zzz.t

	% prove -PFoo -r t/
	# runs all the tests

	# the plugin:
	package App::Prove::Plugin::Foo;
	use TAP::Parser::Source::Foo;
	use TAP::Parser::Formatter::Foo;
	sub load {
	      my ($class, $p) = @_;
	      my $app  = $p->{app_prove};
	      $app->formatter( 'TAP::Parser::Formatter::Foo' );
	      # how do I set
	      return 1;
	}

So just by using the 'Foo' source, it'll get registered & able to vote  
(eg: for the .foo file).  If it didn't get registered, we'd have to  
have some way of passing in all the source info to TAP::Harness.

Hmm. Same problem as last email - maybe we want that anyway?

-Steve



More information about the tapx-dev mailing list