Module: Janeway::NormalizedPath
- Defined in:
- lib/janeway/normalized_path.rb
Overview
Converts index and name selector values to normalized path components.
This implements the normalized path description in RFC 9535: This does a lot of escaping, and much of it is the inverse of Lexer code that does un-escaping.
Constant Summary collapse
- NORMAL_UNESCAPED_RANGES =
Characters that do not need escaping, defined by hexadecimal range
[(0x20..0x26), (0x28..0x5B), (0x5D..0xD7FF), (0xE000..0x10FFFF)].freeze
- NORMAL_UNESCAPED_REGEX =
Fast-path check for
escape: a single anchored regex covering the same ranges as NORMAL_UNESCAPED_RANGES. Avoids allocating acharsarray and scanning four Range objects per character on the common all-normal case. Regexp.new( '\A[' + NORMAL_UNESCAPED_RANGES.map { |r| "\\u{#{r.min.to_s(16)}}-\\u{#{r.max.to_s(16)}}" }.join + ']*\z' ).freeze
Class Method Summary collapse
- .escape(str) ⇒ Object
-
.escape_char(char) ⇒ String
Escape or hex-encode the given character.
-
.hex_encode_char(char) ⇒ String
Hex-encode the given character.
- .normalize(value) ⇒ Object
-
.normalize_index(index) ⇒ String
Eg.
-
.normalize_name(name) ⇒ String
Eg.
Class Method Details
.escape(str) ⇒ Object
44 45 46 47 48 49 50 |
# File 'lib/janeway/normalized_path.rb', line 44 def self.escape(str) # Common case, all chars are normal — one regex match, no allocations. return str if NORMAL_UNESCAPED_REGEX.match?(str) # Some escaping must be done str.chars.map { |char| escape_char(char) }.join end |
.escape_char(char) ⇒ String
Escape or hex-encode the given character
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/janeway/normalized_path.rb', line 55 def self.escape_char(char) # Character ranges defined by https://www.rfc-editor.org/rfc/rfc9535.html#section-2.7-8 case char.ord # normal-unescaped range when 0x20..0x26, 0x28..0x5B, 0x5D..0xD7FF, 0xE000..0x10FFFF then char # unescaped # normal-escapable range when 0x08 then '\\b' # backspace when 0x0C then '\\f' # form feed when 0x0A then '\\n' # line feed / newline when 0x0D then '\\r' # carriage return when 0x09 then '\\t' # horizontal tab when 0x27 then '\\\'' # apostrophe when 0x5C then '\\\\' # backslash else # normal-hexchar range hex_encode_char(char) end end |
.hex_encode_char(char) ⇒ String
Hex-encode the given character
78 79 80 |
# File 'lib/janeway/normalized_path.rb', line 78 def self.hex_encode_char(char) format('\\u00%02x', char.ord) end |
.normalize(value) ⇒ Object
23 24 25 26 27 28 29 30 |
# File 'lib/janeway/normalized_path.rb', line 23 def self.normalize(value) case value when String then normalize_name(value) when Integer then normalize_index(value) else raise "Cannot normalize #{value.inspect}" end end |
.normalize_index(index) ⇒ String
Returns eg. "[1]".
34 35 36 |
# File 'lib/janeway/normalized_path.rb', line 34 def self.normalize_index(index) "[#{index}]" end |
.normalize_name(name) ⇒ String
Returns eg. "['']".
40 41 42 |
# File 'lib/janeway/normalized_path.rb', line 40 def self.normalize_name(name) "['#{escape(name)}']" end |