File Coverage

blib/lib/Bio/Phylo/NeXML/Meta.pm
Criterion Covered Total %
statement 44 66 66.6
branch 2 10 20.0
condition 2 6 33.3
subroutine 15 21 71.4
pod 10 10 100.0
total 73 113 64.6


line stmt bran cond sub pod time code
1             package Bio::Phylo::NeXML::Meta;
2 10     10   60 use strict;
  10         18  
  10         278  
3 10     10   47 use base 'Bio::Phylo::Listable';
  10         18  
  10         1054  
4 10     10   59 use Bio::Phylo::Util::CONSTANT qw'_DOMCREATOR_ _META_ /looks_like/';
  10         18  
  10         1680  
5 10     10   61 use Bio::Phylo::Util::Exceptions 'throw';
  10         17  
  10         395  
6 10     10   52 use Bio::Phylo::Factory;
  10         18  
  10         54  
7             {
8             my $fac = Bio::Phylo::Factory->new;
9             my @fields = \( my ( %property, %content ) );
10             my $TYPE_CONSTANT = _META_;
11             my $CONTAINER_CONSTANT = $TYPE_CONSTANT;
12              
13             =head1 NAME
14              
15             Bio::Phylo::NeXML::Meta - Single predicate/object annotation, attached to an
16             xml-writable subject
17              
18             =head1 SYNOPSIS
19              
20             use Bio::Phylo::Factory;
21             use Bio::Phylo::Util::CONSTANT ':namespaces';
22             my $fac = Bio::Phylo::Factory->new;
23             my $url = 'http://purl.org/phylo/treebase/phylows/study/TB2:S1787';
24             my $proj = $fac->create_project->add_meta(
25             $fac->create_meta(
26             '-namespaces' => { 'cdao' => _NS_CDAO_ },
27             '-triple' => {
28             'cdao:hasMeta' => $fac->create_meta(
29             '-namespaces' => { 'cdao' => _NS_CDAO_ },
30             '-triple' => { 'cdao:has_External_Reference' => $url }
31             )
32             }
33             )
34             );
35              
36             =head1 DESCRIPTION
37              
38             To comply with the NeXML standard (L<http://www.nexml.org>), Bio::Phylo
39             implements metadata annotations which consist conceptually of RDF triples where
40             the subject is a container object that subclasses
41             L<Bio::Phylo::NeXML::Writable>, and the predicate and object are defined in
42             this class.
43              
44             The objects of the triples provided by this class can be of any simple type
45             (string, number) or one of L<XML::DOM>, L<XML::GDOME>, L<XML::LibXML>,
46             L<XML::Twig>, L<XML::DOM2>, L<XML::DOMBacked>, L<XML::Handler>, L<XML::Element>,
47             L<XML::API>, L<XML::Code> or L<XML::XMLWriter> or L<RDF::Core::Model>.
48              
49             When serialized, the Bio::Phylo::NeXML::Meta object in NeXML is typically written out
50             as an element called 'meta', with RDFa compliant attributes.
51              
52             =head1 METHODS
53              
54             =head2 CONSTRUCTOR
55              
56             =over
57              
58             =item new()
59              
60             Type : Constructor
61             Title : new
62             Usage : my $anno = Bio::Phylo::NeXML::Meta->new;
63             Function: Initializes a Bio::Phylo::NeXML::Meta object.
64             Returns : A Bio::Phylo::NeXML::Meta object.
65             Args : optional constructor arguments are key/value
66             pairs where the key corresponds with any of
67             the methods that starts with set_ (i.e. mutators)
68             and the value is the permitted argument for such
69             a method. The method name is changed such that,
70             in order to access the set_value($val) method
71             in the constructor, you would pass -value => $val
72              
73             =cut
74              
75             # sub new { return shift->SUPER::new( '-tag' => 'meta', @_ ) }
76             my $set_content = sub {
77             my ( $self, $content ) = @_;
78             my $predicateName = 'property';
79             $content{ $self->get_id } = $content;
80             my %resource = ( 'xsi:type' => 'nex:ResourceMeta' );
81             my %literal = ( 'xsi:type' => 'nex:LiteralMeta' );
82             if ( not ref $content ) {
83             if ( $content && ( $content =~ m|^http://| or $content =~ m|^urn:| ) ) {
84             $content =~ s/&([^a])/&amp;$1/g;
85             $self->set_attributes( 'href' => $content, %resource );
86             if ( my $prop = $self->get_attributes('property') ) {
87             $self->set_attributes( 'rel' => $prop );
88             $self->unset_attribute('property');
89             $predicateName = 'rel';
90             }
91             }
92             else {
93             $self->set_attributes( 'content' => $content, %literal );
94             if ( looks_like_number $content ) {
95             my $dt = $content == int($content)
96             && $content !~ /\./ ? 'integer' : 'float';
97             $self->set_attributes( 'datatype' => 'xsd:' . $dt );
98             }
99             elsif ( $content && ( $content eq 'true' or $content eq 'false' ) ) {
100             $self->set_attributes( 'datatype' => 'xsd:boolean' );
101             }
102             else {
103             $self->set_attributes( 'datatype' => 'xsd:string' );
104             }
105             }
106             }
107             else {
108             if ( looks_like_instance $content,
109             'Bio::Phylo' and $content->_type == $TYPE_CONSTANT )
110             {
111             $self->insert($content)->set_attributes(%resource);
112             if ( my $prop = $self->get_attributes('property') ) {
113             $self->set_attributes( 'rel' => $prop );
114             $self->unset_attribute('property');
115             $predicateName = 'rel';
116             }
117             }
118             elsif ( looks_like_instance $content, 'DateTime' ) {
119             $self->set_attributes(
120             'content' => $content->iso8601(),
121             'datatype' => 'xsd:date',
122             %literal
123             );
124             }
125             else {
126             $self->set_attributes( 'datatype' => 'rdf:XMLLiteral', %resource );
127             $self->insert( $fac->create_xmlliteral($content) );
128             $self->unset_attribute('content');
129             }
130             }
131             $property{ shift->get_id } = $predicateName;
132             return $self;
133             };
134             my $set_property = sub {
135             my ( $self, $property ) = @_;
136             if ( $property =~ m/^([a-zA-Z_]+):([a-zA-Z0-9_\-\.]+)$/ ) {
137             my ( $prefix, $prop ) = ( $1, $2 );
138             if ( $self->get_namespaces($prefix) ) {
139             $self->set_attributes( 'property' => $property );
140             }
141             else {
142             throw 'BadArgs' => "Prefix $prefix not bound to a namespace";
143             }
144             }
145             else {
146             throw 'BadString' => "$property is not a valid CURIE";
147             }
148             };
149              
150             =back
151              
152             =head2 MUTATORS
153              
154             =over
155              
156             =item set_triple()
157              
158             Populates the triple, assuming that the invocant is attached to a subject.
159              
160             Type : Mutator
161             Title : set_triple
162             Usage : $meta->set_triple( $predicate, $object );
163             Function: Populates the triple.
164             Returns : Modified object.
165             Args : $predicate - a CURIE whose namespace prefix must
166             have been bound previously using
167             $meta->set_namespaces( $prefix, $uri );
168             $object - any of the valid object types: a number,
169             a string, a url, a nested annotation
170             or anything that can be adapted by
171             Bio::Phylo::NeXML::Meta::XMLLiteral
172              
173             =cut
174              
175             sub set_triple : Clonable {
176 1494     1494 1 2540 my ( $self, $property, $content ) = @_;
177 1494 100 66     4646 if ( ref($property) && ref($property) eq 'HASH' ) {
178 1423         1726 ( $property, $content ) = each %{$property};
  1423         3948  
179             }
180 1494         3370 $set_property->( $self, $property );
181 1494         3194 $set_content->( $self, $content );
182 1494         2803 return $self;
183 10     10   69 }
  10         18  
  10         65  
184              
185             =back
186              
187             =head2 ACCESSORS
188              
189             =over
190              
191             =item get_triple ()
192              
193             Returns predicate and object for the triple
194              
195             Type : Accessor
196             Title : get_triple
197             Usage : my ( $predicate, $object ) = $anno->get_triple;
198             Function: Returns triple
199             Returns : Predicate and object of a triple
200             Args : NONE
201              
202             =cut
203              
204             sub get_triple {
205 0     0 1 0 my $self = shift;
206 0         0 return $self->get_predicate, $self->get_object;
207             }
208              
209             =item get_object()
210              
211             Returns triple object
212              
213             Type : Accessor
214             Title : get_object
215             Usage : my $val = $anno->get_object;
216             Function: Returns triple object
217             Returns : A triple object
218             Args : NONE
219              
220             =cut
221              
222 1714     1714 1 3676 sub get_object { $content{ shift->get_id } }
223              
224             =item get_predicate()
225              
226             Returns triple predicate
227              
228             Type : Accessor
229             Title : get_predicate
230             Usage : my $val = $anno->get_predicate;
231             Function: Returns triple predicate
232             Returns : A triple predicate
233             Args : NONE
234              
235             =cut
236              
237             sub get_predicate {
238 15014     15014 1 18676 my $self = shift;
239 15014         26551 my $predicateName = $property{ $self->get_id };
240 15014         29549 return $self->get_attributes->{$predicateName};
241             }
242              
243             =item get_predicate_namespace()
244              
245             Returns predicate namespace
246              
247             Type : Accessor
248             Title : get_predicate_namespace
249             Usage : my $val = $anno->get_predicate_namespace;
250             Function: Returns predicate namespace
251             Returns : A namespace
252             Args : NONE
253              
254             =cut
255            
256             sub get_predicate_namespace {
257 1282     1282 1 1629 my $self = shift;
258 1282         1847 my $predicate = $self->get_predicate;
259 1282         3453 my ( $pre, $pred ) = split /:/, $predicate;
260 1282         2916 return $self->get_namespaces($pre);
261             }
262              
263             =item get_predicate_local()
264              
265             Returns predicate without prefix
266              
267             Type : Accessor
268             Title : get_predicate_local
269             Usage : my $val = $anno->get_predicate_local;
270             Function: Returns predicate without prefix
271             Returns : A predicate
272             Args : NONE
273              
274             =cut
275            
276             sub get_predicate_local {
277 637     637 1 842 my $self = shift;
278 637         967 my $predicate = $self->get_predicate;
279 637         1738 my ( $pre, $pred ) = split /:/, $predicate;
280 637         1520 return $pred;
281             }
282              
283             =item get_object_type()
284              
285             Returns data type of object
286              
287             Type : Accessor
288             Title : get_object_type
289             Usage : my $val = $anno->get_object_type;
290             Function: Returns data type of object
291             Returns : A local predicate, e.g. 'boolean'
292             Args : NONE
293              
294             =cut
295            
296             sub get_object_type {
297 0     0 1 0 my $self = shift;
298 0 0       0 if ( my $type = $self->get_attributes('datatype') ) {
299 0         0 my ( $pre, $datatype ) = split /:/, $type;
300 0         0 return $datatype;
301             }
302             }
303              
304             =back
305              
306             =head2 TESTS
307              
308             =over
309              
310             =item is_resource()
311              
312             Returns whether the object is a resource (e.g. an href or a nested XMLLiteral)
313              
314             Type : Accessor
315             Title : is_resource
316             Usage : my $val = $anno->is_resource;
317             Function: Returns whether object is a resource
318             Returns : Boolean
319             Args : NONE
320              
321             =cut
322            
323             sub is_resource {
324 0     0 1 0 my $self = shift;
325 0         0 return $self->get_attributes('xsi:type') =~ /ResourceMeta/;
326             }
327              
328             =item is_xml_literal()
329              
330             Returns whether the object is a nested XMLLiteral
331              
332             Type : Accessor
333             Title : is_xml_literal
334             Usage : my $val = $anno->is_xml_literal;
335             Function: Returns whether object is a nested XMLLiteral
336             Returns : Boolean
337             Args : NONE
338              
339             =cut
340            
341             sub is_xml_literal {
342 0     0 1 0 my $self = shift;
343 0         0 return $self->get_object_type eq 'XMLLiteral';
344             }
345            
346             =back
347              
348             =head2 SERIALIZERS
349              
350             =over
351              
352             =item to_dom()
353              
354             Type : Serializer
355             Title : to_dom
356             Usage : $obj->to_dom
357             Function: Generates a DOM subtree from the invocant and
358             its contained objects
359             Returns : a DOM element object (default: XML::Twig flavor)
360             Args : DOM factory object
361             Note : This is the generic function. It is redefined in the
362             classes below.
363             =cut
364              
365             sub to_dom {
366 0     0 1 0 my ( $self, $dom ) = @_;
367 0   0     0 $dom ||= Bio::Phylo::NeXML::DOM->get_dom;
368 0 0       0 if ( looks_like_object $dom, _DOMCREATOR_ ) {
369 0         0 my $elt = $self->get_dom_elt($dom);
370 0 0       0 if ( $self->can('get_entities') ) {
371 0         0 for my $ent ( @{ $self->get_entities } ) {
  0         0  
372 0 0       0 if ( looks_like_implementor $ent, 'to_dom' ) {
373 0         0 $elt->set_child( $ent->to_dom($dom) );
374             }
375             }
376             }
377 0         0 return $elt;
378             }
379             else {
380 0         0 throw 'BadArgs' => 'DOM factory object not provided';
381             }
382             }
383              
384             =back
385              
386             =cut
387              
388             # podinherit_insert_token
389              
390             =head1 SEE ALSO
391              
392             There is a mailing list at L<https://groups.google.com/forum/#!forum/bio-phylo>
393             for any user or developer questions and discussions.
394              
395             =over
396              
397             =item L<Bio::Phylo::Dictionary>
398              
399             Annotation objects are combined into a dictionary.
400              
401             =item L<Bio::Phylo::NeXML::Writable>
402              
403             This object inherits from L<Bio::Phylo::NeXML::Writable>, so methods
404             defined there are also applicable here.
405              
406             =item L<Bio::Phylo::Manual>
407              
408             Also see the manual: L<Bio::Phylo::Manual> and L<http://rutgervos.blogspot.com>.
409              
410             =back
411              
412             =head1 CITATION
413              
414             If you use Bio::Phylo in published research, please cite it:
415              
416             B<Rutger A Vos>, B<Jason Caravas>, B<Klaas Hartmann>, B<Mark A Jensen>
417             and B<Chase Miller>, 2011. Bio::Phylo - phyloinformatic analysis using Perl.
418             I<BMC Bioinformatics> B<12>:63.
419             L<http://dx.doi.org/10.1186/1471-2105-12-63>
420              
421             =cut
422              
423 1423     1423   3162 sub _tag { 'meta' }
424 2866     2866   4713 sub _type { $TYPE_CONSTANT }
425 0     0     sub _container { $CONTAINER_CONSTANT }
426              
427             sub _cleanup : Destructor {
428 1423     1423   2318 my $id = shift->get_id;
429 1423         4864 delete $_->{$id} for @fields;
430 10     10   6202 }
  10         21  
  10         51  
431             }
432             1;