Class: Insta::Redaction::Selector
- Inherits:
-
Object
- Object
- Insta::Redaction::Selector
- Defined in:
- lib/insta/redaction/selector.rb,
sig/insta/redaction/selector.rbs
Defined Under Namespace
Classes: Segment
Constant Summary collapse
- SEGMENT_TYPES =
: Array
[:key, :index, :wildcard, :deep_wildcard, :full_range].freeze
Instance Attribute Summary collapse
-
#segments ⇒ Array[Segment]
readonly
: Array.
Instance Method Summary collapse
-
#deep_wildcard_match?(path, deep_index) ⇒ Boolean
: (Array[{ type: Symbol, value: untyped }], Integer) -> bool.
-
#exact_match?(path, expected_segments) ⇒ Boolean
: (Array[{ type: Symbol, value: untyped }], Array) -> bool.
-
#initialize(selector_string) ⇒ Selector
constructor
: (String) -> void.
-
#matches?(path) ⇒ Boolean
: (Array[{ type: Symbol, value: untyped }]) -> bool.
-
#parse(input) ⇒ Array[Segment]
: (String) -> Array.
-
#parse_bracket_segment(input, position, result) ⇒ Integer
: (String, Integer, Array) -> Integer.
-
#parse_dot_segment(input, position, result) ⇒ Integer
: (String, Integer, Array) -> Integer.
-
#parse_index_segment(input, position, result) ⇒ Integer
: (String, Integer, Array) -> Integer.
-
#parse_key_segment(input, position, result) ⇒ Integer
: (String, Integer, Array) -> Integer.
-
#parse_quoted_key_segment(input, position, result) ⇒ Integer
: (String, Integer, Array) -> Integer.
-
#parse_wildcard_segment(input, position, result) ⇒ Integer
: (String, Integer, Array) -> Integer.
-
#segment_matches?(segment, path_entry) ⇒ Boolean
: (Segment, { type: Symbol, value: untyped }) -> bool.
Constructor Details
#initialize(selector_string) ⇒ Selector
: (String) -> void
13 14 15 |
# File 'lib/insta/redaction/selector.rb', line 13 def initialize(selector_string) @segments = parse(selector_string) end |
Instance Attribute Details
Instance Method Details
#deep_wildcard_match?(path, deep_index) ⇒ Boolean
: (Array[{ type: Symbol, value: untyped }], Integer) -> bool
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/insta/redaction/selector.rb', line 142 def deep_wildcard_match?(path, deep_index) before = segments[0...deep_index] || [] #: Array[Segment] after = segments[(deep_index + 1)..] || [] #: Array[Segment] return false if path.length < before.length + after.length before.each_with_index do |segment, index| return false unless segment_matches?(segment, path[index]) end return true if after.empty? after_length = after.length path_length = path.length after.each_with_index do |segment, index| path_index = path_length - after_length + index return false unless segment_matches?(segment, path[path_index]) end true end |
#exact_match?(path, expected_segments) ⇒ Boolean
: (Array[{ type: Symbol, value: untyped }], Array) -> bool
166 167 168 169 170 171 172 173 174 |
# File 'lib/insta/redaction/selector.rb', line 166 def exact_match?(path, expected_segments) return false unless path.length == expected_segments.length expected_segments.each_with_index do |segment, index| return false unless segment_matches?(segment, path[index]) end true end |
#matches?(path) ⇒ Boolean
: (Array[{ type: Symbol, value: untyped }]) -> bool
18 19 20 21 22 23 24 25 26 |
# File 'lib/insta/redaction/selector.rb', line 18 def matches?(path) deep_index = segments.index { |segment| segment.type == :deep_wildcard } if deep_index deep_wildcard_match?(path, deep_index) else exact_match?(path, segments) end end |
#parse(input) ⇒ Array[Segment]
: (String) -> Array
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/insta/redaction/selector.rb', line 31 def parse(input) raise ArgumentError, "Selector must not be empty" if input.empty? raise ArgumentError, "Selector must start with '.' or '['" unless input.start_with?(".", "[") result = [] #: Array[Segment] position = 0 while position < input.length case input[position] when "." position = parse_dot_segment(input, position + 1, result) when "[" position = parse_bracket_segment(input, position + 1, result) else raise ArgumentError, "Unexpected character '#{input[position]}' at position #{position}" end end result end |
#parse_bracket_segment(input, position, result) ⇒ Integer
: (String, Integer, Array) -> Integer
93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/insta/redaction/selector.rb', line 93 def parse_bracket_segment(input, position, result) if position < input.length && input[position] == "]" result << Segment.new(type: :full_range, value: nil) position + 1 elsif position < input.length && input[position] == '"' parse_quoted_key_segment(input, position + 1, result) else parse_index_segment(input, position, result) end end |
#parse_dot_segment(input, position, result) ⇒ Integer
: (String, Integer, Array) -> Integer
53 54 55 56 57 58 59 |
# File 'lib/insta/redaction/selector.rb', line 53 def parse_dot_segment(input, position, result) if position < input.length && input[position] == "*" parse_wildcard_segment(input, position + 1, result) else parse_key_segment(input, position, result) end end |
#parse_index_segment(input, position, result) ⇒ Integer
: (String, Integer, Array) -> Integer
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/insta/redaction/selector.rb', line 125 def parse_index_segment(input, position, result) digits = +"" while position < input.length && input[position] =~ /\d/ digits << input[position].to_s position += 1 end raise ArgumentError, "Expected number or ']' in bracket" if digits.empty? raise ArgumentError, "Expected ']' after index" if position >= input.length || input[position] != "]" result << Segment.new(type: :index, value: digits.to_i) position + 1 end |
#parse_key_segment(input, position, result) ⇒ Integer
: (String, Integer, Array) -> Integer
77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/insta/redaction/selector.rb', line 77 def parse_key_segment(input, position, result) key = +"" while position < input.length && input[position] != "." && input[position] != "[" key << input[position].to_s position += 1 end raise ArgumentError, "Empty key in selector at position #{position}" if key.empty? result << Segment.new(type: :key, value: key) position end |
#parse_quoted_key_segment(input, position, result) ⇒ Integer
: (String, Integer, Array) -> Integer
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/insta/redaction/selector.rb', line 106 def parse_quoted_key_segment(input, position, result) key = +"" while position < input.length && input[position] != '"' key << input[position].to_s position += 1 end raise ArgumentError, "Unterminated quoted key in selector" if position >= input.length position += 1 raise ArgumentError, "Expected ']' after quoted key" if position >= input.length || input[position] != "]" result << Segment.new(type: :key, value: key) position + 1 end |
#parse_wildcard_segment(input, position, result) ⇒ Integer
: (String, Integer, Array) -> Integer
62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/insta/redaction/selector.rb', line 62 def parse_wildcard_segment(input, position, result) if position < input.length && input[position] == "*" raise ArgumentError, "Only one deep wildcard (**) allowed per selector" if result.any? { |segment| segment.type == :deep_wildcard } result << Segment.new(type: :deep_wildcard, value: nil) position + 1 else result << Segment.new(type: :wildcard, value: nil) position end end |
#segment_matches?(segment, path_entry) ⇒ Boolean
: (Segment, { type: Symbol, value: untyped }) -> bool
177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/insta/redaction/selector.rb', line 177 def segment_matches?(segment, path_entry) case segment.type when :key path_entry[:type] == :key && path_entry[:value].to_s == segment.value when :index path_entry[:type] == :index && path_entry[:value] == segment.value when :wildcard path_entry[:type] == :key when :full_range path_entry[:type] == :index else false end end |