jsonpath 1.1.3 → 1.1.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 89da09f37794d1cf177f887ea0a6c7d0da21d7106f8fd92d74d0615148feca02
4
- data.tar.gz: 116f72d5493e540e5fde487dac9e57c3ff7f4c5122b66997a09eea899cda59a7
3
+ metadata.gz: ffcdd9076a2bd58ead93c850c8a1ed842a202e6db62314fb2b6c8fd5f8650fb5
4
+ data.tar.gz: 3d6624bd18086aa892f93bff141dd7bf33e516e02c3fd7e8828db13eb3a84436
5
5
  SHA512:
6
- metadata.gz: 25d571cacbb85435c838c25b5d3c9cd8d6d1c11b743927531af80cdfe45d4670e6e37b21030608cf2b2ff4c04c78033caeb492ceb76db24e5b35d9a514b9e669
7
- data.tar.gz: 1b0fa8cdc648f6d889f00cd751e3e03e7f32693a5897238584d0ee67e3e3542117901755393bb36e513be6addc2fd4ab3223782df005f20024763cc14e0fc350
6
+ metadata.gz: 492ed8f729cfdb038c2b0303f49bf2bf1bfb85bd4a7d6ae2e37c2b559bf288b73110db65b2c1642f4e1954cde213d10488ab996ad9261c108f253f03aeb41d12
7
+ data.tar.gz: 2642b36da6a171649a9b0dc2e973994a7d3268e71a62ea290e75f91bd7f7af621b0b0dd6d9fb6a1f7148943f2c5ce6965f8de0db69db4041bc973576b7694425
@@ -8,9 +8,11 @@ jobs:
8
8
  fail-fast: false
9
9
  matrix:
10
10
  ruby-version:
11
- - '2.5'
12
11
  - '2.6'
13
12
  - '2.7'
13
+ - '3.2'
14
+ - '3.1'
15
+ - '3.0'
14
16
  - ruby-head
15
17
  - jruby-head
16
18
  - truffleruby-head
data/jsonpath.gemspec CHANGED
@@ -5,7 +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
- s.required_ruby_version = '>= 2.5'
8
+ s.required_ruby_version = '>= 2.6'
9
9
  s.authors = ['Joshua Hull', 'Gergely Brautigam']
10
10
  s.summary = 'Ruby implementation of http://goessner.net/articles/JsonPath/'
11
11
  s.description = 'Ruby implementation of http://goessner.net/articles/JsonPath/.'
@@ -154,8 +154,9 @@ class JsonPath
154
154
  return Integer(exp) if exp[0] != '('
155
155
  return nil unless @_current_node
156
156
 
157
- identifiers = /@?((?<!\d)\.(?!\d)(\w+))+/.match(exp)
158
- if !identifiers.nil? && !@_current_node.methods.include?(identifiers[2].to_sym)
157
+ identifiers = /@?(((?<!\d)\.(?!\d)(\w+))|\['(.*?)'\])+/.match(exp)
158
+ # to filter arrays with known/unknown name.
159
+ if (!identifiers.nil? && !(@_current_node.methods.include?(identifiers[2]&.to_sym) || @_current_node.methods.include?(identifiers[4]&.to_sym)))
159
160
  exp_to_eval = exp.dup
160
161
  begin
161
162
  return JsonPath::Parser.new(@_current_node, @options).parse(exp_to_eval)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class JsonPath
4
- VERSION = '1.1.3'
4
+ VERSION = '1.1.5'
5
5
  end
data/lib/jsonpath.rb CHANGED
@@ -12,25 +12,27 @@ require 'jsonpath/parser'
12
12
  # into a token array.
13
13
  class JsonPath
14
14
  PATH_ALL = '$..*'
15
+ MAX_NESTING_ALLOWED = 100
15
16
 
16
17
  DEFAULT_OPTIONS = {
17
18
  :default_path_leaf_to_null => false,
18
19
  :symbolize_keys => false,
19
20
  :use_symbols => false,
20
21
  :allow_send => true,
21
- :max_nesting => 100
22
+ :max_nesting => MAX_NESTING_ALLOWED
22
23
  }
23
24
 
24
25
  attr_accessor :path
25
26
 
26
27
  def initialize(path, opts = {})
27
28
  @opts = DEFAULT_OPTIONS.merge(opts)
29
+ set_max_nesting
28
30
  scanner = StringScanner.new(path.strip)
29
31
  @path = []
30
32
  until scanner.eos?
31
33
  if (token = scanner.scan(/\$\B|@\B|\*|\.\./))
32
34
  @path << token
33
- elsif (token = scanner.scan(/[$@a-zA-Z0-9:{}_-]+/))
35
+ elsif (token = scanner.scan(/[$@\p{Alnum}:{}_ -]+/))
34
36
  @path << "['#{token}']"
35
37
  elsif (token = scanner.scan(/'(.*?)'/))
36
38
  @path << "[#{token}]"
@@ -78,14 +80,14 @@ class JsonPath
78
80
 
79
81
  def on(obj_or_str, opts = {})
80
82
  a = enum_on(obj_or_str).to_a
81
- if opts[:symbolize_keys]
83
+ if symbolize_keys?(opts)
82
84
  a.map! do |e|
83
85
  e.each_with_object({}) { |(k, v), memo| memo[k.to_sym] = v; }
84
86
  end
85
87
  end
86
88
  a
87
89
  end
88
-
90
+
89
91
  def self.fetch_all_path(obj)
90
92
  all_paths = ['$']
91
93
  find_path(obj, '$', all_paths, obj.class == Array)
@@ -146,4 +148,13 @@ class JsonPath
146
148
  def deep_clone
147
149
  Marshal.load Marshal.dump(self)
148
150
  end
151
+
152
+ def set_max_nesting
153
+ return unless @opts[:max_nesting].is_a?(Integer) && @opts[:max_nesting] > MAX_NESTING_ALLOWED
154
+ @opts[:max_nesting] = false
155
+ end
156
+
157
+ def symbolize_keys?(opts)
158
+ opts.fetch(:symbolize_keys, @opts&.dig(:symbolize_keys))
159
+ end
149
160
  end
@@ -245,7 +245,7 @@ class TestJsonpath < MiniTest::Unit::TestCase
245
245
  end
246
246
 
247
247
  def test_counting
248
- assert_equal 57, JsonPath.new('$..*').on(@object).to_a.size
248
+ assert_equal 59, JsonPath.new('$..*').on(@object).to_a.size
249
249
  end
250
250
 
251
251
  def test_space_in_path
@@ -475,6 +475,16 @@ class TestJsonpath < MiniTest::Unit::TestCase
475
475
  JsonPath.new('$.store._links').on(@object)
476
476
  end
477
477
 
478
+ def test_support_for_umlauts_in_member_names
479
+ assert_equal [@object['store']['Übermorgen']],
480
+ JsonPath.new('$.store.Übermorgen').on(@object)
481
+ end
482
+
483
+ def test_support_for_spaces_in_member_name
484
+ assert_equal [@object['store']['Title Case']],
485
+ JsonPath.new('$.store.Title Case').on(@object)
486
+ end
487
+
478
488
  def test_dig_return_string
479
489
  assert_equal ['asdf'], JsonPath.new("$.store.book..tags[?(@ == 'asdf')]").on(@object)
480
490
  assert_equal [], JsonPath.new("$.store.book..tags[?(@ == 'not_asdf')]").on(@object)
@@ -885,13 +895,17 @@ class TestJsonpath < MiniTest::Unit::TestCase
885
895
  path = "$..book[?((@['author'] == 'Evelyn Waugh' || @['author'] == 'Herman Melville') && (@['price'] == 33 || @['price'] == 9))]"
886
896
  assert_equal [@object['store']['book'][2]], JsonPath.new(path).on(@object)
887
897
  end
888
-
889
- def test_complex_nested_grouping_unmatched_parent
890
- path = "$..book[?((@['author'] == 'Evelyn Waugh' || @['author'] == 'Herman Melville' && (@['price'] == 33 || @['price'] == 9))]"
891
- err = assert_raises(ArgumentError, 'should have raised an exception') { JsonPath.new(path).on(@object) }
892
- assert_match(/unmatched parenthesis in expression: \(\(false \|\| false && \(false \|\| true\)\)/, err.message)
898
+
899
+ def test_nested_with_unknown_key
900
+ path = "$..[?(@.price == 9 || @.price == 33)].title"
901
+ assert_equal ["Sayings of the Century", "Moby Dick", "Sayings of the Century", "Moby Dick"], JsonPath.new(path).on(@object)
893
902
  end
894
903
 
904
+ def test_nested_with_unknown_key_filtered_array
905
+ path = "$..[?(@['price'] == 9 || @['price'] == 33)].title"
906
+ assert_equal ["Sayings of the Century", "Moby Dick", "Sayings of the Century", "Moby Dick"], JsonPath.new(path).on(@object)
907
+ end
908
+
895
909
  def test_runtime_error_frozen_string
896
910
  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')
897
911
  json = '
@@ -1195,6 +1209,31 @@ class TestJsonpath < MiniTest::Unit::TestCase
1195
1209
  assert_equal [{}], JsonPath.new('$.a.b.c', max_nesting: false).on(json)
1196
1210
  end
1197
1211
 
1212
+ def test_initialize_with_max_nesting_exceeding_limit
1213
+ json = {
1214
+ a: {
1215
+ b: {
1216
+ c: {
1217
+ }
1218
+ }
1219
+ }
1220
+ }.to_json
1221
+
1222
+ json_obj = JsonPath.new('$.a.b.c', max_nesting: 105)
1223
+ assert_equal [{}], json_obj.on(json)
1224
+ assert_equal false, json_obj.instance_variable_get(:@opts)[:max_nesting]
1225
+ end
1226
+
1227
+ def test_initialize_without_max_nesting_exceeding_limit
1228
+ json_obj = JsonPath.new('$.a.b.c', max_nesting: 90)
1229
+ assert_equal 90, json_obj.instance_variable_get(:@opts)[:max_nesting]
1230
+ end
1231
+
1232
+ def test_initialize_with_max_nesting_false_limit
1233
+ json_obj = JsonPath.new('$.a.b.c', max_nesting: false)
1234
+ assert_equal false, json_obj.instance_variable_get(:@opts)[:max_nesting]
1235
+ end
1236
+
1198
1237
  def example_object
1199
1238
  { 'store' => {
1200
1239
  'book' => [
@@ -1246,10 +1285,12 @@ class TestJsonpath < MiniTest::Unit::TestCase
1246
1285
  },
1247
1286
  '@id' => 'http://example.org/store/42',
1248
1287
  '$meta-data' => 'whatevs',
1288
+ 'Übermorgen' => 'The day after tomorrow',
1289
+ 'Title Case' => 'A title case string',
1249
1290
  '_links' => { 'self' => {} }
1250
1291
  } }
1251
1292
  end
1252
-
1293
+
1253
1294
  def test_fetch_all_path
1254
1295
  data = {
1255
1296
  "foo" => nil,
@@ -1271,4 +1312,10 @@ class TestJsonpath < MiniTest::Unit::TestCase
1271
1312
  assert_equal ["success"], JsonPath.on(json, "$.test.$")
1272
1313
  assert_equal ["123"], JsonPath.on(json, "$.test.a")
1273
1314
  end
1315
+
1316
+ def test_symbolize_key
1317
+ data = { "store" => { "book" => [{"category" => "reference"}]}}
1318
+ assert_equal [{"category": "reference"}], JsonPath.new('$..book[0]', symbolize_keys: true).on(data)
1319
+ assert_equal [{"category": "reference"}], JsonPath.new('$..book[0]').on(data, symbolize_keys: true)
1320
+ end
1274
1321
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonpath
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.3
4
+ version: 1.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Hull
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-05-09 00:00:00.000000000 Z
12
+ date: 2023-10-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: multi_json
@@ -152,7 +152,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
152
152
  requirements:
153
153
  - - ">="
154
154
  - !ruby/object:Gem::Version
155
- version: '2.5'
155
+ version: '2.6'
156
156
  required_rubygems_version: !ruby/object:Gem::Requirement
157
157
  requirements:
158
158
  - - ">="