activerdf 1.2 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/lib/active_rdf/objectmanager/resource.rb +165 -146
- data/lib/active_rdf.rb +14 -14
- metadata +2 -2
data/Rakefile
CHANGED
@@ -23,6 +23,7 @@ module RDFS
|
|
23
23
|
def initialize uri
|
24
24
|
raise ActiveRdfError, "creating resource <#{uri}>" unless uri.is_a?(String)
|
25
25
|
@uri = uri
|
26
|
+
@predicates = Hash.new
|
26
27
|
end
|
27
28
|
|
28
29
|
# setting our own class uri to rdfs:resource
|
@@ -144,6 +145,10 @@ module RDFS
|
|
144
145
|
# 4. eyal.age is a custom-written method in class Person
|
145
146
|
# evidence: eyal type ?c, ?c.methods includes age
|
146
147
|
# action: inject age into eyal and invoke
|
148
|
+
#
|
149
|
+
# 5. eyal.age is registered abbreviation
|
150
|
+
# evidence: age in @predicates
|
151
|
+
# action: return object from triple (eyal, @predicates[age], ?o)
|
147
152
|
|
148
153
|
# maybe change order in which to check these, checking (4) is probably
|
149
154
|
# cheaper than (1)-(2) but (1) and (2) are probably more probable (getting
|
@@ -151,8 +156,8 @@ module RDFS
|
|
151
156
|
|
152
157
|
$activerdflog.debug "RDFS::Resource: method_missing on instance: called with method name #{method}"
|
153
158
|
|
154
|
-
# are we doing an update or not?
|
155
|
-
|
159
|
+
# are we doing an update or not?
|
160
|
+
# checking if method ends with '='
|
156
161
|
|
157
162
|
if method.to_s[-1..-1] == '='
|
158
163
|
methodname = method.to_s[0..-2]
|
@@ -162,161 +167,175 @@ module RDFS
|
|
162
167
|
update = false
|
163
168
|
end
|
164
169
|
|
170
|
+
# check possibility (5)
|
171
|
+
if @predicates.include?(methodname)
|
172
|
+
return predicate_invocation(@predicates[methodname], args, update)
|
173
|
+
end
|
174
|
+
|
165
175
|
candidates = if update
|
166
176
|
(class_level_predicates + direct_predicates).compact.uniq
|
167
177
|
else
|
168
178
|
direct_predicates
|
169
179
|
end
|
170
|
-
|
171
|
-
# checking possibility (1) and (3)
|
172
|
-
candidates.each do |pred|
|
173
|
-
if Namespace.localname(pred) == methodname
|
174
|
-
# found a property invocation of eyal: option 1) or 2)
|
175
|
-
# query execution will return either the value for the predicate (1)
|
176
|
-
# or nil (2)
|
177
|
-
if update
|
178
|
-
# TODO: delete old value if overwriting
|
179
|
-
# FederiationManager.delete(self, pred, nil)
|
180
|
-
|
181
|
-
# handling eyal.friends = [armin, andreas] --> expand array values
|
182
|
-
args.each do |value|
|
183
|
-
FederationManager.add(self, pred, value)
|
184
|
-
end
|
185
|
-
return args
|
186
|
-
else
|
187
|
-
# look into args, if it contains a hash with {:array => true} then
|
188
|
-
# we should not flatten the query results
|
189
|
-
return get_property_value(pred, args)
|
190
|
-
end
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
raise ActiveRdfError, "could not set #{methodname} to #{args}: no suitable
|
195
|
-
predicate found. Maybe you are missing some schema information?" if update
|
196
|
-
|
197
|
-
# get/set attribute value did not succeed, so checking option (2) and (4)
|
198
|
-
|
199
|
-
# checking possibility (2), it is not handled correctly above since we use
|
200
|
-
# direct_predicates instead of class_level_predicates. If we didn't find
|
201
|
-
# anything with direct_predicates, we need to try the
|
202
|
-
# class_level_predicates. Only if we don't find either, we
|
203
|
-
# throw "method_missing"
|
204
|
-
candidates = class_level_predicates
|
205
|
-
|
206
|
-
# if any of the class_level candidates fits the sought method, then we
|
207
|
-
# found situation (2), so we return nil or [] depending on the {:array =>
|
208
|
-
# true} value
|
209
|
-
if candidates.any?{|c| Namespace.localname(c) == methodname}
|
210
|
-
return_ary = args[0][:array] if args[0].is_a? Hash
|
211
|
-
if return_ary
|
212
|
-
return []
|
213
|
-
else
|
214
|
-
return nil
|
215
180
|
|
216
|
-
|
217
|
-
|
181
|
+
# checking possibility (1) and (3)
|
182
|
+
candidates.each do |pred|
|
183
|
+
if Namespace.localname(pred) == methodname
|
184
|
+
return predicate_invocation(pred, args, update)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
raise ActiveRdfError, "could not set #{methodname} to #{args}: no suitable
|
189
|
+
predicate found. Maybe you are missing some schema information?" if update
|
190
|
+
|
191
|
+
# get/set attribute value did not succeed, so checking option (2) and (4)
|
192
|
+
|
193
|
+
# checking possibility (2), it is not handled correctly above since we use
|
194
|
+
# direct_predicates instead of class_level_predicates. If we didn't find
|
195
|
+
# anything with direct_predicates, we need to try the
|
196
|
+
# class_level_predicates. Only if we don't find either, we
|
197
|
+
# throw "method_missing"
|
198
|
+
candidates = class_level_predicates
|
199
|
+
|
200
|
+
# if any of the class_level candidates fits the sought method, then we
|
201
|
+
# found situation (2), so we return nil or [] depending on the {:array =>
|
202
|
+
# true} value
|
203
|
+
if candidates.any?{|c| Namespace.localname(c) == methodname}
|
204
|
+
return_ary = args[0][:array] if args[0].is_a? Hash
|
205
|
+
if return_ary
|
206
|
+
return []
|
207
|
+
else
|
208
|
+
return nil
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
# checking possibility (4)
|
213
|
+
# TODO: implement search strategy to select in which class to invoke
|
214
|
+
# e.g. if to_s defined in Resource and in Person we should use Person
|
215
|
+
$activerdflog.debug "RDFS::Resource: method_missing option 4: custom class method"
|
216
|
+
self.type.each do |klass|
|
217
|
+
if klass.instance_methods.include?(method.to_s)
|
218
|
+
_dup = klass.new(uri)
|
219
|
+
return _dup.send(method,*args)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# if none of the three possibilities work out, we don't know this method
|
224
|
+
# invocation, but we don't want to throw NoMethodError, instead we return
|
225
|
+
# nil, so that eyal.age does not raise error, but returns nil. (in RDFS,
|
226
|
+
# we are never sure that eyal cannot have an age, we just dont know the
|
227
|
+
# age right now)
|
228
|
+
nil
|
229
|
+
end
|
218
230
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
231
|
+
# saves instance into datastore
|
232
|
+
def save
|
233
|
+
db = ConnectionPool.write_adapter
|
234
|
+
rdftype = Namespace.lookup(:rdf, :type)
|
235
|
+
types.each do |t|
|
236
|
+
db.add(self, rdftype, t)
|
237
|
+
end
|
238
|
+
|
239
|
+
Query.new.distinct(:p,:o).where(self, :p, :o).execute do |p, o|
|
240
|
+
db.add(self, p, o)
|
241
|
+
end
|
242
|
+
end
|
229
243
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
# age right now)
|
235
|
-
nil
|
236
|
-
end
|
237
|
-
|
238
|
-
# saves instance into datastore
|
239
|
-
def save
|
240
|
-
db = ConnectionPool.write_adapter
|
241
|
-
rdftype = Namespace.lookup(:rdf, :type)
|
242
|
-
types.each do |t|
|
243
|
-
db.add(self, rdftype, t)
|
244
|
+
def type
|
245
|
+
types.collect do |type|
|
246
|
+
ObjectManager.construct_class(type)
|
247
|
+
end
|
244
248
|
end
|
245
249
|
|
246
|
-
|
247
|
-
|
250
|
+
def add_predicate localname, fulluri
|
251
|
+
localname = localname.to_s
|
252
|
+
fulluri = RDFS::Resource.new(fulluri) if fulluri.is_a? String
|
253
|
+
|
254
|
+
# predicates is a hash from abbreviation string to full uri resource
|
255
|
+
@predicates[localname] = fulluri
|
248
256
|
end
|
249
|
-
end
|
250
257
|
|
251
|
-
def type
|
252
|
-
types.collect do |type|
|
253
|
-
ObjectManager.construct_class(type)
|
254
|
-
end
|
255
|
-
end
|
256
|
-
|
257
|
-
# overrides built-in instance_of? to use rdf:type definitions
|
258
|
-
def instance_of?(klass)
|
259
|
-
self.type.include?(klass)
|
260
|
-
end
|
261
|
-
|
262
|
-
# returns all predicates that fall into the domain of the rdf:type of this
|
263
|
-
# resource
|
264
|
-
def class_level_predicates
|
265
|
-
type = Namespace.lookup(:rdf, 'type')
|
266
|
-
domain = Namespace.lookup(:rdfs, 'domain')
|
267
|
-
Query.new.distinct(:p).where(self,type,:t).where(:p, domain, :t).execute || []
|
268
|
-
end
|
269
|
-
|
270
|
-
# returns all predicates that are directly defined for this resource
|
271
|
-
def direct_predicates(distinct = true)
|
272
|
-
if distinct
|
273
|
-
q = Query.new.distinct(:p)
|
274
|
-
else
|
275
|
-
q = Query.new.select(:p)
|
276
|
-
end
|
277
|
-
q.where(self,:p, :o).execute
|
278
|
-
end
|
279
|
-
|
280
|
-
def property_accessors
|
281
|
-
direct_predicates.collect {|pred| Namespace.localname(pred) }
|
282
|
-
end
|
283
|
-
|
284
|
-
# alias include? to ==, so that you can do paper.creator.include?(eyal)
|
285
|
-
# without worrying whether paper.creator is single- or multi-valued
|
286
|
-
alias include? ==
|
287
|
-
|
288
|
-
# returns uri of resource, can be overridden in subclasses
|
289
|
-
def to_s
|
290
|
-
"<#{uri}>"
|
291
|
-
end
|
292
|
-
|
293
|
-
# # label of resource (rdfs:label if available, uri otherwise)
|
294
|
-
# def label
|
295
|
-
# get_property_value(Namespace.lookup(:rdfs,:label)) || uri
|
296
|
-
# end
|
297
|
-
|
298
|
-
private
|
299
|
-
def get_property_value(predicate, args=[])
|
300
|
-
return_ary = args[0][:array] if args[0].is_a?(Hash)
|
301
|
-
flatten_results = !return_ary
|
302
|
-
query = Query.new.distinct(:o).where(self, predicate, :o)
|
303
|
-
query.execute(:flatten => flatten_results)
|
304
|
-
end
|
305
|
-
|
306
|
-
# returns all rdf:types of this resource
|
307
|
-
def types
|
308
|
-
type = Namespace.lookup(:rdf, :type)
|
309
|
-
|
310
|
-
# we lookup the type in the database
|
311
|
-
types = Query.new.distinct(:t).where(self,type,:t).execute
|
312
|
-
|
313
|
-
# we are also always of type rdfs:resource and of our own class (e.g. foaf:Person)
|
314
|
-
defaults = []
|
315
|
-
defaults << Namespace.lookup(:rdfs,:Resource)
|
316
|
-
defaults << self.class.class_uri
|
317
|
-
|
318
|
-
(types + defaults).uniq
|
319
|
-
end
|
320
258
|
|
321
|
-
|
259
|
+
# overrides built-in instance_of? to use rdf:type definitions
|
260
|
+
def instance_of?(klass)
|
261
|
+
self.type.include?(klass)
|
262
|
+
end
|
263
|
+
|
264
|
+
# returns all predicates that fall into the domain of the rdf:type of this
|
265
|
+
# resource
|
266
|
+
def class_level_predicates
|
267
|
+
type = Namespace.lookup(:rdf, 'type')
|
268
|
+
domain = Namespace.lookup(:rdfs, 'domain')
|
269
|
+
Query.new.distinct(:p).where(self,type,:t).where(:p, domain, :t).execute || []
|
270
|
+
end
|
271
|
+
|
272
|
+
# returns all predicates that are directly defined for this resource
|
273
|
+
def direct_predicates(distinct = true)
|
274
|
+
if distinct
|
275
|
+
q = Query.new.distinct(:p)
|
276
|
+
else
|
277
|
+
q = Query.new.select(:p)
|
278
|
+
end
|
279
|
+
direct = q.where(self,:p, :o).execute
|
280
|
+
return (direct + direct.collect {|d| ancestors(d)}).flatten.uniq
|
281
|
+
end
|
282
|
+
|
283
|
+
def property_accessors
|
284
|
+
direct_predicates.collect {|pred| Namespace.localname(pred) }
|
285
|
+
end
|
286
|
+
|
287
|
+
# alias include? to ==, so that you can do paper.creator.include?(eyal)
|
288
|
+
# without worrying whether paper.creator is single- or multi-valued
|
289
|
+
alias include? ==
|
290
|
+
|
291
|
+
# returns uri of resource, can be overridden in subclasses
|
292
|
+
def to_s
|
293
|
+
"<#{uri}>"
|
294
|
+
end
|
295
|
+
|
296
|
+
# # label of resource (rdfs:label if available, uri otherwise)
|
297
|
+
# def label
|
298
|
+
# get_property_value(Namespace.lookup(:rdfs,:label)) || uri
|
299
|
+
# end
|
300
|
+
|
301
|
+
private
|
302
|
+
|
303
|
+
def ancestors(predicate)
|
304
|
+
subproperty = Namespace.lookup(:rdfs,:subPropertyOf)
|
305
|
+
Query.new.distinct(:p).where(predicate, subproperty, :p).execute
|
306
|
+
end
|
307
|
+
|
308
|
+
def predicate_invocation(predicate, args, update)
|
309
|
+
if update
|
310
|
+
args.each do |value|
|
311
|
+
FederationManager.add(self, predicate, value)
|
312
|
+
end
|
313
|
+
args
|
314
|
+
else
|
315
|
+
get_property_value(predicate, args)
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
def get_property_value(predicate, args=[])
|
320
|
+
return_ary = args[0][:array] if args[0].is_a?(Hash)
|
321
|
+
flatten_results = !return_ary
|
322
|
+
query = Query.new.distinct(:o).where(self, predicate, :o)
|
323
|
+
query.execute(:flatten => flatten_results)
|
324
|
+
end
|
325
|
+
|
326
|
+
# returns all rdf:types of this resource
|
327
|
+
def types
|
328
|
+
type = Namespace.lookup(:rdf, :type)
|
329
|
+
|
330
|
+
# we lookup the type in the database
|
331
|
+
types = Query.new.distinct(:t).where(self,type,:t).execute
|
332
|
+
|
333
|
+
# we are also always of type rdfs:resource and of our own class (e.g. foaf:Person)
|
334
|
+
defaults = []
|
335
|
+
defaults << Namespace.lookup(:rdfs,:Resource)
|
336
|
+
defaults << self.class.class_uri
|
337
|
+
|
338
|
+
(types + defaults).uniq
|
339
|
+
end
|
340
|
+
end
|
322
341
|
end
|
data/lib/active_rdf.rb
CHANGED
@@ -27,20 +27,20 @@ def load_adapter s
|
|
27
27
|
end
|
28
28
|
|
29
29
|
require 'rubygems'
|
30
|
-
#determine
|
31
|
-
if Gem::cache
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
30
|
+
# determine whether activerdf is installed as a gem:
|
31
|
+
if Gem::cache.search(/^activerdf$/).empty?
|
32
|
+
# we are not running as a gem
|
33
|
+
$activerdflog.info 'ActiveRDF is NOT installed as a Gem'
|
34
|
+
load_adapter this_dir + '/../activerdf-rdflite/lib/activerdf_rdflite/rdflite'
|
35
|
+
load_adapter this_dir + '/../activerdf-rdflite/lib/activerdf_rdflite/fetching'
|
36
|
+
load_adapter this_dir + '/../activerdf-rdflite/lib/activerdf_rdflite/suggesting'
|
37
|
+
load_adapter this_dir + '/../activerdf-redland/lib/activerdf_redland/redland'
|
38
|
+
load_adapter this_dir + '/../activerdf-sparql/lib/activerdf_sparql/sparql'
|
39
|
+
load_adapter this_dir + '/../activerdf-yars/lib/activerdf_yars/jars2'
|
40
40
|
else
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
41
|
+
# we are running as a gem
|
42
|
+
require 'gem_plugin'
|
43
|
+
$activerdflog.info 'ActiveRDF is installed as a Gem'
|
44
|
+
GemPlugin::Manager.instance.load "activerdf" => GemPlugin::INCLUDE
|
45
45
|
end
|
46
46
|
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: activerdf
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version:
|
7
|
-
date:
|
6
|
+
version: 1.2.1
|
7
|
+
date: 2007-01-30 00:00:00 +00:00
|
8
8
|
summary: Offers object-oriented access to RDF (with adapters to several datastores).
|
9
9
|
require_paths:
|
10
10
|
- lib
|