stardog-rb 0.0.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/lib/stardog.rb +528 -0
- metadata +46 -0
data/lib/stardog.rb
ADDED
@@ -0,0 +1,528 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require 'json'
|
3
|
+
require 'tempfile'
|
4
|
+
|
5
|
+
require "net/http"
|
6
|
+
|
7
|
+
module Net
|
8
|
+
|
9
|
+
class HTTPGenericRequest
|
10
|
+
|
11
|
+
def write_header(sock, ver, path)
|
12
|
+
buf = "#{@method} #{path} HTTP/#{ver}\r\n"
|
13
|
+
each_capitalized do |k,v|
|
14
|
+
if k.downcase == "sd-connection-string"
|
15
|
+
k = "SD-Connection-String"
|
16
|
+
end
|
17
|
+
buf << "#{k}: #{v}\r\n"
|
18
|
+
end
|
19
|
+
buf << "\r\n"
|
20
|
+
#puts "WRITING..."
|
21
|
+
#puts buf
|
22
|
+
sock.write buf
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
module Stardog
|
30
|
+
|
31
|
+
# Current version of the library.
|
32
|
+
VERSION = "0.0.1"
|
33
|
+
|
34
|
+
DEBUG = ENV["STARDOG_RB_DEBUG"] || false
|
35
|
+
|
36
|
+
class StardogResponse
|
37
|
+
attr_reader :status, :body
|
38
|
+
|
39
|
+
def initialize(status, body)
|
40
|
+
@status = status
|
41
|
+
@body = body
|
42
|
+
end
|
43
|
+
|
44
|
+
def success?
|
45
|
+
@status.to_s =~ /^2\d{2}$/
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_s
|
49
|
+
"#{status}\n--------\n#{body}\n--------\n"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class LinkedJSON
|
54
|
+
|
55
|
+
def initialize(attributes = {})
|
56
|
+
@attributes = attributes
|
57
|
+
end
|
58
|
+
|
59
|
+
def get(key)
|
60
|
+
@attributes[key]
|
61
|
+
end
|
62
|
+
|
63
|
+
def set(key,value)
|
64
|
+
@attributes[key] = value
|
65
|
+
end
|
66
|
+
|
67
|
+
def [](arg)
|
68
|
+
@attributes[arg]
|
69
|
+
end
|
70
|
+
|
71
|
+
def []=(arg,value)
|
72
|
+
@attributes[arg] = value
|
73
|
+
end
|
74
|
+
|
75
|
+
def raw_json
|
76
|
+
@attributes
|
77
|
+
end
|
78
|
+
|
79
|
+
def to_s
|
80
|
+
@attributes.to_json
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
class Connection
|
86
|
+
|
87
|
+
attr_accessor :endpoint, :reasoning, :credentials
|
88
|
+
|
89
|
+
def initialize
|
90
|
+
# By default (for testing)
|
91
|
+
@endpoint = 'http://localhost:5822/'
|
92
|
+
@credentials = {:user =>'admin', :password => 'admin'}
|
93
|
+
end
|
94
|
+
|
95
|
+
def set_credentials(username, password)
|
96
|
+
@credentials = {:user => username, :password => password}
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
def get_property(database, uri, property)
|
101
|
+
str_query = 'select ?val where { '+ uri +' '+ property +' ?val }'
|
102
|
+
|
103
|
+
json_res = query(database, str_query).body
|
104
|
+
|
105
|
+
if (json_res["results"] && json_res["results"]["bindings"].length > 0)
|
106
|
+
json_res["results"]["bindings"].first["val"]["value"]
|
107
|
+
else
|
108
|
+
nil
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def get_db(database)
|
113
|
+
http_request("GET", database)
|
114
|
+
end
|
115
|
+
|
116
|
+
def get_db_size(database)
|
117
|
+
http_request("GET", "#{database}/size")
|
118
|
+
end
|
119
|
+
|
120
|
+
def query(database, query, options = {})
|
121
|
+
base_uri = options[:base_uri]
|
122
|
+
limit = options[:limit]
|
123
|
+
offset = options[:offset]
|
124
|
+
accept = options[:accept]
|
125
|
+
|
126
|
+
accept_header = accept ? accept : 'application/sparql-results+json'
|
127
|
+
options = {
|
128
|
+
:query => query
|
129
|
+
}
|
130
|
+
|
131
|
+
options[:"base-uri"] = base_uri if base_uri
|
132
|
+
options[:limit] = limit if limit
|
133
|
+
options[:offset] = offset if offset
|
134
|
+
|
135
|
+
http_request("GET", "#{database}/query", accept, options)
|
136
|
+
end
|
137
|
+
|
138
|
+
def add(database, body, graph_uri=nil, content_type="text/plain")
|
139
|
+
with_transaction(database) do |txId|
|
140
|
+
add_in_transaction(database, txId, body, graph_uri, content_type)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def remove(database, body, graph_uri=nil, content_type="text/plain")
|
145
|
+
with_transaction(database) do |txId|
|
146
|
+
remove_in_transaction(database, txId, body, graph_uri, content_type)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def query_graph(database, query, base_uri, options)
|
151
|
+
base_uri = options[:base_uri]
|
152
|
+
limit = options[:limit]
|
153
|
+
offset = options[:offset]
|
154
|
+
accept = options[:accept]
|
155
|
+
|
156
|
+
accept_header = accept ? accept : 'application/ld+json'
|
157
|
+
options = {
|
158
|
+
:query => query
|
159
|
+
}
|
160
|
+
|
161
|
+
options[:"base-uri"] = base_uri if base_uri
|
162
|
+
options[:limit] = limit if limit
|
163
|
+
options[:offset] = offset if offset
|
164
|
+
|
165
|
+
http_request("GET", "#{database}/query", accept, options)
|
166
|
+
end
|
167
|
+
|
168
|
+
def query_explain(database, query, options = {})
|
169
|
+
base_uri = options[:base_uri]
|
170
|
+
|
171
|
+
options = {
|
172
|
+
:query => query
|
173
|
+
}
|
174
|
+
|
175
|
+
options[:"base-uri"] = base_uri if base_uri
|
176
|
+
|
177
|
+
http_request("GET", "#{database}/explain", "text/plain", options)
|
178
|
+
end
|
179
|
+
|
180
|
+
################
|
181
|
+
# Transactions
|
182
|
+
################
|
183
|
+
|
184
|
+
def begin(database)
|
185
|
+
result = http_request("POST", "#{database}/transaction/begin", "text/plain", "")
|
186
|
+
if(result.status == 200)
|
187
|
+
result.body
|
188
|
+
else
|
189
|
+
raise Exception.new("Error beginning transaction #{result}")
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
|
194
|
+
def commit(database, txID)
|
195
|
+
http_request("POST", "#{database}/transaction/commit/#{txID}", "text/plain", "")
|
196
|
+
end
|
197
|
+
|
198
|
+
def rollback(database, txID)
|
199
|
+
http_request("POST", "#{database}/transaction/rollback/#{txID}", "text/plain", "")
|
200
|
+
end
|
201
|
+
|
202
|
+
# Initiates a transaction and handles the commit or rollback of it.
|
203
|
+
# if an exception is raised the transaction will be committed.
|
204
|
+
# It accepts a block that will receive a transaction ID as argument.
|
205
|
+
# - db_name
|
206
|
+
# - transaction block
|
207
|
+
def with_transaction(db_name)
|
208
|
+
begin
|
209
|
+
txID = self.begin(db_name)
|
210
|
+
yield txID
|
211
|
+
commit(db_name,txID)
|
212
|
+
true
|
213
|
+
rescue Exception => ex
|
214
|
+
debug "* Error in transaction #{txID}"
|
215
|
+
debug ex.message
|
216
|
+
debug ex.backtrace.join("\n")
|
217
|
+
rollback(db_name, txID)
|
218
|
+
false
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def query(database, query, options = {})
|
223
|
+
base_uri = options[:base_uri]
|
224
|
+
limit = options[:limit]
|
225
|
+
offset = options[:offset]
|
226
|
+
accept = options[:accept]
|
227
|
+
ask_request = options.delete(:ask)
|
228
|
+
|
229
|
+
accept = 'text/boolean' if(ask_request)
|
230
|
+
accept_header = accept ? accept : 'application/sparql-results+json'
|
231
|
+
|
232
|
+
options = {
|
233
|
+
:query => query
|
234
|
+
}
|
235
|
+
|
236
|
+
options[:"base-uri"] = base_uri if base_uri
|
237
|
+
options[:limit] = limit if limit
|
238
|
+
options[:offset] = offset if offset
|
239
|
+
|
240
|
+
http_request("GET", "#{database}/query", accept_header, options, nil, (ask_request ? false: true))
|
241
|
+
end
|
242
|
+
|
243
|
+
def query_in_transaction(database, txID, query, options = {})
|
244
|
+
base_uri = options[:base_uri]
|
245
|
+
limit = options[:limit]
|
246
|
+
offset = options[:offset]
|
247
|
+
accept = options[:accept]
|
248
|
+
ask_request = options.delete(:ask)
|
249
|
+
|
250
|
+
accept = 'text/boolean' if(ask_request)
|
251
|
+
accept_header = accept ? accept : 'application/sparql-results+json'
|
252
|
+
|
253
|
+
options = {
|
254
|
+
:query => query
|
255
|
+
}
|
256
|
+
|
257
|
+
options["base-uri"] = base_uri if base_uri
|
258
|
+
options[:limit] = limit if limit
|
259
|
+
options[:offset] = offset if offset
|
260
|
+
|
261
|
+
http_request("GET", "#{database}/#{txID}/query", accept_header, options, nil, (ask_request ? false: true))
|
262
|
+
end
|
263
|
+
|
264
|
+
def add_in_transaction(database, txID, body, graph_uri=nil, content_type="text/plain")
|
265
|
+
options = nil
|
266
|
+
options = {"graph-uri" => graph_uri} if graph_uri
|
267
|
+
|
268
|
+
if(File.exists?(body))
|
269
|
+
body = File.open(body,"r").read
|
270
|
+
elsif(body =~ /^https?:\/\/[\S]+$/)
|
271
|
+
result = http_request("GET", body, (content_type == "text/plain" ? "*/*" : content_type), {}, nil, false)
|
272
|
+
raise Exception.new("Error adding data from remote URL #{body} => #{result.status} : #{result}") if result.status != 200
|
273
|
+
body = result.body
|
274
|
+
end
|
275
|
+
|
276
|
+
http_request("POST", "#{database}/#{txID}/add", "*/*", options, body, false, content_type, nil)
|
277
|
+
end
|
278
|
+
|
279
|
+
def remove_in_transaction(database, txID, body, graph_uri=nil, content_type="text/plain")
|
280
|
+
options = nil
|
281
|
+
options = {"graph-uri" => graph_uri} if graph_uri
|
282
|
+
|
283
|
+
if(File.exists?(body))
|
284
|
+
body = File.open(body,"r").read
|
285
|
+
elsif(body =~ /^https?:\/\/[\S]+$/)
|
286
|
+
result = http_request("GET", body, (content_type == "text/plain" ? "*/*" : content_type), {}, nil, false)
|
287
|
+
raise Exception.new("Error adding data from remote URL #{body} => #{result.status} : #{result}") if result.status != 200
|
288
|
+
body = result.body
|
289
|
+
end
|
290
|
+
|
291
|
+
http_request("POST", "#{database}/#{txID}/remove", "text/plain", options, body, false, content_type, nil)
|
292
|
+
end
|
293
|
+
|
294
|
+
def clear_db(database, txId, graph_uri = nil)
|
295
|
+
options = nil
|
296
|
+
options = {"graph-uri" => graph_uri} if graph_uri
|
297
|
+
|
298
|
+
http_request("POST", database + "/" + txId + "/clear", "text/plain", options);
|
299
|
+
end
|
300
|
+
|
301
|
+
################
|
302
|
+
# Reasoning
|
303
|
+
################
|
304
|
+
|
305
|
+
def reasoning_explain(database, axioms, options = {})
|
306
|
+
content_type = options[:content_type] || "text/plain"
|
307
|
+
txID = options[:tx_id]
|
308
|
+
|
309
|
+
url = "#{database}/reasoning"
|
310
|
+
url = "#{url}/#{txID}" if txID
|
311
|
+
|
312
|
+
url = "#{url}/explain"
|
313
|
+
|
314
|
+
http_request("POST", url, "application/x-turtle", {}, axioms, false, content_type)
|
315
|
+
end
|
316
|
+
|
317
|
+
def consistent?(database)
|
318
|
+
res = http_request("GET", "#{database}/reasoning/consistency", "text/boolean", {}, nil, false)
|
319
|
+
(res.body == "true" ? true : false)
|
320
|
+
end
|
321
|
+
|
322
|
+
#######################
|
323
|
+
# Database Operations
|
324
|
+
#######################
|
325
|
+
|
326
|
+
# List all available databases
|
327
|
+
def list_dbs
|
328
|
+
http_request("GET", "admin/databases", "application/json", "")
|
329
|
+
end
|
330
|
+
|
331
|
+
|
332
|
+
# Get configuration properties for the database.
|
333
|
+
# The list of properties can be found here: http://stardog.com/docs/admin/#admin-db
|
334
|
+
# By default, "database.name", "icv.enabled", "search.enabled", "database.online", "index.type" properties a requested.
|
335
|
+
def db_options(db_name, options = ["database.name", "icv.enabled", "search.enabled", "database.online", "index.type"])
|
336
|
+
http_request("PUT", "admin/databases/#{db_name}/options", "application/json", {}, options.inject({}){|ac,i| ac[i]=""; ac})
|
337
|
+
end
|
338
|
+
|
339
|
+
# Set properties for a DB.
|
340
|
+
# options and values must be passed as the second argument to the method.
|
341
|
+
# DB must be offline before being setting the new values.
|
342
|
+
# The lis of properties can be found here: http://stardog.com/docs/admin/#admin-db
|
343
|
+
# - db_name
|
344
|
+
# - options: hash with properties and values.
|
345
|
+
def set_db_options(db_name, options)
|
346
|
+
http_request("POST", "admin/databases/#{db_name}/options", "application/json", {}, options)
|
347
|
+
end
|
348
|
+
|
349
|
+
# Copy a database
|
350
|
+
# Copies a database. The source database must be offline.
|
351
|
+
# The target database will be created.
|
352
|
+
def copy_db(db_source,db_target)
|
353
|
+
http_request("PUT", "admin/databases/#{db_source}/copy", "application/json", { "to" => db_target })
|
354
|
+
end
|
355
|
+
|
356
|
+
# Creates a new database
|
357
|
+
def create_db(dbname, creation_options={})
|
358
|
+
options = creation_options[:options] || {}
|
359
|
+
files = creation_options[:files] ||= []
|
360
|
+
if(files.empty?)
|
361
|
+
http_request("POST", "admin/databases", "text/plain", {}, {:dbname => dbname, :options => options, :files => files}.to_json, true, "application/json", true)
|
362
|
+
else
|
363
|
+
f = Tempfile.new("stardog_rb_#{Time.now.to_i}")
|
364
|
+
f << "{\"dbname\":\"#{dbname}\",\"options\":#{options.to_json},\"files\":[{"
|
365
|
+
files.each_with_index do |datafile,i|
|
366
|
+
f << "\"name\":\"#{File.basename(datafile)}\", \"content\":"
|
367
|
+
f << File.open(datafile,"r").read.chomp.to_json
|
368
|
+
f << "," if i != (files.length - 1)
|
369
|
+
end
|
370
|
+
f << "}]}"
|
371
|
+
f.flush
|
372
|
+
f.close
|
373
|
+
http_request("POST", "admin/databases", "text/plain", {}, File.new(f.path), true, "application/json", true)
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
# Drops an existent database.
|
378
|
+
def drop_db(dbname)
|
379
|
+
http_request("DELETE", "admin/databases/#{dbname}", "application/json", "")
|
380
|
+
end
|
381
|
+
|
382
|
+
|
383
|
+
# Sets database offline.
|
384
|
+
# * strategy_op: 'WAIT' | 'NO_WAIT', default 'WAIT'.
|
385
|
+
# * timeout: timeout in ms, default 3 ms.
|
386
|
+
def offline_db(dbname, strategy_op = 'WAIT', timeout = 3)
|
387
|
+
http_request("PUT", "admin/databases/#{dbname}/offline", "application/json", {}, { "strategy" => strategy_op, "timeout" => timeout })
|
388
|
+
end
|
389
|
+
|
390
|
+
# Sets database offline.
|
391
|
+
# * strategy_op: 'WAIT' | 'NO_WAIT', default 'WAIT'.
|
392
|
+
def online_db(dbname, strategy_op)
|
393
|
+
http_request("PUT", "admin/databases/#{dbname}/online", "application/json", {}, { "strategy" => strategy_op })
|
394
|
+
end
|
395
|
+
|
396
|
+
################
|
397
|
+
# Admin
|
398
|
+
################
|
399
|
+
def clear_stardog
|
400
|
+
list_dbs.body["databases"].each do |db|
|
401
|
+
drop_db db
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
def shutdown_server()
|
406
|
+
http_request("POST", "admin/shutdown", "application/json")
|
407
|
+
end
|
408
|
+
|
409
|
+
private
|
410
|
+
|
411
|
+
def http_request(method, resource, accept = "*/*", params = {}, msg_body = nil, is_json_body = true, content_type = nil, multipart = false)
|
412
|
+
url = if(resource =~ /https?/)
|
413
|
+
resource
|
414
|
+
else
|
415
|
+
"#{@endpoint}#{resource}"
|
416
|
+
end
|
417
|
+
if(params.is_a?(Hash) && params.keys.length > 0)
|
418
|
+
params = params.keys.map{|k| "#{CGI::escape(k.to_s)}=#{CGI::escape(params[k].to_s)}" }.join('&')
|
419
|
+
url = "#{url}?#{params}"
|
420
|
+
elsif(params.is_a?(String) && params != "")
|
421
|
+
url = "#{url}?#{params}"
|
422
|
+
end
|
423
|
+
arguments = {
|
424
|
+
:method => method.to_s.downcase.to_sym,
|
425
|
+
:url => url,
|
426
|
+
:headers => {:accept => accept},
|
427
|
+
}
|
428
|
+
if @reasoning
|
429
|
+
arguments[:headers]["SD-Connection-String"] = "reasoning=#{@reasoning}"
|
430
|
+
end
|
431
|
+
|
432
|
+
#arguments.merge!(credentials) if credentials
|
433
|
+
if credentials
|
434
|
+
arguments[:url].gsub!("http://","http://#{credentials[:user]}:#{credentials[:password]}@")
|
435
|
+
end
|
436
|
+
|
437
|
+
arguments[:payload] = msg_body if msg_body
|
438
|
+
|
439
|
+
if(is_json_body)
|
440
|
+
arguments[:headers][:content_type] = "application/json"
|
441
|
+
arguments[:payload] = arguments[:payload].to_json if arguments.to_json != "" && !multipart
|
442
|
+
else
|
443
|
+
arguments[:headers][:content_type] = content_type if content_type
|
444
|
+
end
|
445
|
+
|
446
|
+
file = nil
|
447
|
+
if(multipart)
|
448
|
+
|
449
|
+
unless(arguments[:payload].is_a?(File))
|
450
|
+
file = Tempfile.new("stardog_rb_#{Time.now.to_i.to_s}")
|
451
|
+
file.write(arguments[:payload])
|
452
|
+
file.close
|
453
|
+
arguments[:payload] = File.new(file)
|
454
|
+
arguments[:multipart] = true
|
455
|
+
end
|
456
|
+
arguments[:payload] = {
|
457
|
+
:file => arguments[:payload],
|
458
|
+
:multipart => true
|
459
|
+
}
|
460
|
+
end
|
461
|
+
|
462
|
+
|
463
|
+
debug "ARGUMENTS:"
|
464
|
+
debug arguments.inspect
|
465
|
+
response = RestClient::Request.execute(arguments)
|
466
|
+
debug "RESPONSE:"
|
467
|
+
debug response.code
|
468
|
+
debug "---"
|
469
|
+
debug response.headers
|
470
|
+
debug "---"
|
471
|
+
debug response.body
|
472
|
+
debug "-----------------------\n"
|
473
|
+
|
474
|
+
if response.code.to_s =~ /^2\d{2}$/
|
475
|
+
if response.headers[:content_type] && response.headers[:content_type].index("json")
|
476
|
+
json_data = JSON.parse(response.body)
|
477
|
+
|
478
|
+
result = if json_data.is_a?(Array)
|
479
|
+
json_data.inject([]) { |ac, i| ac << i if(i["@id"] || i["@context"]); ac }
|
480
|
+
else
|
481
|
+
LinkedJSON.new(json_data)
|
482
|
+
end
|
483
|
+
StardogResponse.new(response.code, result)
|
484
|
+
elsif response.headers[:content_type] && response.headers[:content_type].index("application/xml")
|
485
|
+
StardogResponse.new(response.code, Nokogiri::XML(response.body))
|
486
|
+
else
|
487
|
+
StardogResponse.new(response.code, response.body)
|
488
|
+
end
|
489
|
+
else
|
490
|
+
StardogResponse.new(response.code, response.body)
|
491
|
+
end
|
492
|
+
|
493
|
+
rescue => exception
|
494
|
+
if(exception.respond_to?(:response))
|
495
|
+
debug "RESPONSE:"
|
496
|
+
debug exception.response.code
|
497
|
+
debug "---"
|
498
|
+
debug exception.response.headers
|
499
|
+
debug "---"
|
500
|
+
debug exception.response.body
|
501
|
+
debug "-----------------------\n"
|
502
|
+
|
503
|
+
StardogResponse.new(exception.response.code, exception.response.body)
|
504
|
+
else
|
505
|
+
raise exception
|
506
|
+
end
|
507
|
+
ensure
|
508
|
+
file.unlink unless file.nil?
|
509
|
+
end # end of http_request
|
510
|
+
|
511
|
+
def debug(msg)
|
512
|
+
puts msg if Stardog::DEBUG
|
513
|
+
end
|
514
|
+
|
515
|
+
end # end of Connection
|
516
|
+
|
517
|
+
|
518
|
+
# Returns a connection
|
519
|
+
def stardog(endpoint = nil, options = {})
|
520
|
+
connection = Connection.new
|
521
|
+
connection.endpoint = endpoint if endpoint
|
522
|
+
connection.reasoning = options[:reasoning] if options[:reasoning]
|
523
|
+
connection.set_credentials(options[:user], options[:password]) if options[:user] && options[:password]
|
524
|
+
|
525
|
+
connection
|
526
|
+
end
|
527
|
+
|
528
|
+
end
|
metadata
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: stardog-rb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Antonio Garrote
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-08 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Port of the JS bindings for Stardog.
|
15
|
+
email:
|
16
|
+
- antoniogarrote@gmail.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- lib/stardog.rb
|
22
|
+
homepage: http://antoniogarrote.com/social/stream
|
23
|
+
licenses: []
|
24
|
+
post_install_message:
|
25
|
+
rdoc_options: []
|
26
|
+
require_paths:
|
27
|
+
- lib
|
28
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
35
|
+
none: false
|
36
|
+
requirements:
|
37
|
+
- - ! '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
requirements: []
|
41
|
+
rubyforge_project:
|
42
|
+
rubygems_version: 1.8.25
|
43
|
+
signing_key:
|
44
|
+
specification_version: 3
|
45
|
+
summary: HTTP Bindings for Stardog RDF data base
|
46
|
+
test_files: []
|