Class: JsonPath::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/jsonpath/parser.rb

Overview

Parser parses and evaluates an expression passed to @_current_node.

Instance Method Summary collapse

Constructor Details

#initialize(node) ⇒ Parser

Returns a new instance of Parser.



9
10
11
12
# File 'lib/jsonpath/parser.rb', line 9

def initialize(node)
  @_current_node = node
  @_expr_map = {}
end

Instance Method Details

#construct_expression_map(exps) ⇒ Object

Construct a map for which the keys are the expressions  and the values are the corresponding parsed results. Exp.: =~ /herman|lukyanenko/i)”=>0 “@[‘isTrue’]”=>true



41
42
43
44
45
46
47
# File 'lib/jsonpath/parser.rb', line 41

def construct_expression_map(exps)
  exps.each_with_index do |item, index|
    next if item == '&&' || item == '||'
    item = item.strip.gsub(/\)*$/, '').gsub(/^\(*/, '')
    @_expr_map[item] = parse_exp(item)
  end
end

#parse(exp) ⇒ Object

parse will parse an expression in the following way. Split the expression up into an array of legs for && and || operators. Parse this array into a map for which the keys are the parsed legs  of the split. This map is then used to replace the expression with their corresponding boolean or numeric value. This might look something like this: ((false || false) && (false || true))  Once this string is assembled… we proceed to evaluate from left to right.  The above string is broken down like this: (false && (false || true)) (false && true)  false

Raises:

  • (ArgumentError)


25
26
27
28
29
30
31
32
33
34
# File 'lib/jsonpath/parser.rb', line 25

def parse(exp)
  exps = exp.split(/(&&)|(\|\|)/)
  construct_expression_map(exps)
  @_expr_map.each {|k, v| exp.sub!(k, "#{v}")}
  raise ArgumentError, "unmatched parenthesis in expression: #{exp}" unless check_parenthesis_count(exp)
  while (exp.include?("("))
    exp = parse_parentheses(exp)
  end
  bool_or_exp(exp)
end

#parse_exp(exp) ⇒ Object

 using a scanner break down the individual expressions and determine if there is a match in the JSON for it or not.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/jsonpath/parser.rb', line 51

def parse_exp(exp)
  exp = exp.sub(/@/, '').gsub(/^\(/, '').gsub(/\)$/, '').tr('"', '\'').strip
  scanner = StringScanner.new(exp)
  elements = []
  until scanner.eos?
    if scanner.scan(/\./)
      sym = scanner.scan(/\w+/)
      op = scanner.scan(/./)
      num = scanner.scan(/\d+/)
      return @_current_node.send(sym.to_sym).send(op.to_sym, num.to_i)
    end
    if t = scanner.scan(/\['[a-zA-Z@&\*\/\$%\^\?_]+'\]+/)
      elements << t.gsub(/\[|\]|'|\s+/, '')
    elsif t = scanner.scan(/(\s+)?[<>=][=~]?(\s+)?/)
      operator = t
    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(/.*/)
      raise "Could not process symbol: #{t}"
    end
  end

  el = if elements.empty?
         @_current_node
       else
         dig(elements, @_current_node)
       end
  return false if el.nil?
  return true if operator.nil? && el

  el = Float(el) rescue el
  operand = Float(operand) rescue operand

  el.__send__(operator.strip, operand)
end