"TAPlug"s for TAP::Harness

Andy Armstrong andy at hexten.net
Wed Jun 10 14:03:57 GMT 2009


On 10 Jun 2009, at 07:51, Eric Wilhelm wrote:
>> I'm not sure what the solution to that is, apart from "make it
>> pluggable",
>
> There already are some hooks defined.
>
>      parser_args
>      made_parser
>      before_runtests
>      after_runtests
>      after_test
>
> Though apparently lacking some documentation?

Yeah, that's right.

> And (at a glance) it doesn't look like it's possible to stack more  
> than
> one callback at any point.  Andy?

No, you can have multiple handlers registered for an event - they're  
called in registration order.

> Now, of course the thing David was on about is that you have to be
> writing code with "TAP::Harness->new(...)" to set such callbacks and  
> it
> is too many layers of abstraction away from the gripping end of the
> stick.

Indeed. In many cases it's Test::Harness that gets in the way. Some  
history: originally the intention was that Test::Harness would be a  
legacy interface, not support any new features and just do its best to  
work like Test::Harness 2.64. Everyone's tests would migrate to using  
TAP::Harness directly and the call to TAP::Harness->new would be  
closer to the surface.

We supposed - back when that plan was hatched - that it'd take a while  
for the Test::Harness interface to fall into disuse. In particular we  
anticipated having to wait until TAP::Harness was in core.

I still quite like that plan :)

So I'm diffident about exposing new features through the Test::Harness  
interface. Breaking the tyranny of that interface was one of the  
original goals here. That's why things like HARNESS_OPTIONS are a  
little half-hearted. Somebody asked for it so I added it - but I  
didn't want it to become the de-facto way of specifying the options  
that it exposes.

> What I propose as a possible interface is to empower new() to load and
> probe a list of "Provides Lesser-Used Goodies" classes.  (Not really
> roles, but playing a similar, uh... role.)
>
>  TAP::Harness->new(
>    ...
>    utilize => [
>      ["TAPlug::Archiver", @args_for_init],
>      ["TAPlug::Ponies", color => "red"],
>      ...
>    ],
>  );
>
> Wherin "TAPlug::Archiver->init($harness, @args_for_init)" returns a  
> hash
> with $callback_name => $subref, each of which is then installed in the
> $harness object.  TAP::Harness would be responsible for require()ing
> each plug.
>
> These plugs could be thin setup layers on top of whatever mechanism is
> needed, or might just implement everything in the returned subref.
>
> This would mean that callers like Module::Build can add e.g. a -- 
> taplug
> option following perl's -M conventions of "Module=arg,arg".
>
>  ./Build test --taplug Archiver=args,for,init --taplug  
> Ponies=color,red
>
> Plugs would be responsible for not breaking each other (or  
> sufficiently
> educating the user about how to mix them), but by having the $harness
> object at their init(), they could conceivably introspect any existing
> plugs (assuming that TAP::Harness retains package names in an ordered
> list of who got where when.)


That's certainly possible. It's already nearly possible. You can pass  
a list of callbacks to TAP::Harness->new. If you had an additional  
callback that was called during TAP::Harness construction you could  
write:

   TAP::Harness->new(
     callbacks => { postinit => sub {
       my $self = shift;
       TAPlug::Archiver->hook($self, @args);
     }});

Which I think achieves the same thing but with less hard wired plumbing.

I currently use the before_runtests hook to do that kind of thing but  
you're right - it'd be better to be able to have it happen during  
harness init.

-- 
Andy Armstrong, Hexten



More information about the tapx-dev mailing list