File Coverage

blib/lib/RDF/LDF.pm
Criterion Covered Total %
statement 277 286 96.8
branch 85 122 69.6
condition 28 52 53.8
subroutine 44 44 100.0
pod 2 6 33.3
total 436 510 85.4


line stmt bran cond sub pod time code
1             package RDF::LDF;
2              
3 5     5   3567575 use strict;
  5         32  
  5         141  
4 5     5   26 use warnings;
  5         18  
  5         141  
5 5     5   24 use feature qw(state);
  5         10  
  5         661  
6 5     5   1222 use utf8;
  5         40  
  5         76  
7              
8 5     5   1283 use Moo;
  5         21052  
  5         38  
9 5     5   13788 use Data::Compare;
  5         60954  
  5         43  
10 5     5   20978 use RDF::NS;
  5         123801  
  5         181  
11 5     5   898 use RDF::Trine;
  5         2694502  
  5         296  
12 5     5   3230 use RDF::Query;
  5         3759987  
  5         280  
13 5     5   53 use URI::Escape;
  5         11  
  5         274  
14 5     5   32 use LWP::UserAgent;
  5         12  
  5         117  
15 5     5   26 use HTTP::Request::Common;
  5         7  
  5         369  
16 5     5   3198 use Log::Any ();
  5         43295  
  5         122  
17 5     5   2229 use Cache::LRU;
  5         3198  
  5         170  
18 5     5   33 use Clone qw(clone);
  5         15  
  5         232  
19 5     5   31 use JSON;
  5         9  
  5         52  
20 5     5   2897 use URI::Template;
  5         26454  
  5         226  
21 5     5   2245 use RDF::LDF::Error;
  5         13  
  5         18387  
22              
23             our $VERSION = '0.251';
24              
25             has url => (
26             is => 'ro' ,
27             required => 1
28             );
29              
30             has sn => (
31             is => 'ro' ,
32             lazy => 1,
33             builder => sub {
34 3     3   68 RDF::NS->new->REVERSE;
35             }
36             );
37              
38             has lru => (
39             is => 'ro' ,
40             lazy => 1,
41             builder => sub {
42 3     3   54 Cache::LRU->new( size => 100 );
43             }
44             );
45              
46             has log => (
47             is => 'ro',
48             lazy => 1,
49             builder => sub {
50 3     3   60 Log::Any->get_logger(category => ref(shift));
51             }
52             );
53              
54             # Public method
55             sub is_fragment_server {
56 3     3 0 22175 my $self = shift;
57 3 100       38 my $federated = ref($self->url) ? $self->url : [ $self->url ];
58 3         8 for my $part (@$federated) {
59 5 50       24 return 0 unless $self->get_query_pattern($part);
60             }
61 3         34 return 1;
62             }
63              
64             # Public method
65             # Optimized method to find all bindings matching a pattern
66             # See:
67             # Verborgh, Ruben, et al. Querying Datasets on the Web with High Availability. ISWC2014
68             # http://linkeddatafragments.org/publications/iswc2014.pdf
69             sub get_pattern {
70 7     7 1 11540 my ($self,$bgp,$context,%args) = @_;
71              
72 7 100       32 unless (defined $bgp) {
73 1         10 RDF::LDF::Error->throw(text => "can't execute get_pattern for an empty pattern");
74             }
75              
76 6 100 66     98 my (@triples) = ($bgp->isa('RDF::Trine::Statement') or $bgp->isa('RDF::Query::Algebra::Filter'))
77             ? $bgp
78             : $bgp->triples;
79              
80 6 50       42 unless (@triples) {
81 0         0 RDF::LDF::Error->throw(text => "can't execute get_pattern for an empty pattern");
82             }
83              
84 6         33 my @vars = $bgp->referenced_variables;
85              
86 6         546 my @bgps = map { $self->_parse_triple_pattern($_)} @triples;
  8         35  
87              
88             my $sub = sub {
89 12     12   7332 state $it = $self->_find_variable_bindings(\@bgps);
90 12         33 my $b = $it->();
91              
92 12 100       48 return undef unless $b;
93              
94 10         117 my $binding = RDF::Trine::VariableBindings->new({});
95              
96 10         133 for my $key (keys %$b) {
97 26         203 my $val = $b->{$key};
98 26         94 $key =~ s{^\?}{};
99 26         74 $binding->set($key => $val);
100             }
101              
102 10         88 $binding;
103 6         40 };
104              
105 6         81 RDF::Trine::Iterator::Bindings->new($sub,\@vars);
106             }
107              
108             sub _find_variable_bindings {
109 14     14   30 my $self = shift;
110 14         51 my $bgps = shift;
111 14   100     64 my $bindings = shift // {};
112              
113             my $iterator = sub {
114 26     26   38 state $it;
115 26         75 state $results = sub {};
116              
117 26         39 my $ret;
118              
119             # Loop over all variabe bindings with multiple matches
120 26         58 while (!defined($ret = $results->())) {
121 28 100       73 unless (defined $it) {
122             # Find the an binding iterator for the best pattern from $bgpgs
123 14         47 ($it,$bgps) = $self->_find_variable_bindings_($bgps);
124              
125 14 50       52 return undef unless $it;
126             }
127              
128             # Update all the other bgps with the current binding..
129 28         60 my $this_binding = $it->();
130              
131 28 100       96 return undef unless $this_binding;
132              
133 18         79 $bindings = { %$bindings , %$this_binding };
134              
135 18 100       138 return $bindings unless @$bgps;
136              
137             # Apply all the bindings to the rest of the bgps;
138 8         44 my $bgps_prime = $self->_apply_binding($this_binding,$bgps);
139              
140 8         31 $results = $self->_find_variable_bindings($bgps_prime,$bindings);
141             }
142              
143 6         16 $ret;
144 14         93 };
145              
146 14         50 $iterator;
147             }
148              
149             # Given an array ref of patterns return the variable bindings for the
150             # pattern with the least number of triples.
151             #
152             # my ($iterator, $rest) = $self->_find_variable_bindings([ {pattern} , {pattern} , ... ]);
153             #
154             # where:
155             #
156             # $iterator - Iterator for variable bindings for the winnnig pattern, or undef when no
157             # patterns are provided or we get zero results
158             #
159             # $rest - An array ref of patterns not containing the best pattern
160             sub _find_variable_bindings_ {
161 14     14   39 my ($self,$bgps) = @_;
162              
163 14 50 33     64 return (undef, undef) unless _is_array_ref($bgps) && @$bgps > 0;
164              
165 14         59 my ($pattern,$rest) = $self->_find_best_pattern($bgps);
166              
167 14 50       42 return (undef,undef) unless defined $pattern;
168              
169 14         55 my $it = $self->get_statements($pattern);
170              
171             # Build a mapping of variable bindings to Triple nodes. E.g.
172             # {
173             # '?s' => 'subject' ,
174             # '?p' => 'predicate' ,
175             # '?o' => 'object' ,
176             #}
177 14 100       51 my %pattern_var_map = map { $pattern->{$_} =~ /^\?/ ? ($pattern->{$_} , $_) : () } keys %$pattern;
  42         180  
178 14         39 my $num_of_bindings = keys %pattern_var_map;
179              
180             my $sub = sub {
181 28     28   63 my $triple = $it->();
182              
183 28 100       105 return undef unless defined $triple;
184              
185 18         73 my %var_map = %pattern_var_map;
186              
187 18         62 for (keys %var_map) {
188 30         111 my $method = $var_map{$_};
189 30         90 $var_map{$_} = $triple->$method;
190             }
191              
192 18         164 return {%var_map};
193 14         64 };
194              
195 14         50 return ($sub,$rest);
196             }
197              
198             sub _apply_binding {
199 8     8   30 my ($self,$binding,$bgps) = @_;
200              
201 8 50 33     23 return unless _is_array_ref($bgps) && @$bgps > 0;
202              
203 8         114 my $copy = clone $bgps;
204 8         18 my @new = ();
205              
206 8         22 for my $pattern (@$copy) {
207 8         25 for (qw(subject predicate object)) {
208 24         46 my $val = $pattern->{$_};
209 24 100 66     105 if (defined($val) && $binding->{$val}) {
210 8         304 my $str_val = $self->_node_as_string($binding->{$val});
211 8         83 $pattern->{$_} = $str_val
212             }
213             }
214 8         19 push @new, $pattern;
215             }
216              
217 8         38 return \@new;
218             }
219              
220             # Create a pattern which binds to the graph pattern
221             #
222             # Usage:
223             #
224             # my $triples = [
225             # { subject => ... , predicate => ... , object => ... } , #tp1
226             # { subject => ... , predicate => ... , object => ... } , #tp2
227             # ...
228             # { subject => ... , predicate => ... , object => ... } , #tpN
229             # ];
230             #
231             # my ($pattern, $rest) = $self->_find_best_pattern($triples);
232             #
233             # $pattern => Pattern in $triples which least amount of results
234             # $rest => All patterns in $triples except $pattern
235             #
236             sub _find_best_pattern {
237 14     14   39 my ($self,$triples) = @_;
238              
239 14 50       42 return undef unless @$triples > 0;
240              
241             # If we only have one tripple pattern, the use it to create the bind
242 14 100       42 if (@$triples == 1) {
243 12         46 return $triples->[0] , [];
244             }
245              
246 2         5 my $best_pattern = undef;
247 2         5 my $best_count = undef;
248              
249 2         7 for my $pattern (@$triples) {
250 4   50     13 my $count = $self->_total_triples($pattern) // 0;
251              
252 4 50 66     32 if ($count == 0) {
    100          
253 0         0 $best_pattern = undef;
254 0         0 $best_count = 0;
255 0         0 last;
256             }
257             elsif (!defined $best_count || $count < $best_count) {
258 2         3 $best_count = $count;
259 2         6 $best_pattern = $pattern;
260             }
261             }
262              
263 2 50       11 return (undef,$triples) unless defined $best_pattern;
264              
265 2 100       9 my @rest_triples = map { Data::Compare::Compare($_,$best_pattern) ? () : ($_) } @$triples;
  4         162  
266              
267 2         385 return ($best_pattern, \@rest_triples);
268             }
269              
270             # Find the total number of triples available for a pattern
271             #
272             # Usage:
273             #
274             # my $count = $self->_total_triples(
275             # { subject => ... , predicate => ... , object => ...}
276             # );
277             # Where
278             # $count is a number
279             sub _total_triples {
280 4     4   10 my ($self,$pattern) = @_;
281              
282             # Retrieve one...
283 4         23 my $iterator = $self->get_statements($pattern);
284              
285 4 50       11 return 0 unless $iterator;
286              
287 4         11 my ($model,$info) = $iterator->();
288              
289 4         65 $info->{hydra_totalItems};
290             }
291              
292             sub _node_as_string {
293 32     32   174 my $self = shift;
294 32         44 my $node = shift;
295 32 50 33     70 if (_is_blessed($node) && $node->isa('RDF::Trine::Node')) {
296 32 100       157 if ($node->isa('RDF::Trine::Node::Variable')) {
    50          
297 16         52 return $node->as_string; # ?foo
298             } elsif ($node->isa('RDF::Trine::Node::Literal')) {
299 0         0 return $node->as_string; # includes quotes and any language or datatype
300             } else {
301 16         50 return $node->value; # the raw IRI or blank node identifier value, without other syntax
302             }
303             }
304 0         0 return '';
305             }
306              
307             # For an BGP triple create a fragment pattern
308             sub _parse_triple_pattern {
309 8     8   20 my ($self,$triple) = @_;
310 8         25 my $subject = $self->_node_as_string($triple->subject);
311 8         102 my $predicate = $self->_node_as_string($triple->predicate);
312 8         81 my $object = $self->_node_as_string($triple->object);
313 8         100 my $hash = {
314             subject => $subject ,
315             predicate => $predicate,
316             object => $object
317             };
318 8         30 return $hash;
319             }
320              
321             # Dynamic find out which triple patterns need to be used to query the fragment server
322             # Returns a hash:
323             # {
324             # rdf_subject => <name_of_subject_variable> ,
325             # rdf_predicate => <name_of_predicate_variable> ,
326             # rdf_object => <name_of_object_variable>
327             # hydra_template => <endpoint_for_tripple_pattern>
328             # }
329             sub get_query_pattern {
330 42     42 0 100 my ($self,$url) = @_;
331              
332 42         111 my $fragment = $self->get_model_and_info($url);
333              
334 42 50       122 return undef unless defined $fragment;
335              
336 42         85 my $info = $fragment->{info};
337              
338 42         419 my $pattern;
339              
340 42 50       87 return undef unless _is_hash_ref($info);
341              
342 42 50       139 return undef unless $info->{hydra_template};
343              
344 42         322 for (keys %$info) {
345 716 100 100     1328 next unless _is_hash_ref($info->{$_}) && $info->{$_}->{hydra_property};
346 126         2418 my $property = join "_" , $self->sn->qname($info->{$_}->{hydra_property});
347 126         32610 my $variable = $info->{$_}->{hydra_variable};
348              
349 126         489 $pattern->{$property} = $variable;
350             }
351              
352 42 50       167 return undef unless $pattern->{rdf_subject};
353 42 50       109 return undef unless $pattern->{rdf_predicate};
354 42 50       131 return undef unless $pattern->{rdf_object};
355              
356 42         94 $pattern->{hydra_template} = $info->{hydra_template};
357              
358 42         108 $pattern;
359             }
360              
361             #----------------------------------------------------------------------------------
362              
363             # Public method
364             sub get_statements {
365 19     19 1 43 my ($self,@triple) = @_;
366 19         43 my ($subject,$predicate,$object);
367              
368 19 50       79 if (@triple == 3) {
    100          
369 0         0 ($subject,$predicate,$object) = @triple;
370             }
371             elsif (_is_hash_ref($triple[0])) {
372 18         40 $subject = $triple[0]->{subject};
373 18         41 $predicate = $triple[0]->{predicate};
374 18         31 $object = $triple[0]->{object};
375             }
376              
377 19 0 33     52 $subject = $subject->value if (_is_blessed($subject) && $subject->isa('RDF::Trine::Node') and not $subject->is_variable);
      33        
378 19 0 33     44 $predicate = $predicate->value if (_is_blessed($predicate) && $predicate->isa('RDF::Trine::Node') and not $predicate->is_variable);
      33        
379 19 0 33     43 if (_is_blessed($object) && $object->isa('RDF::Trine::Node') and not $object->is_variable) {
      33        
380 0 0       0 $object = ($object->isa('RDF::Trine::Node::Literal')) ? $object->as_string : $object->value;
381             }
382              
383             # Do a federated search over all the URLs provided
384 19 100       124 my $parts = ref($self->url) ? $self->url : [ $self->url ];
385 19         35 my @federated;
386              
387 19         45 for my $part (@$parts) {
388 37         7700 my $pattern = $self->get_query_pattern($part);
389 37 50       100 return undef unless defined $pattern;
390              
391 37         57 my %params;
392 37 100       87 $params{ $pattern->{rdf_subject} } = $subject if _is_string($subject);
393 37 100       84 $params{ $pattern->{rdf_predicate} } = $predicate if _is_string($predicate);
394 37 100       103 $params{ $pattern->{rdf_object} } = $object if _is_string($object);
395              
396 37         245 my $template = URI::Template->new($pattern->{hydra_template});
397 37         4452 push @federated , $template->process(%params)->as_string;
398             }
399              
400             my $sub = sub {
401 34     34   966 state $model;
402 34         46 state $info;
403 34         42 state $iterator;
404 34         66 state $url = shift(@federated);
405              
406 34         55 my $triple;
407              
408 34   100     47 do {
409 44 100       128 unless (defined $model) {
410             # When no more result pages are available switch
411             # to the next federated url...
412 37 100 100     149 return unless defined($url) || defined($url = pop(@federated));
413              
414 31         110 my $fragment = $self->get_model_and_info($url);
415              
416 31 50       122 return unless defined $fragment->{model};
417              
418 31         75 $model = $fragment->{model};
419 31         64 $info = $fragment->{info};
420              
421 31         77 $url = $info->{hydra_next};
422 31         127 $iterator = $model->get_statements;
423             }
424              
425 38         17254 $triple = $iterator->next;
426              
427 38 100       6876 unless ($iterator->peek) {
428 23         661 $model = undef;
429             }
430             }
431             while (!defined $triple && defined($url = pop(@federated)));
432              
433 28 100       1711 wantarray ? ($triple,$info) : $triple;
434 19         7282 };
435              
436 19         64 $sub;
437             }
438              
439             # Fetch a fragment page and extract the metadata
440             sub get_model_and_info {
441 73     73 0 139 my ($self,$url) = @_;
442              
443 73 100       1654 if (my $cache = $self->lru->get($url)) {
444 49         1306 return $cache;
445             }
446              
447 24         502 my $model = $self->get_fragment($url);
448 24         70 my $info = {};
449              
450 24 50       102 if (defined $model) {
451 24         149 $info = $self->_model_metadata($model,$url, clean => 1);
452             }
453              
454 24         345 my $fragment = { model => $model , info => $info };
455              
456 24         897 $self->lru->set($url => $fragment);
457              
458 24         1209 $fragment;
459             }
460              
461             # Fetch a result page from fragment server
462             sub get_fragment {
463 24     24 0 75 my ($self,$url) = @_;
464              
465 24 50       76 return undef unless $url;
466              
467 24         487 $self->log->info("fetching: $url");
468              
469 24         8770 my $model = RDF::Trine::Model->temporary_model;
470              
471             # JSON support in RDF::Trine isn't JSON-LD
472             # Set the accept header quality parameter at a minimum for this format
473 24         2058 my $ua = clone(RDF::Trine->default_useragent);
474 24         7564 $ua->agent("RDF:::LDF/$RDF::LDF::VERSION " . $ua->_agent);
475 24         2763 $ua->default_header('Accept','text/turtle;q=1.0,application/turtle;q=1.0,application/x-turtle;q=1.0,application/rdf+xml;q=0.9,text/x-nquads;q=0.9,application/json;q=0.1,application/x-rdf+json;q=0.1');
476              
477 24         1099 eval {
478             # Need to explicitly set the useragent to keep the accept headers
479 24         308 RDF::Trine::Parser->parse_url_into_model($url, $model, useragent => $ua);
480             };
481              
482 24 50       3814026 if ($@) {
483 0         0 $self->log->error("failed to parse input");
484             }
485              
486 24         120 return $model;
487             }
488              
489             # Create a hash with fragment metadata from a RDF::Trine::Model
490             # parameters:
491             # $model - RDF::Trine::Model
492             # $this_uri - result page URL
493             # %opts
494             # clean => 1 - remove the metadata from the model
495             sub _model_metadata {
496 24     24   147 my ($self,$model,$this_uri,%opts) = @_;
497              
498 24         65 my $info = {};
499              
500 24         140 $self->_build_metadata($model, {
501             subject => RDF::Trine::Node::Resource->new($this_uri)
502             } , $info);
503              
504 24 50       149 if ($opts{clean}) {
505 24         398 $model->remove_statements(
506             RDF::Trine::Node::Resource->new($this_uri),
507             undef,
508             undef
509             );
510 24         840232 $model->remove_statements(
511             undef,
512             undef,
513             RDF::Trine::Node::Resource->new($this_uri)
514             );
515             }
516              
517 24         22130 for my $predicate (
518             'http://www.w3.org/ns/hydra/core#variable' ,
519             'http://www.w3.org/ns/hydra/core#property' ,
520             'http://www.w3.org/ns/hydra/core#mapping' ,
521             'http://www.w3.org/ns/hydra/core#template' ,
522             'http://www.w3.org/ns/hydra/core#member' ,
523             'http://www.w3.org/ns/hydra/core#variableRepresentation' ,
524             ) {
525 144         887098 $self->_build_metadata($model, {
526             predicate => RDF::Trine::Node::Resource->new($predicate)
527             }, $info);
528              
529 144 50       594 if ($opts{clean}) {
530 144         1795 $model->remove_statements(
531             undef,
532             RDF::Trine::Node::Resource->new($predicate) ,
533             undef);
534             }
535             }
536              
537 24 50       4129 my $source = $info->{dct_source}->[0] if _is_array_ref($info->{dct_source});
538              
539 24 50       110 if ($source) {
540 24         112 $self->_build_metadata($model, {
541             subject => RDF::Trine::Node::Resource->new($source)
542             }, $info);
543              
544 24 50       109 if ($opts{clean}) {
545 24         344 $model->remove_statements(
546             RDF::Trine::Node::Resource->new($source),
547             undef,
548             undef
549             );
550 24         372178 $model->remove_statements(
551             undef,
552             undef,
553             RDF::Trine::Node::Resource->new($source)
554             );
555             }
556             }
557              
558 24         4412 $info;
559             }
560              
561             # Helper method for _parse_model
562             sub _build_metadata {
563 192     192   4357 my ($self, $model, $triple, $info) = @_;
564              
565             my $iterator = $model->get_statements(
566             $triple->{subject},
567             $triple->{predicate},
568             $triple->{object}
569 192         1180 );
570              
571 192         221830 while (my $triple = $iterator->next) {
572 621         71555 my $subject = $triple->subject->as_string;
573 621         8206 my $predicate = $triple->predicate->uri_value;
574 621         5577 my $object = $triple->object->value;
575              
576 621         21304 my $qname = join "_" , $self->sn->qname($predicate);
577              
578 621 100       268410 if ($qname =~ /^(hydra_variable|hydra_property)$/) {
    100          
    100          
579 144         449 my $id= $triple->subject->value;
580              
581 144         2429 $info->{"_$id"}->{$qname} = $object;
582             }
583             elsif ($qname eq 'hydra_mapping') {
584 72         244 my $id= $triple->subject->value;
585              
586 72         822 push @{$info->{"_$id"}->{$qname}} , $object;
  72         488  
587             }
588             elsif ($qname =~ /^(void|hydra)_/) {
589 237         1426 $info->{$qname} = $object;
590             }
591             else {
592 168         297 push @{$info->{$qname}} , $object;
  168         1008  
593             }
594             }
595              
596 192         6479 $info;
597             }
598              
599             sub _is_array_ref {
600 46     46   328 return ref($_[0]) eq 'ARRAY';
601             }
602              
603             sub _is_hash_ref {
604 777     777   2326 return ref($_[0]) eq 'HASH';
605             }
606              
607             sub _is_blessed {
608 89     89   422 return ref($_[0]) =~ /\S/;
609             }
610              
611             sub _is_string {
612 111   33 111   866 return defined($_[0]) && !ref($_[0]) && ref(\$_[0]) ne 'GLOB' && length($_[0]) > 0;
613             }
614              
615             1;
616              
617             __END__
618              
619             =head1 NAME
620              
621             RDF::LDF - Linked Data Fragments client
622              
623             =begin markdown
624              
625             # STATUS
626             [![Build Status](https://travis-ci.org/phochste/RDF-LDF.svg)](https://travis-ci.org/phochste/RDF-LDF)
627             [![Coverage Status](https://coveralls.io/repos/phochste/RDF-LDF/badge.svg)](https://coveralls.io/r/phochste/RDF-LDF)
628             [![Kwalitee Score](http://cpants.cpanauthors.org/dist/RDF-LDF.png)](http://cpants.cpanauthors.org/dist/RDF-LDF)
629              
630             =end markdown
631              
632             =head1 SYNOPSIS
633              
634             use RDF::Trine::Store::LDF;
635             use RDF::Trine::Store;
636              
637             # To use a HTTP cache:
638             use LWP::UserAgent::CHICaching;
639             my $cache = CHI->new( driver => 'Memory', global => 1 );
640             my $ua = LWP::UserAgent::CHICaching->new(cache => $cache);
641             RDF::Trine->default_useragent($ua);
642              
643             my $store = RDF::Trine::Store->new_with_config({
644             storetype => 'LDF',
645             url => $url
646             });
647              
648             my $it = $store->get_statements();
649              
650             while (my $st = $it->next) {
651             # $st is a RDF::Trine::Statement
652             print "$st\n";
653             }
654              
655             # Or the low level modules themselves
656              
657             use RDF::LDF;
658              
659             my $client = RDF::LDF->new(url => 'http://fragments.dbpedia.org/2014/en');
660              
661             my $iterator = $client->get_statements($subject, $predicate, $object);
662              
663             while (my $statement = $iterator->()) {
664             # $model is a RDF::Trine::Statement
665             }
666              
667              
668             =head1 DESCRIPTION
669              
670             RDF::LDF implements a basic L<Linked Data Fragment|http://linkeddatafragments.org/> client.
671              
672             This a low level module to implement the Linked Data Fragment protocol. You probably want to
673             use L<RDF::Trine::Store::LDF>.
674              
675             =head1 CONFIGURATION
676              
677             =over
678              
679             =item url
680              
681             URL to retrieve RDF from.
682              
683             Experimental: more than one URL can be provided for federated search over many LDF endpoints.
684              
685             my $store = RDF::Trine::Store->new_with_config({
686             storetype => 'LDF',
687             url => [ $url1, $url2, $url3 ]
688             });
689              
690             # or
691              
692             my $client = RDF::LDF->new(url => [ $url1, $url2, $url3 ]);
693              
694             =back
695              
696             =head1 METHODS
697              
698             =over
699              
700             =item get_statements( $subject, $predicate, $object )
701              
702             Return an iterator for every RDF::Trine::Statement served by the LDF server.
703              
704             =item get_pattern( $bgp );
705              
706             Returns a stream object of all bindings matching the specified graph pattern.
707              
708             =back
709              
710             =head1 CONTRIBUTORS
711              
712             Patrick Hochstenbach, C<< patrick.hochstenbach at ugent.be >>
713              
714             Gregory Todd Williams, C<< greg@evilfunhouse.com >>
715              
716             Jacob Voss, C<< voss@gbv.de >>
717              
718             =head1 COPYRIGHT AND LICENSE
719              
720             This software is copyright (c) 2015 by Patrick Hochstenbach.
721              
722             This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
723              
724             =encoding utf8
725              
726             =cut