rdf-4store 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +1 -0
- data/README +43 -0
- data/UNLICENSE +24 -0
- data/VERSION +1 -0
- data/lib/rdf/4store.rb +9 -0
- data/lib/rdf/four_store/repository.rb +296 -0
- data/lib/rdf/four_store/version.rb +23 -0
- metadata +154 -0
data/AUTHORS
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Fumihiro Kato <fumi@fumi.me>
|
data/README
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# 4store Storage Adapter for RDF.rb
|
2
|
+
|
3
|
+
This is an [RDF.rb][] storage adapter that allows you to use the [4store][] RDF Database.
|
4
|
+
|
5
|
+
See <http://blog.datagraph.org/2010/04/rdf-repository-howto> for an overview.
|
6
|
+
|
7
|
+
## Status
|
8
|
+
|
9
|
+
This is still in alpha status, don't use in production environment.
|
10
|
+
|
11
|
+
## Requirements
|
12
|
+
|
13
|
+
This plugin depends on the unsafe mode of 4s-httpd.
|
14
|
+
|
15
|
+
$ 4s-backend demo
|
16
|
+
$ 4s-httpd -U -s -1 demo
|
17
|
+
|
18
|
+
## Resources
|
19
|
+
|
20
|
+
* <http://rdf.rubyforge.org> - RDF.rb's home page
|
21
|
+
* <http://rdf.rubyforge.org/RDF/Repository.html> - RDF.rb's Repository documentation
|
22
|
+
* <http://4store.org> - 4store's home page
|
23
|
+
* <http://github.com/fumi/rdf-4store>
|
24
|
+
|
25
|
+
### Support
|
26
|
+
|
27
|
+
Please post questions or feedback to the [W3C-ruby-rdf mailing list][].
|
28
|
+
|
29
|
+
### Author
|
30
|
+
|
31
|
+
* Fumihiro Kato <fumi@fumi.me> | <http://github.com/fumi> | <http://fumi.me>
|
32
|
+
|
33
|
+
### 'License'
|
34
|
+
|
35
|
+
This is free and unemcumbered software released into the public domain. For
|
36
|
+
more information, see the accompanying UNLICENSE file.
|
37
|
+
|
38
|
+
If you're unfamiliar with public domain, that means it's perfectly fine to
|
39
|
+
start with this skeleton and code away, later relicensing as you see fit.
|
40
|
+
|
41
|
+
[RDF.rb]: http://rdf.rubyforge.org/
|
42
|
+
[4store]: http://4store.org/
|
43
|
+
[W3C-ruby-rdf mailing list]: http://lists.w3.org/Archives/Public/public-rdf-ruby/
|
data/UNLICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
This is free and unencumbered software released into the public domain.
|
2
|
+
|
3
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
4
|
+
distribute this software, either in source code form or as a compiled
|
5
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
6
|
+
means.
|
7
|
+
|
8
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
9
|
+
of this software dedicate any and all copyright interest in the
|
10
|
+
software to the public domain. We make this dedication for the benefit
|
11
|
+
of the public at large and to the detriment of our heirs and
|
12
|
+
successors. We intend this dedication to be an overt act of
|
13
|
+
relinquishment in perpetuity of all present and future rights to this
|
14
|
+
software under copyright law.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
20
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
21
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
For more information, please refer to <http://unlicense.org/>
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/lib/rdf/4store.rb
ADDED
@@ -0,0 +1,296 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'enumerator'
|
5
|
+
require 'rdf'
|
6
|
+
require 'sparql/client'
|
7
|
+
require 'nokogiri'
|
8
|
+
|
9
|
+
module RDF::FourStore
|
10
|
+
|
11
|
+
##
|
12
|
+
# RDF::Repository backend for 4store
|
13
|
+
#
|
14
|
+
# @see http://4store.org
|
15
|
+
# @see
|
16
|
+
class Repository < ::SPARQL::Client::Repository
|
17
|
+
|
18
|
+
attr_reader :endpointURI, :dataURI, :updateURI, :statusURI, :sizeURI
|
19
|
+
|
20
|
+
DEFAULT_CONTEXT = "local:".freeze
|
21
|
+
|
22
|
+
##
|
23
|
+
# Constructor of RDF::FourStore::Repository
|
24
|
+
#
|
25
|
+
# @param [String] uri
|
26
|
+
# @param [Hash] options
|
27
|
+
# @return [RDF::FourStore::Repository]
|
28
|
+
# @example
|
29
|
+
# RDF::FourStore::Respository.new('http://localhost:8080')
|
30
|
+
#
|
31
|
+
def initialize(uri_or_options = {})
|
32
|
+
case uri_or_options
|
33
|
+
when String
|
34
|
+
@options = {}
|
35
|
+
@uri = uri_or_options.to_s
|
36
|
+
when Hash
|
37
|
+
@options = uri_or_options.dup
|
38
|
+
@uri = @options.delete([:uri])
|
39
|
+
else
|
40
|
+
raise ArgumentError, "expected String or Hash, but got #{uri_or_options.inspect}"
|
41
|
+
end
|
42
|
+
@uri.sub!(/\/$/, '')
|
43
|
+
@endpointURI = @uri + "/sparql/"
|
44
|
+
@dataURI = @uri + "/data/"
|
45
|
+
@updateURI = @uri + "/update/"
|
46
|
+
@statusURI = @uri + "/status/"
|
47
|
+
@sizeURI = @statusURI + "size/"
|
48
|
+
|
49
|
+
super(@endpointURI, options)
|
50
|
+
end
|
51
|
+
|
52
|
+
##
|
53
|
+
# Loads RDF statements from the given file or URL into `self`.
|
54
|
+
#
|
55
|
+
# @see RDF::Mutable#load
|
56
|
+
# @param [String, #to_s] filename
|
57
|
+
# @param [Hash{Symbol => Object}] options
|
58
|
+
# @return [void]
|
59
|
+
def load(filename, options = {})
|
60
|
+
return super(filename, options) if /^https?:\/\//.match(filename)
|
61
|
+
|
62
|
+
uri = nil
|
63
|
+
|
64
|
+
if options[:context]
|
65
|
+
uri = @dataURI + options[:context]
|
66
|
+
else
|
67
|
+
uri = @dataURI + 'file://' + File.expand_path(filename)
|
68
|
+
end
|
69
|
+
|
70
|
+
uri = URI.parse(uri)
|
71
|
+
content = open(filename).read
|
72
|
+
begin
|
73
|
+
req = Net::HTTP::Put.new(uri.path)
|
74
|
+
Net::HTTP.start(uri.host, uri.port) do |http|
|
75
|
+
http.request(req, content)
|
76
|
+
end
|
77
|
+
rescue Errno::ECONNREFUSED, Errno::ECONNRESET, TimeoutError
|
78
|
+
retry
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
alias_method :load!, :load
|
83
|
+
|
84
|
+
##
|
85
|
+
# Returns the number of statements in this repository.
|
86
|
+
# @see RDF::Repository#count
|
87
|
+
# @return [Integer]
|
88
|
+
def count
|
89
|
+
c = 0
|
90
|
+
doc = Nokogiri::HTML(open(@sizeURI))
|
91
|
+
doc.search('tr').each do |tr|
|
92
|
+
td = tr.search('td')
|
93
|
+
c = td[0].content if td[0]
|
94
|
+
end
|
95
|
+
c.to_i # the last one is the total number
|
96
|
+
end
|
97
|
+
alias_method :size, :count
|
98
|
+
alias_method :length, :count
|
99
|
+
|
100
|
+
##
|
101
|
+
# Enumerates each RDF statement in this repository.
|
102
|
+
#
|
103
|
+
# @yield [statement]
|
104
|
+
# @yieldparam [RDF::Statement] statement
|
105
|
+
# @return [Enumerator]
|
106
|
+
# @see RDF::Repository#each
|
107
|
+
# @see SPARQL::Client::Rpository#each
|
108
|
+
def each(&block)
|
109
|
+
unless block_given?
|
110
|
+
RDF::Enumerator.new(self, :each)
|
111
|
+
else
|
112
|
+
# TODO: check why @client.construct does not work here.
|
113
|
+
statements = @client.query("CONSTRUCT { ?s ?p ?o } WHERE { ?s ?p ?o }")
|
114
|
+
statements.each_statement(&block) if statements
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
##
|
119
|
+
# @private
|
120
|
+
# @see RDF::Enumerable#has_triple?
|
121
|
+
def has_triple?(triple)
|
122
|
+
has_statement?(RDF::Statement.from(triple))
|
123
|
+
end
|
124
|
+
|
125
|
+
##
|
126
|
+
# @private
|
127
|
+
# @see RDF::Enumerable#has_quad?
|
128
|
+
def has_quad?(quad)
|
129
|
+
has_statement?(RDF::Statement.new(quad[0], quad[1], quad[2], :context => quad[3]))
|
130
|
+
end
|
131
|
+
|
132
|
+
##
|
133
|
+
# @private
|
134
|
+
# @see RDF::Enumerable#has_statement?
|
135
|
+
def has_statement?(statement)
|
136
|
+
context = statement.context
|
137
|
+
dump = dump_statement(statement)
|
138
|
+
if context
|
139
|
+
@client.query("ASK { GRAPH <#{context}> { #{dump} } } ")
|
140
|
+
else
|
141
|
+
@client.query("ASK { #{dump} } ")
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
##
|
146
|
+
# @see RDF::Mutable#insert_statement
|
147
|
+
# @private
|
148
|
+
def insert_statement(statement)
|
149
|
+
#TODO: save the given RDF::Statement. Don't save duplicates.
|
150
|
+
#
|
151
|
+
#unless has_statement?(statement)
|
152
|
+
dump = dump_statement(statement)
|
153
|
+
post_data(dump, statement.context)
|
154
|
+
#end
|
155
|
+
end
|
156
|
+
|
157
|
+
##
|
158
|
+
# @see RDF::Mutable#delete_statement
|
159
|
+
# @private
|
160
|
+
def delete_statement(statement)
|
161
|
+
if has_statement?(statement)
|
162
|
+
context = statement.context || DEFAULT_CONTEXT
|
163
|
+
dump = dump_statement(statement)
|
164
|
+
q = "DELETE DATA { GRAPH <#{context}> { #{dump} } }"
|
165
|
+
post_update(q, context)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
##
|
170
|
+
# @private
|
171
|
+
# @see RDF::Mutable#clear
|
172
|
+
def clear_statements
|
173
|
+
q = "SELECT ?g WHERE { GRAPH ?g { ?s ?p ?o . } FILTER (?g != <#{DEFAULT_CONTEXT}>) }"
|
174
|
+
@client.query(q).each do |solution|
|
175
|
+
post_update("CLEAR GRAPH <#{solution[:g]}>")
|
176
|
+
end
|
177
|
+
post_update("CLEAR GRAPH <#{DEFAULT_CONTEXT}>")
|
178
|
+
end
|
179
|
+
|
180
|
+
##
|
181
|
+
# Queries `self` for RDF statements matching the given `pattern`.
|
182
|
+
#
|
183
|
+
# @param [Query, Statement, Array(Value), Hash] pattern
|
184
|
+
# @yield [statement]
|
185
|
+
# @yieldparam [Statement]
|
186
|
+
# @return [Enumerable<Statement>]
|
187
|
+
def query(pattern, &block)
|
188
|
+
case pattern
|
189
|
+
when RDF::Statement
|
190
|
+
h = {
|
191
|
+
:subject => pattern.subject || :s,
|
192
|
+
:predicate => pattern.predicate || :p,
|
193
|
+
:object => pattern.object || :o,
|
194
|
+
:context => pattern.context || nil
|
195
|
+
}
|
196
|
+
super(RDF::Query::Pattern.new(h), &block)
|
197
|
+
when Array
|
198
|
+
h = {
|
199
|
+
:subject => pattern[0] || :s,
|
200
|
+
:predicate => pattern[1] || :p,
|
201
|
+
:object => pattern[2] || :o,
|
202
|
+
:context => pattern[3] || nil
|
203
|
+
}
|
204
|
+
super(RDF::Query::Pattern.new(h), &block)
|
205
|
+
when Hash
|
206
|
+
pattern[:subject] ||= :s
|
207
|
+
pattern[:predicate] ||= :p
|
208
|
+
pattern[:object] ||= :o
|
209
|
+
super(RDF::Query::Pattern.new(pattern), &block)
|
210
|
+
else
|
211
|
+
super(pattern, &block)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def query_pattern(pattern, &block)
|
216
|
+
context = pattern.context || DEFAULT_CONTEXT
|
217
|
+
str = pattern.to_s
|
218
|
+
q = "CONSTRUCT { #{str} } WHERE { GRAPH <#{context}> { #{str} } } "
|
219
|
+
result = @client.query(q)
|
220
|
+
if result
|
221
|
+
if block_given?
|
222
|
+
result.each_statement(&block)
|
223
|
+
else
|
224
|
+
result
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def dump_statement(statement)
|
230
|
+
dump_statements([statement])
|
231
|
+
end
|
232
|
+
|
233
|
+
def dump_statements(statements)
|
234
|
+
graph = RDF::Graph.new
|
235
|
+
graph.insert_statements(statements)
|
236
|
+
RDF::Writer.for(:ntriples).dump(graph)
|
237
|
+
end
|
238
|
+
|
239
|
+
def post_data(content, context = nil)
|
240
|
+
context ||= DEFAULT_CONTEXT
|
241
|
+
uri = URI.parse(@dataURI)
|
242
|
+
|
243
|
+
req = Net::HTTP::Post.new(uri.path)
|
244
|
+
req.form_data = {
|
245
|
+
'data' => content,
|
246
|
+
'graph' => context,
|
247
|
+
'mime-type' => 'application/x-turtle'
|
248
|
+
}
|
249
|
+
|
250
|
+
Net::HTTP.start(uri.host, uri.port) do |http|
|
251
|
+
http.request(req)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def post_update(content, context = nil)
|
256
|
+
context ||= DEFAULT_CONTEXT
|
257
|
+
uri = URI.parse(@updateURI)
|
258
|
+
|
259
|
+
req = Net::HTTP::Post.new(uri.path)
|
260
|
+
req.form_data = {
|
261
|
+
'update' => content,
|
262
|
+
'graph' => context,
|
263
|
+
'content-type' => 'triples',
|
264
|
+
}
|
265
|
+
|
266
|
+
Net::HTTP.start(uri.host, uri.port) do |http|
|
267
|
+
http.request(req)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
##
|
272
|
+
# @private
|
273
|
+
# @see RDF::Writable#writable?
|
274
|
+
# @return [Boolean]
|
275
|
+
def writable?
|
276
|
+
true
|
277
|
+
end
|
278
|
+
|
279
|
+
##
|
280
|
+
# @private
|
281
|
+
# @see RDF::Durable#durable?
|
282
|
+
# @return [Boolean]
|
283
|
+
def durable?
|
284
|
+
true
|
285
|
+
end
|
286
|
+
|
287
|
+
##
|
288
|
+
# @private
|
289
|
+
# @see RDF::Countable#empty?
|
290
|
+
# @return [Boolean]
|
291
|
+
def empty?
|
292
|
+
count.zero?
|
293
|
+
end
|
294
|
+
|
295
|
+
end
|
296
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module RDF::FourStore
|
2
|
+
module VERSION
|
3
|
+
MAJOR = 0
|
4
|
+
MINOR = 0
|
5
|
+
TINY = 1
|
6
|
+
EXTRA = nil
|
7
|
+
|
8
|
+
STRING = [MAJOR, MINOR, TINY].join('.')
|
9
|
+
STRING << ".#{EXTRA}" if EXTRA
|
10
|
+
|
11
|
+
##
|
12
|
+
# @return [String]
|
13
|
+
def self.to_s() STRING end
|
14
|
+
|
15
|
+
##
|
16
|
+
# @return [String]
|
17
|
+
def self.to_str() STRING end
|
18
|
+
|
19
|
+
##
|
20
|
+
# @return [Array(Integer, Integer, Integer)]
|
21
|
+
def self.to_a() [MAJOR, MINOR, TINY] end
|
22
|
+
end
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rdf-4store
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Fumihiro Kato
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-07-15 00:00:00 +09:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rdf-spec
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 23
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 2
|
33
|
+
- 0
|
34
|
+
version: 0.2.0
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rspec
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 27
|
46
|
+
segments:
|
47
|
+
- 1
|
48
|
+
- 3
|
49
|
+
- 0
|
50
|
+
version: 1.3.0
|
51
|
+
type: :development
|
52
|
+
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: rdf
|
55
|
+
prerelease: false
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 19
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
- 2
|
65
|
+
- 2
|
66
|
+
version: 0.2.2
|
67
|
+
type: :runtime
|
68
|
+
version_requirements: *id003
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: nokogiri
|
71
|
+
prerelease: false
|
72
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
hash: 5
|
78
|
+
segments:
|
79
|
+
- 1
|
80
|
+
- 4
|
81
|
+
- 1
|
82
|
+
version: 1.4.1
|
83
|
+
type: :runtime
|
84
|
+
version_requirements: *id004
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: sparql-client
|
87
|
+
prerelease: false
|
88
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
hash: 23
|
94
|
+
segments:
|
95
|
+
- 0
|
96
|
+
- 0
|
97
|
+
- 4
|
98
|
+
version: 0.0.4
|
99
|
+
type: :runtime
|
100
|
+
version_requirements: *id005
|
101
|
+
description: RDF.rb plugin providing 4store storage adapter.
|
102
|
+
email: fumi@fumi.me
|
103
|
+
executables: []
|
104
|
+
|
105
|
+
extensions: []
|
106
|
+
|
107
|
+
extra_rdoc_files: []
|
108
|
+
|
109
|
+
files:
|
110
|
+
- AUTHORS
|
111
|
+
- README
|
112
|
+
- UNLICENSE
|
113
|
+
- VERSION
|
114
|
+
- lib/rdf/4store.rb
|
115
|
+
- lib/rdf/four_store/repository.rb
|
116
|
+
- lib/rdf/four_store/version.rb
|
117
|
+
has_rdoc: true
|
118
|
+
homepage: http://github.com/fumi/rdf-4store
|
119
|
+
licenses:
|
120
|
+
- Public Domain
|
121
|
+
post_install_message:
|
122
|
+
rdoc_options: []
|
123
|
+
|
124
|
+
require_paths:
|
125
|
+
- lib
|
126
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
hash: 57
|
132
|
+
segments:
|
133
|
+
- 1
|
134
|
+
- 8
|
135
|
+
- 7
|
136
|
+
version: 1.8.7
|
137
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
hash: 3
|
143
|
+
segments:
|
144
|
+
- 0
|
145
|
+
version: "0"
|
146
|
+
requirements:
|
147
|
+
- 4store 1.0.3 or greater
|
148
|
+
rubyforge_project: rdf
|
149
|
+
rubygems_version: 1.3.7
|
150
|
+
signing_key:
|
151
|
+
specification_version: 3
|
152
|
+
summary: 4store adapter for RDF.rb.
|
153
|
+
test_files: []
|
154
|
+
|