ruby-sesame 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +674 -0
- data/History.txt +3 -0
- data/Manifest.txt +10 -0
- data/README.txt +27 -0
- data/Rakefile +30 -0
- data/lib/ruby-sesame.rb +346 -0
- data/spec/live_spec.rb +273 -0
- data/spec/shared_ruby_sesame_spec.rb +45 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +24 -0
- metadata +74 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
== ruby-sesame
|
2
|
+
A Ruby library to interact with OpenRDF.org's Sesame RDF framework via its REST interface.
|
3
|
+
|
4
|
+
== Authors
|
5
|
+
|
6
|
+
Paul Legato (pjlegato at gmail dot com)
|
7
|
+
|
8
|
+
|
9
|
+
== LICENSE:
|
10
|
+
|
11
|
+
Copyright (C) 2008 Paul Legato (pjlegato at gmail dot com).
|
12
|
+
|
13
|
+
This file is part of Ruby-Sesame.
|
14
|
+
|
15
|
+
Ruby-Sesame is free software: you can redistribute it and/or modify
|
16
|
+
it under the terms of the GNU General Public License as published by
|
17
|
+
the Free Software Foundation, either version 3 of the License, or
|
18
|
+
(at your option) any later version.
|
19
|
+
|
20
|
+
Ruby-Sesame is distributed in the hope that it will be useful,
|
21
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
22
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
23
|
+
GNU General Public License for more details.
|
24
|
+
|
25
|
+
You should have received a copy of the GNU General Public License
|
26
|
+
along with Ruby-Sesame. If not, see <http://www.gnu.org/licenses/>.
|
27
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'hoe'
|
3
|
+
require 'lib/ruby-sesame'
|
4
|
+
require 'spec/rake/spectask'
|
5
|
+
|
6
|
+
Hoe.new('ruby-sesame', RubySesame::Version) do |p|
|
7
|
+
p.rubyforge_name = 'ruby-sesame'
|
8
|
+
p.author = 'Paul Legato'
|
9
|
+
p.summary = 'A Ruby interface to OpenRDF.org\'s Sesame RDF triple store'
|
10
|
+
p.email = 'pjlegato at gmail dot com'
|
11
|
+
p.url = 'http://ruby-sesame.rubyforge.org'
|
12
|
+
p.remote_rdoc_dir = '' # Release to root
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
desc "Run all specs"
|
17
|
+
Spec::Rake::SpecTask.new do |t|
|
18
|
+
t.spec_files = FileList["spec/*_spec.rb"].sort
|
19
|
+
t.spec_opts = ["--options", "spec/spec.opts"]
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "Run all specs and get coverage statistics"
|
23
|
+
Spec::Rake::SpecTask.new('coverage') do |t|
|
24
|
+
t.spec_opts = ["--options", "spec/spec.opts"]
|
25
|
+
t.spec_files = FileList["spec/*_spec.rb"].sort
|
26
|
+
t.rcov_opts = ["--exclude", "spec", "--exclude", "gems"]
|
27
|
+
t.rcov = true
|
28
|
+
end
|
29
|
+
|
30
|
+
task :default => :spec
|
data/lib/ruby-sesame.rb
ADDED
@@ -0,0 +1,346 @@
|
|
1
|
+
# Ruby-Sesame: a Ruby library to interact with OpenRDF.org's Sesame RDF
|
2
|
+
# framework via its REST interface.
|
3
|
+
#
|
4
|
+
# Copyright (C) 2008 Paul Legato (pjlegato at gmail dot com).
|
5
|
+
#
|
6
|
+
# This file is part of Ruby-Sesame.
|
7
|
+
#
|
8
|
+
# Ruby-Sesame is free software: you can redistribute it and/or modify
|
9
|
+
# it under the terms of the GNU General Public License as published by
|
10
|
+
# the Free Software Foundation, either version 3 of the License, or
|
11
|
+
# (at your option) any later version.
|
12
|
+
#
|
13
|
+
# Ruby-Sesame is distributed in the hope that it will be useful,
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
# GNU General Public License for more details.
|
17
|
+
#
|
18
|
+
# You should have received a copy of the GNU General Public License
|
19
|
+
# along with Ruby-Sesame. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
|
21
|
+
require 'curb'
|
22
|
+
require 'json'
|
23
|
+
|
24
|
+
# Curb is faster, but doesn't do DELETE or PUT
|
25
|
+
require 'net/http'
|
26
|
+
require 'uri'
|
27
|
+
|
28
|
+
module RubySesame
|
29
|
+
|
30
|
+
Version = "0.1.0"
|
31
|
+
|
32
|
+
## MIME types for result format to be sent by server.
|
33
|
+
DATA_TYPES = {
|
34
|
+
## MIME types for variable binding formats
|
35
|
+
:XML => "application/sparql-results+xml",
|
36
|
+
:JSON => "application/sparql-results+json",
|
37
|
+
:binary => "application/x-binary-rdf-results-table",
|
38
|
+
|
39
|
+
## MIME types for RDF formats
|
40
|
+
:RDFXML => "application/rdf+xml",
|
41
|
+
:NTriples => "text/plain",
|
42
|
+
:Turtle => "application/x-turtle",
|
43
|
+
:N3 => "text/rdf+n3",
|
44
|
+
:TriX => "application/trix",
|
45
|
+
:TriG => "application/x-trig",
|
46
|
+
|
47
|
+
## MIME types for boolean result formats
|
48
|
+
# :XML type is valid here, too.
|
49
|
+
:PlainTextBoolean => "text/boolean"
|
50
|
+
}
|
51
|
+
|
52
|
+
|
53
|
+
class Server
|
54
|
+
attr_reader :url, :repositories
|
55
|
+
|
56
|
+
#
|
57
|
+
# Initialize a Server object at the given URL. Sesame uses a
|
58
|
+
# stateless REST protocol, so this will not actually do anything
|
59
|
+
# over the network unless query_server_information is true. Loads
|
60
|
+
# the protocol version and repositories available on the server if
|
61
|
+
# it is.
|
62
|
+
#
|
63
|
+
def initialize(url, query_server_information=false)
|
64
|
+
url = url + "/" unless url[-1..-1] == "/"
|
65
|
+
@url = url
|
66
|
+
|
67
|
+
if query_server_information
|
68
|
+
query_version
|
69
|
+
end
|
70
|
+
end # initialize
|
71
|
+
|
72
|
+
|
73
|
+
def query_version
|
74
|
+
@protocol_version = Curl::Easy.http_get(@url + "protocol").body_str.to_i
|
75
|
+
end
|
76
|
+
|
77
|
+
def protocol_version
|
78
|
+
@protocol_version || query_version
|
79
|
+
end
|
80
|
+
|
81
|
+
def repositories
|
82
|
+
@repositories || query_repositories
|
83
|
+
end
|
84
|
+
|
85
|
+
# Get a Repository by id. Returns the first repository if there is more than one.
|
86
|
+
def repository(id)
|
87
|
+
self.repositories.select {|r| r.id == id}.first
|
88
|
+
end
|
89
|
+
|
90
|
+
def query_repositories
|
91
|
+
easy = Curl::Easy.new
|
92
|
+
easy.headers["Accept"] = DATA_TYPES[:JSON]
|
93
|
+
easy.url = @url + "repositories"
|
94
|
+
easy.http_get
|
95
|
+
@repositories = JSON.parse(easy.body_str)["results"]["bindings"].map{|x| Repository.new(self, x) }
|
96
|
+
end
|
97
|
+
|
98
|
+
end # class Server
|
99
|
+
|
100
|
+
class Repository
|
101
|
+
attr_reader :server, :uri, :id, :title, :writable, :readable
|
102
|
+
|
103
|
+
def initialize(server, attrs)
|
104
|
+
@server = server
|
105
|
+
@uri = attrs["uri"]["value"]
|
106
|
+
@id = attrs["id"]["value"]
|
107
|
+
@title = attrs["title"]["value"]
|
108
|
+
@writable = attrs["writable"]["value"] == "true"
|
109
|
+
@readable = attrs["readable"]["value"] == "true"
|
110
|
+
end
|
111
|
+
|
112
|
+
#
|
113
|
+
# The valid result_types depend on what type of query you're
|
114
|
+
# doing: "Relevant values are the MIME types of supported RDF
|
115
|
+
# formats for graph queries, the MIME types of supported variable
|
116
|
+
# binding formats for tuple queries, and the MIME types of
|
117
|
+
# supported boolean result formats for boolean queries."
|
118
|
+
#
|
119
|
+
# Options:
|
120
|
+
#
|
121
|
+
# * :result_type - from DATA_TYPES
|
122
|
+
# * :method - :get or :post
|
123
|
+
# * :query_language - "sparql", "serql", or any other query language your Sesame server supports.
|
124
|
+
# * :infer => true or false. Defaults to true (serverside) if not specified.
|
125
|
+
# * :variable_bindings - if given, should be a Hash. If present, it will
|
126
|
+
# be used to bind variables outside the actual query. Keys are
|
127
|
+
# variable names and values are N-Triples encoded RDF values.
|
128
|
+
|
129
|
+
def query(query, options={})
|
130
|
+
options = {
|
131
|
+
:result_type => DATA_TYPES[:JSON],
|
132
|
+
:method => :get,
|
133
|
+
:query_language => "sparql",
|
134
|
+
}.merge(options)
|
135
|
+
|
136
|
+
easy = Curl::Easy.new
|
137
|
+
easy.headers["Accept"] = options[:result_type]
|
138
|
+
|
139
|
+
if options[:method] == :get
|
140
|
+
easy.url = (self.uri + "?" +
|
141
|
+
"query=#{ easy.escape(query) }&"+
|
142
|
+
"queryLn=#{ easy.escape(options[:query_language]) }&" +
|
143
|
+
(!options[:infer] ? "infer=false&" : "" ) +
|
144
|
+
if options[:variable_bindings]
|
145
|
+
options[:variable_bindings].keys.map {|name|
|
146
|
+
"$<#{ easy.escape(name) }>=#{ easy.escape(options[:variable_bindings][name]) }"
|
147
|
+
}.join("&")
|
148
|
+
else
|
149
|
+
""
|
150
|
+
end
|
151
|
+
).chop
|
152
|
+
|
153
|
+
|
154
|
+
easy.http_get
|
155
|
+
|
156
|
+
else # POST.
|
157
|
+
easy.url = self.uri
|
158
|
+
|
159
|
+
fields = ["query=#{ easy.escape(query) }",
|
160
|
+
"queryLn=#{ easy.escape(options[:query_language]) }"
|
161
|
+
]
|
162
|
+
|
163
|
+
fields.push("infer=false") unless options[:infer]
|
164
|
+
|
165
|
+
options[:variable_bindings].keys.map {|name|
|
166
|
+
field.push("$<#{ easy.escape(name) }>=#{ easy.escape(options[:variable_bindings][name]) }")
|
167
|
+
} if options[:variable_bindings]
|
168
|
+
|
169
|
+
easy.http_post(fields)
|
170
|
+
end
|
171
|
+
|
172
|
+
easy.body_str
|
173
|
+
end # query
|
174
|
+
|
175
|
+
#
|
176
|
+
# Returns a list of statements from the repository (i.e. performs the REST GET operation on statements in the repository.)
|
177
|
+
#
|
178
|
+
# N.B. if unqualified with 1 or more options, this will return _all_ statements in the repository.
|
179
|
+
#
|
180
|
+
# Options:
|
181
|
+
#
|
182
|
+
# * result_type is the desired MIME type for results (see the DATA_TYPES constant.) Defaults to :Turtle.
|
183
|
+
#
|
184
|
+
# * 'subj' (optional): Restricts the GET to statements with the specified N-Triples encoded resource as subject.
|
185
|
+
# * 'pred' (optional): Restricts the GET to statements with the specified N-Triples encoded URI as predicate.
|
186
|
+
# * 'obj' (optional): Restricts the GET to statements with the specified N-Triples encoded value as object.
|
187
|
+
#
|
188
|
+
# * 'context' (optional): If specified, restricts the
|
189
|
+
# operation to one or more specific contexts in the
|
190
|
+
# repository. The value of this parameter is either an
|
191
|
+
# N-Triples encoded URI or bnode ID, or the special value
|
192
|
+
# 'null' which represents all context-less statements. If
|
193
|
+
# multiple 'context' parameters are specified as an Array, the request
|
194
|
+
# will operate on the union of all specified contexts. The
|
195
|
+
# operation is executed on all statements that are in the
|
196
|
+
# repository if no context is specified.
|
197
|
+
#
|
198
|
+
# * 'infer' (optional): Boolean; specifies whether inferred statements
|
199
|
+
# should be included in the result of GET requests. Inferred
|
200
|
+
# statements are included by default.
|
201
|
+
#
|
202
|
+
def get_statements(options={})
|
203
|
+
options = {:result_type => DATA_TYPES[:Turtle]}.merge(options)
|
204
|
+
easy = Curl::Easy.new
|
205
|
+
easy.headers["Accept"] = options[:result_type]
|
206
|
+
|
207
|
+
url = self.uri + "/statements?" + self.class.get_parameterize(options.reject{|k,v|
|
208
|
+
![:subj, :pred, :obj, :context, :infer].include?(k)
|
209
|
+
})
|
210
|
+
easy.url = url
|
211
|
+
easy.http_get
|
212
|
+
|
213
|
+
easy.body_str
|
214
|
+
end # get_statements
|
215
|
+
|
216
|
+
# Delete one or more statements from the repository. Takes the same arguments as get_statements.
|
217
|
+
#
|
218
|
+
# If you do not set one of subj, pred, or obj in your options, it will delete ALL statements from the repository.
|
219
|
+
# This is ordinarily not allowed. Set safety=false to delete all statements.
|
220
|
+
#
|
221
|
+
def delete_statements!(options={}, safety=true)
|
222
|
+
|
223
|
+
unless !safety || options.keys.select {|x| [:subj, :pred, :obj].include?(x) }.size > 0
|
224
|
+
raise Exception.new("You asked to delete all statements in the repository. Either give a subj/pred/obj qualifier, or set safety=false")
|
225
|
+
end
|
226
|
+
|
227
|
+
# We have to use net/http, because curb has not yet implemented DELETE as of this writing.
|
228
|
+
|
229
|
+
uri = URI.parse(self.uri + "/statements?" + self.class.get_parameterize(options.reject{|k,v|
|
230
|
+
![:subj, :pred, :obj, :context, :infer].include?(k)
|
231
|
+
}))
|
232
|
+
http = Net::HTTP.start(uri.host, uri.port)
|
233
|
+
http.delete(uri.path)
|
234
|
+
end # delete_statements!
|
235
|
+
|
236
|
+
# Convenience method; deletes all data from the repository.
|
237
|
+
def delete_all_statements!
|
238
|
+
delete_statements!({}, false)
|
239
|
+
end
|
240
|
+
|
241
|
+
# Returns the contexts available in the repository, unprocessed.
|
242
|
+
# Results are in JSON by default, though XML and binary are also available.
|
243
|
+
def raw_contexts(result_format="application/sparql-results+json")
|
244
|
+
easy = Curl::Easy.new
|
245
|
+
easy.headers["Accept"] = result_format
|
246
|
+
|
247
|
+
easy.url = self.uri + "/contexts"
|
248
|
+
easy.http_get
|
249
|
+
easy.body_str
|
250
|
+
end
|
251
|
+
|
252
|
+
# Returns an Array of Strings, where each is the id of a context available on the server.
|
253
|
+
def contexts
|
254
|
+
JSON.parse(raw_contexts())["results"]["bindings"].map{|x| x["contextID"]["value"] }
|
255
|
+
end
|
256
|
+
|
257
|
+
# Return the namespaces available in the repository, raw and unprocessed.
|
258
|
+
# Results are in JSON by default, though XML and binary are also available.
|
259
|
+
def raw_namespaces(result_format="application/sparql-results+json")
|
260
|
+
easy = Curl::Easy.new
|
261
|
+
easy.headers["Accept"] = result_format
|
262
|
+
|
263
|
+
easy.url = self.uri + "/namespaces"
|
264
|
+
easy.http_get
|
265
|
+
easy.body_str
|
266
|
+
end
|
267
|
+
|
268
|
+
# Returns a Hash. Keys are the prefixes, and the values are the corresponding namespaces.
|
269
|
+
def namespaces
|
270
|
+
ns = {}
|
271
|
+
|
272
|
+
JSON.parse(raw_namespaces)["results"]["bindings"].each {|x|
|
273
|
+
ns[x["prefix"]["value"]] = x["namespace"]["value"]
|
274
|
+
}
|
275
|
+
ns
|
276
|
+
end
|
277
|
+
|
278
|
+
# Gets the namespace for the given prefix.
|
279
|
+
# Returns nil if not found.
|
280
|
+
def namespace(prefix)
|
281
|
+
easy = Curl::Easy.new
|
282
|
+
easy.url = self.uri + "/namespaces/" + easy.escape(prefix)
|
283
|
+
easy.http_get
|
284
|
+
ns = easy.body_str
|
285
|
+
ns =~ /^Undefined prefix:/ ? nil : ns
|
286
|
+
end
|
287
|
+
|
288
|
+
# Sets the given prefix to the given namespace.
|
289
|
+
def namespace!(prefix, namespace)
|
290
|
+
uri = URI.parse(self.uri + "/namespaces/" + URI.escape(prefix))
|
291
|
+
http = Net::HTTP.start(uri.host, uri.port)
|
292
|
+
http.send_request('PUT', uri.path, namespace).body
|
293
|
+
end
|
294
|
+
|
295
|
+
# Deletes the namespace with the given prefix.
|
296
|
+
def delete_namespace!(prefix)
|
297
|
+
uri = URI.parse(self.uri + "/namespaces/" + URI.escape(prefix))
|
298
|
+
http = Net::HTTP.start(uri.host, uri.port)
|
299
|
+
http.delete(uri.path)
|
300
|
+
end
|
301
|
+
|
302
|
+
# Deletes all namespaces in the repository.
|
303
|
+
def delete_all_namespaces!
|
304
|
+
uri = URI.parse(self.uri + "/namespaces")
|
305
|
+
http = Net::HTTP.start(uri.host, uri.port)
|
306
|
+
http.delete(uri.path)
|
307
|
+
end
|
308
|
+
|
309
|
+
|
310
|
+
# Adds new data to the repository. The data can be an RDF document or a
|
311
|
+
# "special purpose transaction document". I don't know what the
|
312
|
+
# latter is.
|
313
|
+
def add!(data, data_format=DATA_TYPES[:Turtle])
|
314
|
+
easy = Curl::Easy.new
|
315
|
+
easy.headers["Content-Type"] = data_format
|
316
|
+
|
317
|
+
easy.url = self.uri + "/statements"
|
318
|
+
easy.http_post(data)
|
319
|
+
end # add
|
320
|
+
|
321
|
+
|
322
|
+
# Returns the number of statements in the repository.
|
323
|
+
def size
|
324
|
+
easy = Curl::Easy.new
|
325
|
+
easy.url = self.uri + "/size"
|
326
|
+
easy.http_get
|
327
|
+
easy.body_str.to_i
|
328
|
+
end
|
329
|
+
|
330
|
+
|
331
|
+
# Convert the given hash into an array of strings for a POST.
|
332
|
+
def self.post_parameterize(hash)
|
333
|
+
easy = Curl::Easy.new
|
334
|
+
hash.keys.map{|key|
|
335
|
+
easy.escape(key.to_s) + "=" + easy.escape(hash[key])
|
336
|
+
}
|
337
|
+
end
|
338
|
+
|
339
|
+
# Convert the given hash into a URL paramter string for a GET.
|
340
|
+
def self.get_parameterize(hash)
|
341
|
+
post_parameterize(hash).join("&")
|
342
|
+
end
|
343
|
+
|
344
|
+
|
345
|
+
end # class Repository
|
346
|
+
end
|
data/spec/live_spec.rb
ADDED
@@ -0,0 +1,273 @@
|
|
1
|
+
# Ruby-Sesame: a Ruby library to interact with OpenRDF.org's Sesame RDF
|
2
|
+
# framework via its REST interface.
|
3
|
+
#
|
4
|
+
# Copyright (C) 2008 Paul Legato (pjlegato at gmail dot com).
|
5
|
+
#
|
6
|
+
# This file is part of Ruby-Sesame.
|
7
|
+
#
|
8
|
+
# Ruby-Sesame is free software: you can redistribute it and/or modify
|
9
|
+
# it under the terms of the GNU General Public License as published by
|
10
|
+
# the Free Software Foundation, either version 3 of the License, or
|
11
|
+
# (at your option) any later version.
|
12
|
+
#
|
13
|
+
# Ruby-Sesame is distributed in the hope that it will be useful,
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
# GNU General Public License for more details.
|
17
|
+
#
|
18
|
+
# You should have received a copy of the GNU General Public License
|
19
|
+
# along with Ruby-Sesame. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
#
|
21
|
+
####
|
22
|
+
####
|
23
|
+
#
|
24
|
+
# This specifies the behavior when a live Sesame 2.0 server is running
|
25
|
+
# on localhost:8080 with the default configuration and a repository called "test".
|
26
|
+
#
|
27
|
+
# The contents of the "test" repository may be altered/erased by these tests.
|
28
|
+
#
|
29
|
+
# N.B. It will fail if that is not the case, through no fault of its own.
|
30
|
+
#
|
31
|
+
|
32
|
+
require File.join(File.dirname(__FILE__), *%w[spec_helper])
|
33
|
+
|
34
|
+
require 'xml/libxml'
|
35
|
+
|
36
|
+
URL = "http://localhost:8080/openrdf-sesame"
|
37
|
+
|
38
|
+
TUPLE_QUERY = <<END
|
39
|
+
PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
|
40
|
+
PREFIX sys:<http://www.openrdf.org/config/repository#>
|
41
|
+
SELECT ?id ?p ?o
|
42
|
+
WHERE {
|
43
|
+
?id sys:repositoryID "SYSTEM" .
|
44
|
+
?id ?p ?o .
|
45
|
+
}
|
46
|
+
END
|
47
|
+
|
48
|
+
GRAPH_QUERY = <<END
|
49
|
+
PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
|
50
|
+
PREFIX sys:<http://www.openrdf.org/config/repository#>
|
51
|
+
DESCRIBE ?id
|
52
|
+
WHERE {
|
53
|
+
?id sys:repositoryID "SYSTEM" .
|
54
|
+
}
|
55
|
+
END
|
56
|
+
|
57
|
+
describe "Live Ruby-Sesame tests (**** N.B. these will fail unless you have a properly configured Sesame server running on localhost!)" do
|
58
|
+
it_should_behave_like "shared RubySesame specs"
|
59
|
+
|
60
|
+
before do
|
61
|
+
@server = RubySesame::Server.new(URL)
|
62
|
+
@system = @server.repository("SYSTEM")
|
63
|
+
@test = @server.repository("test")
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should be able to query the Sesame server's version number" do
|
67
|
+
@server.protocol_version.should == 4
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should be able to get a list of repositories" do
|
71
|
+
repos = nil
|
72
|
+
lambda { repos = @server.repositories }.should_not raise_error
|
73
|
+
repos.each {|r| r.class.should == RubySesame::Repository }
|
74
|
+
repos.select {|r| r.title == "System configuration repository" }.size.should == 1
|
75
|
+
repos.select {|r| r.id == "SYSTEM" }.size.should == 1
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should auto-query upon initialization if told to do so" do
|
79
|
+
server = nil
|
80
|
+
lambda { server = RubySesame::Server.new(URL, true) }.should_not raise_error
|
81
|
+
server.protocol_version.should == 4
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should be able to run a GET JSON tuple query on the System repository" do
|
85
|
+
result = nil
|
86
|
+
|
87
|
+
lambda { result = JSON.parse(@system.query(TUPLE_QUERY)) }.should_not raise_error
|
88
|
+
result["head"].should == { "vars" => ["id", "p", "o"] }
|
89
|
+
result["results"]["bindings"].size.should == 4
|
90
|
+
|
91
|
+
result["results"]["bindings"].select{|x| x["o"]["value"] == "http://www.openrdf.org/config/repository#Repository"}.first["p"]["value"].should == "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
|
92
|
+
result["results"]["bindings"].select{|x| x["o"]["value"] == "SYSTEM"}.first["p"]["value"].should == "http://www.openrdf.org/config/repository#repositoryID"
|
93
|
+
result["results"]["bindings"].select{|x| x["o"]["value"] == "System configuration repository"}.first["p"]["value"].should == "http://www.w3.org/2000/01/rdf-schema#label"
|
94
|
+
end
|
95
|
+
|
96
|
+
## TODO: figure out how to verify that this actually does a POST and not a GET.
|
97
|
+
it "should be able to run a POST JSON tuple query on the System repository" do
|
98
|
+
result = nil
|
99
|
+
|
100
|
+
lambda { result = JSON.parse(@system.query(TUPLE_QUERY, :method => :post)) }.should_not raise_error
|
101
|
+
|
102
|
+
result["head"].should == { "vars" => ["id", "p", "o"] }
|
103
|
+
result["results"]["bindings"].size.should == 4
|
104
|
+
|
105
|
+
result["results"]["bindings"].select{|x| x["o"]["value"] == "http://www.openrdf.org/config/repository#Repository"}.first["p"]["value"].should == "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
|
106
|
+
result["results"]["bindings"].select{|x| x["o"]["value"] == "SYSTEM"}.first["p"]["value"].should == "http://www.openrdf.org/config/repository#repositoryID"
|
107
|
+
result["results"]["bindings"].select{|x| x["o"]["value"] == "System configuration repository"}.first["p"]["value"].should == "http://www.w3.org/2000/01/rdf-schema#label"
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should be able to get XML tuple results from the System repository" do
|
111
|
+
result = nil
|
112
|
+
lambda { result = @system.query(TUPLE_QUERY, :result_type => RubySesame::DATA_TYPES[:XML]) }.should_not raise_error
|
113
|
+
|
114
|
+
xml = nil
|
115
|
+
lambda { xml = XML::Parser.string(result).parse }
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should be able to get binary tuple results from the System repository" do
|
119
|
+
result = nil
|
120
|
+
lambda { result = @system.query(TUPLE_QUERY, :result_type => RubySesame::DATA_TYPES[:binary]) }.should_not raise_error
|
121
|
+
|
122
|
+
result[0..3].should == "BRTR"
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should be able to get RDFXML results for a graph query" do
|
126
|
+
result = nil
|
127
|
+
lambda { result = @system.query(GRAPH_QUERY, :result_type => RubySesame::DATA_TYPES[:RDFXML]) }.should_not raise_error
|
128
|
+
|
129
|
+
xml = nil
|
130
|
+
lambda { xml = XML::Parser.string(result).parse }.should_not raise_error
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should be able to get NTriples results for a graph query" do
|
134
|
+
result = nil
|
135
|
+
lambda { result = @system.query(GRAPH_QUERY, :result_type => RubySesame::DATA_TYPES[:NTriples]) }.should_not raise_error
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should be able to get Turtle results for a graph query" do
|
139
|
+
result = nil
|
140
|
+
lambda { result = @system.query(GRAPH_QUERY, :result_type => RubySesame::DATA_TYPES[:Turtle]) }.should_not raise_error
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should be able to get N3 results for a graph query" do
|
144
|
+
result = nil
|
145
|
+
lambda { result = @system.query(GRAPH_QUERY, :result_type => RubySesame::DATA_TYPES[:N3]) }.should_not raise_error
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should be able to get TriX results for a graph query" do
|
149
|
+
result = nil
|
150
|
+
lambda { result = @system.query(GRAPH_QUERY, :result_type => RubySesame::DATA_TYPES[:TriX]) }.should_not raise_error
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should be able to get TriG results for a graph query" do
|
154
|
+
result = nil
|
155
|
+
lambda { result = @system.query(GRAPH_QUERY, :result_type => RubySesame::DATA_TYPES[:TriG]) }.should_not raise_error
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should be able to GET all statements with no arguments and Turtle-format results " do
|
159
|
+
result = nil
|
160
|
+
lambda { result = @system.get_statements() }.should_not raise_error
|
161
|
+
result.should =~ /^@prefix rdf: <http:\/\/www.w3.org\/1999\/02\/22-rdf-syntax-ns#> .\n@prefix sys: <http:\/\/www.openrdf.org\/config\/repository#>/
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should be able to GET all statements with RDFXML-format results " do
|
165
|
+
result = nil
|
166
|
+
lambda { result = @system.get_statements(:result_type => RubySesame::DATA_TYPES[:RDFXML]) }.should_not raise_error
|
167
|
+
result.should =~ /^#{Regexp.quote("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<rdf:RDF\n\txmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"")}/
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should be able to GET a subset of all statements by predicate" do
|
171
|
+
result = nil
|
172
|
+
# get a list of repository names
|
173
|
+
lambda { result = @system.get_statements(:pred => "<http://www.openrdf.org/config/repository#repositoryID>") }.should_not raise_error
|
174
|
+
|
175
|
+
result.should =~ /SYSTEM/
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should be able to GET a subset of all statements by object" do
|
179
|
+
result = nil
|
180
|
+
# get a list of repository names
|
181
|
+
lambda { result = @system.get_statements(:obj => "<http://www.openrdf.org/config/repository#RepositoryContext>") }.should_not raise_error
|
182
|
+
|
183
|
+
result.should =~ / a /
|
184
|
+
end
|
185
|
+
|
186
|
+
it "should be able to get a list of contexts with at least 1 entry" do
|
187
|
+
c = @system.contexts
|
188
|
+
c.size.should >= 1
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should be able to get a Hash of all namespaces from the repository" do
|
192
|
+
ns = nil
|
193
|
+
lambda { ns = @system.namespaces }.should_not raise_error
|
194
|
+
ns.should == {
|
195
|
+
"sys"=>"http://www.openrdf.org/config/repository#",
|
196
|
+
"rdf"=>"http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
197
|
+
}
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should be able to look up specific namespaces" do
|
201
|
+
@system.namespace("NonExistentNamespace").should == nil
|
202
|
+
@system.namespace("rdf").should == "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
203
|
+
@system.namespace("sys").should == "http://www.openrdf.org/config/repository#"
|
204
|
+
end
|
205
|
+
|
206
|
+
it "should be able to create and delete namespaces" do
|
207
|
+
@test.namespace("foo").should == nil
|
208
|
+
|
209
|
+
lambda { @test.namespace!("foo", "http://bar.baz/asdf") }.should_not raise_error
|
210
|
+
@test.namespace("foo").should == "http://bar.baz/asdf"
|
211
|
+
|
212
|
+
lambda { @test.delete_namespace!("foo") }.should_not raise_error
|
213
|
+
@test.namespace("foo").should == nil
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should be able to delete all namespaces" do
|
217
|
+
lambda { @test.namespace!("foo", "http://bar.baz/asdf") }.should_not raise_error
|
218
|
+
lambda { @test.namespace!("bar", "http://bar.asdf.baz/asdf") }.should_not raise_error
|
219
|
+
@test.namespace("foo").should == "http://bar.baz/asdf"
|
220
|
+
@test.namespace("bar").should == "http://bar.asdf.baz/asdf"
|
221
|
+
|
222
|
+
lambda { @test.delete_all_namespaces! }.should_not raise_error
|
223
|
+
|
224
|
+
@test.namespace("foo").should == nil
|
225
|
+
@test.namespace("bar").should == nil
|
226
|
+
end
|
227
|
+
|
228
|
+
|
229
|
+
TEST_DATA = <<END
|
230
|
+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
|
231
|
+
@prefix contact: <http://www.w3.org/2000/10/swap/pim/contact#>.
|
232
|
+
|
233
|
+
<http://www.example.com/test/foo/#{ Time.now.to_i }>
|
234
|
+
rdf:type contact:Person;
|
235
|
+
contact:fullName "Foo Bar";
|
236
|
+
contact:mailbox <mailto:foo@bar.org>;
|
237
|
+
contact:personalTitle "Mr.".
|
238
|
+
END
|
239
|
+
|
240
|
+
it "should be able to add data to the test repository" do
|
241
|
+
result = nil
|
242
|
+
original_count = @test.size
|
243
|
+
lambda { result = @test.add!(TEST_DATA) }.should_not raise_error
|
244
|
+
@test.size.should == original_count + 4 # number of statements in TEST_DATA
|
245
|
+
end
|
246
|
+
|
247
|
+
it "should refuse to delete all statements if 'safety' is not specified" do
|
248
|
+
result = nil
|
249
|
+
lambda { @test.delete_statements! }.should raise_error
|
250
|
+
end
|
251
|
+
|
252
|
+
it "should delete all statements if 'safety' is false" do
|
253
|
+
lambda { @test.add!(TEST_DATA) }.should_not raise_error
|
254
|
+
@test.size.should > 0
|
255
|
+
|
256
|
+
lambda { @test.delete_statements!({}, false) }.should_not raise_error
|
257
|
+
@test.size.should == 0
|
258
|
+
end
|
259
|
+
|
260
|
+
it "should be able to delete all data from the test repository" do
|
261
|
+
lambda { @test.add!(TEST_DATA) }.should_not raise_error
|
262
|
+
@test.size.should > 0
|
263
|
+
|
264
|
+
lambda { @test.delete_all_statements! }.should_not raise_error
|
265
|
+
@test.size.should == 0
|
266
|
+
end
|
267
|
+
|
268
|
+
it "should be able to count the entries in the test repository" do
|
269
|
+
result = nil
|
270
|
+
lambda { result = @test.size }.should_not raise_error
|
271
|
+
end
|
272
|
+
|
273
|
+
end
|