File Coverage

blib/lib/RDF/Trine/Statement.pm
Criterion Covered Total %
statement 118 148 79.7
branch 27 44 61.3
condition 4 9 44.4
subroutine 29 31 93.5
pod 19 19 100.0
total 197 251 78.4


line stmt bran cond sub pod time code
1             # RDF::Trine::Statement
2             # -----------------------------------------------------------------------------
3              
4             =head1 NAME
5              
6             RDF::Trine::Statement - Class for triples and triple patterns
7              
8             =head1 VERSION
9              
10             This document describes RDF::Trine::Statement version 1.018
11              
12             =cut
13              
14             package RDF::Trine::Statement;
15              
16 68     68   473 use strict;
  68         194  
  68         1589  
17 68     68   330 use warnings;
  68         143  
  68         2147  
18 68     68   343 no warnings 'redefine';
  68         136  
  68         1662  
19              
20 68     68   323 use Data::Dumper;
  68         146  
  68         2629  
21 68     68   2971 use Log::Log4perl;
  68         144898  
  68         541  
22 68     68   3971 use Carp qw(carp croak confess);
  68         159  
  68         3407  
23 68     68   380 use Scalar::Util qw(blessed reftype);
  68         157  
  68         2967  
24 68     68   23514 use RDF::Trine::Iterator qw(smap sgrep swatch);
  68         197  
  68         3757  
25 68     68   507 use URI::Escape qw(uri_unescape);
  68         154  
  68         2911  
26 68     68   374 use Encode;
  68         141  
  68         4989  
27              
28             ######################################################################
29              
30             our ($VERSION);
31             BEGIN {
32 68     68   74306 $VERSION = '1.018';
33             }
34              
35             ######################################################################
36              
37             =head1 METHODS
38              
39             =over 4
40              
41             =cut
42              
43             =item C<new ( $s, $p, $o )>
44              
45             Returns a new Triple structure.
46              
47             =cut
48              
49             sub new {
50 6831     6831 1 12335 my $class = shift;
51 6831         15549 my @nodes = @_;
52 6831 100       17884 unless (scalar(@nodes) == 3) {
53 1         22 throw RDF::Trine::Error::MethodInvocationError -text => "Triple constructor must have three node arguments";
54             }
55 6830         16768 my @names = qw(subject predicate object);
56 6830         15692 foreach my $i (0 .. 2) {
57 20490 100       45385 unless (defined($nodes[ $i ])) {
58 50         175 $nodes[ $i ] = RDF::Trine::Node::Variable->new($names[ $i ]);
59             }
60             }
61            
62 6830         23955 return bless( [ @nodes ], $class );
63             }
64              
65             =item C<< construct_args >>
66              
67             Returns a list of arguments that, passed to this class' constructor,
68             will produce a clone of this algebra pattern.
69              
70             =cut
71              
72             sub construct_args {
73 1     1 1 4 my $self = shift;
74 1         5 return ($self->nodes);
75             }
76              
77             =item C<< nodes >>
78              
79             Returns the subject, predicate and object of the triple pattern.
80              
81             =cut
82              
83             sub nodes {
84 9088     9088 1 14860 my $self = shift;
85 9088         23908 return @$self;
86             }
87              
88             =item C<< node_names >>
89              
90             Returns the method names for accessing the nodes of this statement.
91              
92             =cut
93              
94             sub node_names {
95 40     40 1 120 return qw(subject predicate object);
96             }
97              
98             =item C<< subject >>
99              
100             Returns the subject node of the triple pattern.
101              
102             =cut
103              
104             sub subject {
105 16377     16377 1 26516 my $self = shift;
106 16377 100       36707 if (@_) {
107 1         4 $self->[0] = shift;
108             }
109 16377         53638 return $self->[0];
110             }
111              
112             =item C<< predicate >>
113              
114             Returns the predicate node of the triple pattern.
115              
116             =cut
117              
118             sub predicate {
119 10864     10864 1 17726 my $self = shift;
120 10864 100       25083 if (@_) {
121 1         3 $self->[1] = shift;
122             }
123 10864         27810 return $self->[1];
124             }
125              
126             =item C<< object >>
127              
128             Returns the object node of the triple pattern.
129              
130             =cut
131              
132             sub object {
133 17658     17658 1 31523 my $self = shift;
134 17658 100       39426 if (@_) {
135 1         3 $self->[2] = shift;
136             }
137 17658         57011 return $self->[2];
138             }
139              
140             =item C<< as_string >>
141              
142             Returns the statement in a string form.
143              
144             =cut
145              
146             sub as_string {
147 6595     6595 1 12714 my $self = shift;
148 6595         16861 return $self->sse;
149             }
150              
151             =item C<< has_blanks >>
152              
153             Returns true if any of the nodes in this statement are blank nodes.
154              
155             =cut
156              
157             sub has_blanks {
158 135     135 1 209 my $self = shift;
159 135         261 foreach my $node ($self->nodes) {
160 255 100       1027 return 1 if $node->isa('RDF::Trine::Node::Blank');
161             }
162 60         160 return 0;
163             }
164              
165             =item C<< sse >>
166              
167             Returns the SSE string for this algebra expression.
168              
169             =cut
170              
171             sub sse {
172 2271     2271 1 3770 my $self = shift;
173 2271         3343 my $context = shift;
174 2271         4880 return sprintf(
175             '(triple %s %s %s)',
176             $self->subject->sse( $context ),
177             $self->predicate->sse( $context ),
178             $self->object->sse( $context ),
179             );
180             }
181              
182             =item C<< from_sse ( $string, $context ) >>
183              
184             Parses the supplied SSE-encoded string and returns a RDF::Trine::Statement object.
185              
186             =cut
187              
188             sub from_sse {
189 1     1 1 6 my $class = shift;
190 1         3 my $context = $_[1];
191 1         2 $_ = $_[0];
192 1 50       14 if (m/^[(]triple/) {
193 1         5 s/^[(]triple\s+//;
194 1         2 my @nodes;
195 1         5 push(@nodes, RDF::Trine::Node->from_sse( $_, $context ));
196 1         5 push(@nodes, RDF::Trine::Node->from_sse( $_, $context ));
197 1         6 push(@nodes, RDF::Trine::Node->from_sse( $_, $context ));
198 1 50       5 if (m/^\s*[)]/) {
199 1         4 s/^\s*[)]//;
200 1         5 return RDF::Trine::Statement->new( @nodes );
201             } else {
202 0         0 throw RDF::Trine::Error -text => "Cannot parse end-of-triple from SSE string: >>$_<<";
203             }
204             } else {
205 0         0 throw RDF::Trine::Error -text => "Cannot parse triple from SSE string: >>$_<<";
206             }
207             }
208              
209             =item C<< type >>
210              
211             Returns the type of this algebra expression.
212              
213             =cut
214              
215             sub type {
216 76     76 1 235 return 'TRIPLE';
217             }
218              
219             =item C<< referenced_variables >>
220              
221             Returns a list of the variable names used in this algebra expression.
222              
223             =cut
224              
225             sub referenced_variables {
226 693     693 1 1265 my $self = shift;
227 693         2063 return RDF::Trine::_uniq(map { $_->name } grep { $_->isa('RDF::Trine::Node::Variable') } $self->nodes);
  1855         4457  
  2539         7670  
228             }
229              
230             =item C<< definite_variables >>
231              
232             Returns a list of the variable names that will be bound after evaluating this algebra expression.
233              
234             =cut
235              
236             sub definite_variables {
237 2     2 1 9 my $self = shift;
238 2         7 return $self->referenced_variables;
239             }
240              
241             =item C<< clone >>
242              
243             =cut
244              
245             sub clone {
246 3     3 1 10 my $self = shift;
247 3         8 my $class = ref($self);
248 3         10 return $class->new( $self->nodes );
249             }
250              
251             =item C<< bind_variables ( \%bound ) >>
252              
253             Returns a new algebra pattern with variables named in %bound replaced by their corresponding bound values.
254              
255             =cut
256              
257             sub bind_variables {
258 6     6 1 17 my $self = shift;
259 6         13 my $class = ref($self);
260 6         10 my $bound = shift;
261 6         18 my @nodes = $self->nodes;
262 6         15 foreach my $i (0 .. 2) {
263 18         30 my $n = $nodes[ $i ];
264 18 100       81 if ($n->isa('RDF::Trine::Node::Variable')) {
265 9         29 my $name = $n->name;
266 9 100       93 if (my $value = $bound->{ $name }) {
267 8         22 $nodes[ $i ] = $value;
268             }
269             }
270             }
271 6         23 return $class->new( @nodes );
272             }
273              
274             =item C<< subsumes ( $statement ) >>
275              
276             Returns true if this statement will subsume the $statement when matched against
277             a triple store.
278              
279             =cut
280              
281             sub subsumes {
282 8     8 1 13 my $self = shift;
283 8         12 my $st = shift;
284 8         20 my @nodes = $self->nodes;
285 8         20 my @match = $st->nodes;
286            
287 8         12 my %bind;
288 8         30 my $l = Log::Log4perl->get_logger("rdf.trine.statement");
289 8         927 foreach my $i (0..2) {
290 23         39 my $m = $match[ $i ];
291 23 100       91 if ($nodes[$i]->isa('RDF::Trine::Node::Variable')) {
292 5         16 my $name = $nodes[$i]->name;
293 5 50       11 if (exists( $bind{ $name } )) {
294 0         0 $l->debug("variable $name has already been bound");
295 0 0       0 if (not $bind{ $name }->equal( $m )) {
296 0         0 $l->debug("-> and " . $bind{$name}->sse . " does not equal " . $m->sse);
297 0         0 return 0;
298             }
299             } else {
300 5         11 $bind{ $name } = $m;
301             }
302             } else {
303 18 100       57 return 0 unless ($nodes[$i]->equal( $m ));
304             }
305             }
306 7         34 return 1;
307             }
308              
309              
310             =item C<< from_redland ( $statement ) >>
311              
312             Given a RDF::Redland::Statement object, returns a perl-native
313             RDF::Trine::Statement object.
314              
315             =cut
316              
317             sub from_redland {
318 0     0 1 0 my $self = shift;
319 0         0 my $rstmt = shift;
320 0         0 my $rs = $rstmt->subject;
321 0         0 my $rp = $rstmt->predicate;
322 0         0 my $ro = $rstmt->object;
323            
324             my $cast = sub {
325 0     0   0 my $node = shift;
326 0         0 my $type = $node->type;
327 0 0       0 if ($type == $RDF::Redland::Node::Type_Resource) {
    0          
    0          
328 0         0 my $uri = $node->uri->as_string;
329 0 0       0 if ($uri =~ /%/) {
330             # Redland's parser doesn't properly unescape percent-encoded RDF URI References
331 0         0 $uri = decode_utf8(uri_unescape(encode_utf8($uri)));
332             }
333 0         0 return RDF::Trine::Node::Resource->new( $uri );
334             } elsif ($type == $RDF::Redland::Node::Type_Blank) {
335 0         0 return RDF::Trine::Node::Blank->new( $node->blank_identifier );
336             } elsif ($type == $RDF::Redland::Node::Type_Literal) {
337 0         0 my $lang = $node->literal_value_language;
338 0         0 my $dturi = $node->literal_datatype;
339 0 0       0 my $dt = ($dturi)
340             ? $dturi->as_string
341             : undef;
342 0         0 return RDF::Trine::Node::Literal->new( $node->literal_value, $lang, $dt );
343             } else {
344 0         0 croak 'Unknown node type in statement conversion';
345             }
346 0         0 };
347            
348 0         0 my @nodes;
349 0         0 foreach my $n ($rs, $rp, $ro) {
350 0         0 push(@nodes, $cast->( $n ));
351             }
352 0         0 my $st = $self->new( @nodes );
353 0         0 return $st;
354             }
355              
356             =item C<< rdf_compatible >>
357              
358             Returns true if and only if the statement can be expressed in RDF. That is,
359             the subject of the statement must be a resource or blank node; the predicate
360             must be a resource; and the object must be a resource, blank node or literal.
361              
362             RDF::Trine::Statement does allow statements to be created which cannot be
363             expressed in RDF - for instance, statements including variables.
364              
365             =cut
366              
367             sub rdf_compatible {
368 4     4 1 5 my $self = shift;
369              
370             return
371 4 50 33     11 unless $self->subject->is_resource
372             || $self->subject->is_blank;
373            
374             return
375 4 50       12 unless $self->predicate->is_resource;
376            
377             return
378 4 100 33     10 unless $self->object->is_resource
      66        
379             || $self->object->is_blank
380             || $self->object->is_literal;
381            
382 3         10 return $self;
383             }
384              
385             1;
386              
387             __END__
388              
389             =back
390              
391             =head1 BUGS
392              
393             Please report any bugs or feature requests to through the GitHub web interface
394             at L<https://github.com/kasei/perlrdf/issues>.
395              
396             =head1 AUTHOR
397              
398             Gregory Todd Williams C<< <gwilliams@cpan.org> >>
399              
400             =head1 COPYRIGHT
401              
402             Copyright (c) 2006-2012 Gregory Todd Williams. This
403             program is free software; you can redistribute it and/or modify it under
404             the same terms as Perl itself.
405              
406             =cut