Skip to content

Commit 3f26a8d

Browse files
committed
Exclude '_' and '-' from PN_LOCAL escapes. Not all reserved characters need to be escaped in SPARQL/Turtle, but they must be unescaped when encountered.
1 parent 47e399b commit 3f26a8d

3 files changed

Lines changed: 17 additions & 5 deletions

File tree

lib/rdf/model/uri.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,9 @@ class URI
112112
).freeze
113113

114114
# Characters in a PName which must be escaped
115-
PN_ESCAPE_CHARS = /[~\.\-!\$&'\(\)\*\+,;=\/\?\#@%_]/.freeze
116-
PN_ESCAPES = /\\#{PN_ESCAPE_CHARS}/.freeze
115+
# Note: not all reserved characters need to be escaped in SPARQL/Turtle, but they must be unescaped when encountered
116+
PN_ESCAPE_CHARS = /[~\.!\$&'\(\)\*\+,;=\/\?\#@%]/.freeze
117+
PN_ESCAPES = /\\#{Regexp.union(PN_ESCAPE_CHARS, /[\-_]/)}/.freeze
117118

118119
##
119120
# Cache size may be set through {RDF.config} using `uri_cache_size`.

lib/rdf/vocabulary.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ def expand_pname(pname)
389389
return pname unless pname.is_a?(String) || pname.is_a?(Symbol)
390390
prefix, suffix = pname.to_s.split(":", 2)
391391
# Unescape escaped PN_ESCAPE_CHARS
392-
if suffix.match?(/\\#{RDF::URI::PN_ESCAPE_CHARS}/)
392+
if suffix.match?(RDF::URI::PN_ESCAPES)
393393
suffix = suffix.gsub(RDF::URI::PN_ESCAPES) {|matched| matched[1..-1]}
394394
end
395395
if prefix == "rdf"

spec/model_uri_spec.rb

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -890,7 +890,6 @@
890890

891891
context "escapes" do
892892
{
893-
"http://example.org/c-" => 'ex:c\-',
894893
"http://example.org/c!" => 'ex:c\!',
895894
"http://example.org/c$" => 'ex:c\$',
896895
"http://example.org/c&" => 'ex:c\&',
@@ -899,7 +898,7 @@
899898
"http://example.org/c*+" => 'ex:c\*\+',
900899
"http://example.org/c;=" => 'ex:c\;\=',
901900
"http://example.org/c/#" => 'ex:c\/\#',
902-
"http://example.org/c@_" => 'ex:c\@\_',
901+
"http://example.org/c@" => 'ex:c\@',
903902
"http://example.org/c:d?" => 'ex:c:d\?',
904903
"http://example.org/c~z." => 'ex:c\~z\.',
905904
}.each do |orig, result|
@@ -910,6 +909,18 @@
910909
expect(pname).to eql result
911910
end
912911
end
912+
913+
{
914+
"http://example.org/c-" => 'ex:c\-',
915+
"http://example.org/c_" => 'ex:c\_',
916+
}.each do |orig, result|
917+
it "does not #{orig} => #{result}" do
918+
uri = RDF::URI(orig)
919+
pname = uri.pname(prefixes: {ex: "http://example.org/"})
920+
expect(uri).to be_valid
921+
expect(pname).not_to eql result
922+
end
923+
end
913924
end
914925
end
915926

0 commit comments

Comments
 (0)