Skip to content

Commit e753d0c

Browse files
committed
Single quote (') was missing from N-Triples/Quads escaped characters.
1 parent 5fb4774 commit e753d0c

4 files changed

Lines changed: 32 additions & 17 deletions

File tree

lib/rdf/ntriples/reader.rb

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class Reader < RDF::Reader
3232
format RDF::NTriples::Format
3333

3434
# @see http://www.w3.org/TR/rdf-testcases/#ntrip_strings
35-
ESCAPE_CHARS = ["\b", "\f", "\t", "\n", "\r", "\"", "\\"].freeze
35+
ESCAPE_CHARS = ["\b", "\f", "\t", "\n", "\r", "\"", "'", "\\"].freeze
3636
UCHAR4 = /\\u([0-9A-Fa-f]{4,4})/.freeze
3737
UCHAR8 = /\\U([0-9A-Fa-f]{8,8})/.freeze
3838
UCHAR = Regexp.union(UCHAR4, UCHAR8).freeze
@@ -60,7 +60,7 @@ class Reader < RDF::Reader
6060
# 166s
6161
PN_CHARS = /-|[0-9]|#{PN_CHARS_U}|#{U_CHARS2}/.freeze
6262
# 159s
63-
ECHAR = /\\[tbnrf\\"]/.freeze
63+
ECHAR = /\\[tbnrf"'\\]/.freeze
6464
# 18
6565
IRIREF = /<((?:#{IRI_RANGE}|#{UCHAR})*)>/.freeze
6666
# 141s
@@ -155,9 +155,16 @@ def self.parse_literal(input, **options)
155155
end
156156

157157
# cache constants to optimize escaping the escape chars in self.unescape
158-
ESCAPE_CHARS_ESCAPED = ESCAPE_CHARS.each_with_object({}) do |escape, memo|
159-
memo[escape.inspect[1...-1]] = escape
160-
end.freeze
158+
ESCAPE_CHARS_ESCAPED = {
159+
"\\b" => "\b",
160+
"\\f" => "\f",
161+
"\\t" => "\t",
162+
"\\n" => "\n",
163+
"\\r" => "\r",
164+
"\\\"" => "\"",
165+
"\\'" => "'",
166+
"\\\\" => "\\"
167+
} .freeze
161168
ESCAPE_CHARS_ESCAPED_REGEXP = Regexp.union(
162169
ESCAPE_CHARS_ESCAPED.keys
163170
).freeze
@@ -180,7 +187,7 @@ def self.unescape(string)
180187

181188
string = string.dup if has_escape_chars || has_uchar
182189

183-
# Decode \t|\n|\r|\"|\\ character escapes using Regexp:
190+
# Decode \t|\n|\r|\"\'\|\\ character escapes using Regexp:
184191
string.gsub!(ESCAPE_CHARS_ESCAPED_REGEXP) do
185192
ESCAPE_CHARS_ESCAPED.fetch($~[0])
186193
end if has_escape_chars

lib/rdf/ntriples/writer.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class Writer < RDF::Writer
4242
format RDF::NTriples::Format
4343

4444
# @see http://www.w3.org/TR/rdf-testcases/#ntrip_strings
45-
ESCAPE_PLAIN = /\A[\x20-\x21\x23-#{Regexp.escape '['}#{Regexp.escape ']'}-\x7E]*\z/m.freeze
45+
ESCAPE_PLAIN = /\A[\x20-\x21\x23-\x26\x28#{Regexp.escape '['}#{Regexp.escape ']'}-\x7E]*\z/m.freeze
4646
ESCAPE_PLAIN_U = /\A(?:#{Reader::IRI_RANGE}|#{Reader::UCHAR})*\z/.freeze
4747

4848
##
@@ -132,6 +132,7 @@ def self.escape_ascii(u, encoding)
132132
when (0x0D) then "\\r"
133133
when (0x0E..0x1F) then escape_utf16(u)
134134
when (0x22) then "\\\""
135+
when (0x27) then "\\'"
135136
when (0x5C) then "\\\\"
136137
when (0x7F) then escape_utf16(u)
137138
when (0x00..0x7F) then u.chr
@@ -264,7 +265,7 @@ def format_uri(uri, **options)
264265
string.each_char do |u|
265266
buffer << case u.ord
266267
when (0x00..0x20) then self.class.escape_utf16(u)
267-
when 0x22, 0x3c, 0x3e, 0x5c, 0x5e, 0x60, 0x7b, 0x7c, 0x7d # <>"{}|`\
268+
when 0x22, 0x3c, 0x3e, 0x5c, 0x5e, 0x60, 0x7b, 0x7c, 0x7d # "<>\^`{|}
268269
self.class.escape_utf16(u)
269270
else u
270271
end
@@ -278,7 +279,7 @@ def format_uri(uri, **options)
278279
string.each_byte do |u|
279280
buffer << case u
280281
when (0x00..0x20) then self.class.escape_utf16(u)
281-
when 0x22, 0x3c, 0x3e, 0x5c, 0x5e, 0x60, 0x7b, 0x7c, 0x7d # <>"{}|`\
282+
when 0x22, 0x3c, 0x3e, 0x5c, 0x5e, 0x60, 0x7b, 0x7c, 0x7d # "<>\^`{|}
282283
self.class.escape_utf16(u)
283284
when (0x80..0xFFFF) then self.class.escape_utf16(u)
284285
when (0x10000..0x10FFFF) then self.class.escape_utf32(u)

lib/rdf/repository.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,9 @@ def delete_insert(deletes, inserts)
206206
# @private
207207
# @see RDF::Enumerable#project_graph
208208
def project_graph(graph_name, &block)
209-
RDF::Graph.new(graph_name: graph_name, data: self).
210-
project_graph(graph_name, &block)
209+
graph = RDF::Graph.new(graph_name: graph_name, data: self)
210+
graph.each(&block) if block_given?
211+
graph
211212
end
212213

213214
##

spec/ntriples_spec.rb

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@
291291
'Dürst' => '_:a <http://pred> "D\u00FCrst" .',
292292
'simple literal' => '<http://subj> <http://pred> "simple literal" .',
293293
'backslash:\\' => '<http://subj> <http://pred> "backslash:\\\\" .',
294+
'squote:\'' => '<http://subj> <http://pred> "squote:\'" .',
294295
'dquote:"' => '<http://subj> <http://pred> "dquote:\"" .',
295296
"newline:\n" => '<http://subj> <http://pred> "newline:\n" .',
296297
"return\r" => '<http://subj> <http://pred> "return\r" .',
@@ -334,10 +335,11 @@
334335
"line ending with CR NL" => "<http://example.org/resource4> <http://example.org/property> <http://example.org/resource2> .\r\n",
335336
"literal escapes (1)" => '<http://example.org/resource7> <http://example.org/property> "simple literal" .',
336337
"literal escapes (2)" => '<http://example.org/resource8> <http://example.org/property> "backslash:\\\\" .',
337-
"literal escapes (3)" => '<http://example.org/resource9> <http://example.org/property> "dquote:\"" .',
338-
"literal escapes (4)" => '<http://example.org/resource10> <http://example.org/property> "newline:\n" .',
339-
"literal escapes (5)" => '<http://example.org/resource11> <http://example.org/property> "return:\r" .',
340-
"literal escapes (6)" => '<http://example.org/resource12> <http://example.org/property> "tab:\t" .',
338+
"literal escapes (3)" => '<http://example.org/resource9> <http://example.org/property> "squote:\'" .',
339+
"literal escapes (4)" => '<http://example.org/resource9> <http://example.org/property> "dquote:\"" .',
340+
"literal escapes (5)" => '<http://example.org/resource10> <http://example.org/property> "newline:\n" .',
341+
"literal escapes (6)" => '<http://example.org/resource11> <http://example.org/property> "return:\r" .',
342+
"literal escapes (7)" => '<http://example.org/resource12> <http://example.org/property> "tab:\t" .',
341343
"Space is optional before final . (2)" => ['<http://example.org/resource14> <http://example.org/property> "x".', '<http://example.org/resource14> <http://example.org/property> "x" .'],
342344

343345
"XML Literals as Datatyped Literals (1)" => '<http://example.org/resource21> <http://example.org/property> ""^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .',
@@ -678,7 +680,9 @@
678680
(0x0E..0x1F).each { |u| expect(writer.escape(u.chr, encoding)).to eq "\\u#{u.to_s(16).upcase.rjust(4, '0')}" }
679681
(0x20..0x21).each { |u| expect(writer.escape(u.chr, encoding)).to eq u.chr }
680682
expect(writer.escape(0x22.chr, encoding)).to eq "\\\""
681-
(0x23..0x5B).each { |u| expect(writer.escape(u.chr, encoding)).to eq u.chr }
683+
(0x23..0x26).each { |u| expect(writer.escape(u.chr, encoding)).to eq u.chr }
684+
expect(writer.escape(0x27.chr, encoding)).to eq "\\'"
685+
(0x28..0x5B).each { |u| expect(writer.escape(u.chr, encoding)).to eq u.chr }
682686
expect(writer.escape(0x5C.chr, encoding)).to eq "\\\\"
683687
(0x5D..0x7E).each { |u| expect(writer.escape(u.chr, encoding)).to eq u.chr }
684688
expect(writer.escape(0x7F.chr, encoding)).to eq "\\u007F"
@@ -738,7 +742,9 @@
738742
(0x0E..0x1F).each { |u| expect(writer.escape(u.chr, encoding)).to eq "\\u#{u.to_s(16).upcase.rjust(4, '0')}" }
739743
(0x20..0x21).each { |u| expect(writer.escape(u.chr, encoding)).to eq u.chr }
740744
expect(writer.escape(0x22.chr, encoding)).to eq "\\\""
741-
(0x23..0x5B).each { |u| expect(writer.escape(u.chr, encoding)).to eq u.chr }
745+
(0x23..0x26).each { |u| expect(writer.escape(u.chr, encoding)).to eq u.chr }
746+
expect(writer.escape(0x27.chr, encoding)).to eq "\\'"
747+
(0x28..0x5B).each { |u| expect(writer.escape(u.chr, encoding)).to eq u.chr }
742748
expect(writer.escape(0x5C.chr, encoding)).to eq "\\\\"
743749
(0x5D..0x7E).each { |u| expect(writer.escape(u.chr, encoding)).to eq u.chr }
744750
expect(writer.escape(0x7F.chr, encoding)).to eq "\\u007F"

0 commit comments

Comments
 (0)