jsonpath 1.0.1 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.travis.yml +3 -5
- data/README.md +45 -0
- data/jsonpath.gemspec +1 -9
- data/lib/jsonpath.rb +13 -11
- data/lib/jsonpath/enumerable.rb +25 -2
- data/lib/jsonpath/parser.rb +61 -36
- data/lib/jsonpath/proxy.rb +2 -2
- data/lib/jsonpath/version.rb +1 -1
- data/test/test_jsonpath.rb +144 -1
- metadata +14 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7c156dcfda0e97156b872e63c64fc1b4a4f2379f217103165f22de78e3415800
|
4
|
+
data.tar.gz: ab9647efecba7fa057dc77b4f447c9ea09aba719d117e95edefeace45915c2cb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74ca2152d154f76497df525616aba1792c192be58025c47e6e76a9ebb6c6ebd3a3cbbcf66c2a7b49d4ec1d211ce46ce0b2ba3c334b6c755e0acde4042be9f27f
|
7
|
+
data.tar.gz: 47d2c181d409d1091b23080e8f62f8b708e5bd171040599b2ed3f1ce3c0a379e5a11eb72b441c61395682ec40f1f6d16bdfb51fa967a4a16046ba63caefb99ca
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -123,6 +123,51 @@ For more usage examples and variations on paths, please visit the tests. There a
|
|
123
123
|
end
|
124
124
|
```
|
125
125
|
|
126
|
+
### Selecting Values
|
127
|
+
|
128
|
+
It's possible to select results once a query has been defined after the query. For example given this JSON data:
|
129
|
+
|
130
|
+
```bash
|
131
|
+
{
|
132
|
+
"store": {
|
133
|
+
"book": [
|
134
|
+
{
|
135
|
+
"category": "reference",
|
136
|
+
"author": "Nigel Rees",
|
137
|
+
"title": "Sayings of the Century",
|
138
|
+
"price": 8.95
|
139
|
+
},
|
140
|
+
{
|
141
|
+
"category": "fiction",
|
142
|
+
"author": "Evelyn Waugh",
|
143
|
+
"title": "Sword of Honour",
|
144
|
+
"price": 12.99
|
145
|
+
}
|
146
|
+
]
|
147
|
+
}
|
148
|
+
```
|
149
|
+
|
150
|
+
... and this query:
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
"$.store.book[*](category,author)"
|
154
|
+
```
|
155
|
+
|
156
|
+
... the result can be filtered as such:
|
157
|
+
|
158
|
+
```bash
|
159
|
+
[
|
160
|
+
{
|
161
|
+
"category" : "reference",
|
162
|
+
"author" : "Nigel Rees"
|
163
|
+
},
|
164
|
+
{
|
165
|
+
"category" : "fiction",
|
166
|
+
"author" : "Evelyn Waugh"
|
167
|
+
}
|
168
|
+
]
|
169
|
+
```
|
170
|
+
|
126
171
|
### Running an individual test
|
127
172
|
|
128
173
|
```ruby
|
data/jsonpath.gemspec
CHANGED
@@ -5,10 +5,7 @@ require File.join(File.dirname(__FILE__), 'lib', 'jsonpath', 'version')
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = 'jsonpath'
|
7
7
|
s.version = JsonPath::VERSION
|
8
|
-
|
9
|
-
s.required_rubygems_version =
|
10
|
-
Gem::Requirement.new('>= 0')
|
11
|
-
end
|
8
|
+
s.required_ruby_version = '>= 2.5'
|
12
9
|
s.authors = ['Joshua Hull', 'Gergely Brautigam']
|
13
10
|
s.summary = 'Ruby implementation of http://goessner.net/articles/JsonPath/'
|
14
11
|
s.description = 'Ruby implementation of http://goessner.net/articles/JsonPath/.'
|
@@ -16,17 +13,12 @@ Gem::Specification.new do |s|
|
|
16
13
|
s.extra_rdoc_files = ['README.md']
|
17
14
|
s.files = `git ls-files`.split("\n")
|
18
15
|
s.homepage = 'https://github.com/joshbuddy/jsonpath'
|
19
|
-
s.rdoc_options = ['--charset=UTF-8']
|
20
|
-
s.require_paths = ['lib']
|
21
|
-
s.rubygems_version = '1.3.7'
|
22
16
|
s.test_files = `git ls-files`.split("\n").select { |f| f =~ /^spec/ }
|
23
|
-
s.rubyforge_project = 'jsonpath'
|
24
17
|
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
25
18
|
s.licenses = ['MIT']
|
26
19
|
|
27
20
|
# dependencies
|
28
21
|
s.add_runtime_dependency 'multi_json'
|
29
|
-
s.add_runtime_dependency 'to_regexp', '~> 0.2.1'
|
30
22
|
s.add_development_dependency 'bundler'
|
31
23
|
s.add_development_dependency 'code_stats'
|
32
24
|
s.add_development_dependency 'minitest', '~> 2.2.0'
|
data/lib/jsonpath.rb
CHANGED
@@ -10,7 +10,7 @@ require 'jsonpath/parser'
|
|
10
10
|
# JsonPath: initializes the class with a given JsonPath and parses that path
|
11
11
|
# into a token array.
|
12
12
|
class JsonPath
|
13
|
-
PATH_ALL = '$..*'
|
13
|
+
PATH_ALL = '$..*'
|
14
14
|
|
15
15
|
attr_accessor :path
|
16
16
|
|
@@ -19,21 +19,23 @@ class JsonPath
|
|
19
19
|
scanner = StringScanner.new(path.strip)
|
20
20
|
@path = []
|
21
21
|
until scanner.eos?
|
22
|
-
if token = scanner.scan(/\$\B|@\B|\*|\.\./)
|
22
|
+
if (token = scanner.scan(/\$\B|@\B|\*|\.\./))
|
23
23
|
@path << token
|
24
|
-
elsif token = scanner.scan(/[
|
24
|
+
elsif (token = scanner.scan(/[$@a-zA-Z0-9:{}_-]+/))
|
25
25
|
@path << "['#{token}']"
|
26
|
-
elsif token = scanner.scan(/'(.*?)'/)
|
26
|
+
elsif (token = scanner.scan(/'(.*?)'/))
|
27
27
|
@path << "[#{token}]"
|
28
|
-
elsif token = scanner.scan(/\[/)
|
28
|
+
elsif (token = scanner.scan(/\[/))
|
29
29
|
@path << find_matching_brackets(token, scanner)
|
30
|
-
elsif token = scanner.scan(/\]/)
|
30
|
+
elsif (token = scanner.scan(/\]/))
|
31
31
|
raise ArgumentError, 'unmatched closing bracket'
|
32
|
+
elsif (token = scanner.scan(/\(.*\)/))
|
33
|
+
@path << token
|
32
34
|
elsif scanner.scan(/\./)
|
33
35
|
nil
|
34
|
-
elsif token = scanner.scan(/[><=] \d+/)
|
36
|
+
elsif (token = scanner.scan(/[><=] \d+/))
|
35
37
|
@path.last << token
|
36
|
-
elsif token = scanner.scan(/./)
|
38
|
+
elsif (token = scanner.scan(/./))
|
37
39
|
begin
|
38
40
|
@path.last << token
|
39
41
|
rescue RuntimeError
|
@@ -46,13 +48,13 @@ class JsonPath
|
|
46
48
|
def find_matching_brackets(token, scanner)
|
47
49
|
count = 1
|
48
50
|
until count.zero?
|
49
|
-
if t = scanner.scan(/\[/)
|
51
|
+
if (t = scanner.scan(/\[/))
|
50
52
|
token << t
|
51
53
|
count += 1
|
52
|
-
elsif t = scanner.scan(/\]/)
|
54
|
+
elsif (t = scanner.scan(/\]/))
|
53
55
|
token << t
|
54
56
|
count -= 1
|
55
|
-
elsif t = scanner.scan(/[^\[\]]+/)
|
57
|
+
elsif (t = scanner.scan(/[^\[\]]+/))
|
56
58
|
token << t
|
57
59
|
elsif scanner.eos?
|
58
60
|
raise ArgumentError, 'unclosed bracket'
|
data/lib/jsonpath/enumerable.rb
CHANGED
@@ -12,7 +12,12 @@ class JsonPath
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def each(context = @object, key = nil, pos = 0, &blk)
|
15
|
-
node =
|
15
|
+
node =
|
16
|
+
if key
|
17
|
+
context.is_a?(Hash) || context.is_a?(Array) ? context[key] : context.__send__(key)
|
18
|
+
else
|
19
|
+
context
|
20
|
+
end
|
16
21
|
@_current_node = node
|
17
22
|
return yield_value(blk, context, key) if pos == @path.size
|
18
23
|
|
@@ -23,6 +28,10 @@ class JsonPath
|
|
23
28
|
each(context, key, pos + 1, &blk) if node == @object
|
24
29
|
when /^\[(.*)\]$/
|
25
30
|
handle_wildecard(node, expr, context, key, pos, &blk)
|
31
|
+
when /\(.*\)/
|
32
|
+
keys = expr.gsub(/[()]/, '').split(',').map(&:strip)
|
33
|
+
new_context = filter_context(context, keys)
|
34
|
+
yield_value(blk, new_context, key)
|
26
35
|
end
|
27
36
|
|
28
37
|
if pos > 0 && @path[pos - 1] == '..' || (@path[pos - 1] == '*' && @path[pos] != '..')
|
@@ -35,14 +44,28 @@ class JsonPath
|
|
35
44
|
|
36
45
|
private
|
37
46
|
|
47
|
+
def filter_context(context, keys)
|
48
|
+
case context
|
49
|
+
when Hash
|
50
|
+
# TODO: Change this to `slice(*keys)` when ruby version support is > 2.4
|
51
|
+
context.select { |k| keys.include?(k) }
|
52
|
+
when Array
|
53
|
+
context.each_with_object([]) do |c, memo|
|
54
|
+
memo << c.select { |k| keys.include?(k) }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
38
59
|
def handle_wildecard(node, expr, _context, _key, pos, &blk)
|
39
60
|
expr[1, expr.size - 2].split(',').each do |sub_path|
|
40
61
|
case sub_path[0]
|
41
62
|
when '\'', '"'
|
63
|
+
k = sub_path[1, sub_path.size - 2]
|
42
64
|
if node.is_a?(Hash)
|
43
|
-
k = sub_path[1, sub_path.size - 2]
|
44
65
|
node[k] ||= nil if @options[:default_path_leaf_to_null]
|
45
66
|
each(node, k, pos + 1, &blk) if node.key?(k)
|
67
|
+
elsif node.respond_to?(k.to_s) && !Object.respond_to?(k.to_s)
|
68
|
+
each(node, k, pos + 1, &blk)
|
46
69
|
end
|
47
70
|
when '?'
|
48
71
|
handle_question_mark(sub_path, node, pos, &blk)
|
data/lib/jsonpath/parser.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'strscan'
|
4
|
-
require 'to_regexp'
|
5
4
|
|
6
5
|
class JsonPath
|
7
6
|
# Parser parses and evaluates an expression passed to @_current_node.
|
8
7
|
class Parser
|
8
|
+
REGEX = /\A\/(.+)\/([imxnesu]*)\z|\A%r{(.+)}([imxnesu]*)\z/
|
9
|
+
|
9
10
|
def initialize(node)
|
10
11
|
@_current_node = node
|
11
12
|
@_expr_map = {}
|
@@ -46,46 +47,56 @@ class JsonPath
|
|
46
47
|
end
|
47
48
|
end
|
48
49
|
|
49
|
-
#
|
50
|
+
# Using a scanner break down the individual expressions and determine if
|
50
51
|
# there is a match in the JSON for it or not.
|
51
52
|
def parse_exp(exp)
|
52
53
|
exp = exp.sub(/@/, '').gsub(/^\(/, '').gsub(/\)$/, '').tr('"', '\'').strip
|
54
|
+
exp.scan(/^\[(\d+)\]/) do |i|
|
55
|
+
next if i.empty?
|
56
|
+
|
57
|
+
index = Integer(i[0])
|
58
|
+
raise ArgumentError, 'Node does not appear to be an array.' unless @_current_node.is_a?(Array)
|
59
|
+
raise ArgumentError, "Index out of bounds for nested array. Index: #{index}" if @_current_node.size < index
|
60
|
+
|
61
|
+
@_current_node = @_current_node[index]
|
62
|
+
# Remove the extra '' and the index.
|
63
|
+
exp = exp.gsub(/^\[\d+\]|\[''\]/, '')
|
64
|
+
end
|
53
65
|
scanner = StringScanner.new(exp)
|
54
66
|
elements = []
|
55
67
|
until scanner.eos?
|
56
|
-
if scanner.scan(
|
57
|
-
|
58
|
-
|
59
|
-
num = scanner.scan(/\d+/)
|
60
|
-
return @_current_node.send(sym.to_sym).send(op.to_sym, num.to_i)
|
61
|
-
end
|
62
|
-
if t = scanner.scan(/\['[a-zA-Z@&\*\/\$%\^\?_]+'\]+/)
|
63
|
-
elements << t.gsub(/\[|\]|'|\s+/, '')
|
64
|
-
elsif t = scanner.scan(/(\s+)?[<>=][=~]?(\s+)?/)
|
68
|
+
if (t = scanner.scan(/\['[a-zA-Z@&*\/$%^?_]+'\]|\.[a-zA-Z0-9_]+[?!]?/))
|
69
|
+
elements << t.gsub(/[\[\]'.]|\s+/, '')
|
70
|
+
elsif (t = scanner.scan(/(\s+)?[<>=!\-+][=~]?(\s+)?/))
|
65
71
|
operator = t
|
66
|
-
elsif t = scanner.scan(/(\s+)?'?.*'?(\s+)?/)
|
72
|
+
elsif (t = scanner.scan(/(\s+)?'?.*'?(\s+)?/))
|
67
73
|
# If we encounter a node which does not contain `'` it means
|
68
74
|
# that we are dealing with a boolean type.
|
69
|
-
operand =
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
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
|
85
|
+
elsif (t = scanner.scan(/\/\w+\//))
|
86
|
+
elsif (t = scanner.scan(/.*/))
|
78
87
|
raise "Could not process symbol: #{t}"
|
79
88
|
end
|
80
89
|
end
|
81
90
|
|
82
91
|
el = if elements.empty?
|
83
92
|
@_current_node
|
93
|
+
elsif @_current_node.is_a?(Hash)
|
94
|
+
@_current_node.dig(*elements)
|
84
95
|
else
|
85
|
-
|
96
|
+
elements.inject(@_current_node, &:__send__)
|
86
97
|
end
|
87
|
-
|
88
|
-
return true if
|
98
|
+
|
99
|
+
return (el ? true : false) if el.nil? || operator.nil?
|
89
100
|
|
90
101
|
el = Float(el) rescue el
|
91
102
|
operand = Float(operand) rescue operand
|
@@ -95,14 +106,29 @@ class JsonPath
|
|
95
106
|
|
96
107
|
private
|
97
108
|
|
98
|
-
#
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
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
|
103
128
|
|
104
|
-
|
105
|
-
|
129
|
+
args = [content, flags]
|
130
|
+
args << lang unless lang.empty? # avoid warning
|
131
|
+
Regexp.new(*args)
|
106
132
|
end
|
107
133
|
|
108
134
|
# This will break down a parenthesis from the left to the right
|
@@ -129,10 +155,9 @@ class JsonPath
|
|
129
155
|
top = top.map(&:strip)
|
130
156
|
res = bool_or_exp(top.shift)
|
131
157
|
top.each_with_index do |item, index|
|
132
|
-
|
133
|
-
when '&&'
|
158
|
+
if item == '&&'
|
134
159
|
res &&= top[index + 1]
|
135
|
-
|
160
|
+
elsif item == '||'
|
136
161
|
res ||= top[index + 1]
|
137
162
|
end
|
138
163
|
end
|
@@ -141,9 +166,9 @@ class JsonPath
|
|
141
166
|
# and the closing index will be the last index. To avoid
|
142
167
|
# off-by-one errors we simply return the result at that point.
|
143
168
|
if closing_index + 1 >= str.length && opening_index == 0
|
144
|
-
|
169
|
+
res.to_s
|
145
170
|
else
|
146
|
-
|
171
|
+
"#{str[0..opening_index - 1]}#{res}#{str[closing_index + 1..str.length]}"
|
147
172
|
end
|
148
173
|
end
|
149
174
|
|
data/lib/jsonpath/proxy.rb
CHANGED
@@ -10,11 +10,11 @@ class JsonPath
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def gsub(path, replacement = nil, &replacement_block)
|
13
|
-
_gsub(_deep_copy, path, replacement ? proc
|
13
|
+
_gsub(_deep_copy, path, replacement ? proc(&method(:replacement)) : replacement_block)
|
14
14
|
end
|
15
15
|
|
16
16
|
def gsub!(path, replacement = nil, &replacement_block)
|
17
|
-
_gsub(@obj, path, replacement ? proc
|
17
|
+
_gsub(@obj, path, replacement ? proc(&method(:replacement)) : replacement_block)
|
18
18
|
end
|
19
19
|
|
20
20
|
def delete(path = JsonPath::PATH_ALL)
|
data/lib/jsonpath/version.rb
CHANGED
data/test/test_jsonpath.rb
CHANGED
@@ -70,6 +70,12 @@ class TestJsonpath < MiniTest::Unit::TestCase
|
|
70
70
|
assert_equal [@object['store']['book'][0], @object['store']['book'][2]], JsonPath.new("$..book[?(@['price'] < 10)]").on(@object)
|
71
71
|
assert_equal [@object['store']['book'][0], @object['store']['book'][2]], JsonPath.new("$..book[?(@['price'] == 9)]").on(@object)
|
72
72
|
assert_equal [@object['store']['book'][3]], JsonPath.new("$..book[?(@['price'] > 20)]").on(@object)
|
73
|
+
assert_equal [
|
74
|
+
@object['store']['book'][0],
|
75
|
+
@object['store']['book'][4],
|
76
|
+
@object['store']['book'][5],
|
77
|
+
@object['store']['book'][6]
|
78
|
+
], JsonPath.new("$..book[?(@['category'] != 'fiction')]").on(@object)
|
73
79
|
end
|
74
80
|
|
75
81
|
def test_or_operator
|
@@ -113,6 +119,25 @@ class TestJsonpath < MiniTest::Unit::TestCase
|
|
113
119
|
assert_equal [@object['store']['bicycle']['2seater']], JsonPath.new('$.store.bicycle.2seater').on(@object)
|
114
120
|
end
|
115
121
|
|
122
|
+
def test_recognized_dot_notation_in_filters
|
123
|
+
assert_equal [@object['store']['book'][2], @object['store']['book'][3]], JsonPath.new('$..book[?(@.isbn)]').on(@object)
|
124
|
+
end
|
125
|
+
|
126
|
+
def test_works_on_non_hash
|
127
|
+
klass = Struct.new(:a, :b)
|
128
|
+
object = klass.new('some', 'value')
|
129
|
+
|
130
|
+
assert_equal ['value'], JsonPath.new('$.b').on(object)
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_works_on_non_hash_with_filters
|
134
|
+
klass = Struct.new(:a, :b)
|
135
|
+
first_object = klass.new('some', 'value')
|
136
|
+
second_object = klass.new('next', 'other value')
|
137
|
+
|
138
|
+
assert_equal ['other value'], JsonPath.new('$[?(@.a == "next")].b').on([first_object, second_object])
|
139
|
+
end
|
140
|
+
|
116
141
|
def test_recognize_array_with_evald_index
|
117
142
|
assert_equal [@object['store']['book'][2]], JsonPath.new('$..book[(@.length-5)]').on(@object)
|
118
143
|
end
|
@@ -723,7 +748,7 @@ class TestJsonpath < MiniTest::Unit::TestCase
|
|
723
748
|
end
|
724
749
|
|
725
750
|
def test_runtime_error_frozen_string
|
726
|
-
skip('in ruby version below 2.2.0 this error is not raised') if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.2.0')
|
751
|
+
skip('in ruby version below 2.2.0 this error is not raised') if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.2.0') || Gem::Version.new(RUBY_VERSION) > Gem::Version::new('2.6')
|
727
752
|
json = '
|
728
753
|
{
|
729
754
|
"test": "something"
|
@@ -779,6 +804,124 @@ class TestJsonpath < MiniTest::Unit::TestCase
|
|
779
804
|
assert_equal expected, JsonPath.for(a.to_json).delete('$.itemList[1:6:2]').to_hash
|
780
805
|
end
|
781
806
|
|
807
|
+
def test_nested_values
|
808
|
+
json = '
|
809
|
+
{
|
810
|
+
"phoneNumbers": [
|
811
|
+
[{
|
812
|
+
"type" : "iPhone",
|
813
|
+
"number": "0123-4567-8888"
|
814
|
+
}],
|
815
|
+
[{
|
816
|
+
"type" : "home",
|
817
|
+
"number": "0123-4567-8910"
|
818
|
+
}]
|
819
|
+
]
|
820
|
+
}
|
821
|
+
'.to_json
|
822
|
+
assert_equal [[{ 'type' => 'home', 'number' => '0123-4567-8910' }]], JsonPath.on(json, "$.phoneNumbers[?(@[0].type == 'home')]")
|
823
|
+
assert_equal [], JsonPath.on(json, "$.phoneNumbers[?(@[2].type == 'home')]")
|
824
|
+
json = '
|
825
|
+
{
|
826
|
+
"phoneNumbers":
|
827
|
+
{
|
828
|
+
"type" : "iPhone",
|
829
|
+
"number": "0123-4567-8888"
|
830
|
+
}
|
831
|
+
}
|
832
|
+
'.to_json
|
833
|
+
assert_equal [], JsonPath.on(json, "$.phoneNumbers[?(@[0].type == 'home')]")
|
834
|
+
end
|
835
|
+
|
836
|
+
def test_selecting_multiple_keys
|
837
|
+
json = '
|
838
|
+
{
|
839
|
+
"store": {
|
840
|
+
"book": [
|
841
|
+
{
|
842
|
+
"category": "reference",
|
843
|
+
"author": "Nigel Rees",
|
844
|
+
"title": "Sayings of the Century",
|
845
|
+
"price": 8.95
|
846
|
+
},
|
847
|
+
{
|
848
|
+
"category": "fiction",
|
849
|
+
"author": "Evelyn Waugh",
|
850
|
+
"title": "Sword of Honour",
|
851
|
+
"price": 12.99
|
852
|
+
}
|
853
|
+
]
|
854
|
+
}
|
855
|
+
}
|
856
|
+
'.to_json
|
857
|
+
|
858
|
+
assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }, { 'category' => 'fiction', 'author' => 'Evelyn Waugh' }], JsonPath.on(json, '$.store.book[*](category,author)')
|
859
|
+
end
|
860
|
+
|
861
|
+
def test_selecting_multiple_keys_with_filter
|
862
|
+
json = '
|
863
|
+
{
|
864
|
+
"store": {
|
865
|
+
"book": [
|
866
|
+
{
|
867
|
+
"category": "reference",
|
868
|
+
"author": "Nigel Rees",
|
869
|
+
"title": "Sayings of the Century",
|
870
|
+
"price": 8.95
|
871
|
+
},
|
872
|
+
{
|
873
|
+
"category": "fiction",
|
874
|
+
"author": "Evelyn Waugh",
|
875
|
+
"title": "Sword of Honour",
|
876
|
+
"price": 12.99
|
877
|
+
}
|
878
|
+
]
|
879
|
+
}
|
880
|
+
}
|
881
|
+
'.to_json
|
882
|
+
|
883
|
+
assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, "$.store.book[?(@['price'] == 8.95)](category,author)")
|
884
|
+
assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, "$.store.book[?(@['price'] == 8.95)]( category, author )")
|
885
|
+
end
|
886
|
+
|
887
|
+
def test_selecting_multiple_keys_with_filter_with_space_in_catergory
|
888
|
+
json = '
|
889
|
+
{
|
890
|
+
"store": {
|
891
|
+
"book": [
|
892
|
+
{
|
893
|
+
"cate gory": "reference",
|
894
|
+
"author": "Nigel Rees",
|
895
|
+
"title": "Sayings of the Century",
|
896
|
+
"price": 8.95
|
897
|
+
},
|
898
|
+
{
|
899
|
+
"cate gory": "fiction",
|
900
|
+
"author": "Evelyn Waugh",
|
901
|
+
"title": "Sword of Honour",
|
902
|
+
"price": 12.99
|
903
|
+
}
|
904
|
+
]
|
905
|
+
}
|
906
|
+
}
|
907
|
+
'.to_json
|
908
|
+
|
909
|
+
assert_equal [{ 'cate gory' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, "$.store.book[?(@['price'] == 8.95)]( cate gory, author )")
|
910
|
+
end
|
911
|
+
|
912
|
+
def test_object_method_send
|
913
|
+
j = {height: 5, hash: "some_hash"}.to_json
|
914
|
+
hs = JsonPath.new "$..send"
|
915
|
+
assert_equal([], hs.on(j))
|
916
|
+
hs = JsonPath.new "$..hash"
|
917
|
+
assert_equal(["some_hash"], hs.on(j))
|
918
|
+
hs = JsonPath.new "$..send"
|
919
|
+
assert_equal([], hs.on(j))
|
920
|
+
j = {height: 5, send: "should_still_work"}.to_json
|
921
|
+
hs = JsonPath.new "$..send"
|
922
|
+
assert_equal(['should_still_work'], hs.on(j))
|
923
|
+
end
|
924
|
+
|
782
925
|
def example_object
|
783
926
|
{ 'store' => {
|
784
927
|
'book' => [
|
metadata
CHANGED
@@ -1,23 +1,23 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsonpath
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joshua Hull
|
8
8
|
- Gergely Brautigam
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2020-11-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name: multi_json
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
16
|
requirements:
|
18
17
|
- - ">="
|
19
18
|
- !ruby/object:Gem::Version
|
20
19
|
version: '0'
|
20
|
+
name: multi_json
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -26,26 +26,12 @@ dependencies:
|
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '0'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
|
-
name: to_regexp
|
30
|
-
requirement: !ruby/object:Gem::Requirement
|
31
|
-
requirements:
|
32
|
-
- - "~>"
|
33
|
-
- !ruby/object:Gem::Version
|
34
|
-
version: 0.2.1
|
35
|
-
type: :runtime
|
36
|
-
prerelease: false
|
37
|
-
version_requirements: !ruby/object:Gem::Requirement
|
38
|
-
requirements:
|
39
|
-
- - "~>"
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
version: 0.2.1
|
42
|
-
- !ruby/object:Gem::Dependency
|
43
|
-
name: bundler
|
44
29
|
requirement: !ruby/object:Gem::Requirement
|
45
30
|
requirements:
|
46
31
|
- - ">="
|
47
32
|
- !ruby/object:Gem::Version
|
48
33
|
version: '0'
|
34
|
+
name: bundler
|
49
35
|
type: :development
|
50
36
|
prerelease: false
|
51
37
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -54,12 +40,12 @@ dependencies:
|
|
54
40
|
- !ruby/object:Gem::Version
|
55
41
|
version: '0'
|
56
42
|
- !ruby/object:Gem::Dependency
|
57
|
-
name: code_stats
|
58
43
|
requirement: !ruby/object:Gem::Requirement
|
59
44
|
requirements:
|
60
45
|
- - ">="
|
61
46
|
- !ruby/object:Gem::Version
|
62
47
|
version: '0'
|
48
|
+
name: code_stats
|
63
49
|
type: :development
|
64
50
|
prerelease: false
|
65
51
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -68,12 +54,12 @@ dependencies:
|
|
68
54
|
- !ruby/object:Gem::Version
|
69
55
|
version: '0'
|
70
56
|
- !ruby/object:Gem::Dependency
|
71
|
-
name: minitest
|
72
57
|
requirement: !ruby/object:Gem::Requirement
|
73
58
|
requirements:
|
74
59
|
- - "~>"
|
75
60
|
- !ruby/object:Gem::Version
|
76
61
|
version: 2.2.0
|
62
|
+
name: minitest
|
77
63
|
type: :development
|
78
64
|
prerelease: false
|
79
65
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -82,12 +68,12 @@ dependencies:
|
|
82
68
|
- !ruby/object:Gem::Version
|
83
69
|
version: 2.2.0
|
84
70
|
- !ruby/object:Gem::Dependency
|
85
|
-
name: phocus
|
86
71
|
requirement: !ruby/object:Gem::Requirement
|
87
72
|
requirements:
|
88
73
|
- - ">="
|
89
74
|
- !ruby/object:Gem::Version
|
90
75
|
version: '0'
|
76
|
+
name: phocus
|
91
77
|
type: :development
|
92
78
|
prerelease: false
|
93
79
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -96,12 +82,12 @@ dependencies:
|
|
96
82
|
- !ruby/object:Gem::Version
|
97
83
|
version: '0'
|
98
84
|
- !ruby/object:Gem::Dependency
|
99
|
-
name: rake
|
100
85
|
requirement: !ruby/object:Gem::Requirement
|
101
86
|
requirements:
|
102
87
|
- - ">="
|
103
88
|
- !ruby/object:Gem::Version
|
104
89
|
version: '0'
|
90
|
+
name: rake
|
105
91
|
type: :development
|
106
92
|
prerelease: false
|
107
93
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -142,25 +128,23 @@ homepage: https://github.com/joshbuddy/jsonpath
|
|
142
128
|
licenses:
|
143
129
|
- MIT
|
144
130
|
metadata: {}
|
145
|
-
post_install_message:
|
146
|
-
rdoc_options:
|
147
|
-
- "--charset=UTF-8"
|
131
|
+
post_install_message:
|
132
|
+
rdoc_options: []
|
148
133
|
require_paths:
|
149
134
|
- lib
|
150
135
|
required_ruby_version: !ruby/object:Gem::Requirement
|
151
136
|
requirements:
|
152
137
|
- - ">="
|
153
138
|
- !ruby/object:Gem::Version
|
154
|
-
version: '
|
139
|
+
version: '2.5'
|
155
140
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
156
141
|
requirements:
|
157
142
|
- - ">="
|
158
143
|
- !ruby/object:Gem::Version
|
159
144
|
version: '0'
|
160
145
|
requirements: []
|
161
|
-
|
162
|
-
|
163
|
-
signing_key:
|
146
|
+
rubygems_version: 3.0.8
|
147
|
+
signing_key:
|
164
148
|
specification_version: 4
|
165
149
|
summary: Ruby implementation of http://goessner.net/articles/JsonPath/
|
166
150
|
test_files: []
|