kasabi 0.0.1 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ require 'rake/testtask'
5
5
  require 'rake/clean'
6
6
 
7
7
  NAME = "kasabi"
8
- VER = "0.0.1"
8
+ VER = "0.1.1"
9
9
 
10
10
  RDOC_OPTS = ['--quiet', '--title', 'Kasabi Ruby Client Documentation']
11
11
 
@@ -1,7 +1,9 @@
1
1
  require 'rubygems'
2
+
2
3
  require 'httpclient'
3
4
  require 'json'
4
5
  require 'linkeddata'
6
+ require 'uri'
5
7
 
6
8
  require 'kasabi/api/base_client'
7
9
  require 'kasabi/api/lookup'
@@ -10,3 +12,9 @@ require 'kasabi/api/search'
10
12
  require 'kasabi/api/facet'
11
13
  require 'kasabi/api/augment'
12
14
  require 'kasabi/api/reconcile'
15
+ require 'kasabi/api/store'
16
+ require 'kasabi/api/status'
17
+ require 'kasabi/api/jobs'
18
+ require 'kasabi/api/attribution'
19
+
20
+ require 'kasabi/data/dataset.rb'
@@ -0,0 +1,21 @@
1
+ module Kasabi
2
+
3
+ class Attribution < BaseClient
4
+
5
+ #Initialize the attribution client to work with a specific endpoint
6
+ #
7
+ # The _options_ hash can contain the following values:
8
+ # * *:apikey*: required. apikey authorized to use the API
9
+ # * *:client*: HTTPClient object instance
10
+ def initialize(endpoint, options={})
11
+ super(endpoint, options)
12
+ end
13
+
14
+ def get_attribution()
15
+ response = get(@endpoint)
16
+ validate_response(response)
17
+ return JSON.parse( response.content )
18
+ end
19
+
20
+ end
21
+ end
@@ -18,7 +18,7 @@ module Kasabi
18
18
  #
19
19
  # uri:: the URL for the RSS 1.0 feed
20
20
  def augment_uri(uri)
21
- response = @client.get(@endpoint, {:apikey=>@apikey, "data-uri" => uri})
21
+ response = get(@endpoint, {"data-uri" => uri})
22
22
  validate_response(response)
23
23
 
24
24
  return response.content
@@ -30,7 +30,7 @@ module Kasabi
30
30
  #
31
31
  # data:: a String containing the data to augment
32
32
  def augment(data, content_type="application/rss+xml")
33
- response = @client.post("#{@endpoint}?apikey=#{@apikey}", data, {"Content-Type" => "application/rss+xml"})
33
+ response = post(@endpoint, data, {"Content-Type" => "application/rss+xml"})
34
34
  validate_response(response)
35
35
  return response.content
36
36
  end
@@ -13,11 +13,25 @@ module Kasabi
13
13
  # * *:apikey*: required. apikey authorized to use the API
14
14
  # * *:client*: HTTPClient object instance
15
15
  def initialize(endpoint, options={})
16
- @endpoint = endpoint
16
+ @endpoint = endpoint
17
17
  @client = options[:client] || HTTPClient.new()
18
18
  @apikey = options[:apikey] || nil
19
19
  end
20
20
 
21
+ def client_options
22
+ {:apikey => @apikey, :client => @client}
23
+ end
24
+
25
+ def get(uri, query=nil, headers={})
26
+ headers["X_KASABI_APIKEY"] = @apikey
27
+ return @client.get(uri, query, headers)
28
+ end
29
+
30
+ def post(uri, body="", headers={})
31
+ headers["X_KASABI_APIKEY"] = @apikey
32
+ return @client.post(uri, body, headers)
33
+ end
34
+
21
35
  def validate_response(response)
22
36
  if response.status != 200
23
37
  raise "Unable to perform request. Status: #{response.status}. Message: #{response.content}"
@@ -0,0 +1,33 @@
1
+ module Kasabi
2
+
3
+ module Jobs
4
+
5
+ class Client < Kasabi::BaseClient
6
+ #Initialize the jobs client to work with a specific endpoint
7
+ #
8
+ # The _options_ hash can contain the following values:
9
+ # * *:apikey*: required. apikey authorized to use the API
10
+ # * *:client*: HTTPClient object instance
11
+ def initialize(endpoint, options={})
12
+ super(endpoint, options)
13
+ end
14
+
15
+ def reset(t=Time.now())
16
+ time = t.getutc.strftime("%Y-%m-%dT%H:%M:%SZ")
17
+ type = "reset"
18
+ return submit_job(type, time)
19
+ end
20
+
21
+ def submit_job(type, time)
22
+ response = post( @endpoint, {:jobType=>type, :startTime=>time}, {"Content-Type" => "application/x-www-form-urlencoded"} )
23
+ if response.status != 202
24
+ raise "Failed to submit job request. Status: #{response.status}. Message: #{response.content}"
25
+ end
26
+
27
+ return response.content
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+ end
@@ -14,9 +14,11 @@ module Kasabi
14
14
  end
15
15
 
16
16
  def lookup(uri)
17
- response = @client.get(@endpoint, {:about => uri, :apikey=>@apikey, :output=>"json"} )
17
+ response = get(@endpoint, {:about => uri, :output=>"json"} )
18
18
  validate_response(response)
19
- return JSON.parse( response.content )
19
+ graph = RDF::Graph.new()
20
+ graph.insert( RDF::JSON::Reader.new( StringIO.new( response.content ) ) )
21
+ return graph
20
22
  end
21
23
 
22
24
  end
@@ -25,7 +25,7 @@ module Kasabi
25
25
  #Accepts a block to support iteration through the results. Method will yield
26
26
  #each result and its index.
27
27
  def reconcile(query, &block)
28
- response = @client.get( @endpoint, {"query" => query.to_json, :apikey=>@apikey } )
28
+ response = get( @endpoint, {"query" => query.to_json } )
29
29
  validate_response(response)
30
30
  results = JSON.parse( response.content )
31
31
  if results["result"] && block_given?
@@ -48,7 +48,7 @@ module Kasabi
48
48
  queries.each_with_index do |query, i|
49
49
  json["q#{i}"] = query
50
50
  end
51
- response = @client.get( @endpoint, {"queries" => json.to_json, :apikey=>@apikey } )
51
+ response = get( @endpoint, {"queries" => json.to_json } )
52
52
  validate_response(response)
53
53
  results = JSON.parse( response.content )
54
54
  if block_given?
@@ -14,7 +14,7 @@ module Kasabi
14
14
  super(endpoint, options)
15
15
  end
16
16
 
17
- # Search the Metabox indexes.
17
+ # Perform a search
18
18
  #
19
19
  # query:: the query to perform.
20
20
  # params:: additional query parameters (see below)
@@ -26,7 +26,7 @@ module Kasabi
26
26
  def search(query, params=nil)
27
27
  search_params = build_search_params(query, params)
28
28
  search_params[:output] = "json"
29
- response = @client.get(search_url(), search_params)
29
+ response = get(search_url(), search_params)
30
30
 
31
31
  validate_response(response)
32
32
 
@@ -42,11 +42,7 @@ module Kasabi
42
42
  def search_url()
43
43
  return "#{@endpoint}/search"
44
44
  end
45
-
46
- def authorize_url(search_url)
47
- return "#{search_url}&apikey=#{@apikey}"
48
- end
49
-
45
+
50
46
  # The _params_ hash can contain the following values:
51
47
  # * *:top*: the maximum number of results to return for each facet
52
48
  # * *:output*: the preferred response format, can be html or xml (the default)
@@ -56,7 +52,7 @@ module Kasabi
56
52
  end
57
53
  search_params = build_search_params( query, params)
58
54
  search_params[:fields] = facets.join(",")
59
- response = @client.get(facet_url(), search_params)
55
+ response = get(facet_url(), search_params)
60
56
 
61
57
  validate_response(response)
62
58
 
@@ -70,7 +66,6 @@ module Kasabi
70
66
  search_params = Hash.new
71
67
  end
72
68
  search_params[:query] = query
73
- search_params[:apikey] = @apikey
74
69
  return search_params
75
70
  end
76
71
 
@@ -94,141 +94,16 @@ module Kasabi
94
94
  #A simple SPARQL client that handles the basic HTTP traffic
95
95
  class Client < BaseClient
96
96
 
97
- attr_reader :graphs
98
- attr_reader :named_graphs
99
-
100
97
  #Initialize a client for a specific endpoint
101
98
  #
102
99
  #endpoint:: uri of the SPARQL endpoint
103
100
  #options:: hash containing additional configuration options, including +:apikey+ for specifying api key
104
101
  def initialize(endpoint, options={} )
105
102
  super(endpoint, options)
106
- @graphs = options[:graphs] || nil
107
- @named_graphs = options[:named_graphs] || nil
108
103
  end
109
-
110
- #Add a default graph. This will be added as a default graph in the request protocol
111
- def add_default_graph(graph_uri)
112
- if @graphs == nil
113
- @graphs = []
114
- end
115
- @graphs << graph_uri
116
- end
117
-
118
- #Add a named graph. This will be added as a named graph in the request protocol
119
- def add_named_graph(graph_uri)
120
- if @named_graphs == nil
121
- @named_graphs = []
122
- end
123
- @named_graphs << graph_uri
124
- end
125
-
126
- #Perform a sparql query
127
- #
128
- #sparql:: a valid SPARQL query
129
- #format:: specific a request format. Usually a media-type, but may be a name for a type, if not using Conneg
130
- #graphs:: an array of default graphs
131
- #named_graphs:: an array of named graphs
132
- def query(sparql, format=nil, graphs=nil, named_graphs=nil)
133
-
134
- params = {}
135
- params["query"] = sparql
136
-
137
- if @apikey != nil
138
- params["apikey"] = @apikey
139
- end
140
-
141
- if graphs != nil
142
- params["default-graph-uri"] = graphs
143
- elsif @graphs != nil
144
- params["default-graph-uri"] = @graphs
145
- end
146
104
 
147
- if named_graphs != nil
148
- params["named-graph-uri"] = named_graphs
149
- elsif @named_graphs != nil
150
- params["named-graph-uri"] = @named_graphs
151
- end
152
-
153
- headers = {}
154
- if format != nil
155
-
156
- if @output_parameter_name != nil
157
- params[@output_parameter_name] = format
158
- else
159
- headers["Accept"] = format
160
- end
161
-
162
- end
163
-
164
- return @client.get( @endpoint, params, headers )
165
- end
166
-
167
- #Describe a uri, optionally specifying a form of bounded description
168
- #
169
- #uri:: the uri to describe
170
- #format:: mimetype for results
171
- #type:: symbol indicating type of description, i.e. +:cbd+, +:scbd+, +:lcbd+, or +:slcbd+
172
- def describe_uri(uri, format="application/rdf+xml", type=:cbd)
173
- template = Sparql::DESCRIPTIONS[type]
174
- if template == nil
175
- raise "Unknown description type"
176
- end
177
- query = Sparql::SparqlHelper.apply_initial_bindings(template, {"uri" => "<#{uri}>"} )
178
- return describe(query, format)
179
- end
180
-
181
- #Perform a SPARQL DESCRIBE query.
182
- #
183
- #query:: the SPARQL query
184
- #format:: the preferred response format
185
- def describe(query, format="application/rdf+xml")
186
- return query(query, format)
187
- end
188
-
189
- #DESCRIBE multiple resources in a single query. The provided array should contain
190
- #the uris that are to be described
191
- #
192
- #This will generate a query like:
193
- # DESCRIBE <http://www.example.org> <http://www.example.com> ...
194
- #
195
- #uris:: list of the uris to be described
196
- #format:: the preferred response format. Default is RDF/XML
197
- def multi_describe(uris, format="application/rdf+xml")
198
- query = "DESCRIBE " + uris.map {|u| "<#{u}>" }.join(" ")
199
- return query(query, format)
200
- end
201
-
202
- #Perform a SPARQL CONSTRUCT query.
203
- #
204
- #query:: the SPARQL query
205
- #format:: the preferred response format
206
- def construct(query, format="application/rdf+xml")
207
- return query(query, format)
208
- end
209
-
210
- #Perform a SPARQL ASK query.
211
- #
212
- #query:: the SPARQL query
213
- #format:: the preferred response format
214
- def ask(query, format=Sparql::SPARQL_RESULTS_JSON)
215
- return query(query, format)
216
- end
217
-
218
- #Perform a SPARQL SELECT query.
219
- #
220
- #query:: the SPARQL query
221
- #format:: the preferred response format
222
- def select(query, format=Sparql::SPARQL_RESULTS_JSON)
223
- return query(query, format)
224
- end
225
-
226
- end
227
-
228
- #Simple helper class for manipulating and executing SPARQL queries and manipulating the results
229
- class SparqlHelper
230
105
  VARIABLE_MATCHER = /(\?|\$)([a-zA-Z]+)/
231
-
106
+
232
107
  #Apply some initial bindings to parameters in a query
233
108
  #
234
109
  #The keys in the values hash are used to replace variables in a query
@@ -240,7 +115,7 @@ module Kasabi
240
115
  #
241
116
  #query:: the query whose initial bindings are to be set
242
117
  #values:: hash of query name to value
243
- def SparqlHelper.apply_initial_bindings(query, bindings={})
118
+ def Client.apply_initial_bindings(query, bindings={})
244
119
  copy = query.clone()
245
120
  copy.gsub!(VARIABLE_MATCHER) do |pattern|
246
121
  key = $2
@@ -252,7 +127,7 @@ module Kasabi
252
127
  end
253
128
  return copy
254
129
  end
255
-
130
+
256
131
  #Convert a SPARQL query result binding into a hash suitable for passing
257
132
  #to the apply_initial_bindings method.
258
133
  #
@@ -265,7 +140,7 @@ module Kasabi
265
140
  #query
266
141
  #
267
142
  #result:: hash conforming to structure of a <tt>binding</tt> in the SPARQL JSON format
268
- def SparqlHelper.result_to_query_binding(result)
143
+ def Client.result_to_query_binding(result)
269
144
  hash = {}
270
145
  result.each_pair do |key, value|
271
146
  if value["type"] == "uri"
@@ -279,8 +154,7 @@ module Kasabi
279
154
  end
280
155
  end
281
156
  return hash
282
- end
283
-
157
+ end
284
158
  #Convert Ruby hash structured according to SPARQL JSON format
285
159
  #into an array of hashes by calling result_to_query_binding on each binding
286
160
  #into the results.
@@ -289,8 +163,8 @@ module Kasabi
289
163
  #<tt>results = Sparql::SparqlHelper.select(query, sparql_client)</tt>
290
164
  #<tt>bindings = Sparql::SparqlHelper.results_to_query_bindings(results)</tt>
291
165
  #
292
- #results:: hash conforming to SPARQL SELECT structure
293
- def SparqlHelper.results_to_query_bindings(results)
166
+ #results:: hash conforming to SPARQL SELECT structure
167
+ def Client.results_to_query_bindings(results)
294
168
  bindings = []
295
169
 
296
170
  results["results"]["bindings"].each do |result|
@@ -298,42 +172,100 @@ module Kasabi
298
172
  end
299
173
  return bindings
300
174
  end
301
-
302
- #Perform a simple SELECT query on an endpoint.
303
- #Will request the results using the SPARQL JSON results format, and parse the
304
- #resulting JSON results. The result will therefore be a simple ruby hash of the results
175
+
176
+ #Perform a sparql query.
305
177
  #
306
- #An error will be raised if the response is HTTP OK.
178
+ #sparql:: a valid SPARQL query
179
+ #format:: specific a request format. Usually a media-type, but may be a name for a type, if not using Conneg
180
+ #graphs:: an array of default graphs
181
+ #named_graphs:: an array of named graphs
182
+ def query(sparql, format=nil)
183
+ headers = {}
184
+ if format != nil
185
+ headers["Accept"] = format
186
+ end
187
+
188
+ response = get( @endpoint, {"query" => sparql}, headers )
189
+ validate_response(response)
190
+ return response.content
191
+ end
192
+
193
+ #Describe a uri, optionally specifying a form of bounded description
307
194
  #
308
- #query:: the SPARQL SELECT query
309
- #sparql_client:: a configured Sparql Client object
310
- def SparqlHelper.select(query, sparql_client)
311
- resp = sparql_client.select(query, Sparql::SPARQL_RESULTS_JSON)
312
- if resp.status != 200
313
- raise "Error performing sparql query: #{resp.status} #{resp.reason}\n#{resp.content}"
195
+ #uri:: the uri to describe
196
+ #format:: mimetype for results
197
+ #type:: symbol indicating type of description, i.e. +:cbd+, +:scbd+, +:lcbd+, or +:slcbd+
198
+ def describe_uri(uri, type=:cbd)
199
+ template = Sparql::DESCRIPTIONS[type]
200
+ if template == nil
201
+ raise "Unknown description type"
314
202
  end
315
- return JSON.parse( resp.content )
203
+ query = Client.apply_initial_bindings(template, {"uri" => "<#{uri}>"} )
204
+ return describe(query)
316
205
  end
317
-
318
- #Performs an ASK query on an endpoint, returing a boolean true/false response
206
+
207
+ #Perform a SPARQL DESCRIBE query.
319
208
  #
320
- #Will request the results using the SPARQL JSON results format, parse the
321
- #resulting JSON results, and extract the true/false response.
209
+ #query:: the SPARQL query
210
+ #format:: the preferred response format
211
+ def describe(query)
212
+ response = query(query, "application/json")
213
+ graph = RDF::Graph.new()
214
+ graph.insert( RDF::JSON::Reader.new( StringIO.new( response ) ) )
215
+ return graph
216
+ end
217
+
218
+ #DESCRIBE multiple resources in a single query. The provided array should contain
219
+ #the uris that are to be described
322
220
  #
323
- #query:: the SPARQL SELECT query
324
- #sparql_client:: a configured Sparql Client object
325
- def SparqlHelper.ask(query, sparql_client)
326
- json = SparqlHelper.select(query, sparql_client)
221
+ #This will generate a query like:
222
+ # DESCRIBE <http://www.example.org> <http://www.example.com> ...
223
+ #
224
+ #uris:: list of the uris to be described
225
+ #format:: the preferred response format. Default is RDF/XML
226
+ def multi_describe(uris)
227
+ query = "DESCRIBE " + uris.map {|u| "<#{u}>" }.join(" ")
228
+ response = query(query, "application/json")
229
+ graph = RDF::Graph.new()
230
+ graph.insert( RDF::JSON::Reader.new( StringIO.new( response ) ) )
231
+ return graph
232
+ end
233
+
234
+ #Perform a SPARQL CONSTRUCT query.
235
+ #
236
+ #query:: the SPARQL query
237
+ #format:: the preferred response format
238
+ def construct(query)
239
+ response = query(query, "application/json")
240
+ graph = RDF::Graph.new()
241
+ graph.insert( RDF::JSON::Reader.new( StringIO.new( response ) ) )
242
+ return graph
243
+ end
244
+
245
+ #Perform a SPARQL ASK query.
246
+ #
247
+ #query:: the SPARQL query
248
+ #format:: the preferred response format
249
+ def ask(query)
250
+ json = JSON.parse( query(query, Sparql::SPARQL_RESULTS_JSON) )
327
251
  return json["boolean"] == "true"
328
252
  end
329
-
253
+
330
254
  #Performs an ASK query on the SPARQL endpoint to test whether there are any statements
331
255
  #in the triple store about the specified uri.
332
256
  #
333
257
  #uri:: the uri to test for
334
258
  #sparql_client:: a configured Sparql Client object
335
- def SparqlHelper.exists(uri, sparql_client)
336
- return SparqlHelper.ask("ASK { <#{uri}> ?p ?o }", sparql_client)
259
+ def exists?(uri)
260
+ return ask("ASK { <#{uri}> ?p ?o }")
261
+ end
262
+
263
+ #Perform a SPARQL SELECT query.
264
+ #
265
+ #query:: the SPARQL query
266
+ #format:: the preferred response format
267
+ def select(query)
268
+ return JSON.parse( query(query, Sparql::SPARQL_RESULTS_JSON) )
337
269
  end
338
270
 
339
271
  #Perform a simple SELECT query on an endpoint and return a simple array of values
@@ -349,8 +281,8 @@ module Kasabi
349
281
  #
350
282
  #query:: the SPARQL SELECT query
351
283
  #sparql_client:: a configured Sparql Client object
352
- def SparqlHelper.select_values(query, sparql_client)
353
- results = SparqlHelper.select(query, sparql_client)
284
+ def select_values(query)
285
+ results = select(query)
354
286
  v = results["head"]["vars"][0];
355
287
  values = [];
356
288
  results["results"]["bindings"].each do |binding|
@@ -358,7 +290,7 @@ module Kasabi
358
290
  end
359
291
  return values
360
292
  end
361
-
293
+
362
294
  #Perform a simple SELECT query and return the results as a simple array of hashes.
363
295
  #Each entry in the array will be a row in the results, and each hash will have a key for
364
296
  #each variable.
@@ -370,8 +302,8 @@ module Kasabi
370
302
  #
371
303
  #query:: the SPARQL SELECT query
372
304
  #sparql_client:: a configured Sparql Client object
373
- def SparqlHelper.select_into_array(query, sparql_client)
374
- results = SparqlHelper.select(query, sparql_client)
305
+ def select_into_array(query)
306
+ results = select(query)
375
307
  rows = []
376
308
  results["results"]["bindings"].each do |binding|
377
309
  row = {}
@@ -394,69 +326,13 @@ module Kasabi
394
326
  #
395
327
  #query:: the SPARQL SELECT query
396
328
  #sparql_client:: a configured Sparql Client object
397
- def SparqlHelper.select_single_value(query, sparql_client)
398
- results = SparqlHelper.select(query, sparql_client)
329
+ def select_single_value(query)
330
+ results = select(query)
399
331
  v = results["head"]["vars"][0];
400
332
  return results["results"]["bindings"][0][v]["value"]
401
- end
402
-
403
- #Perform a SPARQL CONSTRUCT query against an endpoint, requesting the results in JSON
404
- #
405
- #Will request the results as application/json (with the expectation that it returns RDF_JSON),
406
- #and parses the resulting JSON document.
407
- #
408
- #query:: the SPARQL SELECT query
409
- #sparql_client:: a configured Sparql Client object
410
- def SparqlHelper.construct_to_resource_hash(query, sparql_client)
411
- resp = sparql_client.construct(query, "application/json")
412
- if resp.status != 200
413
- raise "Error performing sparql query: #{resp.status} #{resp.reason}\n#{resp.content}"
414
- end
415
- return JSON.parse( resp.content )
416
- end
417
-
418
- #Perform a SPARQL DESCRIBE query against an endpoint, requesting the results in JSON
419
- #
420
- #Will request the results as application/json (with the expectation that it returns RDF_JSON),
421
- #and parses the resulting JSON document.
422
- #
423
- #query:: the SPARQL SELECT query
424
- #sparql_client:: a configured Sparql Client object
425
- def SparqlHelper.describe_to_resource_hash(query, sparql_client)
426
- resp = sparql_client.describe(query, "application/json")
427
- if resp.status != 200
428
- raise "Error performing sparql query: #{resp.status} #{resp.reason}\n#{resp.content}"
429
- end
430
- return JSON.parse( resp.content )
431
- end
432
-
433
- #DESCRIBE multiple resources in a single SPARQL request
434
- #
435
- #uris:: an array of URIs
436
- #sparql_client:: a configured Sparql Client objec
437
- def SparqlHelper.multi_describe(uris, sparql_client)
438
- resp = sparql_client.multi_describe(uris, "application/json")
439
- if resp.status != 200
440
- raise "Error performing sparql query: #{resp.status} #{resp.reason}\n#{resp.content}"
441
- end
442
- return JSON.parse( resp.content )
443
- end
444
-
445
- #Describe a single URI using one of several forms of Bounded Description
446
- #See Sparql Client.describe_uri
447
- #
448
- #uri:: resource to describe
449
- #sparql_client:: configured SPARQL client
450
- #type:: form of bounded description to generate
451
- def SparqlHelper.describe_uri(uri, sparql_client, type=:cbd)
452
- resp = sparql_client.describe_uri(uri, "application/json", type)
453
- if resp.status != 200
454
- raise "Error performing sparql query: #{resp.status} #{resp.reason}\n#{resp.content}"
455
- end
456
- return JSON.parse( resp.content )
457
- end
458
- end
459
-
333
+ end
334
+ end
335
+
460
336
  end
461
337
 
462
338
  end