ruby-sesame 0.1.0
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/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
|