File Coverage

blib/lib/RDF/Lazy.pm
Criterion Covered Total %
statement 185 238 77.7
branch 91 134 67.9
condition 30 52 57.6
subroutine 37 44 84.0
pod 15 26 57.6
total 358 494 72.4


line stmt bran cond sub pod time code
1             package RDF::Lazy;
2 9     9   2905492 use strict;
  9         22  
  9         231  
3 9     9   50 use warnings;
  9         15  
  9         258  
4 9     9   116 use v5.10.1;
  9         36  
5              
6             our $VERSION = '0.09';
7              
8 9     9   5374 use RDF::Trine::Model;
  9         14929484  
  9         320  
9 9     9   7087 use RDF::NS qw(20120827);
  9         101002  
  9         286  
10 9     9   12149 use CGI qw(escapeHTML);
  9         307843  
  9         78  
11              
12 9     9   1235 use RDF::Trine::Serializer::RDFXML;
  9         18  
  9         322  
13 9     9   51 use RDF::Trine::Serializer::Turtle;
  9         20  
  9         218  
14 9     9   48 use RDF::Trine::Serializer::RDFJSON;
  9         42  
  9         229  
15 9     9   114 use RDF::Trine::Parser;
  9         19  
  9         200  
16              
17 9     9   6278 use RDF::Lazy::Node;
  9         26  
  9         262  
18 9     9   49 use Scalar::Util qw(blessed refaddr);
  9         16  
  9         518  
19 9     9   47 use Carp qw(carp croak);
  9         16  
  9         31621  
20              
21             our $AUTOLOAD;
22              
23             sub str {
24 3     3 0 973 shift->size . " triples";
25             }
26              
27             sub new {
28 14     14 1 171564 my $class = shift;
29 14 100       97 my ($rdf, %args) = (@_ % 2) ? @_ : (undef,@_);
30              
31 14 100       72 if (defined $args{rdf}) {
32 3 50       15 croak 'Either use first argument or ref => $rdf' if $rdf;
33 3         11 $rdf = $args{rdf};
34             }
35              
36 14   66     116 my $namespaces = $args{namespaces} || RDF::NS->new('any');
37 14 100 100     204098 if (blessed($namespaces) and $namespaces->isa('RDF::NS')) {
    50          
38             # use reference
39             } elsif (ref($namespaces)) {
40 6         39 $namespaces = bless { %$namespaces }, 'RDF::NS';
41             } else {
42 0         0 $namespaces = RDF::NS->new($namespaces);
43             }
44              
45 14         89 my $self = bless {
46             namespaces => $namespaces,
47             }, $class;
48              
49 14 100       71 $self->cache( delete $args{cache} ) if $args{cache};
50              
51 14 100       65 if (blessed $rdf) {
52             # add model by reference
53 4 50 0     46 if ($rdf->isa('RDF::Trine::Model')) {
    0          
    0          
54 4         20 $self->{model} = $rdf; # model added by reference
55             } elsif ($rdf->isa('RDF::Trine::Store')) {
56 0         0 $self->{model} = RDF::Trine::Model->new($rdf);
57             } elsif($rdf->isa('URI') or $rdf->isa('RDF::Trine::Node::Resource')) {
58 0         0 $rdf = $rdf->as_string;
59             } else {
60 0         0 $rdf = undef;
61             }
62             }
63              
64 14 50 66     102 if ($rdf and $rdf =~ /^http:\/\//) {
65 0         0 $self->{model} = RDF::Trine::Model->new;
66 0         0 $self->load( $rdf );
67             }
68              
69 14 50 100     183 croak 'expected RDF::Trine::Model, RDF::Trine::Store or URI'
70             unless $rdf // 1;
71              
72 14 100       77 if ( not $self->{model} ) {
73 10         118 $self->{model} = RDF::Trine::Model->new;
74 10         957 $self->add( $rdf, %args );
75             }
76              
77 14         152623 $self;
78             }
79              
80              
81             sub cache {
82 8     8 1 12 my $self = shift;
83 8 100       26 if (@_) {
84 1         2 my $c = shift;
85 1 50 33     22 croak "cache must support 'get' and 'set' methods"
      33        
86             unless blessed $c and $c->can('get') and $c->can('set');
87 1         6 $self->{cache} = $c;
88             }
89 8         30 $self->{cache};
90             }
91              
92              
93             sub load {
94 3     3 1 887 my ($self, $uri) = @_;
95              
96 3         14 my $size = $self->{model}->size;
97              
98 3 50       193 if ($self->cache) {
99 3         7 my $format = 'Turtle'; # cache must be purged if format changes!
100              
101 3         48 my $rdf = $self->cache->get( $uri );
102 3 100       20 if ($rdf) {
103             RDF::Trine::Parser->new($format)
104 2         14 ->parse_into_model( $uri, $rdf, $self->{model} );
105             } else {
106 1         7 my $model = RDF::Trine::Model->new;
107 1         52 RDF::Trine::Parser->parse_url_into_model( $uri, $model );
108 1         9562 $self->{model}->add_iterator( $model->as_stream );
109              
110 1         1905 $rdf = RDF::Trine::Serializer->new($format)
111             ->serialize_model_to_string( $model );
112 1         3633 $self->cache->set( $uri, $rdf );
113             }
114             } else {
115 0         0 RDF::Trine::Parser->parse_url_into_model( $uri, $self->{model} );
116             }
117              
118 3         22793 return ($self->{model}->size - $size);
119             }
120              
121             # method includes parts of RDF::TrineShortcuts::rdf_parse by Toby Inkster
122             sub add { # rdf by value
123 12     12 1 821 my $self = shift;
124              
125             # TODO: have a look at RDF::TrineShortcuts::rdf_parse
126              
127 12 100 100     98 if (@_ == 3 and $_[1] !~ /^[a-z]+$/) { # TODO: allow 'a'?
128 1         4 my @triple = @_;
129 1         3 @triple = map { $self->uri($_) } @triple;
  3         9  
130 1 50       3 if ( grep { not defined $_ } @triple ) {
  3         8  
131 0         0 croak 'Failed to add pseudo-triple';
132             }
133 1         3 @triple = map { $_->trine } @triple;
  3         8  
134 1         11 my $stm = RDF::Trine::Statement->new( @triple );
135 1         22 $self->model->add_statement( $stm );
136 1         1111 return;
137             }
138              
139 11         31 my ($rdf, %args) = @_;
140              
141 11 50       70 if (blessed $rdf) {
    50          
142 0 0       0 if ($rdf->isa('RDF::Trine::Graph')) {
143 0         0 $rdf = $rdf->get_statements;
144             }
145 0 0       0 if ($rdf->isa('RDF::Trine::Iterator::Graph')) {
    0          
    0          
146 0         0 $self->model->begin_bulk_ops;
147 0         0 while (my $row = $rdf->next) {
148 0         0 $self->model->add_statement( $row );
149             }
150 0         0 $self->model->end_bulk_ops;
151             } elsif ($rdf->isa('RDF::Trine::Statement')) {
152 0         0 $self->model->add_statement( $rdf );
153             } elsif ($rdf->isa('RDF::Trine::Model')) {
154 0         0 $self->add( $rdf->as_stream );
155             } else {
156 0         0 croak 'Cannot add RDF object of type ' . ref($rdf);
157             }
158             } elsif ( ref $rdf ) {
159 0 0       0 if ( ref $rdf eq 'HASH' ) {
160 0         0 $self->model->add_hashref($rdf);
161             } else {
162 0         0 croak 'Cannot add RDF object of type ' . ref($rdf);
163             }
164             } else {
165             # TODO: parse from file, glob, or string in Turtle syntax or other
166             # reuse namespaces if parsing Turtle or SPARQL
167              
168 11   50     90 my $format = $args{format} || 'turtle';
169 11   50     95 my $base = $args{base} || 'http://localhost/';
170 11         119 my $parser = RDF::Trine::Parser->new( $format );
171 11         439 $parser->parse_into_model( $base, $rdf, $self->model );
172             }
173             }
174              
175             sub query {
176             # TODO: See RDF::TrineShortcuts::rdf_query
177 0     0 0 0 carp __PACKAGE__ . '::query not implemented yet';
178             }
179              
180             *sparql = *query;
181              
182 14     14 0 125 sub model { $_[0]->{model} }
183              
184 5     5 0 1200 sub size { $_[0]->{model}->size }
185              
186 12     12 1 35 sub rels { shift->_relrev( 1, 'rel', @_ ); }
187 25     25 1 113 sub rel { shift->_relrev( 0, 'rel', @_ ); }
188 2     2 1 6 sub rev { shift->_relrev( 0, 'rev', @_ ); }
189 5     5 1 39 sub revs { shift->_relrev( 1, 'rev', @_ ); }
190              
191             sub turtle {
192 3     3 0 178 my $self = shift;
193             $self->_serialize(
194 3         37 RDF::Trine::Serializer::Turtle->new( namespaces => $self->{namespaces} ),
195             @_
196             );
197             }
198              
199             *ttl = *turtle;
200              
201             sub rdfjson {
202 0     0 0 0 shift->_serialize( RDF::Trine::Serializer::RDFJSON->new, @_ );
203             }
204              
205             sub rdfxml {
206 0     0 0 0 my $self = shift;
207             $self->_serialize(
208 0         0 RDF::Trine::Serializer::RDFXML->new( namespaces => $self->{namespaces} ),
209             @_
210             );
211             }
212              
213             sub ttlpre {
214 2   50 2 1 377 return '<pre class="turtle">'
215             . escapeHTML( "# " . ($_[0]->str||'') . "\n" . turtle(@_) )
216             . '</pre>';
217             }
218              
219 24     24 1 30651 sub resource { RDF::Lazy::Resource->new( @_ ) }
220 13     13 1 1105 sub literal { RDF::Lazy::Literal->new( @_ ) }
221 3     3 1 1027 sub blank { RDF::Lazy::Blank->new( @_ ) }
222              
223             sub node {
224 0     0 0 0 carp __PACKAGE__ . '::node is depreciated - use ::uri instead!';
225 0         0 uri(@_);
226             }
227              
228             sub uri {
229 134     134 1 4808 my ($self,$node) = @_;
230 134 50       334 return unless defined $node;
231              
232 134 100       418 if (blessed $node) {
233 62 50       323 if ($node->isa('RDF::Lazy::Node')) {
234             # copy from another or from this graph
235             # return $node if refaddr($node->graph) eq refaddr($self);
236 0         0 $node = $self->trine;
237             }
238 62 100       277 if ($node->isa('RDF::Trine::Node::Resource')) {
    100          
    50          
239 44         165 return RDF::Lazy::Resource->new( $self, $node );
240             } elsif ($node->isa('RDF::Trine::Node::Literal')) {
241 16         126 return RDF::Lazy::Literal->new( $self, $node );
242             } elsif ($node->isa('RDF::Trine::Node::Blank')) {
243 2         20 return RDF::Lazy::Blank->new( $self, $node );
244             } else {
245 0         0 carp 'Cannot create RDF::Lazy::Node from ' . ref($node);
246 0         0 return;
247             }
248             }
249              
250 72         99 my ($prefix,$local,$uri);
251              
252 72 100       1101 if ( $node =~ /^<(.*)>$/ ) {
    100          
    100          
    50          
    100          
    100          
    50          
253 7         45 return RDF::Lazy::Resource->new( $self, $1 );
254             } elsif ( $node =~ qr{^(https?://.*)} ) {
255 2         9 return RDF::Lazy::Resource->new( $self, $1 );
256             } elsif ( $node =~ /^_:(.*)$/ ) {
257 1         5 return RDF::Lazy::Blank->new( $self, $1 );
258             } elsif ( $node =~ /^\[\s*\]$/ ) {
259 0         0 return RDF::Lazy::Blank->new( $self );
260             } elsif ( $node =~ /^["'+-0-9]|^(true|false)$/ ) {
261 3         10 return $self->_literal( $node );
262             } elsif ( $node =~ /^([^:]*):([^:]*)$/ ) {
263 32         93 ($prefix,$local) = ($1,$2);
264             } elsif ( $node =~ /^(([^_:]*)_)?([^_:]+.*)$/ ) {
265 27         87 ($prefix,$local) = ($2,$3);
266             } else {
267 0         0 return;
268             }
269              
270 59 100       195 $prefix = "" unless defined $prefix;
271             # if (defined $prefix) {
272 59         306 $uri = $self->{namespaces}->URI("$prefix:$local");
273             # } else {
274             # # Bug in RDF::Trine::NamespaceMap, line 133 - wait until fixed
275             # # $predicate = $self->{namespaces}->uri(":$local");
276             # my $ns = $self->{namespaces}->namesespace_uri("");
277             # $uri = $ns->uri($local) if defined $ns;
278             #}
279              
280 59 100       1197 return unless defined $uri;
281 54         188 return RDF::Lazy::Resource->new( $self, $uri );
282             }
283              
284             sub namespaces {
285 3     3 1 813 return shift->{namespaces};
286             }
287              
288             sub ns {
289 9     9 1 23 my $self = shift;
290 9 50       26 return unless @_;
291              
292 9 100       27 if (@_ == 2) { # set
293 1         4 $self->{namespaces}->{$_[0]} = $_[1];
294 1 50       10 $self->{nsprefix}->{$_[1]} = $_[0] if $self->{nsprefix};
295 1         3 return;
296             }
297 8 100       45 return $self->{namespaces}->{$_[0]}
298             if $_[0] !~ ':'; # get namespace
299             $self->{nsprefix} = $self->{namespaces}->REVERSE
300 6 100       28 unless $self->{nsprefix};
301 6         7374 return $self->{nsprefix}->{$_[0]};
302             }
303              
304             sub subjects {
305 0     0 0 0 my $self = shift;
306 0         0 my ($predicate, $object) = map { my $self->uri($_)->trine } @_;
  0         0  
307 0         0 return map { $self->uri($_) } $self->model->subjects( $predicate, $object );
  0         0  
308             }
309              
310             sub predicates {
311 0     0 0 0 my $self = shift;
312 0         0 my ($subject, $object) = map { $self->uri($_)->trine } @_;
  0         0  
313 0         0 return map { $self->uri($_) } $self->model->predicates( $subject, $object );
  0         0  
314             }
315              
316             sub objects {
317 0     0 0 0 my ($self, $subject, $predicate, %options) = @_;
318 0         0 ($subject, $predicate) = map { $self->uri($_)->trine } ($subject, $predicate);
  0         0  
319 0         0 return map { $self->uri($_) } $self->model->objects( $subject, $predicate, %options );
  0         0  
320             }
321              
322             sub AUTOLOAD {
323 7     7   556 my $self = shift;
324 7 50 33     57 return if !ref($self) or $AUTOLOAD =~ /^(.+::)?DESTROY$/;
325              
326 7         13 my $name = $AUTOLOAD;
327 7         36 $name =~ s/.*:://;
328              
329 7         25 return $self->uri($name);
330             }
331              
332             ### internal methods
333              
334             # parts from RDF/Trine/Parser/Turtle.pm
335             my $xsd = RDF::Trine::Namespace->new('http://www.w3.org/2001/XMLSchema#');
336             #my $r_language = qr'[a-z]+(-[a-z0-9]+)*'i;
337             my $r_double = qr'^[+-]?([0-9]+\.[0-9]*[eE][+-]?[0-9]+|\.[0-9]+[eE][+-]?[0-9]+|[0-9]+[eE][+-]?[0-9]+)$';
338             my $r_decimal = qr'^[+-]?([0-9]+\.[0-9]*|\.([0-9])+)$';
339             my $r_integer = qr'^[+-]?[0-9]+';
340             my $r_boolean = qr'^(true|false)$';
341             my $r_string1 = qr'^"(.*)"(\@([a-z]+(-[a-z0-9]+)*))?$'i;
342             my $r_string2 = qr'^"(.*)"(\@([a-z]+(-[a-z0-9]+)*))?$'i;
343              
344             sub _literal {
345 3     3   5 my ($self, $s) = @_;
346              
347 3         5 my ($literal, $language, $datatype);
348              
349 3 100 66     49 if ( $s =~ $r_string1 or $s =~ $r_string2 ) {
    50          
    50          
    50          
    50          
350 2         6 ($literal, $language) = ($1,$3);
351             } elsif( $s =~ $r_double ) {
352 0         0 $literal = $s;
353 0         0 $datatype = $xsd->double;
354             } elsif( $s =~ $r_decimal ) {
355 0         0 $literal = $s;
356 0         0 $datatype = $xsd->decimal;
357             } elsif( $s =~ $r_integer ) {
358 0         0 $literal = $s;
359 0         0 $datatype = $xsd->integer;
360             } elsif( $s =~ $r_boolean ) {
361 1         2 $literal = $s;
362 1         18 $datatype = $xsd->boolean;
363             }
364              
365 3         46 return $self->literal( $literal, $language, $datatype );
366             }
367              
368             sub _query {
369 37     37   83 my ($self,$all,$dir,$subject,$property,@filter) = @_;
370              
371 37 100 66     322 $subject = $self->uri($subject)
372             unless blessed($subject) and $subject->isa('RDF::Lazy::Node');
373              
374 37 50       99 if (defined $property) {
375 37   100     103 $property = $self->uri($property) // return;
376             }
377 32 50       276 $property = $property->trine if defined $property;
378              
379 32         73 my @res;
380              
381 32 100       83 if ($dir eq 'rel') {
    50          
382 29         101 @res = $self->{model}->objects( $subject->trine, $property );
383             } elsif ($dir eq 'rev') {
384 3         11 @res = $self->{model}->subjects( $property, $subject->trine );
385             }
386              
387              
388 32         21733 @res = map { $self->uri( $_ ) } @res;
  41         110  
389              
390             # TODO apply filters one by one and return in order of filters
391 32 100       89 @res = grep { $_->is(@filter) } @res if @filter;
  11         60  
392              
393 32 100       169 return $all ? \@res : $res[0];
394             }
395              
396             sub _relrev {
397 44     44   66 my $self = shift;
398 44         67 my $all = shift;
399 44         105 my $type = shift;
400 44         65 my $subject = shift;
401              
402 44 100       137 if (@_) {
403             # get objects / subjects
404 37         72 my ($property,@filter) = @_;
405 37 50 66     361 $all = 1 if ($property and not ref $property and $property =~ s/^(.+[^_])_$/$1/);
      66        
406              
407 37         8949 return $self->_query( $all, $type, $subject, $property, @filter );
408             } else {
409             # get all predicates
410 7 50 33     61 $subject = $self->uri($subject)
411             unless blessed($subject) and $subject->isa('RDF::Lazy::Node');
412              
413 7         12 my @res;
414              
415 7 100       21 if ($type eq 'rel') {
    50          
416 3         12 @res = $self->{model}->predicates( $subject->trine, undef );
417             } elsif ($type eq 'rev') {
418 4         13 @res = $self->{model}->predicates( undef, $subject->trine );
419             }
420              
421 7 100       1448 return $all ? [ map { $self->uri( $_ ) } @res ] : $self->uri( $res[0] );
  4         10  
422             }
423             }
424              
425             sub _serialize {
426 3     3   14657 my ($self, $serializer, $subject) = @_;
427 3         6 my $iterator;
428              
429 3 100       15 if ($subject) {
430 1 50 33     19 $subject = $self->uri($subject)
431             unless blessed($subject) and $subject->isa('RDF::Lazy::Node');
432 1         5 $iterator = $self->{model}->bounded_description( $subject->trine );
433             } else {
434 2         13 $iterator = $self->model->as_stream;
435             }
436              
437 3         3043 return $serializer->serialize_iterator_to_string( $iterator );
438             }
439              
440             1;
441             __END__
442              
443             =head1 NAME
444              
445             RDF::Lazy - Lazy typing access to RDF data
446              
447             =head1 SYNOPSIS
448              
449             ### How to create a graph
450              
451             $g = RDF::Lazy->new(
452             rdf => $data, # RDF::Trine::Model or ::Store (by reference)
453             namespaces => { # namespace prefix, RDF::NS or RDF::Trine::NamespaceMap
454             foaf => 'http://xmlns.com/foaf/0.1/',
455             rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
456             xsd => "http://www.w3.org/2001/XMLSchema#",
457             }
458             );
459              
460             $g = RDF::Lazy->new( $data, format => 'turtle' ); # parse RDF/Turtle
461             $g = RDF::Lazy->new( $data, format => 'rdfxml' ); # parse RDF/XML
462             $g = RDF::Lazy->new( "http://example.org/" ); # retrieve LOD
463              
464             ### How to get nodes
465              
466             $p = $g->resource('http://xmlns.com/foaf/0.1/Person'); # get node
467             $p = $g->uri('<http://xmlns.com/foaf/0.1/Person>'); # alternatively
468             $p = $g->uri('foaf:Person); # same but lazier
469             $p = $g->foaf_Person; # same but laziest
470              
471             $l = $g->literal('Alice'); # get literal node
472             $l = $g->literal('Alice','en'); # get literal node with language
473             $l = $g->literal('123','xsd:integer'); # get literal node with datatype
474              
475             $b = $g->blank('x123'); # get blank node
476             $b = $g->blank; # get blank node with random id
477              
478             ### How to retrieve RDF
479              
480             $x->rel('foaf:knows'); # retrieve a person that $x knows
481             $x->rev('foaf:knows'); # retrieve a person known by $x
482              
483             $x->rels('foaf:knows'); # retrieve all people that $x knows
484             $x->revs('foaf:knows'); # retrieve all people known by $x
485              
486             $x->foaf_knows; # short form of $x->rel('foaf:knows')
487             $x->foaf_knows_; # short form of $x->rels('foaf:knows')
488              
489             $x->rels; # array reference with a list of properties
490             $x->revs; # same as rels, but other direction
491              
492             $x->type; # same as $x->rel('rdf:type')
493             $x->types; # same as $x->rels('rdf:type')
494              
495             $g->subjects( 'rdf:type', 'foaf:Person' ); # retrieve subjects
496             $g->predicates( $subject, $object ); # list predicates
497             $g->objects( $subject, 'foaf:knows' ); # list objects
498              
499             ### How to add RDF
500              
501             $g->add( $rdfdata, format => 'rdfxml' ); # parse and add
502             $g->add( $subject, $predicate, $object ); # add single triple
503              
504             ### How to show RDF
505              
506             $g->turtle; # dump in RDF/Turtle syntax
507             $g->ttlpre; # dump in RDF/Turtle, wrapped in a HTML <pre> tag
508             $g->rdfxml; # dump in RDF/XML
509             $g->rdfjson; # dump in RDF/JSON
510              
511             =head1 DESCRIPTION
512              
513             This module wraps L<RDF::Trine::Node> to provide simple node-centric access to
514             RDF data. It was designed to access RDF within L<Template> Toolkit but the
515             module does not depend on or and can be used independently. Basically, an
516             instance of RDF::Lazy contains an unlabeled RDF graph and a set of namespace
517             prefixes. For lazy access and graph traversal, each RDF node
518             (L<RDF::Lazy::Node>) is tied to the graph.
519              
520             =head1 METHODS
521              
522             =head2 cache( [ $cache ] )
523              
524             Get and/or set a cache for loading RDF from URIs or URLs. A C<$cache> can be
525             any blessed object that supports method C<get($uri)> and C<set($uri,$value)>.
526             For instance one can enable a simple file cache with L<CHI> like this:
527              
528             my $rdf = RDF::Lazy->new(
529             cache => CHI->new(
530             driver => 'File', root_dir => '/tmp/cache',
531             expires_in => '1 day'
532             )
533             );
534              
535             By default, RDF is stored in Turtle syntax for easy inspection.
536              
537             =head2 load( $uri )
538              
539             Load RDF from an URI or URL. RDF data is optionally retrieved from a cache.
540             Returns the number of triples that have been added (which could be zero if
541             all loaded triples are duplicates).
542              
543             =head2 new ( [ [ rdf => ] $rdf ] [, namespaces => $namespaces ] [ %options ])
544              
545             Return new RDF graph. Namespaces can be provided as hash reference or as
546             L<RDF::Trine::NamespaceMap> or L<RDF::NS>. By default, the current local
547             version of RDF::NS is used. RDF data can be L<RDF:Trine::Model> or
548             L<RDF::Trine::Store>, which are used by reference, or many other forms, as
549             supported by L<add|/add>.
550              
551             =head2 resource ( $uri )
552              
553             Return L<RDF::Lazy::Resource> node. The following statements are equivalent:
554              
555             $graph->resource('http://example.org');
556             $graph->uri('<http://example.org>');
557              
558             =head2 literal ( $string , $language_or_datatype, $datatype )
559              
560             Return L<RDF::Lazy::Literal> node.
561              
562             =head2 blank ( [ $identifier ] )
563              
564             Return L<RDF::Lazy::Blank> node. A random identifier is generated unless you
565             provide an identifier as parameter.
566              
567             =head2 uri ( $name | $node )
568              
569             Returns a node that is connected to the graph. Note that every valid RDF node
570             is part of any RDF graph: this method does not check whether the graph actually
571             contains a triple with the given node. You can either pass a name or an
572             instance of L<RDF::Trine::Node>. This method is also called for any undefined
573             method, so the following statements are equivalent:
574              
575             $graph->true;
576             $graph->uri('true');
577              
578             =head2 rel / rels / rev / revs
579              
580             Can be used to traverse the graph. See L<RDF::Lazy::Node>:
581              
582             $node->rel( ... ) # where $node is located in $graph
583             $graph->rel( $node, ... ) # equivalent
584              
585             =head2 add
586              
587             Add RDF data. I<Sorry, not documented yet!>
588              
589             =head2 ttl ( [ $node ] )
590              
591             Returns a RDF/Turtle representation of a node's bounded description.
592              
593             =head2 ttlpre ( [ $node ] )
594              
595             Returns an HTML escaped RDF/Turtle representation of a node's bounded
596             description, wrapped in a HTML C<< <pre class="turtle"> >> element.
597              
598             =head2 ns ( $prefix | $namespace | $prefix => $namespace )
599              
600             Gets or sets a namespace mapping for the entire graph. By default, RDF::Lazy
601             makes use of popular namespaces defined in L<RDF::NS>.
602              
603             $g->ns('dc'); # returns 'http://purl.org/dc/elements/1.1/'
604             $g->ns('http://purl.org/dc/elements/1.1/'); # returns 'dc'
605             $g->ns( dc => 'http://example.org/' ); # modify mapping
606              
607             =head1 SEE ALSO
608              
609             L<RDF::Helper> and L<RDF::TrineShortcuts> provide similar APIs. Another similar framework
610             for PHP and Python is Graphite: http://graphite.ecs.soton.ac.uk/,
611             http://code.google.com/p/python-graphite/.
612              
613             =encoding utf-8
614              
615             =head1 AUTHOR
616              
617             Jakob Voß <voss@gbv.de>
618              
619             =head1 COPYRIGHT AND LICENSE
620              
621             This software is copyright (c) 2013 by Jakob Voß.
622              
623             This is free software; you can redistribute it and/or modify it under
624             the same terms as the Perl 5 programming language system itself.
625              
626             =cut