11# frozen_string_literal: true
22
33require 'strscan'
4- require 'to_regexp'
54
65class JsonPath
76 # Parser parses and evaluates an expression passed to @_current_node.
87 class Parser
8+ REGEX = /\A \/ (.+)\/ ([imxnesu]*)\z |\A %r{(.+)}([imxnesu]*)\z /
9+
910 def initialize ( node )
1011 @_current_node = node
1112 @_expr_map = { }
@@ -71,13 +72,16 @@ def parse_exp(exp)
7172 elsif ( t = scanner . scan ( /(\s +)?'?.*'?(\s +)?/ ) )
7273 # If we encounter a node which does not contain `'` it means
7374 # that we are dealing with a boolean type.
74- operand = if t == 'true'
75- true
76- elsif t == 'false'
77- false
78- else
79- operator . to_s . strip == '=~' ? t . to_regexp : t . gsub ( %r{^'|'$} , '' ) . strip
80- end
75+ operand =
76+ if t == 'true'
77+ true
78+ elsif t == 'false'
79+ false
80+ elsif operator . to_s . strip == '=~'
81+ parse_regex ( t )
82+ else
83+ t . gsub ( %r{^'|'$} , '' ) . strip
84+ end
8185 elsif ( t = scanner . scan ( /\/ \w +\/ / ) )
8286 elsif ( t = scanner . scan ( /.*/ ) )
8387 raise "Could not process symbol: #{ t } "
@@ -102,6 +106,31 @@ def parse_exp(exp)
102106
103107 private
104108
109+ # /foo/i -> Regex.new("foo", Regexp::IGNORECASE) without using eval
110+ # also supports %r{foo}i
111+ # following https://github.com/seamusabshere/to_regexp/blob/master/lib/to_regexp.rb
112+ def parse_regex ( t )
113+ t =~ REGEX
114+ content = $1 || $3
115+ options = $2 || $4
116+
117+ raise "unsupported regex #{ t } use /foo/ style" if !content || !options
118+
119+ content = content . gsub '\\/' , '/'
120+
121+ flags = 0
122+ flags |= Regexp ::IGNORECASE if options . include? ( 'i' )
123+ flags |= Regexp ::MULTILINE if options . include? ( 'm' )
124+ flags |= Regexp ::EXTENDED if options . include? ( 'x' )
125+
126+ # 'n' = none, 'e' = EUC, 's' = SJIS, 'u' = UTF-8
127+ lang = options . scan ( /[nes]/ ) . join . downcase # ignores u since that is default and causes a warning
128+
129+ args = [ content , flags ]
130+ args << lang unless lang . empty? # avoid warning
131+ Regexp . new ( *args )
132+ end
133+
105134 # This will break down a parenthesis from the left to the right
106135 # and replace the given expression with it's returned value.
107136 # It does this in order to make it easy to eliminate groups
0 commit comments