activerdf 1.2 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|