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 +4 -4
- data/.github/workflows/test.yml +3 -1
- data/jsonpath.gemspec +1 -1
- data/lib/jsonpath/enumerable.rb +3 -2
- data/lib/jsonpath/version.rb +1 -1
- data/lib/jsonpath.rb +15 -4
- data/test/test_jsonpath.rb +54 -7
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ffcdd9076a2bd58ead93c850c8a1ed842a202e6db62314fb2b6c8fd5f8650fb5
|
4
|
+
data.tar.gz: 3d6624bd18086aa892f93bff141dd7bf33e516e02c3fd7e8828db13eb3a84436
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 492ed8f729cfdb038c2b0303f49bf2bf1bfb85bd4a7d6ae2e37c2b559bf288b73110db65b2c1642f4e1954cde213d10488ab996ad9261c108f253f03aeb41d12
|
7
|
+
data.tar.gz: 2642b36da6a171649a9b0dc2e973994a7d3268e71a62ea290e75f91bd7f7af621b0b0dd6d9fb6a1f7148943f2c5ce6965f8de0db69db4041bc973576b7694425
|
data/.github/workflows/test.yml
CHANGED
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.
|
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/.'
|
data/lib/jsonpath/enumerable.rb
CHANGED
@@ -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
|
-
|
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)
|
data/lib/jsonpath/version.rb
CHANGED
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 =>
|
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(/[
|
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
|
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
|
data/test/test_jsonpath.rb
CHANGED
@@ -245,7 +245,7 @@ class TestJsonpath < MiniTest::Unit::TestCase
|
|
245
245
|
end
|
246
246
|
|
247
247
|
def test_counting
|
248
|
-
assert_equal
|
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
|
890
|
-
path = "$..
|
891
|
-
|
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.
|
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-
|
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.
|
155
|
+
version: '2.6'
|
156
156
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
157
157
|
requirements:
|
158
158
|
- - ">="
|