ResultFactory.pm revision 1.5
1package TAP::Parser::ResultFactory;
2
3use strict;
4use warnings;
5
6use TAP::Parser::Result::Bailout ();
7use TAP::Parser::Result::Comment ();
8use TAP::Parser::Result::Plan    ();
9use TAP::Parser::Result::Pragma  ();
10use TAP::Parser::Result::Test    ();
11use TAP::Parser::Result::Unknown ();
12use TAP::Parser::Result::Version ();
13use TAP::Parser::Result::YAML    ();
14
15use base 'TAP::Object';
16
17##############################################################################
18
19=head1 NAME
20
21TAP::Parser::ResultFactory - Factory for creating TAP::Parser output objects
22
23=head1 SYNOPSIS
24
25  use TAP::Parser::ResultFactory;
26  my $token   = {...};
27  my $factory = TAP::Parser::ResultFactory->new;
28  my $result  = $factory->make_result( $token );
29
30=head1 VERSION
31
32Version 3.44
33
34=cut
35
36our $VERSION = '3.44';
37
38=head2 DESCRIPTION
39
40This is a simple factory class which returns a L<TAP::Parser::Result> subclass
41representing the current bit of test data from TAP (usually a single line).
42It is used primarily by L<TAP::Parser::Grammar>.  Unless you're subclassing,
43you probably won't need to use this module directly.
44
45=head2 METHODS
46
47=head2 Class Methods
48
49=head3 C<new>
50
51Creates a new factory class.
52I<Note:> You currently don't need to instantiate a factory in order to use it.
53
54=head3 C<make_result>
55
56Returns an instance the appropriate class for the test token passed in.
57
58  my $result = TAP::Parser::ResultFactory->make_result($token);
59
60Can also be called as an instance method.
61
62=cut
63
64sub make_result {
65    my ( $proto, $token ) = @_;
66    my $type = $token->{type};
67    return $proto->class_for($type)->new($token);
68}
69
70=head3 C<class_for>
71
72Takes one argument: C<$type>.  Returns the class for this $type, or C<croak>s
73with an error.
74
75=head3 C<register_type>
76
77Takes two arguments: C<$type>, C<$class>
78
79This lets you override an existing type with your own custom type, or register
80a completely new type, eg:
81
82  # create a custom result type:
83  package MyResult;
84  use strict;
85  use base 'TAP::Parser::Result';
86
87  # register with the factory:
88  TAP::Parser::ResultFactory->register_type( 'my_type' => __PACKAGE__ );
89
90  # use it:
91  my $r = TAP::Parser::ResultFactory->( { type => 'my_type' } );
92
93Your custom type should then be picked up automatically by the L<TAP::Parser>.
94
95=cut
96
97our %CLASS_FOR = (
98	plan    => 'TAP::Parser::Result::Plan',
99	pragma  => 'TAP::Parser::Result::Pragma',
100	test    => 'TAP::Parser::Result::Test',
101	comment => 'TAP::Parser::Result::Comment',
102	bailout => 'TAP::Parser::Result::Bailout',
103	version => 'TAP::Parser::Result::Version',
104	unknown => 'TAP::Parser::Result::Unknown',
105	yaml    => 'TAP::Parser::Result::YAML',
106);
107
108sub class_for {
109    my ( $class, $type ) = @_;
110
111    # return target class:
112    return $CLASS_FOR{$type} if exists $CLASS_FOR{$type};
113
114    # or complain:
115    require Carp;
116    Carp::croak("Could not determine class for result type '$type'");
117}
118
119sub register_type {
120    my ( $class, $type, $rclass ) = @_;
121
122    # register it blindly, assume they know what they're doing
123    $CLASS_FOR{$type} = $rclass;
124    return $class;
125}
126
1271;
128
129=head1 SUBCLASSING
130
131Please see L<TAP::Parser/SUBCLASSING> for a subclassing overview.
132
133There are a few things to bear in mind when creating your own
134C<ResultFactory>:
135
136=over 4
137
138=item 1
139
140The factory itself is never instantiated (this I<may> change in the future).
141This means that C<_initialize> is never called.
142
143=item 2
144
145C<TAP::Parser::Result-E<gt>new> is never called, $tokens are reblessed.
146This I<will> change in a future version!
147
148=item 3
149
150L<TAP::Parser::Result> subclasses will register themselves with
151L<TAP::Parser::ResultFactory> directly:
152
153  package MyFooResult;
154  TAP::Parser::ResultFactory->register_type( foo => __PACKAGE__ );
155
156Of course, it's up to you to decide whether or not to ignore them.
157
158=back
159
160=head2 Example
161
162  package MyResultFactory;
163
164  use strict;
165
166  use MyResult;
167
168  use base 'TAP::Parser::ResultFactory';
169
170  # force all results to be 'MyResult'
171  sub class_for {
172    return 'MyResult';
173  }
174
175  1;
176
177=head1 SEE ALSO
178
179L<TAP::Parser>,
180L<TAP::Parser::Result>,
181L<TAP::Parser::Grammar>
182
183=cut
184