activerdf 1.0 → 1.1

Sign up to get free protection for your applications and to get access to all the features.
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