blob: 37ec96b201b1f6015fc34c187680332bb9507a66 [file] [log] [blame]
package TAP::Parser::ResultFactory;
use strict;
use vars qw($VERSION @ISA %CLASS_FOR);
use TAP::Object ();
use TAP::Parser::Result::Bailout ();
use TAP::Parser::Result::Comment ();
use TAP::Parser::Result::Plan ();
use TAP::Parser::Result::Pragma ();
use TAP::Parser::Result::Test ();
use TAP::Parser::Result::Unknown ();
use TAP::Parser::Result::Version ();
use TAP::Parser::Result::YAML ();
@ISA = 'TAP::Object';
##############################################################################
=head1 NAME
TAP::Parser::ResultFactory - Factory for creating TAP::Parser output objects
=head1 SYNOPSIS
use TAP::Parser::ResultFactory;
my $token = {...};
my $factory = TAP::Parser::ResultFactory->new;
my $result = $factory->make_result( $token );
=head1 VERSION
Version 3.23
=cut
$VERSION = '3.23';
=head2 DESCRIPTION
This is a simple factory class which returns a L<TAP::Parser::Result> subclass
representing the current bit of test data from TAP (usually a single line).
It is used primarily by L<TAP::Parser::Grammar>. Unless you're subclassing,
you probably won't need to use this module directly.
=head2 METHODS
=head2 Class Methods
=head3 C<new>
Creates a new factory class.
I<Note:> You currently don't need to instantiate a factory in order to use it.
=head3 C<make_result>
Returns an instance the appropriate class for the test token passed in.
my $result = TAP::Parser::ResultFactory->make_result($token);
Can also be called as an instance method.
=cut
sub make_result {
my ( $proto, $token ) = @_;
my $type = $token->{type};
return $proto->class_for($type)->new($token);
}
=head3 C<class_for>
Takes one argument: C<$type>. Returns the class for this $type, or C<croak>s
with an error.
=head3 C<register_type>
Takes two arguments: C<$type>, C<$class>
This lets you override an existing type with your own custom type, or register
a completely new type, eg:
# create a custom result type:
package MyResult;
use strict;
use vars qw(@ISA);
@ISA = 'TAP::Parser::Result';
# register with the factory:
TAP::Parser::ResultFactory->register_type( 'my_type' => __PACKAGE__ );
# use it:
my $r = TAP::Parser::ResultFactory->( { type => 'my_type' } );
Your custom type should then be picked up automatically by the L<TAP::Parser>.
=cut
BEGIN {
%CLASS_FOR = (
plan => 'TAP::Parser::Result::Plan',
pragma => 'TAP::Parser::Result::Pragma',
test => 'TAP::Parser::Result::Test',
comment => 'TAP::Parser::Result::Comment',
bailout => 'TAP::Parser::Result::Bailout',
version => 'TAP::Parser::Result::Version',
unknown => 'TAP::Parser::Result::Unknown',
yaml => 'TAP::Parser::Result::YAML',
);
}
sub class_for {
my ( $class, $type ) = @_;
# return target class:
return $CLASS_FOR{$type} if exists $CLASS_FOR{$type};
# or complain:
require Carp;
Carp::croak("Could not determine class for result type '$type'");
}
sub register_type {
my ( $class, $type, $rclass ) = @_;
# register it blindly, assume they know what they're doing
$CLASS_FOR{$type} = $rclass;
return $class;
}
1;
=head1 SUBCLASSING
Please see L<TAP::Parser/SUBCLASSING> for a subclassing overview.
There are a few things to bear in mind when creating your own
C<ResultFactory>:
=over 4
=item 1
The factory itself is never instantiated (this I<may> change in the future).
This means that C<_initialize> is never called.
=item 2
C<TAP::Parser::Result-E<gt>new> is never called, $tokens are reblessed.
This I<will> change in a future version!
=item 3
L<TAP::Parser::Result> subclasses will register themselves with
L<TAP::Parser::ResultFactory> directly:
package MyFooResult;
TAP::Parser::ResultFactory->register_type( foo => __PACKAGE__ );
Of course, it's up to you to decide whether or not to ignore them.
=back
=head2 Example
package MyResultFactory;
use strict;
use vars '@ISA';
use MyResult;
use TAP::Parser::ResultFactory;
@ISA = qw( TAP::Parser::ResultFactory );
# force all results to be 'MyResult'
sub class_for {
return 'MyResult';
}
1;
=head1 SEE ALSO
L<TAP::Parser>,
L<TAP::Parser::Result>,
L<TAP::Parser::Grammar>
=cut