lib/jsonpath/parser.rb in jsonpath-1.0.2 vs lib/jsonpath/parser.rb in jsonpath-1.0.3

- old
+ new

@@ -44,45 +44,54 @@ item = item.strip.gsub(/\)*$/, '').gsub(/^\(*/, '') @_expr_map[item] = parse_exp(item) end end - #  using a scanner break down the individual expressions and determine if + # Using a scanner break down the individual expressions and determine if # there is a match in the JSON for it or not. def parse_exp(exp) exp = exp.sub(/@/, '').gsub(/^\(/, '').gsub(/\)$/, '').tr('"', '\'').strip + exp.scan(/^\[(\d+)\]/) do |i| + next if i.empty? + + index = Integer(i[0]) + raise ArgumentError, 'Node does not appear to be an array.' unless @_current_node.is_a?(Array) + raise ArgumentError, "Index out of bounds for nested array. Index: #{index}" if @_current_node.size < index + + @_current_node = @_current_node[index] + # Remove the extra '' and the index. + exp = exp.gsub(/^\[\d+\]|\[''\]/, '') + end scanner = StringScanner.new(exp) elements = [] until scanner.eos? - if t = scanner.scan(/\['[a-zA-Z@&\*\/\$%\^\?_]+'\]|\.[a-zA-Z0-9_]+[?!]?/) + if (t = scanner.scan(/\['[a-zA-Z@&*\/$%^?_]+'\]|\.[a-zA-Z0-9_]+[?!]?/)) elements << t.gsub(/[\[\]'\.]|\s+/, '') - elsif t = scanner.scan(/(\s+)?[<>=!\-+][=~]?(\s+)?/) + elsif (t = scanner.scan(/(\s+)?[<>=!\-+][=~]?(\s+)?/)) operator = t - elsif t = scanner.scan(/(\s+)?'?.*'?(\s+)?/) + elsif (t = scanner.scan(/(\s+)?'?.*'?(\s+)?/)) # If we encounter a node which does not contain `'` it means #  that we are dealing with a boolean type. operand = if t == 'true' true elsif t == 'false' false else operator.to_s.strip == '=~' ? t.to_regexp : t.gsub(%r{^'|'$}, '').strip end - elsif t = scanner.scan(/\/\w+\//) - elsif t = scanner.scan(/.*/) + elsif (t = scanner.scan(/\/\w+\//)) + elsif (t = scanner.scan(/.*/)) raise "Could not process symbol: #{t}" end end el = if elements.empty? @_current_node elsif @_current_node.is_a?(Hash) @_current_node.dig(*elements) else - elements.inject(@_current_node) do |agg, key| - agg.__send__(key) - end + elements.inject(@_current_node, &:__send__) end return (el ? true : false) if el.nil? || operator.nil? el = Float(el) rescue el @@ -115,24 +124,23 @@ # one giant parenthesis. top = to_parse.split(/(&&)|(\|\|)/) top = top.map(&:strip) res = bool_or_exp(top.shift) top.each_with_index do |item, index| - case item - when '&&' + if item == '&&' res &&= top[index + 1] - when '||' + elsif item == '||' res ||= top[index + 1] end end #  if we are at the last item, the opening index will be 0 # and the closing index will be the last index. To avoid # off-by-one errors we simply return the result at that point. if closing_index + 1 >= str.length && opening_index == 0 - return res.to_s + res.to_s else - return "#{str[0..opening_index - 1]}#{res}#{str[closing_index + 1..str.length]}" + "#{str[0..opening_index - 1]}#{res}#{str[closing_index + 1..str.length]}" end end #  This is convoluted and I should probably refactor it somehow. #  The map that is created will contain strings since essentially I'm