rdf 0.1.10 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CONTRIBUTORS +3 -0
- data/README +68 -34
- data/VERSION +1 -1
- data/etc/doap.nt +16 -0
- data/lib/rdf.rb +24 -18
- data/lib/rdf/format.rb +47 -22
- data/lib/rdf/mixin/countable.rb +42 -0
- data/lib/rdf/mixin/durable.rb +2 -0
- data/lib/rdf/mixin/enumerable.rb +72 -50
- data/lib/rdf/mixin/inferable.rb +2 -3
- data/lib/rdf/mixin/mutable.rb +51 -107
- data/lib/rdf/mixin/queryable.rb +43 -11
- data/lib/rdf/mixin/readable.rb +2 -0
- data/lib/rdf/mixin/writable.rb +130 -0
- data/lib/rdf/model/graph.rb +47 -14
- data/lib/rdf/model/literal.rb +12 -2
- data/lib/rdf/model/node.rb +51 -2
- data/lib/rdf/model/resource.rb +7 -10
- data/lib/rdf/model/statement.rb +59 -41
- data/lib/rdf/model/uri.rb +68 -8
- data/lib/rdf/model/value.rb +26 -31
- data/lib/rdf/ntriples/reader.rb +7 -6
- data/lib/rdf/ntriples/writer.rb +90 -0
- data/lib/rdf/query.rb +6 -6
- data/lib/rdf/query/pattern.rb +13 -15
- data/lib/rdf/query/solution.rb +1 -1
- data/lib/rdf/query/variable.rb +3 -1
- data/lib/rdf/reader.rb +2 -1
- data/lib/rdf/repository.rb +97 -47
- data/lib/rdf/util.rb +4 -0
- data/lib/rdf/util/aliasing.rb +51 -0
- data/lib/rdf/util/cache.rb +131 -0
- data/lib/rdf/version.rb +3 -4
- data/lib/rdf/vocab.rb +11 -10
- data/lib/rdf/vocab/cert.rb +13 -0
- data/lib/rdf/vocab/geo.rb +13 -0
- data/lib/rdf/vocab/rsa.rb +12 -0
- data/lib/rdf/writer.rb +102 -109
- metadata +23 -15
data/lib/rdf/ntriples/writer.rb
CHANGED
@@ -27,6 +27,90 @@ module RDF::NTriples
|
|
27
27
|
class Writer < RDF::Writer
|
28
28
|
format RDF::NTriples::Format
|
29
29
|
|
30
|
+
# @see http://www.w3.org/TR/rdf-testcases/#ntrip_strings
|
31
|
+
ESCAPE_PLAIN = /\A[\x20-\x21\x23-\x5B\x5D-\x7E]*\z/m.freeze
|
32
|
+
ESCAPE_ASCII = /\A[\x00-\x7F]*\z/m.freeze
|
33
|
+
|
34
|
+
##
|
35
|
+
# @param [String] string
|
36
|
+
# @return [String]
|
37
|
+
# @see http://www.w3.org/TR/rdf-testcases/#ntrip_strings
|
38
|
+
def self.escape(string)
|
39
|
+
case
|
40
|
+
when string =~ ESCAPE_PLAIN # a shortcut for the simple case
|
41
|
+
string
|
42
|
+
when string.respond_to?(:ascii_only?) && string.ascii_only?
|
43
|
+
StringIO.open do |buffer|
|
44
|
+
string.each_byte { |u| buffer << escape_ascii(u) }
|
45
|
+
buffer.string
|
46
|
+
end
|
47
|
+
when string.respond_to?(:each_codepoint)
|
48
|
+
StringIO.open do |buffer|
|
49
|
+
string.each_codepoint { |u| buffer << escape_unicode(u) }
|
50
|
+
buffer.string
|
51
|
+
end
|
52
|
+
else # works in Ruby 1.8.x, too
|
53
|
+
StringIO.open do |buffer|
|
54
|
+
string.scan(/./mu) { |c| buffer << escape_unicode(u = c.unpack('U*').first) }
|
55
|
+
buffer.string
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# @param [Integer, #ord] u
|
62
|
+
# @return [String]
|
63
|
+
# @see http://www.w3.org/TR/rdf-testcases/#ntrip_strings
|
64
|
+
def self.escape_unicode(u)
|
65
|
+
case (u = u.ord)
|
66
|
+
when (0x00..0x7F) # ASCII 7-bit
|
67
|
+
escape_ascii(u)
|
68
|
+
when (0x80..0xFFFF) # Unicode BMP
|
69
|
+
escape_utf16(u)
|
70
|
+
when (0x10000..0x10FFFF) # Unicode
|
71
|
+
escape_utf32(u)
|
72
|
+
else
|
73
|
+
raise ArgumentError.new("expected a Unicode codepoint in (0x00..0x10FFFF), but got 0x#{u.to_s(16)}")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# @param [Integer, #ord] u
|
79
|
+
# @return [String]
|
80
|
+
# @see http://www.w3.org/TR/rdf-testcases/#ntrip_strings
|
81
|
+
def self.escape_ascii(u)
|
82
|
+
case (u = u.ord)
|
83
|
+
when (0x00..0x08) then escape_utf16(u)
|
84
|
+
when (0x09) then "\\t"
|
85
|
+
when (0x0A) then "\\n"
|
86
|
+
when (0x0B..0x0C) then escape_utf16(u)
|
87
|
+
when (0x0D) then "\\r"
|
88
|
+
when (0x0E..0x1F) then escape_utf16(u)
|
89
|
+
when (0x22) then "\\\""
|
90
|
+
when (0x5C) then "\\\\"
|
91
|
+
when (0x7F) then escape_utf16(u)
|
92
|
+
when (0x00..0x7F) then u.chr
|
93
|
+
else
|
94
|
+
raise ArgumentError.new("expected an ASCII character in (0x00..0x7F), but got 0x#{u.to_s(16)}")
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
##
|
99
|
+
# @param [Integer, #ord] u
|
100
|
+
# @return [String]
|
101
|
+
# @see http://www.w3.org/TR/rdf-testcases/#ntrip_strings
|
102
|
+
def self.escape_utf16(u)
|
103
|
+
sprintf("\\u%04X", u.ord)
|
104
|
+
end
|
105
|
+
|
106
|
+
##
|
107
|
+
# @param [Integer, #ord] u
|
108
|
+
# @return [String]
|
109
|
+
# @see http://www.w3.org/TR/rdf-testcases/#ntrip_strings
|
110
|
+
def self.escape_utf32(u)
|
111
|
+
sprintf("\\U%08X", u.ord)
|
112
|
+
end
|
113
|
+
|
30
114
|
##
|
31
115
|
# Returns the serialized N-Triples representation of the given RDF
|
32
116
|
# value.
|
@@ -121,5 +205,11 @@ module RDF::NTriples
|
|
121
205
|
quoted(escaped(literal.to_s))
|
122
206
|
end
|
123
207
|
end
|
208
|
+
|
209
|
+
##
|
210
|
+
# @private
|
211
|
+
def escaped(string)
|
212
|
+
self.class.escape(string)
|
213
|
+
end
|
124
214
|
end
|
125
215
|
end
|
data/lib/rdf/query.rb
CHANGED
@@ -43,13 +43,13 @@ module RDF
|
|
43
43
|
|
44
44
|
include ::Enumerable
|
45
45
|
|
46
|
-
# @return [Hash{Symbol => Variable}]
|
46
|
+
# @return [Hash{Symbol => RDF::Query::Variable}]
|
47
47
|
attr_reader :variables
|
48
48
|
|
49
|
-
# @return [Array<Pattern>]
|
49
|
+
# @return [Array<RDF::Query::Pattern>]
|
50
50
|
attr_reader :patterns
|
51
51
|
|
52
|
-
# @return [Array<Hash{Symbol => Value}>] An unordered sequence of query solutions.
|
52
|
+
# @return [Array<Hash{Symbol => RDF::Value}>] An unordered sequence of query solutions.
|
53
53
|
attr_accessor :solutions
|
54
54
|
|
55
55
|
# @return [Hash]
|
@@ -81,7 +81,7 @@ module RDF
|
|
81
81
|
# @return [Enumerator]
|
82
82
|
def each_solution(&block)
|
83
83
|
unless block_given?
|
84
|
-
|
84
|
+
enum_for(:each_solution)
|
85
85
|
else
|
86
86
|
solutions.each do |solution|
|
87
87
|
block.call(solution.is_a?(Solution) ? solution : Solution.new(solution))
|
@@ -138,7 +138,7 @@ module RDF
|
|
138
138
|
raise ArgumentError.new("wrong number of arguments (0 for 1)")
|
139
139
|
else
|
140
140
|
# TODO: support for descending sort, e.g. order(:s => :asc, :p => :desc)
|
141
|
-
variables.map!
|
141
|
+
variables.map!(&:to_sym)
|
142
142
|
solutions.sort! do |a, b|
|
143
143
|
a = variables.map { |variable| a[variable].to_s }
|
144
144
|
b = variables.map { |variable| b[variable].to_s }
|
@@ -157,7 +157,7 @@ module RDF
|
|
157
157
|
# @return [Query]
|
158
158
|
def project(*variables)
|
159
159
|
unless variables.empty?
|
160
|
-
variables.map!
|
160
|
+
variables.map!(&:to_sym)
|
161
161
|
solutions.each do |bindings|
|
162
162
|
bindings.delete_if { |k, v| !variables.include?(k) } # FIXME
|
163
163
|
end
|
data/lib/rdf/query/pattern.rb
CHANGED
@@ -20,19 +20,17 @@ class RDF::Query
|
|
20
20
|
# @param [Hash{Symbol => Object}] options
|
21
21
|
# @option options [Boolean] :optional (false)
|
22
22
|
def initialize(subject = nil, predicate = nil, object = nil, options = {})
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
@object = object.is_a?(Symbol) ? Variable.new(object) : object
|
35
|
-
end
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# @private
|
28
|
+
def initialize!
|
29
|
+
@context = Variable.new(@context) if @context.is_a?(Symbol)
|
30
|
+
@subject = Variable.new(@subject) if @subject.is_a?(Symbol)
|
31
|
+
@predicate = Variable.new(@predicate) if @predicate.is_a?(Symbol)
|
32
|
+
@object = Variable.new(@object) if @object.is_a?(Symbol)
|
33
|
+
super
|
36
34
|
end
|
37
35
|
|
38
36
|
##
|
@@ -108,7 +106,7 @@ class RDF::Query
|
|
108
106
|
#
|
109
107
|
# @return [Boolean]
|
110
108
|
def bound?
|
111
|
-
!variables.empty? && variables.values.all?
|
109
|
+
!variables.empty? && variables.values.all?(&:bound?)
|
112
110
|
end
|
113
111
|
|
114
112
|
##
|
@@ -124,7 +122,7 @@ class RDF::Query
|
|
124
122
|
#
|
125
123
|
# @return [Boolean]
|
126
124
|
def unbound?
|
127
|
-
!variables.empty? && variables.values.all?
|
125
|
+
!variables.empty? && variables.values.all?(&:unbound?)
|
128
126
|
end
|
129
127
|
|
130
128
|
##
|
data/lib/rdf/query/solution.rb
CHANGED
@@ -22,7 +22,7 @@ class RDF::Query
|
|
22
22
|
#
|
23
23
|
class Solution
|
24
24
|
# Undefine all superfluous instance methods:
|
25
|
-
undef_method
|
25
|
+
undef_method(*(instance_methods.map(&:to_sym) - [:__id__, :__send__, :__class__, :__eval__, :object_id, :instance_eval, :inspect, :class, :is_a?]))
|
26
26
|
|
27
27
|
include Enumerable
|
28
28
|
|
data/lib/rdf/query/variable.rb
CHANGED
data/lib/rdf/reader.rb
CHANGED
@@ -35,6 +35,7 @@ module RDF
|
|
35
35
|
# @see RDF::Writer
|
36
36
|
class Reader
|
37
37
|
extend ::Enumerable
|
38
|
+
include RDF::Readable
|
38
39
|
include ::Enumerable
|
39
40
|
|
40
41
|
##
|
@@ -148,7 +149,7 @@ module RDF
|
|
148
149
|
|
149
150
|
##
|
150
151
|
# @yield [triple]
|
151
|
-
# @yieldparam [Array(Value)]
|
152
|
+
# @yieldparam [Array(RDF::Value)]
|
152
153
|
# @return [Enumerator]
|
153
154
|
def each_triple(&block)
|
154
155
|
begin
|
data/lib/rdf/repository.rb
CHANGED
@@ -41,10 +41,17 @@ module RDF
|
|
41
41
|
# repository.clear!
|
42
42
|
#
|
43
43
|
class Repository
|
44
|
+
include RDF::Countable
|
44
45
|
include RDF::Enumerable
|
45
|
-
include RDF::Durable
|
46
|
-
include RDF::Mutable
|
47
46
|
include RDF::Queryable
|
47
|
+
include RDF::Mutable
|
48
|
+
include RDF::Durable
|
49
|
+
|
50
|
+
##
|
51
|
+
# Returns the options passed to this repository when it was constructed.
|
52
|
+
#
|
53
|
+
# @return [Hash{Symbol => Object}]
|
54
|
+
attr_reader :options
|
48
55
|
|
49
56
|
##
|
50
57
|
# Returns the {URI} of this repository.
|
@@ -94,10 +101,7 @@ module RDF
|
|
94
101
|
@title = @options.delete(:title)
|
95
102
|
|
96
103
|
# Provide a default in-memory implementation:
|
97
|
-
if self.class.equal?(RDF::Repository)
|
98
|
-
@data = []
|
99
|
-
send(:extend, Implementation)
|
100
|
-
end
|
104
|
+
send(:extend, Implementation) if self.class.equal?(RDF::Repository)
|
101
105
|
|
102
106
|
if block_given?
|
103
107
|
case block.arity
|
@@ -128,6 +132,13 @@ module RDF
|
|
128
132
|
##
|
129
133
|
# @see RDF::Repository
|
130
134
|
module Implementation
|
135
|
+
##
|
136
|
+
# @private
|
137
|
+
def self.extend_object(obj)
|
138
|
+
obj.instance_variable_set(:@data, {})
|
139
|
+
super
|
140
|
+
end
|
141
|
+
|
131
142
|
##
|
132
143
|
# Returns `true` if this repository supports `feature`.
|
133
144
|
#
|
@@ -143,76 +154,115 @@ module RDF
|
|
143
154
|
end
|
144
155
|
|
145
156
|
##
|
146
|
-
#
|
147
|
-
#
|
148
|
-
# @return [Boolean]
|
149
|
-
# @see RDF::Durable#durable?
|
157
|
+
# @private
|
158
|
+
# @see RDF::Durable#durable?
|
150
159
|
def durable?
|
151
160
|
false
|
152
161
|
end
|
153
162
|
|
154
163
|
##
|
155
|
-
#
|
156
|
-
#
|
157
|
-
# @return [Boolean]
|
158
|
-
# @see RDF::Enumerable#empty?
|
164
|
+
# @private
|
165
|
+
# @see RDF::Countable#empty?
|
159
166
|
def empty?
|
160
167
|
@data.empty?
|
161
168
|
end
|
162
169
|
|
163
170
|
##
|
164
|
-
#
|
165
|
-
#
|
166
|
-
# @return [Integer]
|
167
|
-
# @see RDF::Enumerable#count
|
171
|
+
# @private
|
172
|
+
# @see RDF::Countable#count
|
168
173
|
def count
|
169
|
-
|
174
|
+
count = 0
|
175
|
+
@data.each do |c, ss|
|
176
|
+
ss.each do |s, ps|
|
177
|
+
ps.each do |p, os|
|
178
|
+
count += os.size
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
count
|
170
183
|
end
|
171
184
|
|
172
185
|
##
|
173
|
-
#
|
174
|
-
#
|
175
|
-
# @param [Statement] statement
|
176
|
-
# @return [Boolean]
|
177
|
-
# @see RDF::Enumerable#has_statement?
|
186
|
+
# @private
|
187
|
+
# @see RDF::Enumerable#has_statement?
|
178
188
|
def has_statement?(statement)
|
179
|
-
|
189
|
+
s, p, o, c = statement.to_quad
|
190
|
+
@data.has_key?(c) &&
|
191
|
+
@data[c].has_key?(s) &&
|
192
|
+
@data[c][s].has_key?(p) &&
|
193
|
+
@data[c][s][p].include?(o)
|
180
194
|
end
|
181
195
|
|
182
196
|
##
|
183
|
-
#
|
184
|
-
#
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
197
|
+
# @private
|
198
|
+
# @see RDF::Enumerable#each_statement
|
199
|
+
def each_statement(&block)
|
200
|
+
if block_given?
|
201
|
+
# Note that to iterate in a more consistent fashion despite
|
202
|
+
# possible concurrent mutations to `@data`, we use `#dup` to make
|
203
|
+
# shallow copies of the nested hashes before beginning the
|
204
|
+
# iteration over their keys and values.
|
205
|
+
@data.dup.each do |c, ss|
|
206
|
+
ss.dup.each do |s, ps|
|
207
|
+
ps.dup.each do |p, os|
|
208
|
+
os.dup.each do |o|
|
209
|
+
block.call(RDF::Statement.new(s, p, o, :context => c))
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
else
|
215
|
+
enum_statement
|
216
|
+
end
|
191
217
|
end
|
192
218
|
|
219
|
+
alias_method :each, :each_statement
|
220
|
+
|
193
221
|
##
|
194
|
-
#
|
195
|
-
#
|
196
|
-
|
197
|
-
|
222
|
+
# @private
|
223
|
+
# @see RDF::Enumerable#has_context?
|
224
|
+
def has_context?(value)
|
225
|
+
@data.keys.compact.include?(value)
|
226
|
+
end
|
227
|
+
|
228
|
+
##
|
229
|
+
# @private
|
230
|
+
# @see RDF::Enumerable#each_context
|
231
|
+
def each_context(&block)
|
232
|
+
block_given? ? @data.keys.compact.each(&block) : enum_context
|
233
|
+
end
|
234
|
+
|
235
|
+
protected
|
236
|
+
|
237
|
+
##
|
238
|
+
# @private
|
239
|
+
# @see RDF::Mutable#insert
|
198
240
|
def insert_statement(statement)
|
199
|
-
|
241
|
+
unless has_statement?(statement)
|
242
|
+
s, p, o, c = statement.to_quad
|
243
|
+
@data[c] ||= {}
|
244
|
+
@data[c][s] ||= {}
|
245
|
+
@data[c][s][p] ||= []
|
246
|
+
@data[c][s][p] << o
|
247
|
+
end
|
200
248
|
end
|
201
249
|
|
202
250
|
##
|
203
|
-
#
|
204
|
-
#
|
205
|
-
# @param [RDF::Statement] statement
|
206
|
-
# @return [void]
|
251
|
+
# @private
|
252
|
+
# @see RDF::Mutable#delete
|
207
253
|
def delete_statement(statement)
|
208
|
-
|
254
|
+
if has_statement?(statement)
|
255
|
+
s, p, o, c = statement.to_quad
|
256
|
+
@data[c][s][p].delete(o)
|
257
|
+
@data[c][s].delete(p) if @data[c][s][p].empty?
|
258
|
+
@data[c].delete(s) if @data[c][s].empty?
|
259
|
+
@data.delete(c) if @data[c].empty?
|
260
|
+
end
|
209
261
|
end
|
210
262
|
|
211
263
|
##
|
212
|
-
#
|
213
|
-
#
|
214
|
-
# @return [void]
|
215
|
-
# @see RDF::Mutable#clear
|
264
|
+
# @private
|
265
|
+
# @see RDF::Mutable#clear
|
216
266
|
def clear_statements
|
217
267
|
@data.clear
|
218
268
|
end
|
data/lib/rdf/util.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
module RDF; module Util
|
2
|
+
module Aliasing
|
3
|
+
##
|
4
|
+
# Helpers for late-bound instance method aliasing.
|
5
|
+
#
|
6
|
+
# Anything that extends this module will obtain an `alias_method` class
|
7
|
+
# method that creates late-bound instance method aliases instead of the
|
8
|
+
# default early-bound aliases created by Ruby's `Module#alias_method`.
|
9
|
+
#
|
10
|
+
# This is useful because RDF.rb mixins typically alias a number of
|
11
|
+
# overridable methods. For example, `RDF::Enumerable#count` has the
|
12
|
+
# aliases `#size` and `#length`. Normally if implementing classes were
|
13
|
+
# to override the default method, the aliased methods would still be
|
14
|
+
# bound to the mixin's original reference implementation rather than the
|
15
|
+
# new overridden method. Mixing in this module into the implementing
|
16
|
+
# class fixes this problem.
|
17
|
+
#
|
18
|
+
# @example Using late-bound aliasing in a module
|
19
|
+
# module MyModule
|
20
|
+
# extend RDF::Util::Aliasing::LateBound
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# @example Using late-bound aliasing in a class
|
24
|
+
# class MyClass
|
25
|
+
# extend RDF::Util::Aliasing::LateBound
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# @see http://en.wikipedia.org/wiki/Name_binding
|
29
|
+
# @since 0.2.0
|
30
|
+
module LateBound
|
31
|
+
##
|
32
|
+
# Makes `new_name` a late-bound alias of the method `old_name`.
|
33
|
+
#
|
34
|
+
# @example Aliasing the `#count` method to `#size` and `#length`
|
35
|
+
# alias_method :size, :count
|
36
|
+
# alias_method :length, :count
|
37
|
+
#
|
38
|
+
# @param [Symbol, #to_sym] new_name
|
39
|
+
# @param [Symbol, #to_sym] old_name
|
40
|
+
# @return [void]
|
41
|
+
# @see http://ruby-doc.org/core/classes/Module.html#M001653
|
42
|
+
def alias_method(new_name, old_name)
|
43
|
+
new_name, old_name = new_name.to_sym, old_name.to_sym
|
44
|
+
self.__send__(:define_method, new_name) do |*args, &block|
|
45
|
+
__send__(old_name, *args, &block)
|
46
|
+
end
|
47
|
+
return self
|
48
|
+
end
|
49
|
+
end # module LateBound
|
50
|
+
end # module Aliasing
|
51
|
+
end; end # module RDF::Util
|