jmespath 1.1.3 → 1.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of jmespath might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/jmespath.rb +3 -2
- data/lib/jmespath/lexer.rb +12 -4
- data/lib/jmespath/nodes.rb +2 -0
- data/lib/jmespath/nodes/and.rb +25 -0
- data/lib/jmespath/nodes/condition.rb +3 -3
- data/lib/jmespath/nodes/field.rb +6 -3
- data/lib/jmespath/nodes/function.rb +88 -57
- data/lib/jmespath/nodes/not.rb +19 -0
- data/lib/jmespath/nodes/or.rb +1 -1
- data/lib/jmespath/nodes/slice.rb +1 -2
- data/lib/jmespath/parser.rb +30 -4
- data/lib/jmespath/runtime.rb +7 -2
- data/lib/jmespath/token.rb +5 -3
- data/lib/jmespath/util.rb +22 -0
- data/lib/jmespath/version.rb +1 -1
- metadata +20 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fdb6bfadd1b501b4a2316f67248a96b51e350e00
|
4
|
+
data.tar.gz: edf12df4b8e49fc520f507098947c381d4312de1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 135adb95e2c213b911405e10412eb8484009605555433109a12f954aa96376818c74ef94af18868fd7fe309956d6a6457341c5621aeb76ff743f57192a4f8e2b
|
7
|
+
data.tar.gz: c5a3165e77c71faf9f62bba531b8b5091da2f9224693052c27899fee2ba15bd4f5a79e1fb2e5bc1e1407d5927362819ce226b6e6688f3e2a749a11c097a23dd8
|
data/lib/jmespath.rb
CHANGED
@@ -13,6 +13,7 @@ module JMESPath
|
|
13
13
|
autoload :Runtime, 'jmespath/runtime'
|
14
14
|
autoload :Token, 'jmespath/token'
|
15
15
|
autoload :TokenStream, 'jmespath/token_stream'
|
16
|
+
autoload :Util, 'jmespath/util'
|
16
17
|
autoload :VERSION, 'jmespath/version'
|
17
18
|
|
18
19
|
class << self
|
@@ -23,14 +24,14 @@ module JMESPath
|
|
23
24
|
# @param [Hash] data
|
24
25
|
# @return [Mixed,nil] Returns the matched values. Returns `nil` if the
|
25
26
|
# expression does not resolve inside `data`.
|
26
|
-
def search(expression, data)
|
27
|
+
def search(expression, data, runtime_options = {})
|
27
28
|
data = case data
|
28
29
|
when Hash, Struct then data # check for most common case first
|
29
30
|
when Pathname then load_json(data)
|
30
31
|
when IO, StringIO then JSON.load(data.read)
|
31
32
|
else data
|
32
33
|
end
|
33
|
-
Runtime.new.search(expression, data)
|
34
|
+
Runtime.new(runtime_options).search(expression, data)
|
34
35
|
end
|
35
36
|
|
36
37
|
# @api private
|
data/lib/jmespath/lexer.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
gem('json', '>= 1.8.1') # fix for Ruby 1.9.3
|
2
|
+
|
1
3
|
require 'json'
|
2
4
|
require 'set'
|
3
5
|
|
@@ -24,6 +26,8 @@ module JMESPath
|
|
24
26
|
T_UNKNOWN = :unknown
|
25
27
|
T_PIPE = :pipe
|
26
28
|
T_OR = :or
|
29
|
+
T_AND = :and
|
30
|
+
T_NOT = :not
|
27
31
|
T_FILTER = :filter
|
28
32
|
T_LITERAL = :literal
|
29
33
|
T_EOF = :eof
|
@@ -42,6 +46,7 @@ module JMESPath
|
|
42
46
|
STATE_GT = 10
|
43
47
|
STATE_EQ = 11
|
44
48
|
STATE_NOT = 12
|
49
|
+
STATE_AND = 13
|
45
50
|
|
46
51
|
TRANSLATION_TABLE = {
|
47
52
|
'<' => STATE_LT,
|
@@ -50,6 +55,7 @@ module JMESPath
|
|
50
55
|
'!' => STATE_NOT,
|
51
56
|
'[' => STATE_LBRACKET,
|
52
57
|
'|' => STATE_PIPE,
|
58
|
+
'&' => STATE_AND,
|
53
59
|
'`' => STATE_JSON_LITERAL,
|
54
60
|
'"' => STATE_QUOTED_STRING,
|
55
61
|
"'" => STATE_STRING_LITERAL,
|
@@ -74,7 +80,6 @@ module JMESPath
|
|
74
80
|
',' => STATE_SINGLE_CHAR,
|
75
81
|
':' => STATE_SINGLE_CHAR,
|
76
82
|
'@' => STATE_SINGLE_CHAR,
|
77
|
-
'&' => STATE_SINGLE_CHAR,
|
78
83
|
'(' => STATE_SINGLE_CHAR,
|
79
84
|
')' => STATE_SINGLE_CHAR,
|
80
85
|
'{' => STATE_SINGLE_CHAR,
|
@@ -149,7 +154,6 @@ module JMESPath
|
|
149
154
|
',' => T_COMMA,
|
150
155
|
':' => T_COLON,
|
151
156
|
'@' => T_CURRENT,
|
152
|
-
'&' => T_EXPREF,
|
153
157
|
'(' => T_LPAREN,
|
154
158
|
')' => T_RPAREN,
|
155
159
|
'{' => T_LBRACE,
|
@@ -210,7 +214,9 @@ module JMESPath
|
|
210
214
|
end
|
211
215
|
when STATE_STRING_LITERAL
|
212
216
|
# consume raw string literals
|
213
|
-
|
217
|
+
t = inside(chars, "'", T_LITERAL)
|
218
|
+
t.value = t.value.gsub("\\'", "'")
|
219
|
+
tokens << t
|
214
220
|
when STATE_PIPE
|
215
221
|
# consume pipe and OR
|
216
222
|
tokens << match_or(chars, '|', '|', T_OR, T_PIPE)
|
@@ -245,9 +251,11 @@ module JMESPath
|
|
245
251
|
when STATE_EQ
|
246
252
|
# consume equals
|
247
253
|
tokens << match_or(chars, '=', '=', T_COMPARATOR, T_UNKNOWN)
|
254
|
+
when STATE_AND
|
255
|
+
tokens << match_or(chars, '&', '&', T_AND, T_EXPREF)
|
248
256
|
when STATE_NOT
|
249
257
|
# consume not equals
|
250
|
-
tokens << match_or(chars, '!', '=', T_COMPARATOR,
|
258
|
+
tokens << match_or(chars, '!', '=', T_COMPARATOR, T_NOT);
|
251
259
|
else
|
252
260
|
# either '<' or '>'
|
253
261
|
# consume less than and greater than
|
data/lib/jmespath/nodes.rb
CHANGED
@@ -18,6 +18,7 @@ module JMESPath
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
+
autoload :And, 'jmespath/nodes/and'
|
21
22
|
autoload :Comparator, 'jmespath/nodes/comparator'
|
22
23
|
autoload :Comparators, 'jmespath/nodes/comparator'
|
23
24
|
autoload :Condition, 'jmespath/nodes/condition'
|
@@ -30,6 +31,7 @@ module JMESPath
|
|
30
31
|
autoload :Literal, 'jmespath/nodes/literal'
|
31
32
|
autoload :MultiSelectHash, 'jmespath/nodes/multi_select_hash'
|
32
33
|
autoload :MultiSelectList, 'jmespath/nodes/multi_select_list'
|
34
|
+
autoload :Not, 'jmespath/nodes/not'
|
33
35
|
autoload :Or, 'jmespath/nodes/or'
|
34
36
|
autoload :Pipe, 'jmespath/nodes/pipe'
|
35
37
|
autoload :Projection, 'jmespath/nodes/projection'
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module JMESPath
|
2
|
+
module Nodes
|
3
|
+
class And < Node
|
4
|
+
|
5
|
+
def initialize(left, right)
|
6
|
+
@left = left
|
7
|
+
@right = right
|
8
|
+
end
|
9
|
+
|
10
|
+
def visit(value)
|
11
|
+
result = @left.visit(value)
|
12
|
+
if JMESPath::Util.falsey?(result)
|
13
|
+
result
|
14
|
+
else
|
15
|
+
@right.visit(value)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def optimize
|
20
|
+
self.class.new(@left.optimize, @right.optimize)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/jmespath/nodes/field.rb
CHANGED
@@ -46,8 +46,8 @@ module JMESPath
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
-
def visit(
|
50
|
-
@keys.reduce(
|
49
|
+
def visit(obj)
|
50
|
+
@keys.reduce(obj) do |value, key|
|
51
51
|
if value.is_a?(Array) && key.is_a?(Integer)
|
52
52
|
value[key]
|
53
53
|
elsif value.is_a?(Hash)
|
@@ -68,7 +68,10 @@ module JMESPath
|
|
68
68
|
|
69
69
|
private
|
70
70
|
|
71
|
-
|
71
|
+
def keys
|
72
|
+
@keys
|
73
|
+
end
|
74
|
+
|
72
75
|
end
|
73
76
|
end
|
74
77
|
end
|
@@ -5,13 +5,15 @@ module JMESPath
|
|
5
5
|
|
6
6
|
FUNCTIONS = {}
|
7
7
|
|
8
|
-
def initialize(children)
|
8
|
+
def initialize(children, options = {})
|
9
9
|
@children = children
|
10
|
+
@options = options
|
11
|
+
@disable_visit_errors = @options[:disable_visit_errors]
|
10
12
|
end
|
11
13
|
|
12
|
-
def self.create(name, children)
|
14
|
+
def self.create(name, children, options = {})
|
13
15
|
if (type = FUNCTIONS[name])
|
14
|
-
type.new(children)
|
16
|
+
type.new(children, options)
|
15
17
|
else
|
16
18
|
raise Errors::UnknownFunctionError, "unknown function #{name}()"
|
17
19
|
end
|
@@ -22,7 +24,7 @@ module JMESPath
|
|
22
24
|
end
|
23
25
|
|
24
26
|
def optimize
|
25
|
-
self.class.new(@children.map(&:optimize))
|
27
|
+
self.class.new(@children.map(&:optimize), @options)
|
26
28
|
end
|
27
29
|
|
28
30
|
class FunctionName
|
@@ -35,6 +37,12 @@ module JMESPath
|
|
35
37
|
|
36
38
|
private
|
37
39
|
|
40
|
+
def maybe_raise(error_type, message)
|
41
|
+
unless @disable_visit_errors
|
42
|
+
raise error_type, message
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
38
46
|
def call(args)
|
39
47
|
nil
|
40
48
|
end
|
@@ -79,12 +87,12 @@ module JMESPath
|
|
79
87
|
if args.count == 1
|
80
88
|
value = args.first
|
81
89
|
else
|
82
|
-
|
90
|
+
return maybe_raise Errors::InvalidArityError, "function abs() expects one argument"
|
83
91
|
end
|
84
92
|
if Numeric === value
|
85
93
|
value.abs
|
86
94
|
else
|
87
|
-
|
95
|
+
return maybe_raise Errors::InvalidTypeError, "function abs() expects a number"
|
88
96
|
end
|
89
97
|
end
|
90
98
|
end
|
@@ -96,18 +104,18 @@ module JMESPath
|
|
96
104
|
if args.count == 1
|
97
105
|
values = args.first
|
98
106
|
else
|
99
|
-
|
107
|
+
return maybe_raise Errors::InvalidArityError, "function avg() expects one argument"
|
100
108
|
end
|
101
109
|
if Array === values
|
102
110
|
values.inject(0) do |total,n|
|
103
111
|
if Numeric === n
|
104
112
|
total + n
|
105
113
|
else
|
106
|
-
|
114
|
+
return maybe_raise Errors::InvalidTypeError, "function avg() expects numeric values"
|
107
115
|
end
|
108
116
|
end / values.size.to_f
|
109
117
|
else
|
110
|
-
|
118
|
+
return maybe_raise Errors::InvalidTypeError, "function avg() expects a number"
|
111
119
|
end
|
112
120
|
end
|
113
121
|
end
|
@@ -119,12 +127,12 @@ module JMESPath
|
|
119
127
|
if args.count == 1
|
120
128
|
value = args.first
|
121
129
|
else
|
122
|
-
|
130
|
+
return maybe_raise Errors::InvalidArityError, "function ceil() expects one argument"
|
123
131
|
end
|
124
132
|
if Numeric === value
|
125
133
|
value.ceil
|
126
134
|
else
|
127
|
-
|
135
|
+
return maybe_raise Errors::InvalidTypeError, "function ceil() expects a numeric value"
|
128
136
|
end
|
129
137
|
end
|
130
138
|
end
|
@@ -139,10 +147,10 @@ module JMESPath
|
|
139
147
|
if String === haystack || Array === haystack
|
140
148
|
haystack.include?(needle)
|
141
149
|
else
|
142
|
-
|
150
|
+
return maybe_raise Errors::InvalidTypeError, "contains expects 2nd arg to be a list"
|
143
151
|
end
|
144
152
|
else
|
145
|
-
|
153
|
+
return maybe_raise Errors::InvalidArityError, "function contains() expects 2 arguments"
|
146
154
|
end
|
147
155
|
end
|
148
156
|
end
|
@@ -154,12 +162,12 @@ module JMESPath
|
|
154
162
|
if args.count == 1
|
155
163
|
value = args.first
|
156
164
|
else
|
157
|
-
|
165
|
+
return maybe_raise Errors::InvalidArityError, "function floor() expects one argument"
|
158
166
|
end
|
159
167
|
if Numeric === value
|
160
168
|
value.floor
|
161
169
|
else
|
162
|
-
|
170
|
+
return maybe_raise Errors::InvalidTypeError, "function floor() expects a numeric value"
|
163
171
|
end
|
164
172
|
end
|
165
173
|
end
|
@@ -171,15 +179,38 @@ module JMESPath
|
|
171
179
|
if args.count == 1
|
172
180
|
value = args.first
|
173
181
|
else
|
174
|
-
|
182
|
+
return maybe_raise Errors::InvalidArityError, "function length() expects one argument"
|
175
183
|
end
|
176
184
|
case value
|
177
185
|
when Hash, Array, String then value.size
|
178
|
-
else
|
186
|
+
else return maybe_raise Errors::InvalidTypeError, "function length() expects string, array or object"
|
179
187
|
end
|
180
188
|
end
|
181
189
|
end
|
182
190
|
|
191
|
+
class Map < Function
|
192
|
+
|
193
|
+
FUNCTIONS['map'] = self
|
194
|
+
|
195
|
+
def call(args)
|
196
|
+
if args.count != 2
|
197
|
+
return maybe_raise Errors::InvalidArityError, "function map() expects two arguments"
|
198
|
+
end
|
199
|
+
if Nodes::Expression === args[0]
|
200
|
+
expr = args[0]
|
201
|
+
else
|
202
|
+
return maybe_raise Errors::InvalidTypeError, "function map() expects the first argument to be an expression"
|
203
|
+
end
|
204
|
+
if Array === args[1]
|
205
|
+
list = args[1]
|
206
|
+
else
|
207
|
+
return maybe_raise Errors::InvalidTypeError, "function map() expects the second argument to be an list"
|
208
|
+
end
|
209
|
+
list.map { |value| expr.eval(value) }
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
|
183
214
|
class MaxFunction < Function
|
184
215
|
include TypeChecker
|
185
216
|
|
@@ -189,7 +220,7 @@ module JMESPath
|
|
189
220
|
if args.count == 1
|
190
221
|
values = args.first
|
191
222
|
else
|
192
|
-
|
223
|
+
return maybe_raise Errors::InvalidArityError, "function max() expects one argument"
|
193
224
|
end
|
194
225
|
if Array === values
|
195
226
|
return nil if values.empty?
|
@@ -197,7 +228,7 @@ module JMESPath
|
|
197
228
|
first_type = get_type(first)
|
198
229
|
unless first_type == NUMBER_TYPE || first_type == STRING_TYPE
|
199
230
|
msg = "function max() expects numeric or string values"
|
200
|
-
|
231
|
+
return maybe_raise Errors::InvalidTypeError, msg
|
201
232
|
end
|
202
233
|
values.inject([first, first_type]) do |(max, max_type), v|
|
203
234
|
v_type = get_type(v)
|
@@ -206,11 +237,11 @@ module JMESPath
|
|
206
237
|
else
|
207
238
|
msg = "function max() encountered a type mismatch in sequence: "
|
208
239
|
msg << "#{max_type}, #{v_type}"
|
209
|
-
|
240
|
+
return maybe_raise Errors::InvalidTypeError, msg
|
210
241
|
end
|
211
242
|
end.first
|
212
243
|
else
|
213
|
-
|
244
|
+
return maybe_raise Errors::InvalidTypeError, "function max() expects an array"
|
214
245
|
end
|
215
246
|
end
|
216
247
|
end
|
@@ -224,7 +255,7 @@ module JMESPath
|
|
224
255
|
if args.count == 1
|
225
256
|
values = args.first
|
226
257
|
else
|
227
|
-
|
258
|
+
return maybe_raise Errors::InvalidArityError, "function min() expects one argument"
|
228
259
|
end
|
229
260
|
if Array === values
|
230
261
|
return nil if values.empty?
|
@@ -232,7 +263,7 @@ module JMESPath
|
|
232
263
|
first_type = get_type(first)
|
233
264
|
unless first_type == NUMBER_TYPE || first_type == STRING_TYPE
|
234
265
|
msg = "function min() expects numeric or string values"
|
235
|
-
|
266
|
+
return maybe_raise Errors::InvalidTypeError, msg
|
236
267
|
end
|
237
268
|
values.inject([first, first_type]) do |(min, min_type), v|
|
238
269
|
v_type = get_type(v)
|
@@ -241,11 +272,11 @@ module JMESPath
|
|
241
272
|
else
|
242
273
|
msg = "function min() encountered a type mismatch in sequence: "
|
243
274
|
msg << "#{min_type}, #{v_type}"
|
244
|
-
|
275
|
+
return maybe_raise Errors::InvalidTypeError, msg
|
245
276
|
end
|
246
277
|
end.first
|
247
278
|
else
|
248
|
-
|
279
|
+
return maybe_raise Errors::InvalidTypeError, "function min() expects an array"
|
249
280
|
end
|
250
281
|
end
|
251
282
|
end
|
@@ -259,7 +290,7 @@ module JMESPath
|
|
259
290
|
if args.count == 1
|
260
291
|
TYPE_NAMES[get_type(args.first)]
|
261
292
|
else
|
262
|
-
|
293
|
+
return maybe_raise Errors::InvalidArityError, "function type() expects one argument"
|
263
294
|
end
|
264
295
|
end
|
265
296
|
end
|
@@ -277,10 +308,10 @@ module JMESPath
|
|
277
308
|
else raise NotImplementedError
|
278
309
|
end
|
279
310
|
else
|
280
|
-
|
311
|
+
return maybe_raise Errors::InvalidTypeError, "function keys() expects a hash"
|
281
312
|
end
|
282
313
|
else
|
283
|
-
|
314
|
+
return maybe_raise Errors::InvalidArityError, "function keys() expects one argument"
|
284
315
|
end
|
285
316
|
end
|
286
317
|
end
|
@@ -296,10 +327,10 @@ module JMESPath
|
|
296
327
|
elsif Array === value
|
297
328
|
value
|
298
329
|
else
|
299
|
-
|
330
|
+
return maybe_raise Errors::InvalidTypeError, "function values() expects an array or a hash"
|
300
331
|
end
|
301
332
|
else
|
302
|
-
|
333
|
+
return maybe_raise Errors::InvalidArityError, "function values() expects one argument"
|
303
334
|
end
|
304
335
|
end
|
305
336
|
end
|
@@ -312,14 +343,14 @@ module JMESPath
|
|
312
343
|
glue = args[0]
|
313
344
|
values = args[1]
|
314
345
|
if !(String === glue)
|
315
|
-
|
346
|
+
return maybe_raise Errors::InvalidTypeError, "function join() expects the first argument to be a string"
|
316
347
|
elsif Array === values && values.all? { |v| String === v }
|
317
348
|
values.join(glue)
|
318
349
|
else
|
319
|
-
|
350
|
+
return maybe_raise Errors::InvalidTypeError, "function join() expects values to be an array of strings"
|
320
351
|
end
|
321
352
|
else
|
322
|
-
|
353
|
+
return maybe_raise Errors::InvalidArityError, "function join() expects an array of strings"
|
323
354
|
end
|
324
355
|
end
|
325
356
|
end
|
@@ -332,7 +363,7 @@ module JMESPath
|
|
332
363
|
value = args.first
|
333
364
|
String === value ? value : JSON.dump(value)
|
334
365
|
else
|
335
|
-
|
366
|
+
return maybe_raise Errors::InvalidArityError, "function to_string() expects one argument"
|
336
367
|
end
|
337
368
|
end
|
338
369
|
end
|
@@ -349,7 +380,7 @@ module JMESPath
|
|
349
380
|
nil
|
350
381
|
end
|
351
382
|
else
|
352
|
-
|
383
|
+
return maybe_raise Errors::InvalidArityError, "function to_number() expects one argument"
|
353
384
|
end
|
354
385
|
end
|
355
386
|
end
|
@@ -363,11 +394,11 @@ module JMESPath
|
|
363
394
|
if Numeric === n
|
364
395
|
sum + n
|
365
396
|
else
|
366
|
-
|
397
|
+
return maybe_raise Errors::InvalidTypeError, "function sum() expects values to be numeric"
|
367
398
|
end
|
368
399
|
end
|
369
400
|
else
|
370
|
-
|
401
|
+
return maybe_raise Errors::InvalidArityError, "function sum() expects one argument"
|
371
402
|
end
|
372
403
|
end
|
373
404
|
end
|
@@ -379,7 +410,7 @@ module JMESPath
|
|
379
410
|
if args.count > 0
|
380
411
|
args.find { |value| !value.nil? }
|
381
412
|
else
|
382
|
-
|
413
|
+
return maybe_raise Errors::InvalidArityError, "function not_null() expects one or more arguments"
|
383
414
|
end
|
384
415
|
end
|
385
416
|
end
|
@@ -399,14 +430,14 @@ module JMESPath
|
|
399
430
|
if (a_type == STRING_TYPE || a_type == NUMBER_TYPE) && a_type == b_type
|
400
431
|
a <=> b
|
401
432
|
else
|
402
|
-
|
433
|
+
return maybe_raise Errors::InvalidTypeError, "function sort() expects values to be an array of numbers or integers"
|
403
434
|
end
|
404
435
|
end
|
405
436
|
else
|
406
|
-
|
437
|
+
return maybe_raise Errors::InvalidTypeError, "function sort() expects values to be an array of numbers or integers"
|
407
438
|
end
|
408
439
|
else
|
409
|
-
|
440
|
+
return maybe_raise Errors::InvalidArityError, "function sort() expects one argument"
|
410
441
|
end
|
411
442
|
end
|
412
443
|
end
|
@@ -429,14 +460,14 @@ module JMESPath
|
|
429
460
|
if (a_type == STRING_TYPE || a_type == NUMBER_TYPE) && a_type == b_type
|
430
461
|
a_value <=> b_value
|
431
462
|
else
|
432
|
-
|
463
|
+
return maybe_raise Errors::InvalidTypeError, "function sort() expects values to be an array of numbers or integers"
|
433
464
|
end
|
434
465
|
end
|
435
466
|
else
|
436
|
-
|
467
|
+
return maybe_raise Errors::InvalidTypeError, "function sort_by() expects an array and an expression"
|
437
468
|
end
|
438
469
|
else
|
439
|
-
|
470
|
+
return maybe_raise Errors::InvalidArityError, "function sort_by() expects two arguments"
|
440
471
|
end
|
441
472
|
end
|
442
473
|
end
|
@@ -452,7 +483,7 @@ module JMESPath
|
|
452
483
|
type = get_type(expression.eval(values.first))
|
453
484
|
if type != NUMBER_TYPE && type != STRING_TYPE
|
454
485
|
msg = "function #{mode}() expects values to be strings or numbers"
|
455
|
-
|
486
|
+
return maybe_raise Errors::InvalidTypeError, msg
|
456
487
|
end
|
457
488
|
values.send(mode) do |entry|
|
458
489
|
value = expression.eval(entry)
|
@@ -460,17 +491,17 @@ module JMESPath
|
|
460
491
|
if value_type != type
|
461
492
|
msg = "function #{mode}() encountered a type mismatch in "
|
462
493
|
msg << "sequence: #{type}, #{value_type}"
|
463
|
-
|
494
|
+
return maybe_raise Errors::InvalidTypeError, msg
|
464
495
|
end
|
465
496
|
value
|
466
497
|
end
|
467
498
|
else
|
468
499
|
msg = "function #{mode}() expects an array and an expression"
|
469
|
-
|
500
|
+
return maybe_raise Errors::InvalidTypeError, msg
|
470
501
|
end
|
471
502
|
else
|
472
503
|
msg = "function #{mode}() expects two arguments"
|
473
|
-
|
504
|
+
return maybe_raise Errors::InvalidArityError, msg
|
474
505
|
end
|
475
506
|
end
|
476
507
|
end
|
@@ -507,16 +538,16 @@ module JMESPath
|
|
507
538
|
suffix_type = get_type(suffix)
|
508
539
|
if search_type != STRING_TYPE
|
509
540
|
msg = "function ends_with() expects first argument to be a string"
|
510
|
-
|
541
|
+
return maybe_raise Errors::InvalidTypeError, msg
|
511
542
|
end
|
512
543
|
if suffix_type != STRING_TYPE
|
513
544
|
msg = "function ends_with() expects second argument to be a string"
|
514
|
-
|
545
|
+
return maybe_raise Errors::InvalidTypeError, msg
|
515
546
|
end
|
516
547
|
search.end_with?(suffix)
|
517
548
|
else
|
518
549
|
msg = "function ends_with() expects two arguments"
|
519
|
-
|
550
|
+
return maybe_raise Errors::InvalidArityError, msg
|
520
551
|
end
|
521
552
|
end
|
522
553
|
end
|
@@ -533,16 +564,16 @@ module JMESPath
|
|
533
564
|
prefix_type = get_type(prefix)
|
534
565
|
if search_type != STRING_TYPE
|
535
566
|
msg = "function starts_with() expects first argument to be a string"
|
536
|
-
|
567
|
+
return maybe_raise Errors::InvalidTypeError, msg
|
537
568
|
end
|
538
569
|
if prefix_type != STRING_TYPE
|
539
570
|
msg = "function starts_with() expects second argument to be a string"
|
540
|
-
|
571
|
+
return maybe_raise Errors::InvalidTypeError, msg
|
541
572
|
end
|
542
573
|
search.start_with?(prefix)
|
543
574
|
else
|
544
575
|
msg = "function starts_with() expects two arguments"
|
545
|
-
|
576
|
+
return maybe_raise Errors::InvalidArityError, msg
|
546
577
|
end
|
547
578
|
end
|
548
579
|
end
|
@@ -553,7 +584,7 @@ module JMESPath
|
|
553
584
|
def call(args)
|
554
585
|
if args.count == 0
|
555
586
|
msg = "function merge() expects 1 or more arguments"
|
556
|
-
|
587
|
+
return maybe_raise Errors::InvalidArityError, msg
|
557
588
|
end
|
558
589
|
args.inject({}) do |h, v|
|
559
590
|
h.merge(v)
|
@@ -567,14 +598,14 @@ module JMESPath
|
|
567
598
|
def call(args)
|
568
599
|
if args.count == 0
|
569
600
|
msg = "function reverse() expects 1 or more arguments"
|
570
|
-
|
601
|
+
return maybe_raise Errors::InvalidArityError, msg
|
571
602
|
end
|
572
603
|
value = args.first
|
573
604
|
if Array === value || String === value
|
574
605
|
value.reverse
|
575
606
|
else
|
576
607
|
msg = "function reverse() expects an array or string"
|
577
|
-
|
608
|
+
return maybe_raise Errors::InvalidTypeError, msg
|
578
609
|
end
|
579
610
|
end
|
580
611
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module JMESPath
|
2
|
+
module Nodes
|
3
|
+
class Not < Node
|
4
|
+
|
5
|
+
def initialize(expression)
|
6
|
+
@expression = expression
|
7
|
+
end
|
8
|
+
|
9
|
+
def visit(value)
|
10
|
+
JMESPath::Util.falsey?(@expression.visit(value))
|
11
|
+
end
|
12
|
+
|
13
|
+
def optimize
|
14
|
+
self.class.new(@expression.optimize)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/jmespath/nodes/or.rb
CHANGED
data/lib/jmespath/nodes/slice.rb
CHANGED
@@ -6,6 +6,7 @@ module JMESPath
|
|
6
6
|
@start = start
|
7
7
|
@stop = stop
|
8
8
|
@step = step
|
9
|
+
raise Errors::InvalidValueError.new('slice step cannot be 0') if @step == 0
|
9
10
|
end
|
10
11
|
|
11
12
|
def visit(value)
|
@@ -44,8 +45,6 @@ module JMESPath
|
|
44
45
|
def adjust_slice(length, start, stop, step)
|
45
46
|
if step.nil?
|
46
47
|
step = 1
|
47
|
-
elsif step == 0
|
48
|
-
raise Errors::InvalidValueError, 'slice step cannot be 0'
|
49
48
|
end
|
50
49
|
|
51
50
|
if start.nil?
|
data/lib/jmespath/parser.rb
CHANGED
@@ -29,6 +29,7 @@ module JMESPath
|
|
29
29
|
# @option options [Lexer] :lexer
|
30
30
|
def initialize(options = {})
|
31
31
|
@lexer = options[:lexer] || Lexer.new
|
32
|
+
@disable_visit_errors = options[:disable_visit_errors]
|
32
33
|
end
|
33
34
|
|
34
35
|
# @param [String<JMESPath>] expression
|
@@ -71,7 +72,22 @@ module JMESPath
|
|
71
72
|
|
72
73
|
def nud_expref(stream)
|
73
74
|
stream.next
|
74
|
-
Nodes::Expression.new(expr(stream,
|
75
|
+
Nodes::Expression.new(expr(stream, Token::BINDING_POWER[:expref]))
|
76
|
+
end
|
77
|
+
|
78
|
+
def nud_not(stream)
|
79
|
+
stream.next
|
80
|
+
Nodes::Not.new(expr(stream, Token::BINDING_POWER[:not]))
|
81
|
+
end
|
82
|
+
|
83
|
+
def nud_lparen(stream)
|
84
|
+
stream.next
|
85
|
+
result = expr(stream, 0)
|
86
|
+
if stream.token.type != Lexer::T_RPAREN
|
87
|
+
raise Errors::SyntaxError, 'Unclosed `(`'
|
88
|
+
end
|
89
|
+
stream.next
|
90
|
+
result
|
75
91
|
end
|
76
92
|
|
77
93
|
def nud_filter(stream)
|
@@ -142,7 +158,7 @@ module JMESPath
|
|
142
158
|
def led_comparator(stream, left)
|
143
159
|
token = stream.token
|
144
160
|
stream.next
|
145
|
-
right = expr(stream)
|
161
|
+
right = expr(stream, Token::BINDING_POWER[:comparator])
|
146
162
|
Nodes::Comparator.create(token.value, left, right)
|
147
163
|
end
|
148
164
|
|
@@ -189,7 +205,11 @@ module JMESPath
|
|
189
205
|
|
190
206
|
def led_lparen(stream, left)
|
191
207
|
args = []
|
192
|
-
|
208
|
+
if Nodes::Function::FunctionName === left
|
209
|
+
name = left.name
|
210
|
+
else
|
211
|
+
raise Errors::SyntaxError, 'invalid function invocation'
|
212
|
+
end
|
193
213
|
stream.next
|
194
214
|
while stream.token.type != :rparen
|
195
215
|
args << expr(stream, 0)
|
@@ -198,7 +218,7 @@ module JMESPath
|
|
198
218
|
end
|
199
219
|
end
|
200
220
|
stream.next
|
201
|
-
Nodes::Function.create(name, args)
|
221
|
+
Nodes::Function.create(name, args, :disable_visit_errors => @disable_visit_errors)
|
202
222
|
end
|
203
223
|
|
204
224
|
def led_or(stream, left)
|
@@ -207,6 +227,12 @@ module JMESPath
|
|
207
227
|
Nodes::Or.new(left, right)
|
208
228
|
end
|
209
229
|
|
230
|
+
def led_and(stream, left)
|
231
|
+
stream.next
|
232
|
+
right = expr(stream, Token::BINDING_POWER[:or])
|
233
|
+
Nodes::And.new(left, right)
|
234
|
+
end
|
235
|
+
|
210
236
|
def led_pipe(stream, left)
|
211
237
|
stream.next
|
212
238
|
right = expr(stream, Token::BINDING_POWER[:pipe])
|
data/lib/jmespath/runtime.rb
CHANGED
@@ -3,7 +3,7 @@ module JMESPath
|
|
3
3
|
class Runtime
|
4
4
|
|
5
5
|
# @api private
|
6
|
-
DEFAULT_PARSER = CachingParser
|
6
|
+
DEFAULT_PARSER = CachingParser
|
7
7
|
|
8
8
|
# Constructs a new runtime object for evaluating JMESPath expressions.
|
9
9
|
#
|
@@ -35,6 +35,11 @@ module JMESPath
|
|
35
35
|
# caching parser will be used. When `true`, a shared instance of
|
36
36
|
# {CachingParser} is used. Defaults to `true`.
|
37
37
|
#
|
38
|
+
# @option options [Boolean] :disable_visit_errors (false) When `true`,
|
39
|
+
# no errors will be raised during runtime processing. Parse errors
|
40
|
+
# will still be raised, but unexpected data sent to visit will
|
41
|
+
# result in nil being returned.
|
42
|
+
#
|
38
43
|
# @option options [Parser,CachingParser] :parser
|
39
44
|
#
|
40
45
|
def initialize(options = {})
|
@@ -58,7 +63,7 @@ module JMESPath
|
|
58
63
|
if options[:cache_expressions] == false
|
59
64
|
Parser.new(options)
|
60
65
|
else
|
61
|
-
DEFAULT_PARSER
|
66
|
+
DEFAULT_PARSER.new(options)
|
62
67
|
end
|
63
68
|
end
|
64
69
|
|
data/lib/jmespath/token.rb
CHANGED
@@ -18,12 +18,14 @@ module JMESPath
|
|
18
18
|
Lexer::T_EXPREF => 0,
|
19
19
|
Lexer::T_COLON => 0,
|
20
20
|
Lexer::T_PIPE => 1,
|
21
|
-
Lexer::
|
22
|
-
Lexer::
|
23
|
-
Lexer::
|
21
|
+
Lexer::T_OR => 2,
|
22
|
+
Lexer::T_AND => 3,
|
23
|
+
Lexer::T_COMPARATOR => 5,
|
24
|
+
Lexer::T_FLATTEN => 9,
|
24
25
|
Lexer::T_STAR => 20,
|
25
26
|
Lexer::T_FILTER => 21,
|
26
27
|
Lexer::T_DOT => 40,
|
28
|
+
Lexer::T_NOT => 45,
|
27
29
|
Lexer::T_LBRACE => 50,
|
28
30
|
Lexer::T_LBRACKET => 55,
|
29
31
|
Lexer::T_LPAREN => 60,
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module JMESPath
|
2
|
+
# @api private
|
3
|
+
module Util
|
4
|
+
class << self
|
5
|
+
|
6
|
+
# Determines if a value is false as defined by JMESPath:
|
7
|
+
#
|
8
|
+
# https://github.com/jmespath/jmespath.site/blob/master/docs/proposals/improved-filters.rst#and-expressions-1
|
9
|
+
#
|
10
|
+
def falsey?(value)
|
11
|
+
value.nil? ||
|
12
|
+
value === false ||
|
13
|
+
value == '' ||
|
14
|
+
value == {} ||
|
15
|
+
value == [] ||
|
16
|
+
(value.respond_to?(:entries) && value.entries.compact.empty?)
|
17
|
+
# final case necessary to support Enumerable and Struct
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/jmespath/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jmespath
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: '1.2'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Trevor Rowe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
11
|
+
date: 2016-03-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.8.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.8.1
|
13
27
|
description: Implements JMESPath for Ruby
|
14
28
|
email: trevorrowe@gmail.com
|
15
29
|
executables: []
|
@@ -22,6 +36,7 @@ files:
|
|
22
36
|
- lib/jmespath/errors.rb
|
23
37
|
- lib/jmespath/lexer.rb
|
24
38
|
- lib/jmespath/nodes.rb
|
39
|
+
- lib/jmespath/nodes/and.rb
|
25
40
|
- lib/jmespath/nodes/comparator.rb
|
26
41
|
- lib/jmespath/nodes/condition.rb
|
27
42
|
- lib/jmespath/nodes/current.rb
|
@@ -33,6 +48,7 @@ files:
|
|
33
48
|
- lib/jmespath/nodes/literal.rb
|
34
49
|
- lib/jmespath/nodes/multi_select_hash.rb
|
35
50
|
- lib/jmespath/nodes/multi_select_list.rb
|
51
|
+
- lib/jmespath/nodes/not.rb
|
36
52
|
- lib/jmespath/nodes/or.rb
|
37
53
|
- lib/jmespath/nodes/pipe.rb
|
38
54
|
- lib/jmespath/nodes/projection.rb
|
@@ -42,6 +58,7 @@ files:
|
|
42
58
|
- lib/jmespath/runtime.rb
|
43
59
|
- lib/jmespath/token.rb
|
44
60
|
- lib/jmespath/token_stream.rb
|
61
|
+
- lib/jmespath/util.rb
|
45
62
|
- lib/jmespath/version.rb
|
46
63
|
homepage: http://github.com/trevorrowe/jmespath.rb
|
47
64
|
licenses:
|