jsonpath 1.0.7 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a31bb2922acb2b1a6e84a6e640ee148eb1f40f9d8113751c6903149e472e99d9
4
- data.tar.gz: ab119c28fe07e14bfab16e5e2905d59ccf7e8154d5ff817d14a9db92215f8bd2
3
+ metadata.gz: ab3e08744fe7f8ba3b64670fee8f75a0fa4c9b339de8257f64cdc7ea24f26965
4
+ data.tar.gz: 447ce47a7c5df36c2fa290da5aafc77304d5e8db9318cfcac2b97dd9ae8c9c8c
5
5
  SHA512:
6
- metadata.gz: 4ede5f5c546e8ac46689b993ada2d6ed456ed9e9b1027023e421b8d27e99b3f785360a3fcf093a58be473a80ecca3485b709f23575be6b93fb71c2ae46f63966
7
- data.tar.gz: 021a544e520b944266c276b3b79ca53e0311df7ade212655282e4f3f03b9bca18aba5858148dc7de8ec3ca91be67dbd2f5554c4b6a73273c094d94dc31f5aa71
6
+ metadata.gz: 5b458262f098ceea595a91a981136141d0ed3f7ef9782d8a205f619be1bb60a7234af11229527ed9fc9ef3baafec323ad33850d87b4dc389ac482c14bb4aa05f
7
+ data.tar.gz: d1756aa04d5e07de855439aa0a4895078ab5c3c2c90c4c9ec755ba1da2ffb3fe11e59d1819e03f6a82e8670fd810b1c895da150a9d24176ddf4a86a54705fcbf
@@ -0,0 +1,31 @@
1
+ name: test
2
+ on:
3
+ - push
4
+ - pull_request
5
+ jobs:
6
+ test:
7
+ strategy:
8
+ fail-fast: false
9
+ matrix:
10
+ ruby-version:
11
+ - '2.5'
12
+ - '2.6'
13
+ - '2.7'
14
+ - ruby-head
15
+ - jruby-head
16
+ - truffleruby-head
17
+ runs-on:
18
+ - ubuntu-latest
19
+
20
+ runs-on: ${{ matrix.runs-on }}
21
+
22
+ steps:
23
+
24
+ - uses: actions/checkout@v2
25
+
26
+ - uses: ruby/setup-ruby@v1
27
+ with:
28
+ ruby-version: ${{ matrix.ruby-version }}
29
+ bundler-cache: true
30
+
31
+ - run: bundle exec rake test
data/.gitignore CHANGED
@@ -6,3 +6,5 @@ doc/*
6
6
  .DS_Store
7
7
  .idea
8
8
  vendor
9
+ .tags
10
+ *.gem
data/Gemfile CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  source 'http://rubygems.org'
4
4
  gemspec
5
- gem 'rubocop', require: true, group: :test
5
+ # gem 'rubocop', require: true, group: :test
6
6
  gem 'simplecov', require: false, group: :test
data/README.md CHANGED
@@ -4,8 +4,8 @@ This is an implementation of http://goessner.net/articles/JsonPath/.
4
4
 
5
5
  ## What is JsonPath?
6
6
 
7
- JsonPath is a way of addressing elements within a JSON object. Similar to xpath of yore, JsonPath lets you
8
- traverse a json object and manipulate or access it.
7
+ JsonPath is a way of addressing elements within a JSON object. Similar to xpath
8
+ of yore, JsonPath lets you traverse a json object and manipulate or access it.
9
9
 
10
10
  ## Usage
11
11
 
@@ -15,8 +15,8 @@ There is stand-alone usage through the binary `jsonpath`
15
15
 
16
16
  jsonpath [expression] (file|string)
17
17
 
18
- If you omit the second argument, it will read stdin, assuming one valid JSON object
19
- per line. Expression must be a valid jsonpath expression.
18
+ If you omit the second argument, it will read stdin, assuming one valid JSON
19
+ object per line. Expression must be a valid jsonpath expression.
20
20
 
21
21
  ### Library
22
22
 
@@ -40,8 +40,8 @@ json = <<-HERE_DOC
40
40
  HERE_DOC
41
41
  ```
42
42
 
43
- Now that we have a JSON object, let's get all the prices present in the object. We create an object for the path
44
- in the following way.
43
+ Now that we have a JSON object, let's get all the prices present in the object.
44
+ We create an object for the path in the following way.
45
45
 
46
46
  ```ruby
47
47
  path = JsonPath.new('$..price')
@@ -54,14 +54,15 @@ path.on(json)
54
54
  # => [19.95, 8.95, 12.99, 8.99, 22.99]
55
55
  ```
56
56
 
57
- Or on some other object ...
57
+ Or reuse it later on some other object (thread safe) ...
58
58
 
59
59
  ```ruby
60
60
  path.on('{"books":[{"title":"A Tale of Two Somethings","price":18.88}]}')
61
61
  # => [18.88]
62
62
  ```
63
63
 
64
- You can also just combine this into one mega-call with the convenient `JsonPath.on` method.
64
+ You can also just combine this into one mega-call with the convenient
65
+ `JsonPath.on` method.
65
66
 
66
67
  ```ruby
67
68
  JsonPath.on(json, '$..author')
@@ -73,29 +74,36 @@ Of course the full JsonPath syntax is supported, such as array slices
73
74
  ```ruby
74
75
  JsonPath.new('$..book[::2]').on(json)
75
76
  # => [
76
- # {"price"=>8.95, "category"=>"reference", "author"=>"Nigel Rees", "title"=>"Sayings of the Century"},
77
- # {"price"=>8.99, "category"=>"fiction", "author"=>"Herman Melville", "title"=>"Moby Dick", "isbn"=>"0-553-21311-3"}
77
+ # {"price" => 8.95, "category" => "reference", "title" => "Sayings of the Century", "author" => "Nigel Rees"},
78
+ # {"price" => 8.99, "category" => "fiction", "isbn" => "0-553-21311-3", "title" => "Moby Dick", "author" => "Herman Melville","color" => "blue"},
78
79
  # ]
79
80
  ```
80
81
 
81
- ...and evals.
82
+ ...and evals, including those with conditional operators
82
83
 
83
84
  ```ruby
84
- JsonPath.new('$..price[?(@ < 10)]').on(json)
85
+ JsonPath.new("$..price[?(@ < 10)]").on(json)
85
86
  # => [8.95, 8.99]
87
+
88
+ JsonPath.new("$..book[?(@['price'] == 8.95 || @['price'] == 8.99)].title").on(json)
89
+ # => ["Sayings of the Century", "Moby Dick"]
90
+
91
+ JsonPath.new("$..book[?(@['price'] == 8.95 && @['price'] == 8.99)].title").on(json)
92
+ # => []
86
93
  ```
87
94
 
88
- There is a convenience method, `#first` that gives you the first element for a JSON object and path.
95
+ There is a convenience method, `#first` that gives you the first element for a
96
+ JSON object and path.
89
97
 
90
98
  ```ruby
91
- JsonPath.new('$..color').first(object)
99
+ JsonPath.new('$..color').first(json)
92
100
  # => "red"
93
101
  ```
94
102
 
95
103
  As well, we can directly create an `Enumerable` at any time using `#[]`.
96
104
 
97
105
  ```ruby
98
- enum = JsonPath.new('$..color')[object]
106
+ enum = JsonPath.new('$..color')[json]
99
107
  # => #<JsonPath::Enumerable:...>
100
108
  enum.first
101
109
  # => "red"
@@ -103,29 +111,77 @@ enum.any?{ |c| c == 'red' }
103
111
  # => true
104
112
  ```
105
113
 
106
- ### More examples
114
+ For more usage examples and variations on paths, please visit the tests. There
115
+ are some more complex ones as well.
116
+
117
+ ### Querying ruby data structures
118
+
119
+ If you have ruby hashes with symbolized keys as input, you
120
+ can use `:use_symbols` to make JsonPath work fine on them too:
107
121
 
108
- For more usage examples and variations on paths, please visit the tests. There are some more complex ones as well.
122
+ ```ruby
123
+ book = { title: "Sayings of the Century" }
124
+
125
+ JsonPath.new('$.title').on(book)
126
+ # => []
127
+
128
+ JsonPath.new('$.title', use_symbols: true).on(book)
129
+ # => ["Sayings of the Century"]
130
+ ```
109
131
 
110
- ### Conditional Operators Are Also Supported
132
+ JsonPath also recognizes objects responding to `dig` (introduced
133
+ in ruby 2.3), and therefore works out of the box with Struct,
134
+ OpenStruct, and other Hash-like structures:
111
135
 
112
136
  ```ruby
113
- def test_or_operator
114
- assert_equal [@object['store']['book'][1], @object['store']['book'][3]], JsonPath.new("$..book[?(@['price'] == 13 || @['price'] == 23)]").on(@object)
115
- end
137
+ book_class = Struct.new(:title)
138
+ book = book_class.new("Sayings of the Century")
116
139
 
117
- def test_and_operator
118
- assert_equal [], JsonPath.new("$..book[?(@['price'] == 13 && @['price'] == 23)]").on(@object)
119
- end
140
+ JsonPath.new('$.title').on(book)
141
+ # => ["Sayings of the Century"]
142
+ ```
143
+
144
+ JsonPath is able to query pure ruby objects and uses `__send__`
145
+ on them. The option is enabled by default in JsonPath 1.x, but
146
+ we encourage to enable it explicitly:
147
+
148
+ ```ruby
149
+ book_class = Class.new{ attr_accessor :title }
150
+ book = book_class.new
151
+ book.title = "Sayings of the Century"
120
152
 
121
- def test_and_operator_with_more_results
122
- assert_equal [@object['store']['book'][1]], JsonPath.new("$..book[?(@['price'] < 23 && @['price'] > 9)]").on(@object)
123
- end
153
+ JsonPath.new('$.title', allow_send: true).on(book)
154
+ # => ["Sayings of the Century"]
155
+ ```
156
+
157
+ ### Other available options
158
+
159
+ By default, JsonPath does not return null values on unexisting paths.
160
+ This can be changed using the `:default_path_leaf_to_null` option
161
+
162
+ ```ruby
163
+ JsonPath.new('$..book[*].isbn').on(json)
164
+ # => ["0-553-21311-3", "0-395-19395-8"]
165
+
166
+ JsonPath.new('$..book[*].isbn', default_path_leaf_to_null: true).on(json)
167
+ # => [nil, nil, "0-553-21311-3", "0-395-19395-8"]
168
+ ```
169
+
170
+ When JsonPath returns a Hash, you can ask to symbolize its keys
171
+ using the `:symbolize_keys` option
172
+
173
+ ```ruby
174
+ JsonPath.new('$..book[0]').on(json)
175
+ # => [{"category" => "reference", ...}]
176
+
177
+ JsonPath.new('$..book[0]', symbolize_keys: true).on(json)
178
+ # => [{category: "reference", ...}]
124
179
  ```
125
180
 
126
181
  ### Selecting Values
127
182
 
128
- It's possible to select results once a query has been defined after the query. For example given this JSON data:
183
+ It's possible to select results once a query has been defined after the query. For
184
+ example given this JSON data:
129
185
 
130
186
  ```bash
131
187
  {
@@ -168,15 +224,10 @@ It's possible to select results once a query has been defined after the query. F
168
224
  ]
169
225
  ```
170
226
 
171
- ### Running an individual test
172
-
173
- ```ruby
174
- ruby -Ilib:../lib test/test_jsonpath.rb --name test_wildcard_on_intermediary_element_v6
175
- ```
176
-
177
227
  ### Manipulation
178
228
 
179
- If you'd like to do substitution in a json object, you can use `#gsub` or `#gsub!` to modify the object in place.
229
+ If you'd like to do substitution in a json object, you can use `#gsub`
230
+ or `#gsub!` to modify the object in place.
180
231
 
181
232
  ```ruby
182
233
  JsonPath.for('{"candy":"lollipop"}').gsub('$..candy') {|v| "big turks" }.to_hash
@@ -188,7 +239,9 @@ The result will be
188
239
  {'candy' => 'big turks'}
189
240
  ```
190
241
 
191
- If you'd like to remove all nil keys, you can use `#compact` and `#compact!`. To remove all keys under a certain path, use `#delete` or `#delete!`. You can even chain these methods together as follows:
242
+ If you'd like to remove all nil keys, you can use `#compact` and `#compact!`.
243
+ To remove all keys under a certain path, use `#delete` or `#delete!`. You can
244
+ even chain these methods together as follows:
192
245
 
193
246
  ```ruby
194
247
  json = '{"candy":"lollipop","noncandy":null,"other":"things"}'
@@ -200,6 +253,49 @@ o = JsonPath.for(json).
200
253
  # => {"candy" => "big turks"}
201
254
  ```
202
255
 
256
+ ### Fetch all paths
257
+
258
+ To fetch all possible paths in given json, you can use `fetch_all_paths` method.
259
+
260
+ data:
261
+
262
+ ```bash
263
+ {
264
+ "store": {
265
+ "book": [
266
+ {
267
+ "category": "reference",
268
+ "author": "Nigel Rees"
269
+ },
270
+ {
271
+ "category": "fiction",
272
+ "author": "Evelyn Waugh"
273
+ }
274
+ ]
275
+ }
276
+ ```
277
+
278
+ ... and this query:
279
+
280
+ ```ruby
281
+ JsonPath.fetch_all_path(data)
282
+ ```
283
+
284
+ ... the result will be:
285
+
286
+ ```bash
287
+ ["$", "$.store", "$.store.book", "$.store.book[0].category", "$.store.book[0].author", "$.store.book[0]", "$.store.book[1].category", "$.store.book[1].author", "$.store.book[1]"]
288
+ ```
289
+
290
+
291
+
203
292
  # Contributions
204
293
 
205
- Please feel free to submit an Issue or a Pull Request any time you feel like you would like to contribute. Thank you!
294
+ Please feel free to submit an Issue or a Pull Request any time you feel like
295
+ you would like to contribute. Thank you!
296
+
297
+ ## Running an individual test
298
+
299
+ ```ruby
300
+ ruby -Ilib:../lib test/test_jsonpath.rb --name test_wildcard_on_intermediary_element_v6
301
+ ```
data/jsonpath.gemspec CHANGED
@@ -23,5 +23,6 @@ Gem::Specification.new do |s|
23
23
  s.add_development_dependency 'code_stats'
24
24
  s.add_development_dependency 'minitest', '~> 2.2.0'
25
25
  s.add_development_dependency 'phocus'
26
+ s.add_development_dependency 'racc'
26
27
  s.add_development_dependency 'rake'
27
28
  end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ class JsonPath
4
+ module Dig
5
+
6
+ # Similar to what Hash#dig or Array#dig
7
+ def dig(context, *keys)
8
+ keys.inject(context){|memo,k|
9
+ dig_one(memo, k)
10
+ }
11
+ end
12
+
13
+ # Returns a hash mapping each key from keys
14
+ # to its dig value on context.
15
+ def dig_as_hash(context, keys)
16
+ keys.each_with_object({}) do |k, memo|
17
+ memo[k] = dig_one(context, k)
18
+ end
19
+ end
20
+
21
+ # Dig the value of k on context.
22
+ def dig_one(context, k)
23
+ case context
24
+ when Hash
25
+ context[@options[:use_symbols] ? k.to_sym : k]
26
+ when Array
27
+ context[k.to_i]
28
+ else
29
+ if context.respond_to?(:dig)
30
+ context.dig(k)
31
+ elsif @options[:allow_send]
32
+ context.__send__(k)
33
+ end
34
+ end
35
+ end
36
+
37
+ # Yields the block if context has a diggable
38
+ # value for k
39
+ def yield_if_diggable(context, k, &blk)
40
+ case context
41
+ when Array
42
+ nil
43
+ when Hash
44
+ k = @options[:use_symbols] ? k.to_sym : k
45
+ return yield if context.key?(k) || @options[:default_path_leaf_to_null]
46
+ else
47
+ if context.respond_to?(:dig)
48
+ digged = dig_one(context, k)
49
+ yield if !digged.nil? || @options[:default_path_leaf_to_null]
50
+ elsif @options[:allow_send] && context.respond_to?(k.to_s) && !Object.respond_to?(k.to_s)
51
+ yield
52
+ end
53
+ end
54
+ end
55
+
56
+ end
57
+ end
@@ -3,6 +3,7 @@
3
3
  class JsonPath
4
4
  class Enumerable
5
5
  include ::Enumerable
6
+ include Dig
6
7
 
7
8
  def initialize(path, object, mode, options = {})
8
9
  @path = path.path
@@ -12,12 +13,7 @@ class JsonPath
12
13
  end
13
14
 
14
15
  def each(context = @object, key = nil, pos = 0, &blk)
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
+ node = key ? dig_one(context, key) : context
21
17
  @_current_node = node
22
18
  return yield_value(blk, context, key) if pos == @path.size
23
19
 
@@ -47,11 +43,10 @@ class JsonPath
47
43
  def filter_context(context, keys)
48
44
  case context
49
45
  when Hash
50
- # TODO: Change this to `slice(*keys)` when ruby version support is > 2.4
51
- context.select { |k| keys.include?(k) }
46
+ dig_as_hash(context, keys)
52
47
  when Array
53
48
  context.each_with_object([]) do |c, memo|
54
- memo << c.select { |k| keys.include?(k) }
49
+ memo << dig_as_hash(c, keys)
55
50
  end
56
51
  end
57
52
  end
@@ -61,16 +56,14 @@ class JsonPath
61
56
  case sub_path[0]
62
57
  when '\'', '"'
63
58
  k = sub_path[1, sub_path.size - 2]
64
- if node.is_a?(Hash)
65
- node[k] ||= nil if @options[:default_path_leaf_to_null]
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)
59
+ yield_if_diggable(node, k) do
68
60
  each(node, k, pos + 1, &blk)
69
61
  end
70
62
  when '?'
71
63
  handle_question_mark(sub_path, node, pos, &blk)
72
64
  else
73
65
  next if node.is_a?(Array) && node.empty?
66
+ next if node.nil? # when default_path_leaf_to_null is true
74
67
 
75
68
  array_args = sub_path.split(':')
76
69
  if array_args[0] == '*'
@@ -130,7 +123,7 @@ class JsonPath
130
123
  def yield_value(blk, context, key)
131
124
  case @mode
132
125
  when nil
133
- blk.call(key ? context[key] : context)
126
+ blk.call(key ? dig_one(context, key) : context)
134
127
  when :compact
135
128
  if key && context[key].nil?
136
129
  key.is_a?(Integer) ? context.delete_at(key) : context.delete(key)
@@ -158,16 +151,13 @@ class JsonPath
158
151
  identifiers = /@?((?<!\d)\.(?!\d)(\w+))+/.match(exp)
159
152
  if !identifiers.nil? && !@_current_node.methods.include?(identifiers[2].to_sym)
160
153
  exp_to_eval = exp.dup
161
- exp_to_eval[identifiers[0]] = identifiers[0].split('.').map do |el|
162
- el == '@' ? '@' : "['#{el}']"
163
- end.join
164
154
  begin
165
- return JsonPath::Parser.new(@_current_node).parse(exp_to_eval)
155
+ return JsonPath::Parser.new(@_current_node, @options).parse(exp_to_eval)
166
156
  rescue StandardError
167
157
  return default
168
158
  end
169
159
  end
170
- JsonPath::Parser.new(@_current_node).parse(exp)
160
+ JsonPath::Parser.new(@_current_node, @options).parse(exp)
171
161
  end
172
162
  end
173
163
  end
@@ -5,11 +5,14 @@ require 'strscan'
5
5
  class JsonPath
6
6
  # Parser parses and evaluates an expression passed to @_current_node.
7
7
  class Parser
8
+ include Dig
9
+
8
10
  REGEX = /\A\/(.+)\/([imxnesu]*)\z|\A%r{(.+)}([imxnesu]*)\z/
9
11
 
10
- def initialize(node)
12
+ def initialize(node, options)
11
13
  @_current_node = node
12
14
  @_expr_map = {}
15
+ @options = options
13
16
  end
14
17
 
15
18
  # parse will parse an expression in the following way.
@@ -65,7 +68,7 @@ class JsonPath
65
68
  scanner = StringScanner.new(exp)
66
69
  elements = []
67
70
  until scanner.eos?
68
- if (t = scanner.scan(/\['[a-zA-Z@&*\/$%^?_]+'\]|\.[a-zA-Z0-9_]+[?!]?/))
71
+ if (t = scanner.scan(/\['[a-zA-Z@&*\/$%^?_]+'\]|\.[a-zA-Z0-9_]+[?]?/))
69
72
  elements << t.gsub(/[\[\]'.]|\s+/, '')
70
73
  elsif (t = scanner.scan(/(\s+)?[<>=!\-+][=~]?(\s+)?/))
71
74
  operator = t
@@ -91,7 +94,7 @@ class JsonPath
91
94
  el = if elements.empty?
92
95
  @_current_node
93
96
  elsif @_current_node.is_a?(Hash)
94
- @_current_node.dig(*elements)
97
+ dig(@_current_node, *elements)
95
98
  else
96
99
  elements.inject(@_current_node, &:__send__)
97
100
  end
@@ -156,9 +159,11 @@ class JsonPath
156
159
  res = bool_or_exp(top.shift)
157
160
  top.each_with_index do |item, index|
158
161
  if item == '&&'
159
- res &&= top[index + 1]
162
+ next_value = bool_or_exp(top[index + 1])
163
+ res &&= next_value
160
164
  elsif item == '||'
161
- res ||= top[index + 1]
165
+ next_value = bool_or_exp(top[index + 1])
166
+ res ||= next_value
162
167
  end
163
168
  end
164
169
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class JsonPath
4
- VERSION = '1.0.7'
4
+ VERSION = '1.1.2'
5
5
  end
data/lib/jsonpath.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require 'strscan'
4
4
  require 'multi_json'
5
5
  require 'jsonpath/proxy'
6
+ require 'jsonpath/dig'
6
7
  require 'jsonpath/enumerable'
7
8
  require 'jsonpath/version'
8
9
  require 'jsonpath/parser'
@@ -12,10 +13,18 @@ require 'jsonpath/parser'
12
13
  class JsonPath
13
14
  PATH_ALL = '$..*'
14
15
 
16
+ DEFAULT_OPTIONS = {
17
+ :default_path_leaf_to_null => false,
18
+ :symbolize_keys => false,
19
+ :use_symbols => false,
20
+ :allow_send => true,
21
+ :max_nesting => 100
22
+ }
23
+
15
24
  attr_accessor :path
16
25
 
17
26
  def initialize(path, opts = {})
18
- @opts = opts
27
+ @opts = DEFAULT_OPTIONS.merge(opts)
19
28
  scanner = StringScanner.new(path.strip)
20
29
  @path = []
21
30
  until scanner.eos?
@@ -78,13 +87,46 @@ class JsonPath
78
87
  end
79
88
  a
80
89
  end
90
+
91
+ def self.fetch_all_path(obj)
92
+ all_paths = ['$']
93
+ find_path(obj, '$', all_paths, obj.class == Array)
94
+ return all_paths
95
+ end
96
+
97
+ def self.find_path(obj, root_key, all_paths, is_array = false)
98
+ obj.each do |key, value|
99
+ table_params = { key: key, root_key: root_key}
100
+ is_loop = value.class == Array || value.class == Hash
101
+ if is_loop
102
+ path_exp = construct_path(table_params)
103
+ all_paths << path_exp
104
+ find_path(value, path_exp, all_paths, value.class == Array)
105
+ elsif is_array
106
+ table_params[:index] = obj.find_index(key)
107
+ path_exp = construct_path(table_params)
108
+ find_path(key, path_exp, all_paths, key.class == Array) if key.class == Hash || key.class == Array
109
+ all_paths << path_exp
110
+ else
111
+ all_paths << construct_path(table_params)
112
+ end
113
+ end
114
+ end
115
+
116
+ def self.construct_path(table_row)
117
+ if table_row[:index]
118
+ return table_row[:root_key] + '['+ table_row[:index].to_s + ']'
119
+ else
120
+ return table_row[:root_key] + '.'+ table_row[:key]
121
+ end
122
+ end
81
123
 
82
124
  def first(obj_or_str, *args)
83
125
  enum_on(obj_or_str).first(*args)
84
126
  end
85
127
 
86
128
  def enum_on(obj_or_str, mode = nil)
87
- JsonPath::Enumerable.new(self, self.class.process_object(obj_or_str), mode,
129
+ JsonPath::Enumerable.new(self, self.class.process_object(obj_or_str, @opts), mode,
88
130
  @opts)
89
131
  end
90
132
  alias [] enum_on
@@ -99,8 +141,8 @@ class JsonPath
99
141
 
100
142
  private
101
143
 
102
- def self.process_object(obj_or_str)
103
- obj_or_str.is_a?(String) ? MultiJson.decode(obj_or_str) : obj_or_str
144
+ def self.process_object(obj_or_str, opts = {})
145
+ obj_or_str.is_a?(String) ? MultiJson.decode(obj_or_str, max_nesting: opts[:max_nesting]) : obj_or_str
104
146
  end
105
147
 
106
148
  def deep_clone
@@ -70,24 +70,60 @@ 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
+ end
74
+
75
+ def test_not_equals_operator
76
+ expected =
77
+ [
78
+ @object['store']['book'][0],
79
+ @object['store']['book'][4],
80
+ @object['store']['book'][5],
81
+ @object['store']['book'][6]
82
+ ]
83
+ assert_equal(expected, JsonPath.new("$..book[?(@['category'] != 'fiction')]").on(@object))
84
+ assert_equal(expected, JsonPath.new("$..book[?(@['category']!=fiction)]").on(@object))
85
+ assert_equal(expected, JsonPath.new("$..book[?(@.category!=fiction)]").on(@object))
86
+ assert_equal(expected, JsonPath.new("$..book[?(@.category != 'fiction')]").on(@object))
79
87
  end
80
88
 
81
89
  def test_or_operator
82
90
  assert_equal [@object['store']['book'][1], @object['store']['book'][3]], JsonPath.new("$..book[?(@['price'] == 13 || @['price'] == 23)]").on(@object)
91
+ result = ["Sayings of the Century", "Sword of Honour", "Moby Dick", "The Lord of the Rings"]
92
+ assert_equal result, JsonPath.new("$..book[?(@.price==13 || @.price==9 || @.price==23)].title").on(@object)
93
+ assert_equal result, JsonPath.new("$..book[?(@.price==9 || @.price==23 || @.price==13)].title").on(@object)
94
+ assert_equal result, JsonPath.new("$..book[?(@.price==23 || @.price==13 || @.price==9)].title").on(@object)
95
+ end
96
+
97
+ def test_or_operator_with_not_equals
98
+ # Should be the same regardless of key style ( @.key vs @['key'] )
99
+ result = ['Nigel Rees', 'Evelyn Waugh', 'Herman Melville', 'J. R. R. Tolkien', 'Lukyanenko']
100
+ assert_equal result, JsonPath.new("$..book[?(@['title']=='Osennie Vizity' || @['author']!='Lukyanenko')].author").on(@object)
101
+ assert_equal result, JsonPath.new("$..book[?(@.title=='Osennie Vizity' || @.author != Lukyanenko )].author").on(@object)
102
+ assert_equal result, JsonPath.new("$..book[?(@.title=='Osennie Vizity' || @.author!=Lukyanenko )].author").on(@object)
83
103
  end
84
104
 
85
105
  def test_and_operator
86
106
  assert_equal [], JsonPath.new("$..book[?(@['price'] == 13 && @['price'] == 23)]").on(@object)
107
+ assert_equal [], JsonPath.new("$..book[?(@.price>=13 && @.category==fiction && @.title==no_match)]").on(@object)
108
+ assert_equal [], JsonPath.new("$..book[?(@.title==no_match && @.category==fiction && @.price==13)]").on(@object)
109
+ assert_equal [], JsonPath.new("$..book[?(@.price==13 && @.title==no_match && @.category==fiction)]").on(@object)
110
+ assert_equal [], JsonPath.new("$..book[?(@.price==13 && @.bad_key_name==true && @.category==fiction)]").on(@object)
111
+
112
+ expected = [@object['store']['book'][1]]
113
+ assert_equal expected, JsonPath.new("$..book[?(@['price'] < 23 && @['price'] > 9)]").on(@object)
114
+ assert_equal expected, JsonPath.new("$..book[?(@.price < 23 && @.price > 9)]").on(@object)
115
+
116
+ expected = ['Sword of Honour', 'The Lord of the Rings']
117
+ assert_equal expected, JsonPath.new("$..book[?(@.price>=13 && @.category==fiction)].title").on(@object)
118
+ assert_equal ['The Lord of the Rings'], JsonPath.new("$..book[?(@.category==fiction && @.isbn && @.price>9)].title").on(@object)
119
+ assert_equal ['Sayings of the Century'], JsonPath.new("$..book[?(@['price'] == 9 && @.author=='Nigel Rees')].title").on(@object)
120
+ assert_equal ['Sayings of the Century'], JsonPath.new("$..book[?(@['price'] == 9 && @.tags..asdf)].title").on(@object)
87
121
  end
88
122
 
89
- def test_and_operator_with_more_results
90
- assert_equal [@object['store']['book'][1]], JsonPath.new("$..book[?(@['price'] < 23 && @['price'] > 9)]").on(@object)
123
+ def test_and_operator_with_not_equals
124
+ expected = ['Nigel Rees']
125
+ assert_equal expected, JsonPath.new("$..book[?(@['price']==9 && @['category']!=fiction)].author").on(@object)
126
+ assert_equal expected, JsonPath.new("$..book[?(@.price==9 && @.category!=fiction)].author").on(@object)
91
127
  end
92
128
 
93
129
  def test_nested_grouping
@@ -130,6 +166,50 @@ class TestJsonpath < MiniTest::Unit::TestCase
130
166
  assert_equal ['value'], JsonPath.new('$.b').on(object)
131
167
  end
132
168
 
169
+ def test_works_on_object
170
+ klass = Class.new{
171
+ attr_reader :b
172
+ def initialize(b)
173
+ @b = b
174
+ end
175
+ }
176
+ object = klass.new("value")
177
+
178
+ assert_equal ["value"], JsonPath.new('$.b').on(object)
179
+ end
180
+
181
+ def test_works_on_object_can_be_disabled
182
+ klass = Class.new{
183
+ attr_reader :b
184
+ def initialize(b)
185
+ @b = b
186
+ end
187
+ }
188
+ object = klass.new("value")
189
+
190
+ assert_equal [], JsonPath.new('$.b', allow_send: false).on(object)
191
+ end
192
+
193
+ def test_works_on_diggable
194
+ klass = Class.new{
195
+ attr_reader :h
196
+ def initialize(h)
197
+ @h = h
198
+ end
199
+ def dig(*keys)
200
+ @h.dig(*keys)
201
+ end
202
+ }
203
+
204
+ object = klass.new('a' => 'some', 'b' => 'value')
205
+ assert_equal ['value'], JsonPath.new('$.b').on(object)
206
+
207
+ object = {
208
+ "foo" => klass.new('a' => 'some', 'b' => 'value')
209
+ }
210
+ assert_equal ['value'], JsonPath.new('$.foo.b').on(object)
211
+ end
212
+
133
213
  def test_works_on_non_hash_with_filters
134
214
  klass = Struct.new(:a, :b)
135
215
  first_object = klass.new('some', 'value')
@@ -138,6 +218,24 @@ class TestJsonpath < MiniTest::Unit::TestCase
138
218
  assert_equal ['other value'], JsonPath.new('$[?(@.a == "next")].b').on([first_object, second_object])
139
219
  end
140
220
 
221
+ def test_works_on_hash_with_summary
222
+ object = {
223
+ "foo" => [{
224
+ "a" => "some",
225
+ "b" => "value"
226
+ }]
227
+ }
228
+ assert_equal [{ "b" => "value" }], JsonPath.new("$.foo[*](b)").on(object)
229
+ end
230
+
231
+ def test_works_on_non_hash_with_summary
232
+ klass = Struct.new(:a, :b)
233
+ object = {
234
+ "foo" => [klass.new("some", "value")]
235
+ }
236
+ assert_equal [{ "b" => "value" }], JsonPath.new("$.foo[*](b)").on(object)
237
+ end
238
+
141
239
  def test_recognize_array_with_evald_index
142
240
  assert_equal [@object['store']['book'][2]], JsonPath.new('$..book[(@.length-5)]').on(@object)
143
241
  end
@@ -508,11 +606,42 @@ class TestJsonpath < MiniTest::Unit::TestCase
508
606
  'name' => 'testname2'
509
607
  }]
510
608
  }
511
- assert_equal [{ 'isTrue' => true, 'name' => 'testname1' }], JsonPath.new('$.data[?(@.isTrue)]').on(data)
609
+
610
+ # These queries should be equivalent
611
+ expected = [{ 'isTrue' => true, 'name' => 'testname1' }]
612
+ assert_equal expected, JsonPath.new('$.data[?(@.isTrue)]').on(data)
613
+ assert_equal expected, JsonPath.new('$.data[?(@.isTrue==true)]').on(data)
614
+ assert_equal expected, JsonPath.new('$.data[?(@.isTrue == true)]').on(data)
615
+
616
+ # These queries should be equivalent
617
+ expected = [{ 'isTrue' => false, 'name' => 'testname2' }]
618
+ assert_equal expected, JsonPath.new('$.data[?(@.isTrue != true)]').on(data)
619
+ assert_equal expected, JsonPath.new('$.data[?(@.isTrue!=true)]').on(data)
620
+ assert_equal expected, JsonPath.new('$.data[?(@.isTrue==false)]').on(data)
621
+ end
622
+
623
+ def test_and_operator_with_boolean_parameter_value
624
+ data = {
625
+ 'data' => [{
626
+ 'hasProperty1' => true,
627
+ 'hasProperty2' => false,
628
+ 'name' => 'testname1'
629
+ }, {
630
+ 'hasProperty1' => false,
631
+ 'hasProperty2' => true,
632
+ 'name' => 'testname2'
633
+ }, {
634
+ 'hasProperty1' => true,
635
+ 'hasProperty2' => true,
636
+ 'name' => 'testname3'
637
+ }]
638
+ }
639
+ assert_equal ['testname3'], JsonPath.new('$.data[?(@.hasProperty1 && @.hasProperty2)].name').on(data)
512
640
  end
513
641
 
514
642
  def test_regex_simple
515
643
  assert_equal %w[asdf asdf2], JsonPath.new('$.store.book..tags[?(@ =~ /asdf/)]').on(@object)
644
+ assert_equal %w[asdf asdf2], JsonPath.new('$.store.book..tags[?(@=~/asdf/)]').on(@object)
516
645
  end
517
646
 
518
647
  def test_regex_simple_miss
@@ -849,7 +978,34 @@ class TestJsonpath < MiniTest::Unit::TestCase
849
978
  assert_equal [], JsonPath.on(json, "$.phoneNumbers[?(@[0].type == 'home')]")
850
979
  end
851
980
 
852
- def test_selecting_multiple_keys
981
+ def test_selecting_multiple_keys_on_hash
982
+ json = '
983
+ {
984
+ "category": "reference",
985
+ "author": "Nigel Rees",
986
+ "title": "Sayings of the Century",
987
+ "price": 8.95
988
+ }
989
+ '.to_json
990
+ assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, '$.(category,author)')
991
+ end
992
+
993
+ def test_selecting_multiple_keys_on_sub_hash
994
+ skip("Failing as the semantics of .(x,y) is unclear")
995
+ json = '
996
+ {
997
+ "book": {
998
+ "category": "reference",
999
+ "author": "Nigel Rees",
1000
+ "title": "Sayings of the Century",
1001
+ "price": 8.95
1002
+ }
1003
+ }
1004
+ '.to_json
1005
+ assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, '$.book.(category,author)')
1006
+ end
1007
+
1008
+ def test_selecting_multiple_keys_on_array
853
1009
  json = '
854
1010
  {
855
1011
  "store": {
@@ -874,7 +1030,7 @@ class TestJsonpath < MiniTest::Unit::TestCase
874
1030
  assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }, { 'category' => 'fiction', 'author' => 'Evelyn Waugh' }], JsonPath.on(json, '$.store.book[*](category,author)')
875
1031
  end
876
1032
 
877
- def test_selecting_multiple_keys_with_filter
1033
+ def test_selecting_multiple_keys_on_array_with_filter
878
1034
  json = '
879
1035
  {
880
1036
  "store": {
@@ -925,6 +1081,32 @@ class TestJsonpath < MiniTest::Unit::TestCase
925
1081
  assert_equal [{ 'cate gory' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, "$.store.book[?(@['price'] == 8.95)]( cate gory, author )")
926
1082
  end
927
1083
 
1084
+ def test_use_symbol_opt
1085
+ json = {
1086
+ store: {
1087
+ book: [
1088
+ {
1089
+ category: "reference",
1090
+ author: "Nigel Rees",
1091
+ title: "Sayings of the Century",
1092
+ price: 8.95
1093
+ },
1094
+ {
1095
+ category: "fiction",
1096
+ author: "Evelyn Waugh",
1097
+ title: "Sword of Honour",
1098
+ price: 12.99
1099
+ }
1100
+ ]
1101
+ }
1102
+ }
1103
+ on = ->(path){ JsonPath.on(json, path, use_symbols: true) }
1104
+ assert_equal ['reference', 'fiction'], on.("$.store.book[*].category")
1105
+ assert_equal ['reference', 'fiction'], on.("$..category")
1106
+ assert_equal ['reference'], on.("$.store.book[?(@['price'] == 8.95)].category")
1107
+ assert_equal [{'category' => 'reference'}], on.("$.store.book[?(@['price'] == 8.95)](category)")
1108
+ end
1109
+
928
1110
  def test_object_method_send
929
1111
  j = {height: 5, hash: "some_hash"}.to_json
930
1112
  hs = JsonPath.new "$..send"
@@ -945,6 +1127,70 @@ class TestJsonpath < MiniTest::Unit::TestCase
945
1127
  assert_equal ['foo'], JsonPath.new('$.1').on(data.to_json)
946
1128
  end
947
1129
 
1130
+ def test_behavior_on_null_and_missing
1131
+ data = {
1132
+ "foo" => nil,
1133
+ "bar" => {
1134
+ "baz" => nil
1135
+ },
1136
+ "bars" => [
1137
+ { "foo" => 12 },
1138
+ { "foo" => nil },
1139
+ { }
1140
+ ]
1141
+ }
1142
+ assert_equal [nil], JsonPath.new('$.foo').on(data)
1143
+ assert_equal [nil], JsonPath.new('$.bar.baz').on(data)
1144
+ assert_equal [], JsonPath.new('$.baz').on(data)
1145
+ assert_equal [], JsonPath.new('$.bar.foo').on(data)
1146
+ assert_equal [12, nil], JsonPath.new('$.bars[*].foo').on(data)
1147
+ end
1148
+
1149
+ def test_default_path_leaf_to_null_opt
1150
+ data = {
1151
+ "foo" => nil,
1152
+ "bar" => {
1153
+ "baz" => nil
1154
+ },
1155
+ "bars" => [
1156
+ { "foo" => 12 },
1157
+ { "foo" => nil },
1158
+ { }
1159
+ ]
1160
+ }
1161
+ assert_equal [nil], JsonPath.new('$.foo', default_path_leaf_to_null: true).on(data)
1162
+ assert_equal [nil], JsonPath.new('$.bar.baz', default_path_leaf_to_null: true).on(data)
1163
+ assert_equal [nil], JsonPath.new('$.baz', default_path_leaf_to_null: true).on(data)
1164
+ assert_equal [nil], JsonPath.new('$.bar.foo', default_path_leaf_to_null: true).on(data)
1165
+ assert_equal [12, nil, nil], JsonPath.new('$.bars[*].foo', default_path_leaf_to_null: true).on(data)
1166
+ end
1167
+
1168
+ def test_raise_max_nesting_error
1169
+ json = {
1170
+ a: {
1171
+ b: {
1172
+ c: {
1173
+ }
1174
+ }
1175
+ }
1176
+ }.to_json
1177
+
1178
+ assert_raises(MultiJson::ParseError) { JsonPath.new('$.a', max_nesting: 1).on(json) }
1179
+ end
1180
+
1181
+ def test_with_max_nesting_false
1182
+ json = {
1183
+ a: {
1184
+ b: {
1185
+ c: {
1186
+ }
1187
+ }
1188
+ }
1189
+ }.to_json
1190
+
1191
+ assert_equal [{}], JsonPath.new('$.a.b.c', max_nesting: false).on(json)
1192
+ end
1193
+
948
1194
  def example_object
949
1195
  { 'store' => {
950
1196
  'book' => [
@@ -999,4 +1245,19 @@ class TestJsonpath < MiniTest::Unit::TestCase
999
1245
  '_links' => { 'self' => {} }
1000
1246
  } }
1001
1247
  end
1248
+
1249
+ def test_fetch_all_path
1250
+ data = {
1251
+ "foo" => nil,
1252
+ "bar" => {
1253
+ "baz" => nil
1254
+ },
1255
+ "bars" => [
1256
+ { "foo" => 12 },
1257
+ { "foo" => nil },
1258
+ { }
1259
+ ]
1260
+ }
1261
+ assert_equal ["$", "$.foo", "$.bar", "$.bar.baz", "$.bars", "$.bars[0].foo", "$.bars[0]", "$.bars[1].foo", "$.bars[1]", "$.bars[2]"], JsonPath.fetch_all_path(data)
1262
+ end
1002
1263
  end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest/autorun'
4
+ require 'phocus'
5
+ require 'jsonpath'
6
+ require 'json'
7
+
8
+ class TestJsonpathReadme < MiniTest::Unit::TestCase
9
+
10
+ def setup
11
+ @json = <<-HERE_DOC
12
+ {"store":
13
+ {"bicycle":
14
+ {"price":19.95, "color":"red"},
15
+ "book":[
16
+ {"price":8.95, "category":"reference", "title":"Sayings of the Century", "author":"Nigel Rees"},
17
+ {"price":12.99, "category":"fiction", "title":"Sword of Honour", "author":"Evelyn Waugh"},
18
+ {"price":8.99, "category":"fiction", "isbn":"0-553-21311-3", "title":"Moby Dick", "author":"Herman Melville","color":"blue"},
19
+ {"price":22.99, "category":"fiction", "isbn":"0-395-19395-8", "title":"The Lord of the Rings", "author":"Tolkien"}
20
+ ]
21
+ }
22
+ }
23
+ HERE_DOC
24
+ end
25
+ attr_reader :json
26
+
27
+ def test_library_section
28
+ path = JsonPath.new('$..price')
29
+ assert_equal [19.95, 8.95, 12.99, 8.99, 22.99], path.on(json)
30
+ assert_equal [18.88], path.on('{"books":[{"title":"A Tale of Two Somethings","price":18.88}]}')
31
+ assert_equal ["Nigel Rees", "Evelyn Waugh", "Herman Melville", "Tolkien"], JsonPath.on(json, '$..author')
32
+ assert_equal [
33
+ {"price" => 8.95, "category" => "reference", "title" => "Sayings of the Century", "author" => "Nigel Rees"},
34
+ {"price" => 8.99, "category" => "fiction", "isbn" => "0-553-21311-3", "title" => "Moby Dick", "author" => "Herman Melville","color" => "blue"},
35
+ ], JsonPath.new('$..book[::2]').on(json)
36
+ assert_equal [8.95, 8.99], JsonPath.new("$..price[?(@ < 10)]").on(json)
37
+ assert_equal ["Sayings of the Century", "Moby Dick"], JsonPath.new("$..book[?(@['price'] == 8.95 || @['price'] == 8.99)].title").on(json)
38
+ assert_equal [], JsonPath.new("$..book[?(@['price'] == 8.95 && @['price'] == 8.99)].title").on(json)
39
+ assert_equal "red", JsonPath.new('$..color').first(json)
40
+ end
41
+
42
+ def test_library_section_enumerable
43
+ enum = JsonPath.new('$..color')[json]
44
+ assert_equal "red", enum.first
45
+ assert enum.any?{ |c| c == 'red' }
46
+ end
47
+
48
+ def test_ruby_structures_section
49
+ book = { title: "Sayings of the Century" }
50
+ assert_equal [], JsonPath.new('$.title').on(book)
51
+ assert_equal ["Sayings of the Century"], JsonPath.new('$.title', use_symbols: true).on(book)
52
+
53
+ book_class = Struct.new(:title)
54
+ book = book_class.new("Sayings of the Century")
55
+ assert_equal ["Sayings of the Century"], JsonPath.new('$.title').on(book)
56
+
57
+ book_class = Class.new{ attr_accessor :title }
58
+ book = book_class.new
59
+ book.title = "Sayings of the Century"
60
+ assert_equal ["Sayings of the Century"], JsonPath.new('$.title', allow_send: true).on(book)
61
+ end
62
+
63
+ def test_options_section
64
+ assert_equal ["0-553-21311-3", "0-395-19395-8"], JsonPath.new('$..book[*].isbn').on(json)
65
+ assert_equal [nil, nil, "0-553-21311-3", "0-395-19395-8"], JsonPath.new('$..book[*].isbn', default_path_leaf_to_null: true).on(json)
66
+
67
+ assert_equal ["price", "category", "title", "author"], JsonPath.new('$..book[0]').on(json).map(&:keys).flatten.uniq
68
+ assert_equal [:price, :category, :title, :author], JsonPath.new('$..book[0]').on(json, symbolize_keys: true).map(&:keys).flatten.uniq
69
+ end
70
+
71
+ def selecting_value_section
72
+ json = <<-HERE_DOC
73
+ {
74
+ "store": {
75
+ "book": [
76
+ {
77
+ "category": "reference",
78
+ "author": "Nigel Rees",
79
+ "title": "Sayings of the Century",
80
+ "price": 8.95
81
+ },
82
+ {
83
+ "category": "fiction",
84
+ "author": "Evelyn Waugh",
85
+ "title": "Sword of Honour",
86
+ "price": 12.99
87
+ }
88
+ ]
89
+ }
90
+ HERE_DOC
91
+ got = JsonPath.on(json, "$.store.book[*](category,author)")
92
+ expected = [
93
+ {
94
+ "category" => "reference",
95
+ "author" => "Nigel Rees"
96
+ },
97
+ {
98
+ "category" => "fiction",
99
+ "author" => "Evelyn Waugh"
100
+ }
101
+ ]
102
+ assert_equal expected, got
103
+ end
104
+
105
+ def test_manipulation_section
106
+ assert_equal({"candy" => "big turks"}, JsonPath.for('{"candy":"lollipop"}').gsub('$..candy') {|v| "big turks" }.to_hash)
107
+
108
+ json = '{"candy":"lollipop","noncandy":null,"other":"things"}'
109
+ o = JsonPath.for(json).
110
+ gsub('$..candy') {|v| "big turks" }.
111
+ compact.
112
+ delete('$..other').
113
+ to_hash
114
+ assert_equal({"candy" => "big turks"}, o)
115
+ end
116
+
117
+ end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonpath
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.7
4
+ version: 1.1.2
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: 2020-12-15 00:00:00.000000000 Z
12
+ date: 2022-04-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: multi_json
@@ -81,6 +81,20 @@ dependencies:
81
81
  - - ">="
82
82
  - !ruby/object:Gem::Version
83
83
  version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: racc
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
84
98
  - !ruby/object:Gem::Dependency
85
99
  name: rake
86
100
  requirement: !ruby/object:Gem::Requirement
@@ -106,11 +120,11 @@ extra_rdoc_files:
106
120
  - README.md
107
121
  files:
108
122
  - ".gemtest"
123
+ - ".github/workflows/test.yml"
109
124
  - ".gitignore"
110
125
  - ".rspec"
111
126
  - ".rubocop.yml"
112
127
  - ".rubocop_todo.yml"
113
- - ".travis.yml"
114
128
  - Gemfile
115
129
  - LICENSE.md
116
130
  - README.md
@@ -118,17 +132,19 @@ files:
118
132
  - bin/jsonpath
119
133
  - jsonpath.gemspec
120
134
  - lib/jsonpath.rb
135
+ - lib/jsonpath/dig.rb
121
136
  - lib/jsonpath/enumerable.rb
122
137
  - lib/jsonpath/parser.rb
123
138
  - lib/jsonpath/proxy.rb
124
139
  - lib/jsonpath/version.rb
125
140
  - test/test_jsonpath.rb
126
141
  - test/test_jsonpath_bin.rb
142
+ - test/test_readme.rb
127
143
  homepage: https://github.com/joshbuddy/jsonpath
128
144
  licenses:
129
145
  - MIT
130
146
  metadata: {}
131
- post_install_message:
147
+ post_install_message:
132
148
  rdoc_options: []
133
149
  require_paths:
134
150
  - lib
@@ -143,8 +159,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
143
159
  - !ruby/object:Gem::Version
144
160
  version: '0'
145
161
  requirements: []
146
- rubygems_version: 3.0.3
147
- signing_key:
162
+ rubygems_version: 3.3.7
163
+ signing_key:
148
164
  specification_version: 4
149
165
  summary: Ruby implementation of http://goessner.net/articles/JsonPath/
150
166
  test_files: []
data/.travis.yml DELETED
@@ -1,8 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.5
4
- - 2.6
5
- - 2.7
6
- - ruby-head
7
- - jruby-head
8
- - truffleruby-head