iq_rdf 0.2.2 → 0.2.3
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.
- checksums.yaml +4 -4
- data/iq_rdf.gemspec +2 -0
- data/lib/iq_rdf/document.rb +10 -8
- data/lib/iq_rdf/literal.rb +20 -4
- data/lib/iq_rdf/version.rb +1 -1
- data/test/test_helper.rb +2 -0
- data/test/turtle_test.rb +57 -0
- metadata +15 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e76fe4fdce925931dc7ec6d5edbbb31c205713e92162fddb028548cf13784fc6
|
|
4
|
+
data.tar.gz: 691b0e21d7db159fad7f95d478edf1fadb1884e136a761dd0d25f5166f7a7b5a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9f5ec87e657fda841765741e59e717e6864e019229901e07c957317e7da80514330264ee106821ec24e786ebc5cdc1d31557258e7594f4ba4dbcd68ac95bd53c
|
|
7
|
+
data.tar.gz: 36b99255272b484d44c8fd95546c4626c85df4813d057d7d0b6c5fe2afa287d0ce6b642e653b5226c82f722dbad8af1f9205912725adf12d6b5292bd79c18d53
|
data/iq_rdf.gemspec
CHANGED
|
@@ -32,6 +32,8 @@ Gem::Specification.new do |s|
|
|
|
32
32
|
s.add_dependency "activesupport"
|
|
33
33
|
|
|
34
34
|
s.add_development_dependency "minitest"
|
|
35
|
+
# parses generated output back, so that tests catch invalid serializations
|
|
36
|
+
s.add_development_dependency "rdf-turtle"
|
|
35
37
|
|
|
36
38
|
s.files = %w(LICENSE README.md Rakefile iq_rdf.gemspec) + Dir.glob("{lib,rails,test}/**/*")
|
|
37
39
|
s.test_files = Dir.glob("{test}/**/*")
|
data/lib/iq_rdf/document.rb
CHANGED
|
@@ -62,7 +62,9 @@ module IqRdf
|
|
|
62
62
|
render_blank_node = lambda do |res|
|
|
63
63
|
node_id = blank_nodes[res]
|
|
64
64
|
unless node_id
|
|
65
|
-
|
|
65
|
+
# size, not count: Hash does not override Enumerable#count, which
|
|
66
|
+
# walks every entry - once per blank node that is quadratic
|
|
67
|
+
node_id = blank_nodes.size + 1
|
|
66
68
|
blank_nodes[res] = node_id
|
|
67
69
|
end
|
|
68
70
|
return "_:b#{node_id}"
|
|
@@ -143,18 +145,18 @@ module IqRdf
|
|
|
143
145
|
end
|
|
144
146
|
|
|
145
147
|
def to_turtle
|
|
146
|
-
s = ""
|
|
148
|
+
s = +""
|
|
147
149
|
@namespaces.values.sort{ |n1, n2| n1.turtle_token <=> n2.turtle_token }.each do |namespace|
|
|
148
|
-
s
|
|
150
|
+
s << "@prefix #{namespace.turtle_token}: <#{namespace.uri_prefix}>.\n"
|
|
149
151
|
end
|
|
150
|
-
s
|
|
152
|
+
s << "\n"
|
|
151
153
|
@nodes.each do |subject|
|
|
152
154
|
pref = subject.to_s(@document_language)
|
|
153
155
|
indent = "".ljust(pref.length)
|
|
154
156
|
|
|
155
157
|
# Render subject, if it is defined as a RDF-type.
|
|
156
158
|
if subject.rdf_type
|
|
157
|
-
s
|
|
159
|
+
s << "#{pref} a #{subject.rdf_type}"
|
|
158
160
|
pref = ";\n" + indent
|
|
159
161
|
end
|
|
160
162
|
|
|
@@ -163,13 +165,13 @@ module IqRdf
|
|
|
163
165
|
objects = predicate.nodes.map { |object| object.to_s(indent: indent, lang: predicate.lang || subject.lang || @document_language) }
|
|
164
166
|
.join(", ")
|
|
165
167
|
|
|
166
|
-
s
|
|
168
|
+
s << "#{pref} #{predicate.to_s} #{objects}"
|
|
167
169
|
|
|
168
170
|
pref = ";\n" + indent
|
|
169
171
|
end
|
|
170
|
-
s
|
|
172
|
+
s << ".\n"
|
|
171
173
|
if @config[:empty_line_between_triples]
|
|
172
|
-
s
|
|
174
|
+
s << "\n"
|
|
173
175
|
end
|
|
174
176
|
end
|
|
175
177
|
s
|
data/lib/iq_rdf/literal.rb
CHANGED
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
module IqRdf
|
|
16
16
|
class Literal
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
# Turtle accepts the same escapes as N-Triples, so both formats share this
|
|
19
|
+
ESCAPE_MAP = {
|
|
19
20
|
"\\" => "\\\\",
|
|
20
21
|
'"' => '\\"',
|
|
21
22
|
"\n" => "\\n",
|
|
@@ -23,6 +24,12 @@ module IqRdf
|
|
|
23
24
|
"\t" => "\\t"
|
|
24
25
|
}.freeze
|
|
25
26
|
|
|
27
|
+
# Inside """...""" line breaks and tabs are legal as they are
|
|
28
|
+
LONG_ESCAPE_MAP = {
|
|
29
|
+
"\\" => "\\\\",
|
|
30
|
+
'"' => '\\"'
|
|
31
|
+
}.freeze
|
|
32
|
+
|
|
26
33
|
def initialize(obj, lang = nil, datatype = nil)
|
|
27
34
|
raise "#{datatype.inspect} is not an URI" unless datatype.nil? || datatype.is_a?(::URI) || datatype.is_a?(IqRdf::Uri)
|
|
28
35
|
@obj = obj
|
|
@@ -45,7 +52,6 @@ module IqRdf
|
|
|
45
52
|
def to_s(options = {})
|
|
46
53
|
lang = @lang || options[:lang] # Use the Literals lang when given
|
|
47
54
|
lang = (lang && lang != :none) ? "@#{lang}" : ""
|
|
48
|
-
quote = @obj.to_s.include?("\n") ? '"""' : '"'
|
|
49
55
|
datatype = if @datatype.is_a?(::URI)
|
|
50
56
|
"^^<#{@datatype.to_s}>"
|
|
51
57
|
elsif @datatype.is_a?(IqRdf::Uri)
|
|
@@ -54,7 +60,17 @@ module IqRdf
|
|
|
54
60
|
""
|
|
55
61
|
end
|
|
56
62
|
|
|
57
|
-
|
|
63
|
+
value = @obj.to_s
|
|
64
|
+
|
|
65
|
+
if value.match?(/[\n\r]/)
|
|
66
|
+
# A long string keeps line breaks readable, which is the point of
|
|
67
|
+
# Turtle over N-Triples. Its grammar allows raw line breaks and tabs,
|
|
68
|
+
# so only backslashes and quotes need escaping - escaping every quote
|
|
69
|
+
# also rules out a run of three ending the string prematurely.
|
|
70
|
+
%("""#{value.gsub(/[\\"]/, LONG_ESCAPE_MAP)}"""#{lang}#{datatype})
|
|
71
|
+
else
|
|
72
|
+
%("#{value.gsub(/[\\"\n\r\t]/, ESCAPE_MAP)}"#{lang}#{datatype})
|
|
73
|
+
end
|
|
58
74
|
end
|
|
59
75
|
|
|
60
76
|
def to_ntriples(parent_lang = nil)
|
|
@@ -67,7 +83,7 @@ module IqRdf
|
|
|
67
83
|
(lang && lang != :none) ? "@#{lang}" : ""
|
|
68
84
|
end
|
|
69
85
|
|
|
70
|
-
"\"#{@obj.to_s.gsub(/[\\"\n\r\t]/,
|
|
86
|
+
"\"#{@obj.to_s.gsub(/[\\"\n\r\t]/, ESCAPE_MAP)}\"#{suffix}"
|
|
71
87
|
end
|
|
72
88
|
|
|
73
89
|
def build_xml(xml, &block)
|
data/lib/iq_rdf/version.rb
CHANGED
data/test/test_helper.rb
CHANGED
data/test/turtle_test.rb
CHANGED
|
@@ -163,6 +163,63 @@ over two lines"""@de;
|
|
|
163
163
|
rdf
|
|
164
164
|
end
|
|
165
165
|
|
|
166
|
+
# A carriage return without a newline used to end up raw inside a short
|
|
167
|
+
# string, which is invalid Turtle and made parsers drop the statement.
|
|
168
|
+
def test_control_characters_in_literals
|
|
169
|
+
document = IqRdf::Document.new('http://www.test.de/', :lang => :none)
|
|
170
|
+
|
|
171
|
+
document << IqRdf::testemann do |t|
|
|
172
|
+
t.carriage_return("first\rsecond")
|
|
173
|
+
t.tab("left\tright")
|
|
174
|
+
t.long_with_quote("first\nends with \"")
|
|
175
|
+
t.long_with_three_quotes("first\nwith \"\"\" inside")
|
|
176
|
+
t.long_with_backslash("first\nC:\\temp")
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
assert_equal(<<rdf, document.to_turtle)
|
|
180
|
+
@prefix : <http://www.test.de/>.
|
|
181
|
+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
|
|
182
|
+
|
|
183
|
+
:testemann :carriage_return """first\rsecond""";
|
|
184
|
+
:tab "left\\tright";
|
|
185
|
+
:long_with_quote """first
|
|
186
|
+
ends with \\\"""";
|
|
187
|
+
:long_with_three_quotes """first
|
|
188
|
+
with \\\"\\\"\\\" inside""";
|
|
189
|
+
:long_with_backslash """first
|
|
190
|
+
C:\\\\temp""".
|
|
191
|
+
rdf
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# The assertions above compare against an expected string, which cements the
|
|
195
|
+
# current output but says nothing about whether it is valid Turtle. Parsing
|
|
196
|
+
# the output back does: it catches escaping that a parser rejects, or that
|
|
197
|
+
# silently changes the value.
|
|
198
|
+
def test_literals_survive_a_round_trip
|
|
199
|
+
{
|
|
200
|
+
"plain" => "just text",
|
|
201
|
+
"newline" => "first\nsecond",
|
|
202
|
+
"carriage return" => "first\rsecond",
|
|
203
|
+
"carriage return and newline" => "first\r\nsecond",
|
|
204
|
+
"tab" => "left\tright",
|
|
205
|
+
"quote" => 'said "hello"',
|
|
206
|
+
"trailing quote" => 'ends with "',
|
|
207
|
+
"three quotes" => 'a """ b',
|
|
208
|
+
"backslash" => 'C:\\temp',
|
|
209
|
+
"newline and quote" => "first\nends with \"",
|
|
210
|
+
"newline and three quotes" => "first\nwith \"\"\" inside",
|
|
211
|
+
"newline and backslash" => "first\nC:\\temp",
|
|
212
|
+
}.each do |name, value|
|
|
213
|
+
document = IqRdf::Document.new('http://www.test.de/', :lang => :none)
|
|
214
|
+
document << IqRdf::testemann.some_predicate(value)
|
|
215
|
+
|
|
216
|
+
statements = RDF::Turtle::Reader.new(document.to_turtle, validate: true).to_a
|
|
217
|
+
assert_equal 1, statements.size, "expected one statement for #{name}"
|
|
218
|
+
assert_equal value, statements.first.object.value,
|
|
219
|
+
"#{name} did not survive the round trip"
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
166
223
|
def test_supress_if_empty_otpion
|
|
167
224
|
document = IqRdf::Document.new('http://www.test.de/')
|
|
168
225
|
document.namespaces :foaf => 'http://xmlns.com/foaf/0.1/'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: iq_rdf
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Till Schulte-Coerne
|
|
@@ -65,6 +65,20 @@ dependencies:
|
|
|
65
65
|
- - ">="
|
|
66
66
|
- !ruby/object:Gem::Version
|
|
67
67
|
version: '0'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: rdf-turtle
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0'
|
|
75
|
+
type: :development
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0'
|
|
68
82
|
description: IqRdf - A builder like rdf library for ruby and rails
|
|
69
83
|
email:
|
|
70
84
|
- till.schulte-coerne@innoq.com
|