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

Class Method Summary collapse

Class Method Details

.escape(str) ⇒ Object



35
36
37
38
39
40
41
# File 'lib/janeway/normalized_path.rb', line 35

def self.escape(str)
  # Common case, all chars are normal.
  return str if str.chars.all? { |char| NORMAL_UNESCAPED_RANGES.any? { |range| range.include?(char.ord) } }

  # 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

Parameters:

  • char (String)

    single character, possibly multi-byte

Returns:

  • (String)


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/janeway/normalized_path.rb', line 46

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

Parameters:

  • char (String)

    single character, possibly multi-byte

Returns:

  • (String)


69
70
71
# File 'lib/janeway/normalized_path.rb', line 69

def self.hex_encode_char(char)
  format('\\u00%02x', char.ord)
end

.normalize(value) ⇒ Object



14
15
16
17
18
19
20
21
# File 'lib/janeway/normalized_path.rb', line 14

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]”.

Parameters:

  • index (Integer)

    index selector value

Returns:

  • (String)

    eg. “[1]”



25
26
27
# File 'lib/janeway/normalized_path.rb', line 25

def self.normalize_index(index)
  "[#{index}]"
end

.normalize_name(name) ⇒ String

Returns eg. “[”]”.

Parameters:

  • name (Integer)

    name selector value

Returns:

  • (String)

    eg. “[”]”



31
32
33
# File 'lib/janeway/normalized_path.rb', line 31

def self.normalize_name(name)
  "['#{escape(name)}']"
end