jsonpath 1.0.3 → 1.0.4

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: 762aacec760a67a4097f47df701a1cec0f3f524ae016a2b724873c625c25672d
4
- data.tar.gz: a3076196bc9d30f4cad3ee9c0ab3d58f9bedef4b7d17d7934e7e930c351ee1c0
3
+ metadata.gz: 3d49972014868528c0c690ecec0ec7d6e06056f14a803637d494c87ee3100de0
4
+ data.tar.gz: fbbb8f93028b2aac45f6727aba4e874c51db91bb599bc568ec62c94180595a91
5
5
  SHA512:
6
- metadata.gz: 7894391f0693b7ebb3f3d8bca20dcf2eeb54af85e6ca268ff75fe120c64ae5e8ff09fa9a7b82cacbb8a5776d03dfa0f9bcc1f4716eea63988910cbb501d64236
7
- data.tar.gz: c0f5c57d5c527a432a1c02fa728e32f8f8a7009efd0a31778b2766d97eba1e752ec1779e2d725fc233731f64541be72c9e896a511f312f8b5e3a4a1ed3e31a8d
6
+ metadata.gz: 60c7d6e4075b9ece68f6325d2b836f228b780304ac0ddafbfe2154668f07c10d4faee371135b9b9c55f7548a89a7f755d6536b4305e47f486112549c9b2711b1
7
+ data.tar.gz: cf72f327c8a3d12bb4780cf052846e9183218148dcf5e57fcddaeb0c1b86218f9a082d4b3cb7f7e38e390956176da71a954e855ae33436f9ce396a1eb73fd2f7
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
@@ -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 = '$..*'.freeze
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(/[\$@a-zA-Z0-9:{}_-]+/)
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'
@@ -28,6 +28,10 @@ class JsonPath
28
28
  each(context, key, pos + 1, &blk) if node == @object
29
29
  when /^\[(.*)\]$/
30
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)
31
35
  end
32
36
 
33
37
  if pos > 0 && @path[pos - 1] == '..' || (@path[pos - 1] == '*' && @path[pos] != '..')
@@ -40,6 +44,18 @@ class JsonPath
40
44
 
41
45
  private
42
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
+
43
59
  def handle_wildecard(node, expr, _context, _key, pos, &blk)
44
60
  expr[1, expr.size - 2].split(',').each do |sub_path|
45
61
  case sub_path[0]
@@ -65,7 +65,7 @@ class JsonPath
65
65
  elements = []
66
66
  until scanner.eos?
67
67
  if (t = scanner.scan(/\['[a-zA-Z@&*\/$%^?_]+'\]|\.[a-zA-Z0-9_]+[?!]?/))
68
- elements << t.gsub(/[\[\]'\.]|\s+/, '')
68
+ elements << t.gsub(/[\[\]'.]|\s+/, '')
69
69
  elsif (t = scanner.scan(/(\s+)?[<>=!\-+][=~]?(\s+)?/))
70
70
  operator = t
71
71
  elsif (t = scanner.scan(/(\s+)?'?.*'?(\s+)?/))
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class JsonPath
4
- VERSION = '1.0.3'.freeze
4
+ VERSION = '1.0.4'
5
5
  end
@@ -833,6 +833,82 @@ class TestJsonpath < MiniTest::Unit::TestCase
833
833
  assert_equal [], JsonPath.on(json, "$.phoneNumbers[?(@[0].type == 'home')]")
834
834
  end
835
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
+
836
912
  def example_object
837
913
  { 'store' => {
838
914
  'book' => [
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.0.3
4
+ version: 1.0.4
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: 2019-05-26 00:00:00.000000000 Z
12
+ date: 2019-06-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: multi_json
@@ -158,7 +158,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
158
158
  - !ruby/object:Gem::Version
159
159
  version: '0'
160
160
  requirements: []
161
- rubygems_version: 3.0.3
161
+ rubyforge_project: jsonpath
162
+ rubygems_version: 2.7.3
162
163
  signing_key:
163
164
  specification_version: 4
164
165
  summary: Ruby implementation of http://goessner.net/articles/JsonPath/