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
# 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
  when 0x20..0x26, 0x28..0x5B, 0x5D..0xD7FF, 0xE000..0x10FFFF # normal-unescaped range
    char # unescaped
  when 0x62, 0x66, 0x6E, 0x72, 0x74, 0x27, 0x5C # normal-escapable range
    # backspace, form feed, line feed, carriage return, horizontal tab, apostrophe, backslash
    "\\#{char}" # escaped
  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)


62
63
64
# File 'lib/janeway/normalized_path.rb', line 62

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