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.017
11              
12             =cut
13              
14             package RDF::Trine::Statement;
15              
16 68     68   485 use strict;
  68         147  
  68         1613  
17 68     68   313 use warnings;
  68         140  
  68         2113  
18 68     68   335 no warnings 'redefine';
  68         142  
  68         1691  
19              
20 68     68   332 use Data::Dumper;
  68         153  
  68         2703  
21 68     68   3166 use Log::Log4perl;
  68         150069  
  68         547  
22 68     68   4001 use Carp qw(carp croak confess);
  68         158  
  68         3371  
23 68     68   386 use Scalar::Util qw(blessed reftype);
  68         153  
  68         3015  
24 68     68   23292 use RDF::Trine::Iterator qw(smap sgrep swatch);
  68         207  
  68         4296  
25 68     68   550 use URI::Escape qw(uri_unescape);
  68         159  
  68         3180  
26 68     68   424 use Encode;
  68         156  
  68         5491  
27              
28             ######################################################################
29              
30             our ($VERSION);
31             BEGIN {
32 68     68   77488 $VERSION = '1.017';
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 6834     6834 1 13483 my $class = shift;
51 6834         16844 my @nodes = @_;
52 6834 100       19126 unless (scalar(@nodes) == 3) {
53 1         19 throw RDF::Trine::Error::MethodInvocationError -text => "Triple constructor must have three node arguments";
54             }
55 6833         16897 my @names = qw(subject predicate object);
56 6833         16707 foreach my $i (0 .. 2) {
57 20499 100       47290 unless (defined($nodes[ $i ])) {
58 50         206 $nodes[ $i ] = RDF::Trine::Node::Variable->new($names[ $i ]);
59             }
60             }
61            
62 6833         26066 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         6 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 15573 my $self = shift;
85 9088         25865 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 43     43 1 133 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 16383     16383 1 27901 my $self = shift;
106 16383 100       38060 if (@_) {
107 1         4 $self->[0] = shift;
108             }
109 16383         56693 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 10870     10870 1 18743 my $self = shift;
120 10870 100       26275 if (@_) {
121 1         3 $self->[1] = shift;
122             }
123 10870         30523 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 17664     17664 1 32516 my $self = shift;
134 17664 100       41704 if (@_) {
135 1         2 $self->[2] = shift;
136             }
137 17664         61339 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 6598     6598 1 13376 my $self = shift;
148 6598         18762 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 210 my $self = shift;
159 135         269 foreach my $node ($self->nodes) {
160 255 100       976 return 1 if $node->isa('RDF::Trine::Node::Blank');
161             }
162 60         157 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 2274     2274 1 4206 my $self = shift;
173 2274         3437 my $context = shift;
174 2274         5382 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 10 my $class = shift;
190 1         4 my $context = $_[1];
191 1         4 $_ = $_[0];
192 1 50       10 if (m/^[(]triple/) {
193 1         8 s/^[(]triple\s+//;
194 1         2 my @nodes;
195 1         7 push(@nodes, RDF::Trine::Node->from_sse( $_, $context ));
196 1         6 push(@nodes, RDF::Trine::Node->from_sse( $_, $context ));
197 1         8 push(@nodes, RDF::Trine::Node->from_sse( $_, $context ));
198 1 50       6 if (m/^\s*[)]/) {
199 1         6 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 226 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 1274 my $self = shift;
227 693         2034 return RDF::Trine::_uniq(map { $_->name } grep { $_->isa('RDF::Trine::Node::Variable') } $self->nodes);
  1855         4460  
  2539         7580  
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 13 my $self = shift;
238 2         9 return $self->referenced_variables;
239             }
240              
241             =item C<< clone >>
242              
243             =cut
244              
245             sub clone {
246 3     3 1 16 my $self = shift;
247 3         9 my $class = ref($self);
248 3         11 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 19 my $self = shift;
259 6         14 my $class = ref($self);
260 6         14 my $bound = shift;
261 6         20 my @nodes = $self->nodes;
262 6         17 foreach my $i (0 .. 2) {
263 18         32 my $n = $nodes[ $i ];
264 18 100       81 if ($n->isa('RDF::Trine::Node::Variable')) {
265 9         30 my $name = $n->name;
266 9 100       127 if (my $value = $bound->{ $name }) {
267 8         26 $nodes[ $i ] = $value;
268             }
269             }
270             }
271 6         24 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 14 my $self = shift;
283 8         13 my $st = shift;
284 8         22 my @nodes = $self->nodes;
285 8         21 my @match = $st->nodes;
286            
287 8         14 my %bind;
288 8         37 my $l = Log::Log4perl->get_logger("rdf.trine.statement");
289 8         1088 foreach my $i (0..2) {
290 23         43 my $m = $match[ $i ];
291 23 100       112 if ($nodes[$i]->isa('RDF::Trine::Node::Variable')) {
292 5         23 my $name = $nodes[$i]->name;
293 5 50       15 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         13 $bind{ $name } = $m;
301             }
302             } else {
303 18 100       59 return 0 unless ($nodes[$i]->equal( $m ));
304             }
305             }
306 7         35 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 8 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       13 unless $self->predicate->is_resource;
376            
377             return
378 4 100 33     11 unless $self->object->is_resource
      66        
379             || $self->object->is_blank
380             || $self->object->is_literal;
381            
382 3         13 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