File Coverage

blib/lib/Bio/Phylo/NeXML/Meta.pm
Criterion Covered Total %
statement 47 69 68.1
branch 2 10 20.0
condition 2 6 33.3
subroutine 16 22 72.7
pod 10 10 100.0
total 77 117 65.8


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