kasabi 0.0.1 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/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