File Coverage

blib/lib/Conclave/OTK.pm
Criterion Covered Total %
statement 113 156 72.4
branch 15 28 53.5
condition 0 6 0.0
subroutine 23 28 82.1
pod 19 21 90.4
total 170 239 71.1


line stmt bran cond sub pod time code
1 3     3   79581 use strict;
  3         6  
  3         76  
2 3     3   16 use warnings;
  3         4  
  3         110  
3             package Conclave::OTK;
4             # ABSTRACT: Conclave Ontology Toolkit
5              
6 3     3   1444 use Conclave::OTK::Queries;
  3         8  
  3         545  
7 3     3   2524 use File::HomeDir;
  3         18187  
  3         185  
8 3     3   29 use File::Spec;
  3         6  
  3         8693  
9              
10             sub new {
11 2     2 1 642 my ($class, $base_uri, %opts) = @_;
12 2         7 my $self = bless({}, $class);
13              
14             # set defaults
15 2         6 my $backend = 'File';
16              
17             # attempt to read conf file
18 2 100       9 unless ($opts{ignoreconfigfile}) {
19 1         8 my $conf = File::Spec->catfile(File::HomeDir->my_home, '.conc-otk.conf');
20 1 50       97 if (-e $conf) {
21 0         0 open my $fh, '<', $conf;
22 0         0 while (my $line = <$fh>) {
23 0         0 chomp $line;
24 0         0 my ($k, $v) = split /\s*=\s*/, $line;
25 0 0 0     0 next unless ($k and $v);
26 0 0       0 $opts{$k} = $v unless exists $opts{$k};
27             }
28 0         0 close $fh;
29             }
30             }
31              
32 2 50       13 $backend = $opts{backend} if $opts{backend};
33 2         7 my $module = "Conclave::OTK::Backend::$backend";
34 2 50       14 if ($module =~ m/^([\w:]+)$/) {
35 2     1   161 eval "use $1";
  1     1   643  
  1         4  
  1         26  
  1         13  
  1         2  
  1         20  
36             }
37              
38 2         7 my $format = 'OWL'; # default queries underlying format
39              
40 2         15 $self->{base_uri} = $base_uri;
41 2         6 $self->{graph} = $base_uri;
42              
43 2         14 $self->{backend} = $module->new($base_uri, %opts);
44             $self->{prefixes} = {
45 2         16 'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
46             'owl' => 'http://www.w3.org/2002/07/owl#',
47             'xsd' => 'http://www.w3.org/2001/XMLSchema#',
48             'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#',
49             };
50              
51 2         18 $self->{queries} = Conclave::OTK::Queries->new($format);
52              
53 2         14 return $self;
54             }
55              
56             sub init {
57 1     1 1 8 my ($self, $rdfxml) = @_;
58              
59 1         11 $self->{backend}->init($rdfxml);
60             }
61              
62             sub delete {
63 1     1 1 1002 my ($self) = @_;
64              
65 1         8 $self->{backend}->delete;
66             }
67              
68             sub add_class {
69 3     3 1 1208 my ($self, $name, @parents) = @_;
70              
71             my $vars = {
72             'name' => $self->full_uri($name),
73             'graph' => $self->{graph},
74             'prefixes' => $self->{prefixes},
75 3         18 'parents' => [map {$self->full_uri($_)} @parents],
  3         10  
76             };
77 3         23 my $sparql = $self->{queries}->process('add_class', $vars);
78              
79 3         20 my $result = $self->{backend}->update($sparql);
80 3         1430 return $result;
81             }
82              
83             sub get_classes {
84 2     2 1 1034 my ($self) = @_;
85              
86             my $vars = {
87             'prefixes' => $self->{prefixes},
88             'graph' => $self->{graph},
89 2         14 };
90 2         14 my $sparql = $self->{queries}->process('get_classes', $vars);
91              
92 2         17 my @classes = $self->{backend}->query($sparql);
93 2         1138 return @classes;
94             }
95              
96             sub get_subclasses {
97 5     5 1 1057 my ($self, $class) = @_;
98              
99             my $vars = {
100             'prefixes' => $self->{prefixes},
101             'graph' => $self->{graph},
102 5         30 'class' => $self->full_uri($class),
103             };
104 5         40 my $sparql = $self->{queries}->process('get_subclasses', $vars);
105              
106 5         33 my @classes = $self->{backend}->query($sparql);
107 5         6226 return @classes;
108             }
109              
110             sub get_all_subclasses {
111 0     0 1 0 my ($self, $class) = @_;
112              
113 0         0 my %result;
114 0         0 my @classes = $self->get_subclasses($class);
115 0         0 foreach (@classes) { $result{$_}++ }
  0         0  
116              
117 0         0 foreach (keys %result) {
118 0         0 my @classes = $self->get_subclasses($_);
119 0         0 foreach (@classes) { $result{$_}++ }
  0         0  
120             }
121              
122 0         0 my @result = keys %result;
123 0         0 return @result;
124             }
125              
126             sub get_instance_classes {
127 0     0 1 0 my ($self, $i) = @_;
128              
129             my $vars = {
130             'prefixes' => $self->{prefixes},
131             'graph' => $self->{graph},
132 0         0 'i' => $self->full_uri($i),
133             };
134 0         0 my $sparql = $self->{queries}->process('get_instance_classes', $vars);
135              
136 0         0 my @classes = $self->{backend}->query($sparql);
137 0         0 return @classes;
138             }
139              
140             sub add_instance {
141 2     2 1 1136 my ($self, $name, $class) = @_;
142              
143             my $vars = {
144             'name' => $self->full_uri($name),
145             'class' => $self->full_uri($class),
146             'graph' => $self->{graph},
147             'prefixes' => $self->{prefixes},
148 2         12 };
149 2         18 my $sparql = $self->{queries}->process('add_instance', $vars);
150              
151              
152 2         15 my $result = $self->{backend}->update($sparql);
153 2         1645 return $result;
154             }
155              
156             sub get_instances {
157 2     2 1 1119 my ($self, $class) = @_;
158              
159             my $vars = {
160             'prefixes' => $self->{prefixes},
161             'graph' => $self->{graph},
162 2         15 'class' => $self->full_uri($class),
163             };
164 2         15 my $sparql = $self->{queries}->process('get_instances', $vars);
165              
166              
167 2         16 my @classes = $self->{backend}->query($sparql);
168 2         1936 return @classes;
169             }
170              
171             sub add_obj_prop {
172 1     1 1 991 my ($self, $subject, $relation, $target) = @_;
173              
174             my $vars = {
175             'subject' => $self->full_uri($subject),
176             'relation' => $self->full_uri($relation),
177             'target' => $self->full_uri($target),
178             'graph' => $self->{graph},
179             'prefixes' => $self->{prefixes},
180 1         6 };
181 1         8 my $sparql = $self->{queries}->process('add_obj_prop', $vars);
182              
183              
184 1         8 my $result = $self->{backend}->update($sparql);
185 1         1003 return $result;
186             }
187              
188             sub get_obj_props {
189 2     2 1 1324 my ($self, $instance) = @_;
190              
191             # XXX some backends return str(?n) with < >
192 2         11 $instance = $self->full_uri($instance);
193 2         11 $instance =~ s/^<//;
194 2         10 $instance =~ s/>$//;
195              
196             my $vars = {
197             'prefixes' => $self->{prefixes},
198             'graph' => $self->{graph},
199 2         13 'instance' => $instance,
200             };
201 2         17 my $sparql = $self->{queries}->process('get_obj_props', $vars);
202              
203 2         14 my @props = $self->{backend}->query($sparql);
204 2         2541 return @props;
205             }
206              
207             sub get_obj_props_for {
208 1     1 1 1374 my ($self, $rel, $el) = @_;
209              
210             my $vars = {
211             'prefixes' => $self->{prefixes},
212             'graph' => $self->{graph},
213 1         8 'rel' => $self->full_uri($rel),
214             'el' => $self->full_uri($el),
215             };
216 1         8 my $sparql = $self->{queries}->process('get_obj_props_for', $vars);
217              
218 1         8 my @els = $self->{backend}->query($sparql);
219 1         1352 return @els;
220             }
221              
222             sub get_ranges {
223 0     0 1 0 my ($self) = @_;
224              
225             my $vars = {
226             'prefixes' => $self->{prefixes},
227             'graph' => $self->{graph},
228 0         0 };
229 0         0 my $sparql = $self->{queries}->process('get_ranges', $vars);
230              
231 0         0 my @ranges = $self->{backend}->query($sparql);
232 0         0 return @ranges;
233             }
234              
235             sub get_data_props {
236 2     2 1 1353 my ($self, $instance) = @_;
237 2         10 $instance = $self->full_uri($instance);
238              
239             my $vars = {
240             'prefixes' => $self->{prefixes},
241             'graph' => $self->{graph},
242 2         44 'instance' => $instance,
243             };
244 2         16 my $sparql = $self->{queries}->process('get_data_props', $vars);
245              
246              
247 2         15 my @props = $self->{backend}->query($sparql);
248 2         3049 return @props;
249             }
250              
251             sub add_data_prop {
252 2     2 1 1336 my ($self, $subject, $relation, $target, $type) = @_;
253 2 50       10 $type = 'string' unless $type;
254              
255             my $vars = {
256             'subject' => $self->full_uri($subject),
257             'relation' => $self->full_uri($relation),
258             'target' => $target,
259             'type' => $type,
260             'graph' => $self->{graph},
261             'prefixes' => $self->{prefixes},
262 2         9 };
263 2         16 my $sparql = $self->{queries}->process('add_data_prop', $vars);
264              
265 2         16 my $result = $self->{backend}->update($sparql);
266 2         2504 return $result;
267             }
268              
269             sub full_uri {
270 30     30 1 73 my ($self, $name) = @_;
271 30 100       181 return $name if $name =~ m/^<.*>$/;
272 25 50       90 return "<$name>" if $name =~ m/^http:\/\//;
273              
274 25         191 return '<'.$self->{base_uri}.'#'.$name.'>';
275             }
276              
277             sub shorten_uri {
278 0     0 0 0 my ($self, $uri) = @_;
279 0 0 0     0 return $uri unless ($uri =~ m/^</ and $uri =~ m/>$/);
280              
281 0         0 $uri =~ s/^<//;
282 0         0 $uri =~ s/>$//;
283 0 0       0 return $1 if ($uri =~ m/.*?#(.*?)/);
284            
285 0         0 return $uri;
286             }
287              
288             sub get_class_tree {
289 4     4 1 1231 my ($self, $parent, $flag) = @_;
290 4 100       17 $parent = 'http://www.w3.org/2002/07/owl#Thing' unless ($parent);
291 4 100       14 $flag = 0 unless $flag;
292              
293 4         8 my $curr;
294 4         24 my @child = $self->get_subclasses("<$parent>");
295 4         16 foreach (@child) {
296 3         20 $curr->{$_} = $self->get_class_tree($_,1);
297             }
298              
299 4 100       32 return $flag ? $curr : { $parent => $curr };
300             }
301              
302             sub draw_graph {
303 0     0 1 0 my ($self) = @_;
304              
305             my $vars = {
306             'graph' => $self->{graph},
307             'prefixes' => $self->{prefixes},
308 0         0 };
309 0         0 my $sparql = $self->{queries}->process('select_from_graph', $vars);
310              
311 0         0 my @result = $self->{backend}->query($sparql);
312              
313 0         0 my $dot = "digraph g {\n rankdir=LR;\n";
314 0         0 foreach (@result) {
315 0         0 $dot .= sprintf(" \"%s\" -> \"%s\" [ label = \"%s\" ];\n",
316             $_->[0], $_->[2], $_->[1]);
317             }
318 0         0 $dot .= "}\n";
319              
320 0         0 return $dot;
321             }
322              
323             # FIXME move this somewhere else?
324             sub empty_owl {
325 2     2 0 17 my ($base_uri) = (@_);
326              
327 2         11 my $rdfxml =<<"EOR";
328             <?xml version="1.0" encoding="UTF-8"?>
329              
330             <!DOCTYPE rdf:RDF [
331             <!ENTITY owl "http://www.w3.org/2002/07/owl#" >
332             <!ENTITY xsd "http://www.w3.org/2001/XMLSchema#" >
333             <!ENTITY example "http://local/example" >
334             <!ENTITY rdfs "http://www.w3.org/2000/01/rdf-schema#" >
335             <!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#" >
336             ]>
337              
338             <rdf:RDF xmlns="$base_uri"
339             xml:base="$base_uri"
340             xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
341             xmlns:empty="$base_uri"
342             xmlns:owl="http://www.w3.org/2002/07/owl#"
343             xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
344             xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
345             <owl:Ontology rdf:about="http://local/example"/>
346             </rdf:RDF>
347             EOR
348              
349 2         7 return $rdfxml;
350             }
351              
352             1;
353              
354             __END__
355              
356             =pod
357              
358             =encoding UTF-8
359              
360             =head1 NAME
361              
362             Conclave::OTK - Conclave Ontology Toolkit
363              
364             =head1 VERSION
365              
366             version 0.01
367              
368             =head1 SYNOPSIS
369              
370             use Conclave::OTK;
371              
372             my $onto = Conclave::OTK->new($base_uri);
373              
374             $onto->add_class($class_name);
375             $onto->add_obj_prop($class1, $relation, $class2);
376             $onto->add_data_prop($class, $relation, $value, $type);
377             # default type is string
378              
379             =head1 DESCRIPTION
380              
381             OTK implements a set of operations to handle ontologies. Its' main goal
382             is to provide an ORM-style API, but for RDF documents, to implement
383             ontology oriented applications.
384              
385             This module is under developement, and things still change often.
386              
387             =head1 METHODS
388              
389             =head2 new
390              
391             =head2 init
392              
393             =head2 delete
394              
395             =head2 add_class
396              
397             =head2 get_classes
398              
399             =head2 get_subclasses
400              
401             =head2 get_all_subclasses
402              
403             =head2 get_instance_classes
404              
405             =head2 add_instance
406              
407             =head2 get_instances
408              
409             =head2 add_obj_prop
410              
411             =head2 get_obj_props
412              
413             =head2 get_obj_props_for
414              
415             =head2 get_ranges
416              
417             =head2 get_data_props
418              
419             =head2 add_data_prop
420              
421             =head2 full_uri
422              
423             =head2 get_class_tree
424              
425             =head2 draw_graph
426              
427             =head1 AUTHOR
428              
429             Nuno Carvalho <smash@cpan.org>
430              
431             =head1 COPYRIGHT AND LICENSE
432              
433             This software is copyright (c) 2014-2015 by Nuno Carvalho <smash@cpan.org>.
434              
435             This is free software; you can redistribute it and/or modify it under
436             the same terms as the Perl 5 programming language system itself.
437              
438             =cut