File Coverage

blib/lib/Bio/Phylo/Factory.pm
Criterion Covered Total %
statement 30 59 50.8
branch 5 22 22.7
condition n/a
subroutine 7 10 70.0
pod 3 3 100.0
total 45 94 47.8


line stmt bran cond sub pod time code
1             package Bio::Phylo::Factory;
2 51     51   124005 use strict;
  51         113  
  51         1247  
3 51     51   230 use warnings;
  51         85  
  51         1196  
4 51     51   480 use Bio::Phylo::Util::Exceptions 'throw';
  51         91  
  51         2044  
5 51     51   534 use Bio::Phylo::Util::CONSTANT qw'looks_like_hash looks_like_class';
  51         92  
  51         29426  
6             our $AUTOLOAD;
7             my %class = (
8             'taxa' => 'Bio::Phylo::Taxa',
9             'taxon' => 'Bio::Phylo::Taxa::Taxon',
10             'datum' => 'Bio::Phylo::Matrices::Datum',
11             'matrix' => 'Bio::Phylo::Matrices::Matrix',
12             'characters' => 'Bio::Phylo::Matrices::Characters',
13             'character' => 'Bio::Phylo::Matrices::Character',
14             'datatype' => 'Bio::Phylo::Matrices::Datatype',
15             'forest' => 'Bio::Phylo::Forest',
16             'node' => 'Bio::Phylo::Forest::Node',
17             'tree' => 'Bio::Phylo::Forest::Tree',
18             'logger' => 'Bio::Phylo::Util::Logger',
19             'drawer' => 'Bio::Phylo::Treedrawer',
20             'treedrawer' => 'Bio::Phylo::Treedrawer',
21             'project' => 'Bio::Phylo::Project',
22             'annotation' => 'Bio::Phylo::Annotation',
23             'set' => 'Bio::Phylo::Set',
24             'generator' => 'Bio::Phylo::Generator',
25             'xmlwritable' => 'Bio::Phylo::NeXML::Writable',
26             'xmlliteral' => 'Bio::Phylo::NeXML::Meta::XMLLiteral',
27             'meta' => 'Bio::Phylo::NeXML::Meta',
28             'dom' => 'Bio::Phylo::NeXML::DOM',
29             'document' => 'Bio::Phylo::NeXML::DOM::Document',
30             'element' => 'Bio::Phylo::NeXML::DOM::Element',
31             'client' => 'Bio::Phylo::PhyloWS::Client',
32             'server' => 'Bio::Phylo::PhyloWS::Server',
33             'resource' => 'Bio::Phylo::PhyloWS::Resource',
34             'description' => 'Bio::Phylo::PhyloWS::Resource::Description',
35             );
36              
37             sub import {
38 346     346   784 my $package = shift;
39 346 50       156249 $package->register_class(@_) if @_;
40             }
41              
42             =head1 NAME
43              
44             Bio::Phylo::Factory - Creator of objects, reduces hardcoded class names in code
45              
46             =head1 SYNOPSIS
47              
48             use Bio::Phylo::Factory;
49             my $fac = Bio::Phylo::Factory->new;
50             my $node = $fac->create_node( '-name' => 'node1' );
51              
52             # probably prints 'Bio::Phylo::Forest::Node'?
53             print ref $node;
54              
55             =head1 DESCRIPTION
56              
57             The factory module is used to create other objects without having to 'use'
58             their classes. This allows for greater flexibility in Bio::Phylo's design,
59             as class names are no longer hard-coded all over the place.
60              
61             =head1 METHODS
62              
63             =head2 CONSTRUCTOR
64              
65             =over
66              
67             =item new()
68              
69             Factory constructor.
70              
71             Type : Constructor
72             Title : new
73             Usage : my $fac = Bio::Phylo::Factory->new;
74             Function: Initializes a Bio::Phylo::Factory object.
75             Returns : A Bio::Phylo::Factory object.
76             Args : (optional) a hash keyed on short names, with
77             class names for values. For example,
78             'node' => 'Bio::Phylo::Forest::Node', which
79             will allow you to subsequently call $fac->create_node,
80             which will return a Bio::Phylo::Forest::Node object.
81             (Note that this example is enabled by default, so you
82             don't need to specify it.)
83              
84             =cut
85              
86             sub new {
87 329     329 1 1386 my $class = shift;
88 329 50       1215 if (@_) {
89 0         0 my %args = looks_like_hash @_;
90 0         0 while ( my ( $key, $value ) = each %args ) {
91 0 0       0 if ( looks_like_class $value ) {
92 0         0 $class{$key} = $value;
93             }
94             }
95             }
96 329         1131 bless \$class, $class;
97             }
98              
99             =back
100              
101             =head2 FACTORY METHODS
102              
103             =over
104              
105             =item create($class, %args)
106              
107             Type : Factory methods
108             Title : create
109             Usage : my $foo = $fac->create('Foo::Class');
110             Function: Creates an instance of $class, with constructor arguments %args
111             Returns : A Bio::Phylo::* object.
112             Args : $class, a class name (required),
113             %args, constructor arguments (optional)
114              
115             =cut
116              
117             sub create {
118 0     0 1 0 my $self = shift;
119 0         0 my $class = shift;
120 0 0       0 if ( looks_like_class $class ) {
121 0         0 return $class->new(@_);
122             }
123             }
124              
125             =item register_class()
126              
127             Registers the argument class name such that subsequently
128             the factory can instantiates objects of that class. For
129             example, if you register Foo::Bar, the factory will be
130             able to instantiate objects through the create_bar()
131             method.
132              
133             Type : Factory methods
134             Title : register_class
135             Usage : $fac->register_class('Foo::Bar');
136             Function: Registers a class name for instantiation
137             Returns : Invocant
138             Args : $class, a class name (required), or
139             'bar' => 'Foo::Bar', such that you
140             can subsequently call $fac->create_bar()
141              
142             =cut
143              
144             sub register_class {
145 0     0 1 0 my ( $self, @args ) = @_;
146 0         0 my ( $short, $class );
147 0 0       0 if ( @args == 1 ) {
148 0         0 $class = $args[0];
149             }
150             else {
151 0         0 ( $short, $class ) = @args;
152             }
153 0         0 my $path = $class;
154 0         0 $path =~ s|::|/|g;
155 0         0 $path .= '.pm';
156 0 0       0 if ( not $INC{$path} ) {
157 0         0 eval { require $path };
  0         0  
158 0 0       0 if ($@) {
159 0         0 throw 'ExtensionError' => "Can't register $class - $@";
160             }
161             }
162 0 0       0 if ( not defined $short ) {
163 0         0 $short = $class;
164 0         0 $short =~ s/.*://;
165 0         0 $short = lc $short;
166             }
167 0         0 $class{$short} = $class;
168 0         0 return $self;
169             }
170              
171             # need empty destructor here so we don't autoload it
172       0     sub DESTROY {}
173              
174             sub AUTOLOAD {
175 7612     7612   17709 my $self = shift;
176 7612         10163 my $method = $AUTOLOAD;
177 7612         36767 $method =~ s/.*://;
178 7612         13999 my $type = $method;
179 7612         18850 $type =~ s/^create_//;
180 7612 50       17925 if ( exists $class{$type} ) {
    0          
181 7612         12598 my $class = $class{$type};
182 7612         10697 my $path = $class;
183 7612         23497 $path =~ s|::|/|g;
184 7612         13790 $path .= '.pm';
185 7612 100       17471 if ( not $INC{$path} ) {
186            
187             # here we need to do a string eval use so that the
188             # entire symbol table is populated
189 127         45186 require $path;
190             }
191 7612         30949 return $class{$type}->new(@_);
192             }
193             elsif ( $method =~ qr/^[A-Z]+$/ ) {
194 0           return;
195             }
196             else {
197 0           throw 'UnknownMethod' => "No such method: $method";
198             }
199             }
200              
201             =back
202              
203             =head1 SEE ALSO
204              
205             There is a mailing list at L<https://groups.google.com/forum/#!forum/bio-phylo>
206             for any user or developer questions and discussions.
207              
208             =over
209              
210             =item L<Bio::Phylo::Manual>
211              
212             Also see the manual: L<Bio::Phylo::Manual> and L<http://rutgervos.blogspot.com>.
213              
214             =back
215              
216             =head1 CITATION
217              
218             If you use Bio::Phylo in published research, please cite it:
219              
220             B<Rutger A Vos>, B<Jason Caravas>, B<Klaas Hartmann>, B<Mark A Jensen>
221             and B<Chase Miller>, 2011. Bio::Phylo - phyloinformatic analysis using Perl.
222             I<BMC Bioinformatics> B<12>:63.
223             L<http://dx.doi.org/10.1186/1471-2105-12-63>
224              
225             =cut
226              
227             1;