File Coverage

blib/lib/RDF/Helper/Object.pm
Criterion Covered Total %
statement 24 124 19.3
branch 0 42 0.0
condition 0 14 0.0
subroutine 8 19 42.1
pod 0 9 0.0
total 32 208 15.3


line stmt bran cond sub pod time code
1             package RDF::Helper::Object;
2 11     11   47 use strict;
  11         11  
  11         409  
3 11     11   43 use warnings;
  11         15  
  11         296  
4 11     11   5408 use Data::Dumper;
  11         52029  
  11         658  
5 11     11   3942 use Data::UUID;
  11         5403  
  11         585  
6 11     11   3832 use RDF::Helper::TiedPropertyHash;
  11         22  
  11         281  
7 11     11   51 use vars qw( $AUTOLOAD );
  11         11  
  11         576  
8             use overload
9 11         75 '""' => \&object_uri,
10             'eq' => \&object_uri_equals,
11 11     11   42 '==' => \&object_uri_equals;
  11         17  
12              
13             # TODO:
14             # - Handle namespaces properly
15              
16             =head1 NAME
17              
18             RDF::Helper::Object - Perl extension to use RDF property names as methods
19              
20             =head1 SYNOPSIS
21              
22             use RDF::Helper;
23             my $rdf = RDF::Helper->new(
24             BaseInterface => 'RDF::Trine',
25             namespaces => {
26             dc => 'http://purl.org/dc/terms/',
27             rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
28             '#default' => "http://xmlns.com/foaf/0.1/"
29             }
30             );
31             my $obj = $rdf->get_object('http://dahut.pm.org/dahut_group.rdf#bender');
32             $obj->rdf_type('http://xmlns.com/foaf/0.1/Person');
33             $obj->name("Bender");
34             $obj->dc_description("A description of Bender");
35             print $rdf->serialize(format => 'rdfxml')
36              
37             =head1 DESCRIPTION
38              
39             An object of this class is returned by the L<RDF::Helper>
40             C<get_object> method, which takes a B<subject> URI as the first
41             argument, and optionally a hash or hashref of options as the second
42             argument.
43              
44             On this object, you may then call methods that correspond to property
45             names of the properties you want to get or set.
46              
47             For properties in the default namespace, you may use them without any
48             regard to prefixes, whereas with properties in other namespaces, you
49             need to use the prefix and an underscore before the property name.
50              
51             This class does not make any attempt to verify whether the methods are
52             actually valid properties within the used schema, it just blindly does
53             what you tell it to.
54              
55             =cut
56              
57             sub new {
58 0     0 0   my $proto = shift;
59 0           my %args;
60 0 0         if ($#_ % 2) {
61 0           %args = @_;
62             } else {
63 0           my $ResourceURI = shift;
64 0           %args = @_;
65 0           $args{ResourceURI} = $ResourceURI;
66             }
67 0   0       my $class = ref( $proto ) || $proto;
68              
69 0           my $self = {};
70 0           $self->{_datastore_} = $args{RDFHelper};
71 0           my $ug = new Data::UUID;
72 0           my $uuid = $ug->create();
73              
74 0   0       $self->{_uri_} = $args{ResourceURI} || "urn:" . $ug->to_string( $uuid );
75              
76 0           $self->{_rdftype_} = $args{RDFType};
77 0   0       $self->{_defaultns_} = $args{DefaultNS} || $self->{_datastore_}->namespaces->{'#default'} || '';
78            
79 0 0 0       if ( defined( $args{NoTie} ) and $args{NoTie} == 1 ) {
80             $self->{_data_} = $self->{_datastore_}->property_hash(
81             $self->{_uri_}
82 0           );
83 0           $self->{_tied_} = 0;
84             }
85             else {
86 0 0         unless (defined( $args{TiedHashOptions} )) {
87 0           $args{TiedHashOptions}->{Deep} = 1;
88             }
89             $self->{_data_} = $self->{_datastore_}->tied_property_hash(
90             $self->{_uri_},
91             $args{TiedHashOptions}
92 0           );
93 0           $self->{_tied_} = 1;
94             }
95            
96             #warn "inired with data" . Dumper( $self->{_data_} );
97            
98 0           my $obj = bless $self, $class;
99            
100             # init for new objects
101 0           $obj->object_init_internal;
102              
103 0           return $obj;
104             }
105              
106             sub object_default_namespace {
107 0     0 0   my $self = shift;
108 0 0         if ( @_ ) {
109 0           $self->{_defaultns_} = shift;
110             }
111 0           return $self->{_defaultns_};
112             }
113              
114             sub object_init_internal {
115 0     0 0   my $self = shift;
116 0 0         unless ( defined( $self->{_data_}->{'rdf:type'} ) ) {
117 0           my $type = $self->object_rdfclasstype;
118 0 0         $self->{_data_}->{'rdf:type'} = $type if ($type);
119             }
120             }
121              
122             sub object_is_tied {
123 0     0 0   my $self = shift;
124 0           return $self->{_tied_};
125             }
126              
127             sub object_uri {
128 0     0 0   my $self = shift;
129 0           return $self->{_uri_};
130             }
131              
132             sub object_uri_equals {
133 0     0 0   my $self = shift;
134 0           my $value = shift;
135 0           return $self->object_uri eq $value;
136             }
137              
138             sub object_datastore {
139 0     0 0   my $self = shift;
140 0           return $self->{_datastore_};
141             }
142              
143             sub object_rdfclasstype {
144 0     0 0   my $self = shift;
145 0 0 0       if ( $#_ > -1 and $_[0] ) {
146 0           $self->{_rdftype_} = shift;
147             }
148 0 0         if ($self->{_rdftype_}) {
149 0           return $self->{_rdftype_};
150             } else {
151 0           return $self->{_data_}->{'rdf:type'};
152             }
153             }
154              
155             sub object_data {
156 0     0 0   my $self = shift;
157 0           my $new = shift;
158 0 0         if ( $new ) {
159             # this is a little different since its a tied hash
160 0           %{$self->{_data_}} = ();
  0            
161 0           foreach my $key ( keys( %{$new} ) ) {
  0            
162 0           $self->{_data_}->{$key} = $new->{$key};
163             }
164 0           $self->object_init_internal;
165 0           return 1;
166             }
167             # don'[t cough up the tied data, give a copy
168             # and add the internal properties
169 0           my $clone = {};
170 0           foreach my $k ( keys( %{$self->{_data_}} ) ) {
  0            
171 0           $clone->{$k} = $self->{_data_}->{$k};
172             }
173 0           $clone->{object_uri} = $self->object_uri;
174            
175             #warn "returning clone" . Dumper( $clone );
176 0           return $clone;
177             }
178              
179             sub AUTOLOAD {
180             # don't DESTROY
181 0 0   0     return if $AUTOLOAD =~ /::DESTROY/;
182 0 0         die "Unknown method" if $AUTOLOAD =~ /::object_.*$/;
183              
184 0           my $self = $_[0];
185            
186             # fetch the attribute name
187 0           $AUTOLOAD =~ /.*::([a-zA-Z0-9_]+)/;
188 0           my $ns = $self->object_default_namespace;
189 0           my $attr = $1;
190 0           my $attr_uri = $ns . $attr;
191 0 0         if ($attr =~ /^([^_]+)_(.+)$/) {
192 0           my $nsprefix = $1;
193 0           my $nsattr = $2;
194 0 0         if ($self->{_datastore_}->namespaces->{$nsprefix}) {
195 0           $ns = $self->{_datastore_}->namespaces->{$nsprefix};
196 0           $attr = $nsprefix . ':' . $nsattr;
197 0           $attr_uri = $ns . $nsattr;
198             }
199             }
200              
201            
202 0 0         if ( $attr ) {
203 11     11   7568 no strict 'refs';
  11         15  
  11         2082  
204             # create the method
205 0           *{$AUTOLOAD} = sub {
206             #warn "accessor called: $attr";
207 0     0     my $self = shift;
208 0 0         if ( @_ ) {
209 0           my $val = shift;
210 0 0         unless( defined( $val ) ) {
211 0           delete $self->{_data_}->{$attr};
212 0           return 1;
213             }
214 0           $self->{_data_}->{$attr} = $val;
215 0           return 1;
216             }
217 0 0         if (defined $self->{_data_}->{$attr}) {
218 0           my $result = $self->{_data_}->{$attr};
219 0 0         my @results = ref($result) eq 'ARRAY' ? @$result : $result;
220 0 0         @results = map {ref($_) eq 'HASH' ? $self->{_datastore_}->get_object($_->{resource_uri}) : $_ } @results;
  0            
221 0 0         if ($#results > 0) {
222 0 0         return wantarray ? @results : \@results;
223             } else {
224 0           return $results[0];
225             }
226             }
227 0           return undef;
228 0           };
229             # now do it
230 0           goto &{$AUTOLOAD};
  0            
231             }
232             }
233              
234             1;