Skip to content

Commit 16e5bc2

Browse files
committed
Properly unescaep PN_LOCAL_ESC.
1 parent 76bc642 commit 16e5bc2

5 files changed

Lines changed: 96 additions & 14 deletions

File tree

lib/rdf/turtle/freebase_reader.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@ def read_pname(**options)
6464
end
6565
pfx_iri = prefix(ns)
6666
raise RDF::ReaderError.new("ERROR [line #{lineno}] prefix #{ns.inspect} is not defined", lineno: lineno) unless pfx_iri
67+
68+
# Unescape PN_LOCAL_ESC
69+
suffix = suffix.gsub(PN_LOCAL_ESC) {|esc| esc[1]} if
70+
suffix.match?(PN_LOCAL_ESC)
71+
72+
# Remove any redundant leading hash from suffix
73+
suffix = suffix.sub(/^\#/, "") if pfx_iri.to_s.index("#")
74+
6775
uri = RDF::URI(pfx_iri + suffix)
6876
uri.validate! if validate?
6977
uri

lib/rdf/turtle/reader.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,14 @@ def pname(prefix, suffix)
227227
error("undefined prefix", production: :pname, token: prefix)
228228
''
229229
end
230-
suffix = suffix.to_s.sub(/^\#/, "") if base.index("#")
230+
231+
# Unescape PN_LOCAL_ESC
232+
suffix = suffix.gsub(PN_LOCAL_ESC) {|esc| esc[1]} if
233+
suffix.match?(PN_LOCAL_ESC)
234+
235+
# Remove any redundant leading hash from suffix
236+
suffix = suffix.sub(/^\#/, "") if base.index("#")
237+
231238
debug("pname", depth: options[:depth]) {"base: '#{base}', suffix: '#{suffix}'"}
232239
process_iri(base + suffix.to_s)
233240
end

spec/freebase_spec.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,42 @@
8383
g = RDF::Graph.new << subject
8484
expect(g).to be_equivalent_graph("@prefix foo: <http://example/bar#> ." + input, logger: @logger)
8585
end
86+
87+
context "PN_LOCAL" do
88+
{
89+
"p:_a": "<http://a.example/_a>", # PN_CHARS_U
90+
"p::": "<http://a.example/:>", # PN_LOCAL
91+
"p:0": "<http://a.example/0>", # PN_LOCAL
92+
"p:%B7": "<http://a.example/%B7>", # PN_LOCAL
93+
"p:a.b": "<http://a.example/a.b>", # PN_LOCAL
94+
95+
"p:\\_underscore": "<http://a.example/_underscore>", # PN_LOCAL_ESC
96+
"p:\\~tilda": "<http://a.example/~tilda>", # PN_LOCAL_ESC
97+
"p:\\.dot": "<http://a.example/.dot>", # PN_LOCAL_ESC
98+
"p:\\-dash": "<http://a.example/-dash>", # PN_LOCAL_ESC
99+
"p:\\!exclamation": "<http://a.example/!exclamation>", # PN_LOCAL_ESC
100+
"p:\\$dollar": "<http://a.example/$dollar>", # PN_LOCAL_ESC
101+
"p:\\&amper": "<http://a.example/&amper>", # PN_LOCAL_ESC
102+
"p:\\'squote": "<http://a.example/'squote>", # PN_LOCAL_ESC
103+
"p:\\(paren\\)": "<http://a.example/(paren)>", # PN_LOCAL_ESC
104+
"p:\\*star": "<http://a.example/*star>", # PN_LOCAL_ESC
105+
"p:\\+plus": "<http://a.example/+plus>", # PN_LOCAL_ESC
106+
"p:\\,comma": "<http://a.example/,comma>", # PN_LOCAL_ESC
107+
"p:\\;semi": "<http://a.example/;semi>", # PN_LOCAL_ESC
108+
"p:\\=equal": "<http://a.example/=equal>", # PN_LOCAL_ESC
109+
"p:\\/slash": "<http://a.example//slash>", # PN_LOCAL_ESC
110+
"p:\\?question": "<http://a.example/?question>", # PN_LOCAL_ESC
111+
"p:\\#numbersign": "<http://a.example/#numbersign>", # PN_LOCAL_ESC
112+
"p:\\@ampersand": "<http://a.example/@ampersand>", # PN_LOCAL_ESC
113+
"p:\\%percent": "<http://a.example/%percent>", # PN_LOCAL_ESC
114+
}.each do |pn, iri|
115+
it pn do
116+
ttl = %(@prefix p: <http://a.example/> .\n p:s p:p #{pn} .)
117+
nt = %(<http://a.example/s> <http://a.example/p> #{iri} .)
118+
expect(parse(ttl, validate: false)).to be_equivalent_graph(nt, logger: @logger)
119+
end
120+
end
121+
end
86122
end
87123

88124
describe "with simple sample data" do

spec/reader_spec.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,42 @@
489489
nil => "http://test/"})
490490
end
491491

492+
context "PN_LOCAL" do
493+
{
494+
"p:_a": "<http://a.example/_a>", # PN_CHARS_U
495+
"p::": "<http://a.example/:>", # PN_LOCAL
496+
"p:0": "<http://a.example/0>", # PN_LOCAL
497+
"p:%B7": "<http://a.example/%B7>", # PN_LOCAL
498+
"p:a.b": "<http://a.example/a.b>", # PN_LOCAL
499+
500+
"p:\\_underscore": "<http://a.example/_underscore>", # PN_LOCAL_ESC
501+
"p:\\~tilda": "<http://a.example/~tilda>", # PN_LOCAL_ESC
502+
"p:\\.dot": "<http://a.example/.dot>", # PN_LOCAL_ESC
503+
"p:\\-dash": "<http://a.example/-dash>", # PN_LOCAL_ESC
504+
"p:\\!exclamation": "<http://a.example/!exclamation>", # PN_LOCAL_ESC
505+
"p:\\$dollar": "<http://a.example/$dollar>", # PN_LOCAL_ESC
506+
"p:\\&amper": "<http://a.example/&amper>", # PN_LOCAL_ESC
507+
"p:\\'squote": "<http://a.example/'squote>", # PN_LOCAL_ESC
508+
"p:\\(paren\\)": "<http://a.example/(paren)>", # PN_LOCAL_ESC
509+
"p:\\*star": "<http://a.example/*star>", # PN_LOCAL_ESC
510+
"p:\\+plus": "<http://a.example/+plus>", # PN_LOCAL_ESC
511+
"p:\\,comma": "<http://a.example/,comma>", # PN_LOCAL_ESC
512+
"p:\\;semi": "<http://a.example/;semi>", # PN_LOCAL_ESC
513+
"p:\\=equal": "<http://a.example/=equal>", # PN_LOCAL_ESC
514+
"p:\\/slash": "<http://a.example//slash>", # PN_LOCAL_ESC
515+
"p:\\?question": "<http://a.example/?question>", # PN_LOCAL_ESC
516+
"p:\\#numbersign": "<http://a.example/#numbersign>", # PN_LOCAL_ESC
517+
"p:\\@ampersand": "<http://a.example/@ampersand>", # PN_LOCAL_ESC
518+
"p:\\%percent": "<http://a.example/%percent>", # PN_LOCAL_ESC
519+
}.each do |pn, iri|
520+
it pn do
521+
ttl = %(PREFIX p: <http://a.example/>\n p:s p:p #{pn} .)
522+
nt = %(<http://a.example/s> <http://a.example/p> #{iri} .)
523+
expect(parse(ttl, validate: false)).to be_equivalent_graph(nt, logger: @logger)
524+
end
525+
end
526+
end
527+
492528
{
493529
"@prefix foo: <http://foo/bar#> ." => [true, true],
494530
"@PrEfIx foo: <http://foo/bar#> ." => [false, true],

spec/terminals_spec.rb

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,16 @@
4444
! # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : / < = ? @
4545
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
4646
_ a b c d e f g h i j k l m n o p q r s t u v w x y z ~
47-
ab\\u00E9xy ab\xC3\xA9xy>
48-
\\u03B1:a \xCE\xB1:a
49-
a\\u003Ab a\x3Ab
50-
\\U00010000 \xF0\x90\x80\x80
51-
\\U000EFFFF \xF3\xAF\xBF\xBF
47+
ab\\u00E9xy
48+
\\u03B1:a
49+
a\\u003Ab
50+
\\U00010000
51+
\\U000EFFFF
5252
).each do |string|
5353
it "matches <scheme:#{string.inspect}>" do
54-
begin
55-
string = "<scheme:#{string}>"
56-
string.force_encoding(Encoding::UTF_8)
57-
expect(string).to match(RDF::Turtle::Terminals::IRIREF)
58-
rescue RSpec::Expectations::ExpectationNotMetError
59-
pending "Escapes in IRIs"
60-
fail
61-
end
54+
string = "<scheme:#{string}>"
55+
string.force_encoding(Encoding::UTF_8)
56+
expect(string).to match(RDF::Turtle::Terminals::IRIREF)
6257
end
6358
end
6459
end

0 commit comments

Comments
 (0)