activerdf_net7 1.6.16 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. data/CHANGELOG +63 -0
  2. data/activerdf-jena/lib/activerdf_jena/jena.rb +4 -4
  3. data/activerdf-jena/lib/activerdf_jena/jena_adapter.rb +55 -55
  4. data/activerdf-jena/lib/activerdf_jena/lucene.rb +1 -1
  5. data/activerdf-jena/lib/activerdf_jena/ng4j.rb +7 -7
  6. data/activerdf-jena/lib/activerdf_jena/ng4j_adapter.rb +47 -47
  7. data/activerdf-jena/lib/activerdf_jena/pellet.rb +1 -1
  8. data/activerdf-jena/test/test_jena_adapter.rb +121 -120
  9. data/activerdf-jena/test/test_ng4j_adapter.rb +111 -110
  10. data/activerdf-rdflite/lib/activerdf_rdflite/fetching.rb +23 -19
  11. data/activerdf-rdflite/lib/activerdf_rdflite/rdflite.rb +153 -277
  12. data/activerdf-rdflite/lib/activerdf_rdflite/suggesting.rb +2 -2
  13. data/activerdf-rdflite/test/test_fetching.rb +7 -22
  14. data/activerdf-rdflite/test/test_rdflite.rb +44 -257
  15. data/activerdf-redland/lib/activerdf_redland/redland.rb +246 -282
  16. data/activerdf-redland/test/test_redland_adapter.rb +62 -224
  17. data/activerdf-sesame/ext/wrapper-sesame2.jar +0 -0
  18. data/activerdf-sesame/java/build.number +2 -2
  19. data/activerdf-sesame/java/build.xml +0 -0
  20. data/activerdf-sesame/java/lib/junit-3.8.2.jar +0 -0
  21. data/activerdf-sesame/java/settings.xml +0 -0
  22. data/activerdf-sesame/java/src/org/activerdf/wrapper/sesame2/WrapperForSesame2.java +0 -0
  23. data/activerdf-sesame/java/temp/build/org/activerdf/wrapper/sesame2/WrapperForSesame2.class +0 -0
  24. data/activerdf-sesame/java/temp/manifest/MANIFEST.MF +2 -2
  25. data/activerdf-sesame/java/test-src/org/activerdf/wrapper/sesame2/TestWrapperForSesame2.java +0 -0
  26. data/activerdf-sesame/lib/activerdf_sesame/sesame.rb +360 -364
  27. data/activerdf-sesame/test/test_sesame_adapter.rb +85 -83
  28. data/activerdf-sparql/lib/activerdf_sparql/sparql.rb +147 -148
  29. data/activerdf-sparql/lib/activerdf_sparql/sparql_result_parser.rb +5 -5
  30. data/activerdf-sparql/test/test_sparql_adapter.rb +2 -0
  31. data/activerdf-yars/lib/activerdf_yars/jars2.rb +85 -83
  32. data/lib/active_rdf/federation/active_rdf_adapter.rb +26 -39
  33. data/lib/active_rdf/federation/connection_pool.rb +119 -110
  34. data/lib/active_rdf/federation/federation_manager.rb +51 -51
  35. data/lib/active_rdf/objectmanager/bnode.rb +8 -2
  36. data/lib/active_rdf/objectmanager/literal.rb +81 -50
  37. data/lib/active_rdf/objectmanager/namespace.rb +117 -84
  38. data/lib/active_rdf/objectmanager/object_manager.rb +101 -96
  39. data/lib/active_rdf/objectmanager/ordered_set.rb +1 -1
  40. data/lib/active_rdf/objectmanager/property.rb +345 -0
  41. data/lib/active_rdf/objectmanager/property_list.rb +4 -4
  42. data/lib/active_rdf/objectmanager/property_lookup.rb +57 -0
  43. data/lib/active_rdf/objectmanager/resource.rb +293 -501
  44. data/lib/active_rdf/objectmanager/resource_like.rb +2 -2
  45. data/lib/active_rdf/objectmanager/resource_query.rb +85 -0
  46. data/lib/active_rdf/queryengine/ntriples_parser.rb +75 -68
  47. data/lib/active_rdf/queryengine/query.rb +237 -183
  48. data/lib/active_rdf/queryengine/query2jars2.rb +17 -15
  49. data/lib/active_rdf/queryengine/query2sparql.rb +107 -101
  50. data/lib/active_rdf.rb +28 -17
  51. data/lib/active_rdf_helpers.rb +37 -5
  52. data/lib/active_rdf_log.rb +11 -11
  53. data/test/adapters/test_activerdf_adapter.rb +138 -0
  54. data/test/{test_adapters.rb → adapters/test_adapters.rb} +6 -24
  55. data/test/adapters/test_bnode_capable_adapter.rb +31 -0
  56. data/test/adapters/test_context_aware_adapter.rb +31 -0
  57. data/test/adapters/test_network_aware_adapter.rb +29 -0
  58. data/test/adapters/test_persistent_adapter.rb +21 -0
  59. data/test/adapters/test_read_only_adapter.rb +15 -0
  60. data/test/adapters/test_reasoning_adapter.rb +11 -0
  61. data/test/adapters/test_writable_adapter.rb +163 -0
  62. data/test/common.rb +78 -96
  63. data/test/federation/test_connection_pool.rb +25 -44
  64. data/test/federation/test_federation_manager.rb +45 -45
  65. data/test/objectmanager/test_literal.rb +47 -26
  66. data/test/objectmanager/test_namespace.rb +3 -1
  67. data/test/objectmanager/test_object_manager.rb +35 -45
  68. data/test/objectmanager/test_ordered_set.rb +1 -1
  69. data/test/objectmanager/test_property.rb +261 -0
  70. data/test/objectmanager/test_resource_reading.rb +196 -104
  71. data/test/objectmanager/test_resource_reasoning.rb +26 -0
  72. data/test/objectmanager/test_resource_writing.rb +34 -25
  73. data/test/queryengine/my_external_resource.rb +5 -1
  74. data/test/queryengine/test_external_resource_class.rb +1 -8
  75. data/test/queryengine/test_ntriples_parser.rb +5 -3
  76. data/test/queryengine/test_query.rb +3 -3
  77. data/test/queryengine/test_query2jars2.rb +2 -2
  78. data/test/queryengine/test_query2sparql.rb +2 -2
  79. data/test/queryengine/test_query_engine.rb +46 -28
  80. metadata +16 -8
  81. data/activerdf-rdflite/test/test_bnode_data.nt +0 -5
  82. data/activerdf-rdflite/test/test_data.nt +0 -32
  83. data/activerdf-rdflite/test/test_escaped_data.nt +0 -2
  84. data/activerdf-redland/test/test_person_data.nt +0 -42
  85. data/test/objectmanager/test_talia_syntax.rb +0 -68
@@ -1,7 +1,7 @@
1
- # require 'active_rdf'
1
+ require 'active_rdf'
2
2
  require 'objectmanager/object_manager'
3
3
  require 'objectmanager/namespace'
4
- require 'objectmanager/property_list'
4
+ require 'queryengine/query'
5
5
  require 'instance_exec'
6
6
 
7
7
  module RDFS
@@ -9,601 +9,393 @@ module RDFS
9
9
  # including data lookup (e.g. eyal.age), data updates (e.g. eyal.age=20),
10
10
  # class-level lookup (Person.find_by_name 'eyal'), and class-membership
11
11
  # (eyal.class ...Person).
12
+ class RDFS::Resource
13
+ ##### #####
14
+ ##### class level methods #####
15
+ ##### #####
12
16
 
13
- class Resource
14
-
15
- include ResourceLike
16
-
17
- # adding accessor to the class uri:
18
- # the uri of the rdf resource being represented by this class
19
17
  class << self
20
18
  attr_accessor :class_uri
21
19
  end
22
20
 
23
- # uri of the resource (for instances of this class: rdf resources)
24
- attr_reader :uri
25
-
26
- # creates new resource representing an RDF resource
27
- def initialize uri
28
- @uri = case uri
29
- # allow Resource.new(other_resource)
30
- when RDFS::Resource
31
- uri.uri
32
- # allow Resource.new('<uri>') by stripping out <>
33
- when /^<([^>]*)>$/
34
- $1
35
- # allow Resource.new('uri')
36
- when String
37
- uri
38
- else
39
- raise ActiveRdfError, "cannot create resource <#{uri}>"
40
- end
41
- @predicates = Hash.new
21
+ def Resource.uri
22
+ class_uri.uri
42
23
  end
43
24
 
44
- # setting our own class uri to rdfs:resource
45
- # (has to be done after defining our RDFS::Resource.new
46
- # because it cannot be found in Namespace.lookup otherwise)
47
- self.class_uri = Namespace.lookup(:rdfs, :Resource)
48
-
49
- def self.uri; class_uri.uri; end
50
- def self.==(other)
25
+ def Resource.==(other)
51
26
  other.respond_to?(:uri) ? other.uri == self.uri : false
52
27
  end
53
- def self.localname; Namespace.localname(self); end
54
-
55
- ##### ######
56
- ##### start of instance-level code
57
- ##### ######
58
28
 
59
- def abbreviation; [Namespace.prefix(uri).to_s, localname]; end
60
- # a resource is same as another if they both represent the same uri
61
- def ==(other);
62
- other.respond_to?(:uri) ? other.uri == self.uri : false
29
+ def Resource.eql?(other)
30
+ self == other
63
31
  end
64
- alias_method 'eql?','=='
65
32
 
66
- # overriding hash to use uri.hash
67
- # needed for array.uniq
68
- def hash; uri.hash; end
69
-
70
- def self.to_ntriple; "<#{class_uri.uri}>"; end
71
-
72
- def to_xml
73
- base = Namespace.expand(Namespace.prefix(self),'').chop
74
-
75
- xml = "<?xml version=\"1.0\"?>\n"
76
- xml += "<rdf:RDF xmlns=\"#{base}\#\"\n"
77
- Namespace.abbreviations.each { |p| uri = Namespace.expand(p,''); xml += " xmlns:#{p.to_s}=\"#{uri}\"\n" if uri != base + '#' }
78
- xml += " xml:base=\"#{base}\">\n"
79
-
80
- xml += "<rdf:Description rdf:about=\"\##{localname}\">\n"
81
- direct_predicates.each do |p|
82
- objects = Query.new.distinct(:o).where(self, p, :o).execute
83
- objects.each do |obj|
84
- prefix, localname = Namespace.prefix(p), Namespace.localname(p)
85
- pred_xml = if prefix
86
- "%s:%s" % [prefix, localname]
87
- else
88
- p.uri
89
- end
90
-
91
- case obj
92
- when RDFS::Resource
93
- xml += " <#{pred_xml} rdf:resource=\"#{obj.uri}\"/>\n"
94
- when LocalizedString
95
- xml += " <#{pred_xml} xml:lang=\"#{obj.lang}\">#{obj}</#{pred_xml}>\n"
96
- else
97
- xml += " <#{pred_xml} rdf:datatype=\"#{obj.xsd_type.uri}\">#{obj}</#{pred_xml}>\n"
98
- end
99
- end
100
- end
101
- xml += "</rdf:Description>\n"
102
- xml += "</rdf:RDF>"
33
+ def Resource.localname
34
+ ActiveRDF::Namespace.localname(self)
103
35
  end
104
36
 
105
- ##### #####
106
- ##### class level methods #####
107
- ##### #####
108
-
109
37
  # returns the predicates that have this resource as their domain (applicable
110
38
  # predicates for this resource)
111
39
  def Resource.predicates
112
- domain = Namespace.lookup(:rdfs, :domain)
113
- Query.new.distinct(:p).where(:p, domain, class_uri).execute || []
40
+ class_uri.instance_predicates
114
41
  end
115
42
 
116
- # quick fix for "direct" getting of a property
117
- # return a PropertyCollection (see PropertyCollection class)
118
- def [](property)
119
- if !property.instance_of?(RDFS::Resource)
120
- property = RDFS::Resource.new(property)
121
- end
122
-
123
- plv = Query.new.distinct(:o).where(self, property, :o).execute
124
-
125
- # make and return new propertis collection
126
- PropertyList.new(property, plv, self)
43
+ def Resource.properties
44
+ predicates.collect{|prop| RDF::Property.new(prop)}
127
45
  end
128
46
 
129
- # manages invocations such as Person.find_by_name,
130
- # Person.find_by_foaf::name, Person.find_by_foaf::name_and_foaf::knows, etc.
131
- def Resource.method_missing(method, *args)
132
- if /find_by_(.+)/.match(method.to_s)
133
- ActiveRdfLogger::log_debug "Constructing dynamic finder for #{method}", self
134
-
135
- # construct proxy to handle delayed lookups
136
- # (find_by_foaf::name_and_foaf::age)
137
- proxy = DynamicFinderProxy.new($1, nil, *args)
138
-
139
- # if proxy already found a value (find_by_name) we will not get a more
140
- # complex query, so return the value. Otherwise, return the proxy so that
141
- # subsequent lookups are handled
142
- return proxy.value || proxy
143
- end
47
+ # Find all resources of this type
48
+ def Resource.find_all(options = {}, &blk)
49
+ ActiveRDF::ResourceQuery.new(self,options.delete(:context)).execute(options,&blk)
144
50
  end
145
51
 
146
- # returns array of all instances of this class (e.g. Person.find_all)
147
- # (always returns collection)
148
- def Resource.find_all(*args)
149
- find(:all, *args)
52
+ # Find resources of this type, restricted by optional property args
53
+ # see ActiveRDF::ResourceQuery usage
54
+ def Resource.find_by(context = nil)
55
+ ActiveRDF::ResourceQuery.new(self,context)
150
56
  end
151
57
 
152
- def Resource.find(*args)
153
- class_uri.find(*args)
58
+ # Find an existing resource with the given uri, otherwise returns nil
59
+ def Resource.find(uri)
60
+ res = Resource.new(uri)
61
+ res unless res.new_record?
154
62
  end
155
63
 
156
- ##### #####
157
- ##### instance level methods #####
158
- ##### #####
159
- def find(*args)
160
- # extract sort options from args
161
- options = args.last.is_a?(Hash) ? args.pop : {}
162
-
163
- query = Query.new.distinct(:s)
164
- query.where(:s, Namespace.lookup(:rdf,:type), self)
64
+ # Pass all other methods to class_uri
65
+ def Resource.method_missing(method,*args)
66
+ class_uri.send(method,*args)
67
+ end
165
68
 
166
- if options.include? :order
167
- sort_predicate = options[:order]
168
- query.sort(:sort_value)
169
- query.where(:s, sort_predicate, :sort_value)
170
- end
69
+ # uri of the resource (for instances of this class: rdf resources)
70
+ attr_reader :uri
171
71
 
172
- if options.include? :reverse_order
173
- sort_predicate = options[:reverse_order]
174
- query.reverse_sort(:sort_value)
175
- query.where(:s, sort_predicate, :sort_value)
176
- end
72
+ # creates new resource representing an RDF resource
73
+ def initialize(uri_or_resource)
74
+ @uri = case uri_or_resource
75
+ # allow Resource.new(other_resource)
76
+ when RDFS::Resource
77
+ uri_or_resource.uri
78
+ # allow Resource.new('<uri>') by stripping out <>
79
+ when /^<([^>]*)>$/
80
+ $1
81
+ # allow Resource.new('uri')
82
+ when String
83
+ uri_or_resource
84
+ else
85
+ raise ActiveRdfError, "cannot create resource <#{uri_or_resource}>"
86
+ end
87
+ end
177
88
 
178
- if options.include? :where
179
- raise ActiveRdfError, "where clause should be hash of predicate => object" unless options[:where].is_a? Hash
180
- options[:where].each do |p,o|
181
- if options.include? :context
182
- query.where(:s, p, o, options[:context])
183
- else
184
- query.where(:s, p, o)
185
- end
186
- end
187
- else
188
- if options[:context]
189
- query.where(:s, :p, :o, options[:context])
190
- end
191
- end
89
+ # setting our own class uri to rdfs:resource
90
+ # (has to be done after defining our RDFS::Resource.new
91
+ # because it cannot be found in ActiveRDF::Namespace.lookup otherwise)
92
+ self.class_uri = ActiveRDF::Namespace.lookup(:rdfs, :Resource)
192
93
 
193
- query.limit(options[:limit]) if options[:limit]
194
- query.offset(options[:offset]) if options[:offset]
94
+ ##### #####
95
+ ##### instance level methods #####
96
+ ##### #####
195
97
 
196
- if block_given?
197
- query.execute do |resource|
198
- yield resource
199
- end
200
- else
201
- query.execute(:flatten => false)
202
- end
98
+ # a resource is same as another if they both represent the same uri
99
+ def ==(other);
100
+ other.respond_to?(:uri) ? other.uri == self.uri : false
203
101
  end
102
+ alias_method 'eql?','=='
204
103
 
205
- def localname
206
- Namespace.localname(self)
104
+ # overriding hash to use uri.hash
105
+ # needed for array.uniq
106
+ def hash
107
+ uri.hash
207
108
  end
208
109
 
209
- # Simple query shortcut which return a special object created on-the-fly by which is
210
- # possible to directly obtain every distinct resources where:
211
- # property ==> specified by the user by [] operator
212
- # object ==> current Ruby object representing an RDF resource
213
- def inverse
214
- inverseobj = Object.new
215
- inverseobj.instance_variable_set(:@obj_uri, self)
216
-
217
- class <<inverseobj
218
-
219
- def [](property_uri)
220
- property = RDFS::Resource.new(property_uri)
221
- Query.new.distinct(:s).where(:s, property, @obj_uri).execute
222
- end
223
- private(:type)
224
- end
225
-
226
- return inverseobj
227
- end
228
-
229
- # manages invocations such as eyal.age
230
- def method_missing(method, *args,&block)
231
- # possibilities:
232
- # 1. eyal.age is a property of eyal (triple exists <eyal> <age> "30")
233
- # evidence: eyal age ?a, ?a is not nil (only if value exists)
234
- # action: return ?a
235
- #
236
- # 2. eyal's class is in domain of age, but does not have value for eyal
237
- # explain: eyal is a person and some other person (not eyal) has an age
238
- # evidence: eyal type ?c, age domain ?c
239
- # action: return nil
240
- #
241
- # 3. eyal.age = 30 (setting a value for a property)
242
- # explain: eyal has (or could have) a value for age, and we update that value
243
- # complication: we need to find the full URI for age (by looking at
244
- # possible predicates to use
245
- # evidence: eyal age ?o (eyal has a value for age now, we're updating it)
246
- # evidence: eyal type ?c, age domain ?c (eyal could have a value for age, we're setting it)
247
- # action: add triple (eyal, age, 30), return 30
248
- #
249
- # 4. eyal.age is a custom-written method in class Person
250
- # evidence: eyal type ?c, ?c.methods includes age
251
- # action: inject age into eyal and invoke
252
- #
253
- # 5. eyal.age is registered abbreviation
254
- # evidence: age in @predicates
255
- # action: return object from triple (eyal, @predicates[age], ?o)
256
- #
257
- # 6. eyal.foaf::name, where foaf is a registered abbreviation
258
- # evidence: foaf in Namespace.
259
- # action: return namespace proxy that handles 'name' invocation, by
260
- # rewriting into predicate lookup (similar to case (5)
261
-
262
- ActiveRdfLogger.log_debug(self) { "Method_missing: #{method}" }
263
-
264
- # are we doing an update or not?
265
- # checking if method ends with '='
266
-
267
- update = method.to_s[-1..-1] == '='
268
- methodname = if update
269
- method.to_s[0..-2]
270
- else
271
- method.to_s
272
- end
273
-
274
- # extract single values from array unless user asked for eyal.all_age
275
- flatten = true
276
- if method.to_s[0..3] == 'all_'
277
- flatten = false
278
- methodname = methodname[4..-1]
279
- end
280
-
281
- # check possibility (5)
282
- if @predicates.include?(methodname)
283
- if update
284
- return set_predicate(@predicates[methodname], args)
285
- else
286
- return get_predicate(@predicates[methodname], false, &block)
287
- end
288
- end
289
-
290
- # check possibility (6)
291
- if Namespace.abbreviations.include?(methodname.to_sym)
292
- namespace = Object.new
293
- namespace.instance_variable_set(:@uri, methodname)
294
- namespace.instance_variable_set(:@subject, self)
295
- namespace.instance_variable_set(:@flatten, flatten)
296
-
297
- # catch the invocation on the namespace
298
- class <<namespace
299
- def method_missing(localname, *values, &block)
300
- update = localname.to_s[-1..-1] == '='
301
- predicate = if update
302
- Namespace.lookup(@uri, localname.to_s[0..-2])
303
- else
304
- Namespace.lookup(@uri, localname)
305
- end
110
+ # overriding sort based on uri
111
+ def <=>(other)
112
+ uri <=> other.uri
113
+ end
306
114
 
307
- if update
308
- @subject.set_predicate(predicate, values)
309
- else
310
- @subject.get_predicate(predicate, @flatten, &block)
311
- end
312
- end
313
- private(:type)
314
- end
315
- return namespace
316
- end
115
+ def is_a?(klass)
116
+ klass = ActiveRDF::ObjectManager.construct_class(klass)
117
+ super || types.any?{|t| klass == t}
118
+ end
317
119
 
318
- candidates = if update
319
- (class_level_predicates + direct_predicates).compact.uniq
320
- else
321
- direct_predicates
322
- end
120
+ def instance_of?(klass)
121
+ klass = ActiveRDF::ObjectManager.construct_class(klass)
122
+ super || direct_types.any?{|t| klass == t}
123
+ end
323
124
 
324
- # checking possibility (1) and (3)
325
- candidates.each do |pred|
326
- if Namespace.localname(pred) == methodname
327
- if update
328
- return set_predicate(pred, args)
329
- else
330
- return get_predicate(pred, flatten, &block)
331
- end
332
- end
333
- end
125
+ def new_record?
126
+ ActiveRDF::Query.new.count(:p).where(self,:p,:o).execute == 0
127
+ end
334
128
 
335
- raise ActiveRdfError, "Could not set #{methodname} to #{args}: no suitable predicate found. Maybe you are missing some schema information?" if update
336
-
337
- # get/set attribute value did not succeed, so checking option (2) and (4)
338
-
339
- # checking possibility (2), it is not handled correctly above since we use
340
- # direct_predicates instead of class_level_predicates. If we didn't find
341
- # anything with direct_predicates, we need to try the
342
- # class_level_predicates. Only if we don't find either, we
343
- # throw "method_missing"
344
- candidates = class_level_predicates
345
-
346
- # if any of the class_level candidates fits the sought method, then we
347
- # found situation (2), so we return nil or [] depending on the {:array =>
348
- # true} value
349
- if candidates.any?{ |c| Namespace.localname(c) == methodname }
350
- return_ary = args[0][:array] if args[0].is_a? Hash
351
- if return_ary
352
- return []
353
- else
354
- return nil
355
- end
356
- end
129
+ # saves instance into datastore
130
+ def save
131
+ ActiveRDF::ConnectionPool.write_adapter.add(self,RDF::type,self.class)
132
+ self
133
+ end
357
134
 
358
- # checking possibility (4)
359
- # TODO: implement search strategy to select in which class to invoke
360
- # e.g. if to_s defined in Resource and in Person we should use Person
361
- ActiveRdfLogger::log_debug(self){ "RDFS::Resource: method_missing option 4: custom class method" }
362
- self.type.each do |klass|
363
- if klass.instance_methods.include?(method.to_s)
364
- _dup = klass.new(uri)
365
- return _dup.send(method,*args)
366
- end
367
- end
135
+ def abbreviation
136
+ [ActiveRDF::Namespace.prefix(uri).to_s, localname]
137
+ end
368
138
 
369
- # if none of the three possibilities work out, we don't know this method
370
- # invocation, but we don't want to throw NoMethodError, instead we return
371
- # nil, so that eyal.age does not raise error, but returns nil. (in RDFS,
372
- # we are never sure that eyal cannot have an age, we just dont know the
373
- # age right now)
374
- nil
139
+ # get an abbreviation from to_s
140
+ # returns a copy of uri if no abbreviation found
141
+ def abbr
142
+ (abbr = ActiveRDF::Namespace.abbreviate(uri)) ? abbr : uri
375
143
  end
376
144
 
377
- # saves instance into datastore
378
- def save
379
- db = ConnectionPool.write_adapter
380
- rdftype = Namespace.lookup(:rdf, :type)
381
- types.each do |t|
382
- db.add(self, rdftype, t)
383
- end
145
+ # checks if an abbrivation exists for this resource
146
+ def abbr?
147
+ ActiveRDF::Namespace.prefix(self) ? true : false
148
+ end
384
149
 
385
- Query.new.distinct(:p,:o).where(self, :p, :o).execute do |p, o|
386
- db.add(self, p, o)
387
- end
150
+ def localname
151
+ ActiveRDF::Namespace.localname(self)
388
152
  end
389
153
 
390
- # returns all rdf:type of this instance, e.g. [RDFS::Resource,
391
- # FOAF::Person]
154
+ # returns an RDF::Property for RDF::type's of this resource, e.g. [RDFS::Resource, FOAF::Person]
392
155
  #
393
- # Note: this method performs a database lookup for { self rdf:type ?o }. For
394
- # simple type-checking (to know if you are handling an ActiveRDF object, use
395
- # self.class, which does not do a database query, but simply returns
156
+ # Note: this method performs a database lookup for { self rdf:type ?o }.
157
+ # For simple type-checking (to know if you are handling an ActiveRDF object,
158
+ # use self.class, which does not do a database query, but simply returns
396
159
  # RDFS::Resource.
397
160
  def type
398
- types.collect do |type|
399
- ObjectManager.construct_class(type)
400
- end
161
+ RDF::Property.new(RDF::type, self)
401
162
  end
402
163
 
164
+ def type=(type)
165
+ RDF::Property.new(RDF::type, self).replace(type)
166
+ end
167
+
168
+ def types
169
+ type.to_a | [RDFS::Resource.class_uri] # all resources are subtype of RDFS::Resource
170
+ end
171
+ alias :direct_types :types
172
+
173
+ # returns array of Classes for all types
174
+ def classes
175
+ types.collect{|type_res| ActiveRDF::ObjectManager.construct_class(type_res)}
176
+ end
177
+
178
+ # TODO: remove
403
179
  # define a localname for a predicate URI
404
180
  #
405
- # localname should be a Symbol or String, fulluri a Resource or String, e.g.
406
- # add_predicate(:name, FOAF::lastName)
407
- def add_predicate localname, fulluri
181
+ # localname should be a Symbol or String, fulluri a Resource or String, e.g.
182
+ # register_predicate(:name, FOAF::lastName)
183
+ def register_predicate(localname, fulluri)
184
+ warn "Registered predicates is deprecated. Please use registered namespaces instead."
408
185
  localname = localname.to_s
409
186
  fulluri = RDFS::Resource.new(fulluri) if fulluri.is_a? String
410
187
 
411
188
  # predicates is a hash from abbreviation string to full uri resource
412
- @predicates[localname] = fulluri
189
+ (@predicates ||= {})[localname] = fulluri
413
190
  end
414
191
 
192
+ # returns array of RDFS::Resources for properties that belong to this resource
193
+ def class_predicates
194
+ ActiveRDF::Query.new.distinct(:p).where(:p,RDFS::domain,:t).where(self,RDF::type,:t).execute |
195
+ ActiveRDF::Query.new.distinct(:p).where(:p,RDFS::domain,RDFS::Resource).execute # all resources share RDFS::Resource properties
196
+ end
197
+ alias class_level_predicates class_predicates
415
198
 
416
- # overrides built-in instance_of? to use rdf:type definitions
417
- def instance_of?(klass)
418
- self.type.include?(klass)
199
+ # returns array of RDF::Propertys for properties that belong to this resource
200
+ def class_properties
201
+ class_predicates.collect{|prop| RDF::Property.new(prop,self)}
419
202
  end
420
203
 
421
- # returns all predicates that fall into the domain of the rdf:type of this
422
- # resource
423
- def class_level_predicates
424
- type = Namespace.lookup(:rdf, 'type')
425
- domain = Namespace.lookup(:rdfs, 'domain')
426
- Query.new.distinct(:p).where(self,type,:t).where(:p, domain, :t).execute || []
204
+ # returns array of RDFS::Resources for properties that are directly defined for this resource
205
+ def direct_predicates
206
+ ActiveRDF::Query.new.distinct(:p).where(self,:p,:o).execute
427
207
  end
428
208
 
429
- # returns all predicates that are directly defined for this resource
430
- def direct_predicates(distinct = true)
431
- if distinct
432
- Query.new.distinct(:p).where(self, :p, :o).execute
433
- else
434
- Query.new.select(:p).where(self, :p, :o).execute
435
- end
209
+ # returns array of RDF::Propertys that are directly defined for this resource
210
+ def direct_properties
211
+ direct_predicates.collect{|prop| RDF::Property.new(prop,self)}
436
212
  end
437
213
 
438
- def property_accessors
439
- direct_predicates.collect {|pred| Namespace.localname(pred) }
214
+ # returns array of RDFS::Resources for all known properties of this resource
215
+ def predicates
216
+ direct_predicates | class_predicates
440
217
  end
441
218
 
442
- # alias include? to ==, so that you can do paper.creator.include?(eyal)
443
- # without worrying whether paper.creator is single- or multi-valued
444
- alias include? ==
219
+ # returns array of RDF::Propertys for all known properties of this resource
220
+ def properties
221
+ predicates.collect{|prop| RDF::Property.new(prop,self)}
222
+ end
445
223
 
446
- def set_predicate(predicate, values)
447
- FederationManager.delete(self, predicate, nil)
448
- values.flatten.each {|v| FederationManager.add(self, predicate, v) }
449
- values
224
+ # returns array RDFS::Resources for known properties that do not have a value
225
+ def empty_predicates
226
+ empty_properties.collect{|prop| RDFS::Resource.new(prop)}
450
227
  end
451
228
 
452
- def get_predicate(predicate, flatten=false,&block)
453
- query = Query.new.distinct(:o).where(self, predicate, :o)
454
- if block_given?
455
- yield query, :o
456
- end
457
- values = query.execute(:flatten => flatten)
458
-
459
- # TODO: fix '<<' for Fixnum values etc (we cannot use values.instance_eval
460
- # because Fixnum cannot do instace_eval, they're not normal classes)
461
- if values.is_a?(RDFS::Resource) and !values.nil?
462
- # prepare returned values for accepting << later, eg. in
463
- # eyal.foaf::knows << knud
464
- #
465
- # store @subject, @predicate in returned values
466
- values.instance_exec(self, predicate) do |s,p|
467
- @subj = s
468
- @pred = p
469
- end
229
+ # returns array RDF::Propertys for known properties that do not have a value
230
+ def empty_properties
231
+ properties.reject{|prop| prop.size > 0}
232
+ end
470
233
 
471
- # overwrite << to add triple to db
472
- values.instance_eval do
473
- def <<(value)
474
- FederationManager.add(@subj, @pred, value)
475
- end
476
- end
234
+ # for resources of type RDFS::Class, returns array of RDFS::Resources for the known properties of their objects
235
+ def instance_predicates
236
+ ip = ActiveRDF::Query.new.distinct(:p).where(:p,RDFS::domain,self).execute
237
+ if ip.size > 0
238
+ ip |= ActiveRDF::Query.new.distinct(:p).where(:p,RDFS::domain,RDFS::Resource).execute # all resources share RDFS::Resource properties
239
+ else []
477
240
  end
241
+ end
478
242
 
479
- values
243
+ # for resources of type RDFS::Class, returns array of RDF::Propertys for the known properties of their objects
244
+ def instance_properties
245
+ instance_predicates.collect{|prop| RDF::Property.new(prop,self)}
480
246
  end
481
247
 
482
- private
483
- # def ancestors(predicate)
484
- # subproperty = Namespace.lookup(:rdfs,:subPropertyOf)
485
- # Query.new.distinct(:p).where(predicate, subproperty, :p).execute
486
- # end
248
+ def contexts
249
+ ActiveRDF::Query.new.distinct(:c).where(self,nil,nil,:c).execute
250
+ end
487
251
 
252
+ if $activerdf_internal_reasoning
253
+ # Add support for some limited RDFS reasoning
488
254
 
489
- # returns all rdf:types of this resource but without a conversion to
490
- # Ruby classes (it returns an array of RDFS::Resources)
491
- def types
492
- type = Namespace.lookup(:rdf, :type)
255
+ ### Overidden methods
493
256
 
494
- # we lookup the type in the database
495
- types = Query.new.distinct(:t).where(self,type,:t).execute
257
+ # returns array of RDFS::Resources for all types, including supertypes
258
+ def types
259
+ types = self.type.to_a
260
+ types |= types.collect{|type| type.super_types}.flatten
261
+ types |= [RDFS::Resource.class_uri] # all resources are subtype of RDFS::Resource
262
+ types
263
+ end
496
264
 
497
- # we are also always of type rdfs:resource and of our own class (e.g. foaf:Person)
498
- defaults = []
499
- defaults << Namespace.lookup(:rdfs,:Resource)
500
- defaults << self.class.class_uri
265
+ # returns array of RDFS::Resources for the class properties of this resource, including those of its supertypes
266
+ def class_predicates
267
+ types.inject([]){|class_preds,type| class_preds |= type.instance_predicates}
268
+ end
501
269
 
502
- (types + defaults).uniq
503
- end
504
- end
505
- end
506
-
507
- # proxy to manage find_by_ invocations
508
- class DynamicFinderProxy
509
- @ns = nil
510
- @where = nil
511
- @value = nil
512
- attr_reader :value
513
- private(:type)
514
-
515
- # construct proxy from find_by text
516
- # foaf::name
517
- def initialize(find_string, where, *args)
518
- @where = where || []
519
- parse_attributes(find_string, *args)
520
- end
270
+ # for resources of type RDFS::Class, returns array of RDFS::Resources for the known properties of their objects, including those of its supertypes
271
+ def instance_predicates
272
+ preds = ActiveRDF::Query.new.distinct(:p).where(:p,RDFS::domain,self).execute
273
+ preds |= preds.collect{|p| p.super_predicates}.flatten
274
+ preds |= super_types.collect{|type| type.instance_predicates}.flatten
275
+ preds |= ActiveRDF::Query.new.distinct(:p).where(:p,RDFS::domain,RDFS::Resource).execute # all resources share RDFS::Resource properties
276
+ preds
277
+ end
521
278
 
522
- def method_missing(method, *args)
523
- # we store the ns:name for later (we need to wait until we have the
524
- # arguments before actually constructing the where clause): now we just
525
- # store that a where clause should appear about foaf:name
279
+ ### New methods
526
280
 
527
- # if this method is called name_and_foaf::age we add ourself to the query
528
- # otherwise, the query is built: we execute it and return the results
529
- if method.to_s.include?('_and_')
530
- parse_attributes(method.to_s, *args)
531
- else
532
- @where << Namespace.lookup(@ns, method.to_s)
533
- query(*args)
534
- end
535
- end
281
+ # for resources of type RDFS::Class, returns array of RDFS::Resources for all super types defined by RDF::subClassOf
282
+ def super_types
283
+ sups = ActiveRDF::Query.new.distinct(:super_class).where(self,RDFS::subClassOf,:super_class).execute
284
+ sups |= sups.inject([]){|supsups, sup| supsups |= sup.super_types}
285
+ end
536
286
 
537
- private
538
- # split find_string by occurrences of _and_
539
- def parse_attributes string, *args
540
- attributes = string.split('_and_')
541
- attributes.each do |atr|
542
- # attribute can be:
543
- # - a namespace prefix (foaf): store prefix in @ns to prepare for method_missing
544
- # - name (attribute name): store in where to prepare for method_missing
545
- if Namespace.abbreviations.include?(atr.to_sym)
546
- @ns = atr.to_s.downcase.to_sym
547
- else
548
- # found simple attribute label, e.g. 'name'
549
- # find out candidate (full) predicate for this localname: investigate
550
- # all possible predicates and select first one with matching localname
551
- candidates = Query.new.distinct(:p).where(:s,:p,:o).execute
552
- @where << candidates.select {|cand| Namespace.localname(cand) == atr}.first
287
+ # for resources of type RDFS::Class, returns array of classes for all super types defined by RDF::subClassOf
288
+ # otherwise returns empty array
289
+ def super_classes
290
+ super_types.collect{|type_res| ActiveRDF::ObjectManager.construct_class(type_res)}
553
291
  end
292
+
293
+ # for resources of type RDF::Property, returns array of RDFS::Resources for all super properties defined by RDFS::subPropertyOf
294
+ def super_predicates
295
+ sups = ActiveRDF::Query.new.distinct(:super_property).where(self, RDFS::subPropertyOf, :super_property).execute
296
+ sups |= sups.inject([]){|supsups, sup| supsups |= sup.super_predicates}
297
+ end
298
+
299
+ # for resources of type RDF::Property, returns array of RDF::Propertys for all super properties defined by RDFS::subPropertyOf
300
+ def super_properties
301
+ super_predicates.collect{|prop| RDF::Property.new(prop,self)}
302
+ end
303
+
304
+ # for resources of type RDF::Property, returns array of RDFS::Resources for all sub properties defined by RDFS::subPropertyOf
305
+ def sub_predicates
306
+ subs = ActiveRDF::Query.new.distinct(:sub_property).where(:sub_property, RDFS::subPropertyOf, self).execute
307
+ subs |= subs.inject([]){|subsubs, sub| subsubs |= sub.sub_predicates}
308
+ end
309
+
310
+ # for resources of type RDF::Property, returns array of RDF::Propertys for all sub properties defined by RDFS::subPropertyOf
311
+ def sub_properties
312
+ sub_predicates.collect{|prop| RDF::Property.new(prop,self)}
313
+ end
314
+
315
+ # end $activerdf_internal_reasoning
554
316
  end
555
317
 
556
- # if the last attribute was a prefix, return this dynamic finder (we'll
557
- # catch the following method_missing and construct the real query then)
558
- # if the last attribute was a localname, construct the query now and return
559
- # the results
560
- if Namespace.abbreviations.include?(attributes.last.to_sym)
561
- return self
562
- else
563
- return query(*args)
318
+ alias :to_s :uri
319
+ def to_literal_s
320
+ raise ActiveRDF::ActiveRdfError, "emtpy RDFS::Resources not allowed" if self.uri.size == 0
321
+ "<#{uri}>"
564
322
  end
565
- end
566
323
 
567
- # construct and execute finder query
568
- def query(*args)
569
- # extract options from args or use an empty hash (no options given)
570
- options = args.last.is_a?(Hash) ? args.last : {}
571
-
572
- # build query
573
- query = Query.new.distinct(:s)
574
- @where.each_with_index do |predicate, i|
575
- # specify where clauses, use context if given
576
- if options[:context]
577
- query.where(:s, predicate, args[i], options[:context])
324
+ def inspect
325
+ if ActiveRDF::ConnectionPool.adapters.size > 0
326
+ type =
327
+ if (t = self.type) and t.size > 0
328
+ t = t.collect{|res| res.abbr }
329
+ t.size > 1 ? t.inspect : t.first
330
+ else
331
+ self.class
332
+ end
333
+ label =
334
+ if abbr?
335
+ abbr
336
+ elsif (l = self.label) and l.size > 0
337
+ if l.size == 1 then l.only
338
+ else l.inspect
339
+ end
340
+ else
341
+ uri
342
+ end
578
343
  else
579
- query.where(:s, predicate, args[i])
344
+ type = self.class
345
+ label = self.uri
580
346
  end
347
+ "#<#{type} #{label}>"
581
348
  end
582
349
 
583
- # use sort order if given
584
- if options.include? :order
585
- sort_predicate = options[:order]
586
- query.sort(:sort_value)
587
- # add sort predicate where clause unless we have it already
588
- query.where(:s, sort_predicate, :sort_value) unless @where.include? sort_predicate
589
- end
350
+ def to_xml
351
+ base = ActiveRDF::Namespace.expand(ActiveRDF::Namespace.prefix(self),'').chop
590
352
 
591
- if options.include? :reverse_order
592
- sort_predicate = options[:reverse_order]
593
- query.reverse_sort(:sort_value)
594
- query.where(:s, sort_predicate, :sort_value) unless @where.include? sort_predicate
595
- end
353
+ xml = "<?xml version=\"1.0\"?>\n"
354
+ xml += "<rdf:RDF xmlns=\"#{base}\#\"\n"
355
+ ActiveRDF::Namespace.abbreviations.each { |p| uri = ActiveRDF::Namespace.expand(p,''); xml += " xmlns:#{p.to_s}=\"#{uri}\"\n" if uri != base + '#' }
356
+ xml += " xml:base=\"#{base}\">\n"
596
357
 
597
- query.limit(options[:limit]) if options[:limit]
598
- query.offset(options[:offset]) if options[:offset]
358
+ xml += "<rdf:Description rdf:about=\"\##{localname}\">\n"
359
+ direct_predicates.each do |p|
360
+ objects = ActiveRDF::Query.new.distinct(:o).where(self, p, :o).execute
361
+ objects.each do |obj|
362
+ prefix, localname = ActiveRDF::Namespace.prefix(p), ActiveRDF::Namespace.localname(p)
363
+ pred_xml = if prefix
364
+ "%s:%s" % [prefix, localname]
365
+ else
366
+ p.uri
367
+ end
599
368
 
600
- ActiveRdfLogger::log_debug(self) { "Executing dynamic finder: #{query.to_sp}" }
369
+ case obj
370
+ when RDFS::Resource
371
+ xml += " <#{pred_xml} rdf:resource=\"#{obj.uri}\"/>\n"
372
+ when LocalizedString
373
+ xml += " <#{pred_xml} xml:lang=\"#{obj.lang}\">#{obj}</#{pred_xml}>\n"
374
+ else
375
+ xml += " <#{pred_xml} rdf:datatype=\"#{obj.xsd_type.uri}\">#{obj}</#{pred_xml}>\n"
376
+ end
377
+ end
378
+ end
379
+ xml += "</rdf:Description>\n"
380
+ xml += "</rdf:RDF>"
381
+ end
382
+
383
+ # Searches for property belonging to this resource. Returns RDF::Property.
384
+ # Replaces any existing values if method is an assignment: resource.prop = new_value
385
+ def method_missing(method, *args)
386
+ # check for custom written method
387
+ # eyal.age is a custom-written method in class Person
388
+ # evidence: eyal type ?c, ?c.methods includes age
389
+ # action: return results from calling custom method
390
+ classes.each do |klass|
391
+ if klass.instance_methods.include?(method.to_s)
392
+ _dup = klass.new(uri)
393
+ return _dup.send(method,*args)
394
+ end
395
+ end
601
396
 
602
- # store the query results so that caller (Resource.method_missing) can
603
- # retrieve them (we cannot return them here, since we were invoked from
604
- # the initialize method so all return values are ignored, instead the proxy
605
- # itself is returned)
606
- @value = query.execute
607
- return @value
397
+ # otherwise pass search on to PropertyQuery
398
+ ActiveRDF::PropertyLookup.new(self).method_missing(method, *args)
399
+ end
608
400
  end
609
- end
401
+ end