activerdf 1.0 → 1.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/README CHANGED
@@ -1,5 +1,3 @@
1
- == Welcome to ActiveRDF
2
-
3
1
  ActiveRDF is a library for accessing RDF data from Ruby programs. It can be used
4
2
  as data layer in Ruby-on-Rails, similar to ActiveRecord (which provides an O/R
5
3
  mapping to relational databases). ActiveRDF in RoR allows you to create semantic
@@ -10,16 +8,23 @@ etc. programmatically, without queries.
10
8
  See http://www.activerdf.org for more information.
11
9
 
12
10
  == Getting Started
11
+
12
+ See http://wiki.activerdf.org/GettingStartedGuide for information on how to install
13
+ ActiveRDF, get it running with some data sources, and start using it.
14
+
15
+ == Simple Example
16
+
17
+ The following example uses a SPARQL endpoint with FOAF data and displays all
18
+ people found in the data source:
19
+
13
20
  require 'active_rdf'
14
21
  ConnectionPool.add_data_source :type => :sparql, :host => '...'
15
22
  Namespace.register :foaf, 'http://xmlns.com/foaf/0.1/'
16
23
  ObjectManager.construct_classes
17
24
  people = FOAF::Person.find_all
18
25
 
19
- See http://activerdf.org for more examples.
20
-
21
26
  == License
22
- ActiveRDF is distributed under the LGPL[link:../LICENSE] license.
27
+ ActiveRDF is distributed under the LGPL[link:http://www.gnu.org/licenses/lgpl.html] license.
23
28
 
24
29
  == Authors
25
30
  * Eyal Oren
data/Rakefile CHANGED
@@ -11,7 +11,19 @@ include FileUtils
11
11
  # setup tests and rdoc files
12
12
  setup_tests
13
13
  setup_clean ["pkg", "lib/*.bundle", "*.gem", ".config"]
14
- setup_rdoc ['README', 'LICENSE', 'lib/**/*.rb']
14
+
15
+ # setup rdoc task
16
+ #setup_rdoc ['README', 'LICENSE', 'lib/**/*.rb']
17
+ Rake::RDocTask.new do |rdoc|
18
+ files = ['README', 'LICENSE', 'lib/**/*.rb', 'doc/**/*.rdoc', 'test/*.rb']
19
+ files << 'activerdf-*/lib/**/*.rb'
20
+ rdoc.rdoc_files.add(files)
21
+ rdoc.main = "README" # page to start on
22
+ rdoc.title = "ActiveRDF documentation"
23
+ rdoc.template = "tools/allison/allison.rb"
24
+ rdoc.rdoc_dir = 'doc' # rdoc output folder
25
+ rdoc.options << '--line-numbers' << '--inline-source'
26
+ end
15
27
 
16
28
  # default task: install
17
29
  desc 'test and package gem'
@@ -1,11 +1,8 @@
1
- # Author:: Benjamin Heitmann
2
- # Copyright:: (c) 2005-2006
3
- # License:: LGPL
4
-
5
1
  require 'active_rdf'
6
2
  require 'queryengine/query2sparql'
7
3
 
8
- # generic superclass of all adapters
4
+ # Generic superclass of all adapters
5
+
9
6
  class ActiveRdfAdapter
10
7
  # indicate if adapter can read and write
11
8
  bool_accessor :reads, :writes
@@ -14,5 +11,4 @@ class ActiveRdfAdapter
14
11
  def translate(query)
15
12
  Query2SPARQL.translate(query)
16
13
  end
17
-
18
14
  end
@@ -1,13 +1,9 @@
1
- # Maintains pool of adapter instances that are connected to datasources
2
- # returns right adapter for a given datasource, by either reusing
3
- # existing adapter-instance or creating new adapter-instance
4
- #
5
- # Author:: Eyal Oren
6
- # Copyright:: (c) 2005-2006
7
- # License:: LGPL
8
-
9
1
  require 'active_rdf'
10
2
 
3
+ # Maintains pool of adapter instances that are connected to datasources. Returns
4
+ # right adapter for a given datasource, by either reusing an
5
+ # existing adapter-instance or creating new a adapter-instance.
6
+
11
7
  class ConnectionPool
12
8
  class << self
13
9
  attr_accessor :write_adapter
@@ -37,7 +33,7 @@ class ConnectionPool
37
33
 
38
34
  # clears the pool: removes all registered data sources
39
35
  def ConnectionPool.clear
40
- $log.info "ConnectionPool: clear called"
36
+ $activerdflog.info "ConnectionPool: clear called"
41
37
  @@adapter_pool = []
42
38
  @@adapter_parameters = []
43
39
  self.write_adapter = nil
@@ -59,7 +55,7 @@ class ConnectionPool
59
55
 
60
56
  # returns adapter-instance for given parameters (either existing or new)
61
57
  def ConnectionPool.add_data_source(connection_params)
62
- $log.info "ConnectionPool: add_data_source with params: #{connection_params.inspect}"
58
+ $activerdflog.info "ConnectionPool: add_data_source with params: #{connection_params.inspect}"
63
59
 
64
60
  # either get the adapter-instance from the pool
65
61
  # or create new one (and add it to the pool)
@@ -68,14 +64,14 @@ class ConnectionPool
68
64
  # adapter not in the pool yet: create it,
69
65
  # register its connection parameters in parameters-array
70
66
  # and add it to the pool (at same index-position as parameters)
71
- $log.debug("Create a new adapter for parameters #{connection_params.inspect}")
67
+ $activerdflog.debug("Create a new adapter for parameters #{connection_params.inspect}")
72
68
  adapter = create_adapter(connection_params)
73
69
  @@adapter_parameters << connection_params
74
70
  @@adapter_pool << adapter
75
71
  else
76
72
  # if adapter parametrs registered already,
77
73
  # then adapter must be in the pool, at the same index-position as its parameters
78
- $log.debug("Reusing existing adapter")
74
+ $activerdflog.debug("Reusing existing adapter")
79
75
  adapter = @@adapter_pool[index]
80
76
  end
81
77
 
@@ -85,6 +81,19 @@ class ConnectionPool
85
81
  return adapter
86
82
  end
87
83
 
84
+ # sets adapter-instance for connection parameters (if you want to re-enable an existing adapter)
85
+ def ConnectionPool.set_data_source(adapter, connection_params = {})
86
+ index = @@adapter_parameters.index(connection_params)
87
+ if index.nil?
88
+ @@adapter_parameters << connection_params
89
+ @@adapter_pool << adapter
90
+ else
91
+ @@adapter_pool[index] = adapter
92
+ end
93
+ self.write_adapter = adapter if adapter.writes?
94
+ adapter
95
+ end
96
+
88
97
  # aliasing add_data_source as add
89
98
  # (code bit more complicad since they are class methods)
90
99
  class << self
@@ -94,7 +103,7 @@ class ConnectionPool
94
103
  # adapter-types can register themselves with connection pool by
95
104
  # indicating which adapter-type they are
96
105
  def ConnectionPool.register_adapter(type, klass)
97
- $log.info "ConnectionPool: registering adapter of type #{type} for class #{klass}"
106
+ $activerdflog.info "ConnectionPool: registering adapter of type #{type} for class #{klass}"
98
107
  @@registered_adapter_types[type] = klass
99
108
  end
100
109
 
@@ -1,16 +1,12 @@
1
- # Manages the federation of datasources
2
- # distributes queries to right datasources and merges their results
3
- #
4
- # Author:: Eyal Oren
5
- # Copyright:: (c) 2005-2006
6
- # License:: LGPL
7
1
  require 'federation/connection_pool'
8
2
 
3
+ # Manages the federation of datasources: distributes queries to right
4
+ # datasources and merges their results
5
+
9
6
  class FederationManager
10
7
  # add triple s,p,o to the currently selected write-adapter
11
8
  def FederationManager.add(s,p,o)
12
9
  # TODO: allow addition of full graphs
13
- $log.debug "FederationManager: add: triple is #{s} #{p} #{o}"
14
10
  ConnectionPool.write_adapter.add(s,p,o)
15
11
  end
16
12
 
@@ -22,7 +18,6 @@ class FederationManager
22
18
  raise ActiveRdfError, "cannot execute query without data sources"
23
19
  end
24
20
 
25
- $log.debug "FederationManager: query called with: #{q}"
26
21
  # ask each adapter for query results
27
22
  # and yield them consequtively
28
23
  if block_given?
@@ -72,9 +67,6 @@ class FederationManager
72
67
  end
73
68
  end
74
69
 
75
- $log.debug_pp("FederationManager: query results are %s", final_results)
76
-
77
-
78
- return final_results
70
+ final_results
79
71
  end
80
72
  end
@@ -1,13 +1,8 @@
1
- # Manages namespace abbreviations and expansions
2
- #
3
- # Author:: Eyal Oren
4
- # Copyright:: (c) 2005-2006
5
- # License:: LGPL
6
-
7
1
  require 'active_rdf'
8
2
 
9
- class Namespace
3
+ # Manages namespace abbreviations and expansions
10
4
 
5
+ class Namespace
11
6
  @@namespaces = Hash.new
12
7
  @@inverted_namespaces = Hash.new
13
8
 
@@ -15,7 +10,7 @@ class Namespace
15
10
  # e.g. :rdf and 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
16
11
  def self.register(prefix, fullURI)
17
12
  raise ActiveRdfError, 'prefix nor uri can be empty' if (prefix.to_s.empty? or fullURI.to_s.empty?)
18
- $log.info "Namespace: registering #{fullURI} to #{prefix}"
13
+ $activerdflog.info "Namespace: registering #{fullURI} to #{prefix}"
19
14
  @@namespaces[prefix.to_sym] = fullURI.to_s
20
15
  @@inverted_namespaces[fullURI.to_s] = prefix.to_sym
21
16
  end
@@ -23,7 +18,6 @@ class Namespace
23
18
  # returns a resource whose URI is formed by concatenation of prefix and localname
24
19
  def self.lookup(prefix, localname)
25
20
  full_resource = expand(prefix, localname)
26
- $log.debug "Namespace: lookup for Resource #{full_resource} initiated"
27
21
  RDFS::Resource.new(expand(prefix, localname))
28
22
  end
29
23
 
@@ -1,15 +1,11 @@
1
- # Constructs Ruby classes for RDFS classes (in the right namespace)
2
- #
3
- # Author:: Eyal Oren
4
- # Copyright:: (c) 2005-2006
5
- # License:: LGPL
6
1
  require 'active_rdf'
7
2
 
3
+ # Constructs Ruby classes for RDFS classes (in the right namespace)
4
+
8
5
  class ObjectManager
9
- # constructs empty Ruby classes for all RDF types found in the data
10
- #
11
- # allows users to invoke methods on classes (e.g. FOAF::Person) without
12
- # getting symbol undefined errors (because e.g. foaf:person wasnt encountered
6
+ # Constructs empty Ruby classes for all RDF types found in the data. Allows
7
+ # users to invoke methods on classes (e.g. FOAF::Person) without
8
+ # getting symbol undefined errors (because e.g. foaf:person wasnt encountered
13
9
  # before so no class was created for it)
14
10
  def self.construct_classes
15
11
  # find all rdf:types and construct class for each of them
@@ -31,7 +27,7 @@ class ObjectManager
31
27
  # flattening to get rid of nested arrays
32
28
  # compacting array to get rid of nil (if one of these queries returned nil)
33
29
  klasses = klasses.flatten.compact
34
- $log.debug "ObjectManager: construct_classes: classes found: #{klasses}"
30
+ $activerdflog.debug "ObjectManager: construct_classes: classes found: #{klasses}"
35
31
 
36
32
  # then we construct a Ruby class for each found rdfs:class
37
33
  # and return the set of all constructed classes
@@ -51,31 +47,31 @@ class ObjectManager
51
47
  if prefix.nil?
52
48
  # if the prefix is unknown, we create our own from the full URI
53
49
  modulename = create_module_name(resource)
54
- $log.debug "ObjectManager: construct_class: constructing modulename #{modulename} from URI #{resource}"
50
+ $activerdflog.debug "ObjectManager: construct_class: constructing modulename #{modulename} from URI #{resource}"
55
51
  else
56
52
  # otherwise we convert the registered prefix into a module name
57
53
  modulename = prefix_to_module(prefix)
58
- $log.debug "ObjectManager: construct_class: constructing modulename #{modulename} from registered prefix #{prefix}"
54
+ $activerdflog.debug "ObjectManager: construct_class: constructing modulename #{modulename} from registered prefix #{prefix}"
59
55
  end
60
56
  klassname = localname_to_class(localname)
61
57
 
62
58
  # look whether module defined
63
59
  # else: create it
64
60
  _module = if Object.const_defined?(modulename.to_sym)
65
- $log.debug "ObjectManager: construct_class: module name #{modulename} previously defined"
61
+ $activerdflog.debug "ObjectManager: construct_class: module name #{modulename} previously defined"
66
62
  Object.const_get(modulename.to_sym)
67
63
  else
68
- $log.debug "ObjectManager: construct_class: defining module name #{modulename} now"
64
+ $activerdflog.debug "ObjectManager: construct_class: defining module name #{modulename} now"
69
65
  Object.const_set(modulename, Module.new)
70
66
  end
71
67
 
72
68
  # look whether class defined in that module
73
69
  if _module.const_defined?(klassname.to_sym)
74
- $log.debug "ObjectManager: construct_class: given class #{klassname} defined in the module"
70
+ $activerdflog.debug "ObjectManager: construct_class: given class #{klassname} defined in the module"
75
71
  # if so, return the existing class
76
72
  _module.const_get(klassname.to_sym)
77
73
  else
78
- $log.debug "ObjectManager: construct_class: creating given class #{klassname}"
74
+ $activerdflog.debug "ObjectManager: construct_class: creating given class #{klassname}"
79
75
  # otherwise: create it, inside that module, as subclass of RDFS::Resource
80
76
  # (using toplevel Class.new to prevent RDFS::Class.new from being called)
81
77
  klass = _module.module_eval("#{klassname} = Object::Class.new(RDFS::Resource)")
@@ -1,19 +1,14 @@
1
- # Represents an RDF resource and manages manipulations of that resource,
2
- # including data lookup (e.g. eyal.age), data updates (e.g. eyal.age=20),
3
- # class-level lookup (Person.find_by_name 'eyal'), and class-membership
4
- # (eyal.class ...Person)
5
- #
6
- # Author:: Eyal Oren
7
- # Copyright:: (c) 2005-2006
8
- # License:: LGPL
9
-
10
1
  require 'active_rdf'
11
2
  require 'objectmanager/object_manager'
12
3
  require 'objectmanager/namespace'
13
4
  require 'queryengine/query'
14
5
 
15
- # TODO: add unit test to validate class construction and queries on them
16
6
  module RDFS
7
+ # Represents an RDF resource and manages manipulations of that resource,
8
+ # including data lookup (e.g. eyal.age), data updates (e.g. eyal.age=20),
9
+ # class-level lookup (Person.find_by_name 'eyal'), and class-membership
10
+ # (eyal.class ...Person).
11
+
17
12
  class RDFS::Resource
18
13
  # adding accessor to the class uri:
19
14
  # the uri of the rdf resource being represented by this class
@@ -27,8 +22,6 @@ module RDFS
27
22
  # creates new resource representing an RDF resource
28
23
  def initialize uri
29
24
  raise ActiveRdfError, "creating resource <#{uri}>" unless uri.is_a?(String)
30
-
31
- # $log.debug "RDFS::Resource new: initializing new Resource with #{uri}"
32
25
  @uri = uri
33
26
  end
34
27
 
@@ -77,7 +70,7 @@ module RDFS
77
70
  def Resource.method_missing(method, *args)
78
71
  method_name = method.to_s
79
72
 
80
- $log.debug "RDFS::Resource: method_missing on class: called with method name #{method}"
73
+ $activerdflog.debug "RDFS::Resource: method_missing on class: called with method name #{method}"
81
74
 
82
75
  # extract predicates on which to match
83
76
  # e.g. find_by_name, find_by_name_and_age
@@ -102,12 +95,12 @@ module RDFS
102
95
  end
103
96
 
104
97
  # execute query
105
- $log.debug "RDFS::Resource: method_missing on class: executing query: #{query}"
106
- return query.execute
98
+ $activerdflog.debug "RDFS::Resource: method_missing on class: executing query: #{query}"
99
+ return query.execute(:flatten => true)
107
100
  end
108
101
 
109
102
  # otherwise, if no match found, raise NoMethodError (in superclass)
110
- $log.warn 'RDFS::Resource: method_missing on class: method not matching find_by_*'
103
+ $activerdflog.warn 'RDFS::Resource: method_missing on class: method not matching find_by_*'
111
104
  super
112
105
  end
113
106
 
@@ -156,7 +149,7 @@ module RDFS
156
149
  # cheaper than (1)-(2) but (1) and (2) are probably more probable (getting
157
150
  # attribute values over executing custom methods)
158
151
 
159
- $log.debug "RDFS::Resource: method_missing on instance: called with method name #{method}"
152
+ $activerdflog.debug "RDFS::Resource: method_missing on instance: called with method name #{method}"
160
153
 
161
154
  # are we doing an update or not?
162
155
  # checking if method ends with '='
@@ -170,7 +163,7 @@ module RDFS
170
163
  end
171
164
 
172
165
  candidates = if update
173
- class_level_predicates
166
+ (class_level_predicates + direct_predicates).compact.uniq
174
167
  else
175
168
  direct_predicates
176
169
  end
@@ -198,7 +191,8 @@ module RDFS
198
191
  end
199
192
  end
200
193
 
201
- raise ActiveRdfError, "could not set #{methodname} to #{args}: no suitable predicate found. Maybe you are missing some shcema information?" if update
194
+ raise ActiveRdfError, "could not set #{methodname} to #{args}: no suitable
195
+ predicate found. Maybe you are missing some schema information?" if update
202
196
 
203
197
  # get/set attribute value did not succeed, so checking option (2) and (4)
204
198
 
@@ -225,8 +219,8 @@ module RDFS
225
219
  # checking possibility (4)
226
220
  # TODO: implement search strategy to select in which class to invoke
227
221
  # e.g. if to_s defined in Resource and in Person we should use Person
228
- $log.debug "RDFS::Resource: method_missing on instance: branch selected: execution of custom class method"
229
- self.class.each do |klass|
222
+ $activerdflog.debug "RDFS::Resource: method_missing option 4: custom class method"
223
+ self.type.each do |klass|
230
224
  if klass.instance_methods.include?(method.to_s)
231
225
  _dup = klass.new(uri)
232
226
  return _dup.send(method,*args)
@@ -241,20 +235,28 @@ module RDFS
241
235
  nil
242
236
  end
243
237
 
244
- # returns classes to which this resource belongs (according to rdf:type)
245
- def class
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
+ end
245
+
246
+ Query.new.distinct(:p,:o).where(self, :p, :o).execute do |p, o|
247
+ db.add(self, p, o)
248
+ end
249
+ end
250
+
251
+ def type
246
252
  types.collect do |type|
247
253
  ObjectManager.construct_class(type)
248
254
  end
249
255
  end
250
256
 
251
- def type
252
- get_property_value(Namespace.lookup(:rdf,:type))
253
- end
254
-
255
257
  # overrides built-in instance_of? to use rdf:type definitions
256
258
  def instance_of?(klass)
257
- self.class.include?(klass)
259
+ self.type.include?(klass)
258
260
  end
259
261
 
260
262
  # returns all predicates that fall into the domain of the rdf:type of this
@@ -272,54 +274,49 @@ module RDFS
272
274
  else
273
275
  q = Query.new.select(:p)
274
276
  end
275
- q.where(self,:p, :o).execute(:flatten => false) || []
277
+ q.where(self,:p, :o).execute
276
278
  end
277
279
 
278
280
  def property_accessors
279
281
  direct_predicates.collect {|pred| Namespace.localname(pred) }
280
282
  end
281
283
 
282
- # returns all rdf:types of this resource
283
- def types
284
- type = Namespace.lookup(:rdf, :type)
285
-
286
- # we lookup the type in the database
287
- types = Query.new.distinct(:t).where(self,type,:t).execute(:flatten => false)
288
-
289
- # if we dont know it, we return Resource (as toplevel)
290
- # this should in theory actually never happen (since any node is a rdfs:Resource)
291
- # but could happen if the subject is unknown to the database
292
- # or if the database does not support RDFS inferencing
293
- return [Namespace.lookup(:rdfs,"Resource")] if types.empty?
294
- return types
295
- end
296
-
297
284
  # alias include? to ==, so that you can do paper.creator.include?(eyal)
298
285
  # without worrying whether paper.creator is single- or multi-valued
299
286
  alias include? ==
300
287
 
301
288
  # returns uri of resource, can be overridden in subclasses
302
289
  def to_s
303
- "resource: #{uri}"
290
+ "<#{uri}>"
304
291
  end
305
292
 
306
- def label(*args)
307
- label = get_property_value(Namespace.lookup(:rdfs,:label)) || Namespace.localname(self)
308
-
309
- # empty labels are not useful: replace them by localname
310
- label = Namespace.localname(self) if label.empty?
311
-
312
- # if we have no localname, use full uri
313
- label = uri if label.empty?
314
-
315
- label
293
+ # label of resource (rdfs:label if available, uri otherwise)
294
+ def label
295
+ get_property_value(Namespace.lookup(:rdfs,:label)) || uri
316
296
  end
317
297
 
318
298
  private
319
299
  def get_property_value(predicate, args=[])
320
300
  return_ary = args[0][:array] if args[0].is_a?(Hash)
321
301
  flatten_results = !return_ary
322
- Query.new.distinct(:o).where(self, predicate, :o).execute(:flatten => flatten_results)
302
+ query = Query.new.distinct(:o).where(self, predicate, :o)
303
+ query.execute(:flatten => flatten_results)
323
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
+
324
321
  end
325
322
  end
@@ -1,73 +1,88 @@
1
- # Represents a query on a datasource, abstract representation of SPARQL features
2
- # is passed to federation/adapter for execution on data
3
- #
4
- # Author:: Eyal Oren
5
- # Copyright:: (c) 2005-2006
6
- # License:: LGPL
7
1
  require 'active_rdf'
8
2
  require 'federation/federation_manager'
9
3
 
10
- # TODO add log for every method which constitues to the query
11
-
4
+ # Represents a query on a datasource, abstract representation of SPARQL
5
+ # features. Query is passed to federation manager or adapter for execution on
6
+ # data source. In all clauses symbols represent variables:
7
+ # Query.new.select(:s).where(:s,:p,:o).
12
8
  class Query
13
- attr_reader :select_clauses, :where_clauses, :keywords, :limits, :offsets
14
- bool_accessor :distinct, :ask, :select, :count, :keyword
9
+ attr_reader :select_clauses, :where_clauses, :sort_clauses, :keywords, :limits, :offsets
10
+ bool_accessor :distinct, :ask, :select, :count, :keyword, :reasoning
15
11
 
16
- def initialize
17
- $log.debug "Query: initializing"
18
- distinct = false
12
+ def initialize
13
+ distinct = false
19
14
  limit = nil
20
15
  offset = nil
21
- @select_clauses = []
22
- @where_clauses = []
16
+ @select_clauses = []
17
+ @where_clauses = []
18
+ @sort_clauses = []
23
19
  @keywords = {}
24
- end
20
+ @reasoning = true
21
+ end
25
22
 
23
+ # Clears the select clauses
26
24
  def clear_select
27
- $log.debug "Query: clearing select query"
25
+ $activerdflog.debug "cleared select clause"
28
26
  @select_clauses = []
29
27
  distinct = false
30
28
  end
31
29
 
32
- def select *s
33
- @select = true
34
- s.each do |e|
35
- @select_clauses << parametrise(e)
36
- end
30
+ # Adds variables to select clause
31
+ def select *s
32
+ @select = true
33
+ s.each do |e|
34
+ @select_clauses << parametrise(e)
35
+ end
37
36
  # removing duplicate select clauses
38
37
  @select_clauses.uniq!
39
- $log.debug "Query: the current select clauses are: #{@select_clauses.join(', ')}"
40
- self
41
- end
38
+ self
39
+ end
42
40
 
43
- def ask
44
- @ask = true
45
- $log.debug "Query: the current select clauses are: #{@select_clauses.join(', ')}"
46
- self
47
- end
41
+ # Adds variables to ask clause (see SPARQL specification)
42
+ def ask
43
+ @ask = true
44
+ self
45
+ end
48
46
 
49
- def distinct *s
50
- @distinct = true
51
- select(*s)
52
- end
53
- alias_method :select_distinct, :distinct
47
+ # Adds variables to select distinct clause
48
+ def distinct *s
49
+ @distinct = true
50
+ select(*s)
51
+ end
52
+ alias_method :select_distinct, :distinct
54
53
 
54
+ # Adds variables to count clause
55
55
  def count *s
56
56
  @count = true
57
57
  select(*s)
58
58
  end
59
59
 
60
+ # Adds sort predicates (must appear in select clause)
61
+ def sort *s
62
+ s.each do |e|
63
+ @sort_clauses << parametrise(e)
64
+ end
65
+ # removing duplicate select clauses
66
+ @sort_clauses.uniq!
67
+ self
68
+ end
69
+
70
+ # Adds limit clause (maximum number of results to return)
60
71
  def limit(i)
61
72
  @limits = i
62
73
  self
63
74
  end
64
75
 
76
+ # Add offset clause (ignore first n results)
65
77
  def offset(i)
66
78
  @offsets = i
67
79
  self
68
80
  end
69
81
 
70
- def where s,p,o
82
+ # Adds where clauses (s,p,o) where each constituent is either variable (:s) or
83
+ # an RDFS::Resource. Keyword queries are specified with the special :keyword
84
+ # symbol: Query.new.select(:s).where(:s, :keyword, 'eyal')
85
+ def where s,p,o,c=nil
71
86
  case p
72
87
  when :keyword
73
88
  # treat keywords in where-clauses specially
@@ -79,26 +94,20 @@ class Query
79
94
  # generator.
80
95
  # if you construct this query manually, you shouldn't! if your select
81
96
  # variable happens to be in one of the removed clauses: tough luck.
82
-
83
- unless s.respond_to?(:uri)
84
- unless s.class == Symbol
85
- $log.debug "Query: where: got a Subject which is no Symbol, and no RDFS::Resource, but is instead: #{s}"
86
- raise(ActiveRdfError, "cannot add a where clause, in which s is not a resource and not a variable")
87
- end
88
- end
89
- unless p.respond_to?(:uri)
90
- unless p.class == Symbol
91
- $log.debug "Query: where: got a Predicate which is no Symbol, and no RDFS::Resource, but is instead: #{p}"
92
- raise(ActiveRdfError, "cannot add a where clause, in which s is not a resource and not a variable")
93
- end
94
- end
95
-
96
- @where_clauses << [s,p,o].collect{|arg| parametrise(arg)}
97
+
98
+ unless s.respond_to?(:uri) or s.class == Symbol
99
+ raise(ActiveRdfError, "cannot add a where clause with s #{s}: s must be a resource or a variable")
100
+ end
101
+ unless p.respond_to?(:uri) or p.class == Symbol
102
+ raise(ActiveRdfError, "cannot add a where clause with p #{p}: p must be a resource or a variable")
103
+ end
104
+
105
+ @where_clauses << [s,p,o,c].collect{|arg| parametrise(arg)}.compact
97
106
  end
98
107
  self
99
108
  end
100
109
 
101
- # adds keyword constraint to the query. You can use all Ferret query syntax in
110
+ # Adds keyword constraint to the query. You can use all Ferret query syntax in
102
111
  # the constraint (e.g. keyword_where(:s,'eyal|benjamin')
103
112
  def keyword_where s,o
104
113
  @keyword = true
@@ -111,24 +120,14 @@ class Query
111
120
  self
112
121
  end
113
122
 
114
- # this is not normal behaviour, the method is implemented inside FacetNavigation
115
- # def replace_where_clause old,new
116
- # return unless where_clauses.includes?(old)
117
- # where_clauses.delete(old)
118
- # where_clauses.insert(new)
119
- # end
120
-
121
- # execute query on data sources
122
- # either returns result as array
123
+ # Executes query on data sources. Either returns result as array
123
124
  # (flattened into single value unless specified otherwise)
124
125
  # or executes a block (number of block variables should be
125
126
  # same as number of select variables)
126
127
  #
127
- # usage: results = query.execute
128
- # usage: query.execute do |s,p,o| ... end
129
- def execute(options={:flatten => true}, &block)
130
- $log.debug "Query: executing query: #{self.inspect}"
131
-
128
+ # usage:: results = query.execute
129
+ # usage:: query.execute do |s,p,o| ... end
130
+ def execute(options={:flatten => false}, &block)
132
131
  if block_given?
133
132
  FederationManager.query(self) do |*clauses|
134
133
  block.call(*clauses)
@@ -138,6 +137,7 @@ class Query
138
137
  end
139
138
  end
140
139
 
140
+ # Returns query string depending on adapter (e.g. SPARQL, N3QL, etc.)
141
141
  def to_s
142
142
  if ConnectionPool.read_adapters.empty?
143
143
  inspect
@@ -146,6 +146,7 @@ class Query
146
146
  end
147
147
  end
148
148
 
149
+ # Returns SPARQL serialisation of query
149
150
  def to_sp
150
151
  require 'queryengine/query2sparql'
151
152
  Query2SPARQL.translate(self)
@@ -159,6 +160,8 @@ class Query
159
160
  #'?' + s.to_s
160
161
  when RDFS::Resource
161
162
  s
163
+ when nil
164
+ nil
162
165
  else
163
166
  '"' + s.to_s + '"'
164
167
  end
@@ -1,12 +1,7 @@
1
- # Translates abstract query into jars2 query
2
- # ignores ASK queries
3
- #
4
- # Author:: Eyal Oren
5
- # Copyright:: (c) 2005-2006
6
- # License:: LGPL
7
1
  require 'active_rdf'
8
2
 
9
-
3
+ # Translates abstract query into jars2 query.
4
+ # (ignores ASK queries)
10
5
  class Query2Jars2
11
6
  def self.translate(query)
12
7
  str = ""
@@ -21,7 +16,7 @@ class Query2Jars2
21
16
  # figure it out.
22
17
  end
23
18
 
24
- $log.debug "Query2Jars2: translated #{query} to #{str}"
19
+ $activerdflog.debug "Query2Jars2: translated #{query} to #{str}"
25
20
  return str
26
21
  end
27
22
  end
@@ -1,11 +1,7 @@
1
- # translates abstract query into SPARQL that can be executed on SPARQL-compliant data source
2
- #
3
- # Author:: Eyal Oren
4
- # Copyright:: (c) 2005-2006
5
- # License:: LGPL
6
1
  require 'active_rdf'
7
2
 
8
-
3
+ # Translates abstract query into SPARQL that can be executed on SPARQL-compliant
4
+ # data source.
9
5
  class Query2SPARQL
10
6
  def self.translate(query)
11
7
  str = ""
@@ -19,7 +15,7 @@ class Query2SPARQL
19
15
  str << "ASK { #{where_clauses(query)} }"
20
16
  end
21
17
 
22
- $log.debug "Query2SPARQL: translated the query to #{str}"
18
+ $activerdflog.debug "Query2SPARQL: translated the query to #{str}"
23
19
  return str
24
20
  end
25
21
 
data/lib/active_rdf.rb CHANGED
@@ -1,8 +1,4 @@
1
- # Loader of ActiveRDF library
2
- #
3
- # Author:: Eyal Oren and Renaud Delbru
4
- # Copyright:: (c) 2005-2006 Eyal Oren and Renaud Delbru
5
- # License:: LGPL
1
+ # ActiveRDF loader
6
2
 
7
3
  # adding active_rdf subdirectory to the ruby loadpath
8
4
  file = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
@@ -13,7 +9,7 @@ $: << this_dir + '/active_rdf/'
13
9
  require 'active_rdf_helpers'
14
10
  require 'active_rdf_log'
15
11
 
16
- $log.info "ActiveRDF started, logging level: #{$log.level}"
12
+ $activerdflog.info "ActiveRDF started, logging level: #{$activerdflog.level}"
17
13
 
18
14
  # load standard classes that need to be loaded at startup
19
15
  require 'objectmanager/resource'
@@ -26,7 +22,7 @@ def load_adapter s
26
22
  begin
27
23
  require s
28
24
  rescue StandardError => e
29
- $log.info "could not load adapter #{s}: #{e}"
25
+ $activerdflog.info "could not load adapter #{s}: #{e}"
30
26
  end
31
27
  end
32
28
 
@@ -34,15 +30,17 @@ require 'rubygems'
34
30
  #determine if we are installed as a gem right now:
35
31
  if Gem::cache().search("activerdf").empty?
36
32
  #we are not running as a gem
37
- $log.info 'ActiveRDF is NOT installed as a Gem'
33
+ $activerdflog.info 'ActiveRDF is NOT installed as a Gem'
38
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'
39
37
  load_adapter this_dir + '/../activerdf-redland/lib/activerdf_redland/redland'
40
38
  load_adapter this_dir + '/../activerdf-sparql/lib/activerdf_sparql/sparql'
41
39
  load_adapter this_dir + '/../activerdf-yars/lib/activerdf_yars/jars2'
42
40
  else
43
41
  #we are indeed running as a gem
44
42
  require 'gem_plugin'
45
- $log.info 'ActiveRDF is installed as a Gem'
43
+ $activerdflog.info 'ActiveRDF is installed as a Gem'
46
44
  GemPlugin::Manager.instance.load "activerdf" => GemPlugin::INCLUDE
47
45
  end
48
46
 
@@ -1,9 +1,9 @@
1
- # defining ActiveRDF errors
1
+ # Default ActiveRDF error
2
2
  class ActiveRdfError < StandardError
3
3
  end
4
4
 
5
- # adding bool_accessor to ruby
6
5
  class Module
6
+ # Adds boolean accessor to a class (e.g. person.male?)
7
7
  def bool_accessor *syms
8
8
  attr_accessor(*syms)
9
9
  syms.each { |sym| alias_method "#{sym}?", sym }
@@ -1,27 +1,16 @@
1
1
  require 'logger'
2
2
 
3
- $log =
4
- begin
5
- # us the rails logger if running under rails
6
- RAILS_DEFAULT_LOGGER
7
- rescue NameError
8
- unless ENV['ACTIVE_RDF_LOG'].nil?
9
- # write to environment variable $RDF_LOG if set
10
- Logger.new(ENV['ACTIVE_RDF_LOG'], 1, 100*1024)
11
- else
12
- require 'tmpdir'
13
- # else just write to the temp dir
14
- Logger.new(Dir.tmpdir.to_s + "/activerdf.log", 1, 100*1024);
15
- end
16
- end
3
+ # use either $ACTIVE_RDF_LOG for logging or current directory
4
+ location = ENV['ACTIVE_RDF_LOG'] || "#{Dir.pwd}/activerdf.log"
5
+ $activerdflog = Logger.new(location, 1, 100*1024)
17
6
 
18
7
  # if user has specified loglevel we use that, otherwise we use default level
19
8
  # in the environment variable ACTIVE_RDF_LOG_LEVEL we expect numbers, which we
20
9
  # have to convert
21
10
  if ENV['ACTIVE_RDF_LOG_LEVEL'].nil?
22
- $log.level = Logger::WARN
11
+ $activerdflog.level = Logger::WARN
23
12
  else
24
- $log.level = ENV['ACTIVE_RDF_LOG_LEVEL'].to_i
13
+ $activerdflog.level = ENV['ACTIVE_RDF_LOG_LEVEL'].to_i
25
14
  end
26
15
 
27
16
  class Logger
@@ -28,25 +28,25 @@ class TestResourceReading < Test::Unit::TestCase
28
28
  end
29
29
 
30
30
  def test_eyal_predicates
31
- predicates = @eyal.direct_predicates
32
-
33
- # assert that the three found predicates are eye, age, and type
34
- assert_equal 3, predicates.size
35
- predicates_labels = predicates.collect {|pred| pred.label }
31
+ # assert that eyal's three direct predicates are eye, age, and type
32
+ preds = @eyal.direct_predicates.collect {|p| p.uri }
33
+ assert_equal 3, preds.size
36
34
  ['age', 'eye', 'type'].each do |pr|
37
- assert predicates_labels.include?(pr), "Eyal should have predicate #{pr}"
35
+ assert preds.any? {|uri| uri =~ /.*#{pr}$/ }, "Eyal should have predicate #{pr}"
38
36
  end
39
37
 
40
- # assert that the found predicates on Person are eye, age, and type
41
- predicates_labels = predicates.collect {|pred| pred.label }
42
- ['age', 'eye', 'type'].each do |pr|
43
- assert predicates_labels.include?(pr), "Eyal should have predicate #{pr}"
44
- end
38
+ # test class level predicates
39
+ class_preds = @eyal.class_level_predicates.collect {|p| p.uri }
40
+ # eyal.type: person and resource, has predicates age, eye, and
41
+ # rdfs:label, rdfs:comment, etc.
42
+ assert_equal 10, class_preds.size
45
43
  end
46
44
 
47
45
  def test_eyal_types
48
- type_labels = @eyal.types.collect {|pred| pred.label}
49
- assert_equal ['Person','Resource'], type_labels
46
+ types = @eyal.type
47
+ assert_equal 2, types.size
48
+ assert types.include?(AR::Person)
49
+ assert types.include?(RDFS::Resource)
50
50
  end
51
51
 
52
52
  def test_eyal_age
@@ -15,13 +15,9 @@ class TestQuery < Test::Unit::TestCase
15
15
  end
16
16
 
17
17
  def test_sparql_generation
18
-
19
- # TODO: write tests for distinct, ask
20
-
21
18
  query = Query.new
22
19
  query.select(:s)
23
20
  query.where(:s, RDFS::Resource.new('predicate'), '30')
24
-
25
21
  generated = Query2SPARQL.translate(query)
26
22
  expected = "SELECT ?s WHERE { ?s <predicate> \"30\" . }"
27
23
  assert_equal expected, generated
@@ -33,13 +29,15 @@ class TestQuery < Test::Unit::TestCase
33
29
  generated = Query2SPARQL.translate(query)
34
30
  expected = "SELECT ?s WHERE { ?s <foaf:age> ?a. ?a <rdf:type> <xsd:int> . }"
35
31
  assert_equal expected, generated
32
+ end
36
33
 
37
- # query = Query.new
38
- # query.select(:s).select(:a)
39
- # query.where(:s, 'foaf:age', :a)
40
- # generated = Query2SPARQL.translate(query)
41
- # expected = "SELECT DISTINCT ?s ?a WHERE { ?s foaf:age ?a .}"
42
- # assert_equal expected, generated
34
+ def test_sparql_distinct
35
+ query = Query.new
36
+ query.distinct(:s)
37
+ query.where(:s, RDFS::Resource.new('foaf:age'), :a)
38
+ generated = Query2SPARQL.translate(query)
39
+ expected = "SELECT DISTINCT ?s WHERE { ?s <foaf:age> ?a . }"
40
+ assert_equal expected, generated
43
41
  end
44
42
 
45
43
  def test_query_omnipotent
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: "1.0"
7
- date: 2006-11-02 00:00:00 +00:00
6
+ version: "1.1"
7
+ date: 2006-12-08 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