"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