jsonpath 0.9.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.
@@ -48,13 +48,18 @@ class TestJsonpath < MiniTest::Unit::TestCase
48
48
  end
49
49
 
50
50
  def test_recognize_array_splices
51
- assert_equal [@object['store']['book'][0], @object['store']['book'][1]], JsonPath.new('$..book[0:1:1]').on(@object)
51
+ assert_equal [@object['store']['book'][0]], JsonPath.new('$..book[0:1:1]').on(@object)
52
+ assert_equal [@object['store']['book'][0], @object['store']['book'][1]], JsonPath.new('$..book[0:2:1]').on(@object)
52
53
  assert_equal [@object['store']['book'][1], @object['store']['book'][3], @object['store']['book'][5]], JsonPath.new('$..book[1::2]').on(@object)
53
54
  assert_equal [@object['store']['book'][0], @object['store']['book'][2], @object['store']['book'][4], @object['store']['book'][6]], JsonPath.new('$..book[::2]').on(@object)
54
55
  assert_equal [@object['store']['book'][0], @object['store']['book'][2]], JsonPath.new('$..book[:-5:2]').on(@object)
55
56
  assert_equal [@object['store']['book'][5], @object['store']['book'][6]], JsonPath.new('$..book[5::]').on(@object)
56
57
  end
57
58
 
59
+ def test_slice_array_with_exclusive_end_correctly
60
+ assert_equal [@object['store']['book'][0], @object['store']['book'][1]], JsonPath.new('$..book[:2]').on(@object)
61
+ end
62
+
58
63
  def test_recognize_array_comma
59
64
  assert_equal [@object['store']['book'][0], @object['store']['book'][1]], JsonPath.new('$..book[0,1]').on(@object)
60
65
  assert_equal [@object['store']['book'][2], @object['store']['book'][6]], JsonPath.new('$..book[2,-1::]').on(@object)
@@ -67,16 +72,63 @@ class TestJsonpath < MiniTest::Unit::TestCase
67
72
  assert_equal [@object['store']['book'][3]], JsonPath.new("$..book[?(@['price'] > 20)]").on(@object)
68
73
  end
69
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))
87
+ end
88
+
70
89
  def test_or_operator
71
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)
72
103
  end
73
104
 
74
105
  def test_and_operator
75
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)
121
+ end
122
+
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)
76
127
  end
77
128
 
78
- def test_and_operator_with_more_results
79
- assert_equal [@object['store']['book'][1]], JsonPath.new("$..book[?(@['price'] < 23 && @['price'] > 9)]").on(@object)
129
+ def test_nested_grouping
130
+ path = "$..book[?((@['price'] == 19 && @['author'] == 'Herman Melville') || @['price'] == 23)]"
131
+ assert_equal [@object['store']['book'][3]], JsonPath.new(path).on(@object)
80
132
  end
81
133
 
82
134
  def test_eval_with_floating_point_and_and
@@ -103,6 +155,87 @@ class TestJsonpath < MiniTest::Unit::TestCase
103
155
  assert_equal [@object['store']['bicycle']['2seater']], JsonPath.new('$.store.bicycle.2seater').on(@object)
104
156
  end
105
157
 
158
+ def test_recognized_dot_notation_in_filters
159
+ assert_equal [@object['store']['book'][2], @object['store']['book'][3]], JsonPath.new('$..book[?(@.isbn)]').on(@object)
160
+ end
161
+
162
+ def test_works_on_non_hash
163
+ klass = Struct.new(:a, :b)
164
+ object = klass.new('some', 'value')
165
+
166
+ assert_equal ['value'], JsonPath.new('$.b').on(object)
167
+ end
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
+
213
+ def test_works_on_non_hash_with_filters
214
+ klass = Struct.new(:a, :b)
215
+ first_object = klass.new('some', 'value')
216
+ second_object = klass.new('next', 'other value')
217
+
218
+ assert_equal ['other value'], JsonPath.new('$[?(@.a == "next")].b').on([first_object, second_object])
219
+ end
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
+
106
239
  def test_recognize_array_with_evald_index
107
240
  assert_equal [@object['store']['book'][2]], JsonPath.new('$..book[(@.length-5)]').on(@object)
108
241
  end
@@ -112,7 +245,7 @@ class TestJsonpath < MiniTest::Unit::TestCase
112
245
  end
113
246
 
114
247
  def test_counting
115
- assert_equal 57, JsonPath.new('$..*').on(@object).to_a.size
248
+ assert_equal 59, JsonPath.new('$..*').on(@object).to_a.size
116
249
  end
117
250
 
118
251
  def test_space_in_path
@@ -173,6 +306,83 @@ class TestJsonpath < MiniTest::Unit::TestCase
173
306
  assert_equal({ 'you' => nil }, h)
174
307
  end
175
308
 
309
+ def test_delete_2
310
+ json = { 'store' => {
311
+ 'book' => [
312
+ { 'category' => 'reference',
313
+ 'author' => 'Nigel Rees',
314
+ 'title' => 'Sayings of the Century',
315
+ 'price' => 9,
316
+ 'tags' => %w[asdf asdf2] },
317
+ { 'category' => 'fiction',
318
+ 'author' => 'Evelyn Waugh',
319
+ 'title' => 'Sword of Honour',
320
+ 'price' => 13 },
321
+ { 'category' => 'fiction',
322
+ 'author' => 'Aasdf',
323
+ 'title' => 'Aaasdf2',
324
+ 'price' => 1 }
325
+ ]
326
+ } }
327
+ json_deleted = { 'store' => {
328
+ 'book' => [
329
+ { 'category' => 'fiction',
330
+ 'author' => 'Evelyn Waugh',
331
+ 'title' => 'Sword of Honour',
332
+ 'price' => 13 },
333
+ { 'category' => 'fiction',
334
+ 'author' => 'Aasdf',
335
+ 'title' => 'Aaasdf2',
336
+ 'price' => 1 }
337
+ ]
338
+ } }
339
+ assert_equal(json_deleted, JsonPath.for(json).delete("$..store.book[?(@.category == 'reference')]").obj)
340
+ end
341
+
342
+ def test_delete_3
343
+ json = { 'store' => {
344
+ 'book' => [
345
+ { 'category' => 'reference',
346
+ 'author' => 'Nigel Rees',
347
+ 'title' => 'Sayings of the Century',
348
+ 'price' => 9,
349
+ 'tags' => %w[asdf asdf2],
350
+ 'this' => {
351
+ 'delete_me' => [
352
+ 'no' => 'do not'
353
+ ]
354
+ } },
355
+ { 'category' => 'fiction',
356
+ 'author' => 'Evelyn Waugh',
357
+ 'title' => 'Sword of Honour',
358
+ 'price' => 13 },
359
+ { 'category' => 'fiction',
360
+ 'author' => 'Aasdf',
361
+ 'title' => 'Aaasdf2',
362
+ 'price' => 1 }
363
+ ]
364
+ } }
365
+ json_deleted = { 'store' => {
366
+ 'book' => [
367
+ { 'category' => 'reference',
368
+ 'author' => 'Nigel Rees',
369
+ 'title' => 'Sayings of the Century',
370
+ 'price' => 9,
371
+ 'tags' => %w[asdf asdf2],
372
+ 'this' => {} },
373
+ { 'category' => 'fiction',
374
+ 'author' => 'Evelyn Waugh',
375
+ 'title' => 'Sword of Honour',
376
+ 'price' => 13 },
377
+ { 'category' => 'fiction',
378
+ 'author' => 'Aasdf',
379
+ 'title' => 'Aaasdf2',
380
+ 'price' => 1 }
381
+ ]
382
+ } }
383
+ assert_equal(json_deleted, JsonPath.for(json).delete('$..store.book..delete_me').obj)
384
+ end
385
+
176
386
  def test_delete_for_array
177
387
  before = JsonPath.on(@object, '$..store.book[1]')
178
388
  JsonPath.for(@object).delete!('$..store.book[0]')
@@ -265,6 +475,16 @@ class TestJsonpath < MiniTest::Unit::TestCase
265
475
  JsonPath.new('$.store._links').on(@object)
266
476
  end
267
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
+
268
488
  def test_dig_return_string
269
489
  assert_equal ['asdf'], JsonPath.new("$.store.book..tags[?(@ == 'asdf')]").on(@object)
270
490
  assert_equal [], JsonPath.new("$.store.book..tags[?(@ == 'not_asdf')]").on(@object)
@@ -396,18 +616,65 @@ class TestJsonpath < MiniTest::Unit::TestCase
396
616
  'name' => 'testname2'
397
617
  }]
398
618
  }
399
- assert_equal [{ 'isTrue' => true, 'name' => 'testname1' }], JsonPath.new('$.data[?(@.isTrue)]').on(data)
619
+
620
+ # These queries should be equivalent
621
+ expected = [{ 'isTrue' => true, 'name' => 'testname1' }]
622
+ assert_equal expected, JsonPath.new('$.data[?(@.isTrue)]').on(data)
623
+ assert_equal expected, JsonPath.new('$.data[?(@.isTrue==true)]').on(data)
624
+ assert_equal expected, JsonPath.new('$.data[?(@.isTrue == true)]').on(data)
625
+
626
+ # These queries should be equivalent
627
+ expected = [{ 'isTrue' => false, 'name' => 'testname2' }]
628
+ assert_equal expected, JsonPath.new('$.data[?(@.isTrue != true)]').on(data)
629
+ assert_equal expected, JsonPath.new('$.data[?(@.isTrue!=true)]').on(data)
630
+ assert_equal expected, JsonPath.new('$.data[?(@.isTrue==false)]').on(data)
631
+ end
632
+
633
+ def test_and_operator_with_boolean_parameter_value
634
+ data = {
635
+ 'data' => [{
636
+ 'hasProperty1' => true,
637
+ 'hasProperty2' => false,
638
+ 'name' => 'testname1'
639
+ }, {
640
+ 'hasProperty1' => false,
641
+ 'hasProperty2' => true,
642
+ 'name' => 'testname2'
643
+ }, {
644
+ 'hasProperty1' => true,
645
+ 'hasProperty2' => true,
646
+ 'name' => 'testname3'
647
+ }]
648
+ }
649
+ assert_equal ['testname3'], JsonPath.new('$.data[?(@.hasProperty1 && @.hasProperty2)].name').on(data)
650
+ end
651
+
652
+ def test_regex_simple
653
+ assert_equal %w[asdf asdf2], JsonPath.new('$.store.book..tags[?(@ =~ /asdf/)]').on(@object)
654
+ assert_equal %w[asdf asdf2], JsonPath.new('$.store.book..tags[?(@=~/asdf/)]').on(@object)
655
+ end
656
+
657
+ def test_regex_simple_miss
658
+ assert_equal [], JsonPath.new('$.store.book..tags[?(@ =~ /wut/)]').on(@object)
659
+ end
660
+
661
+ def test_regex_r
662
+ assert_equal %w[asdf asdf2], JsonPath.new('$.store.book..tags[?(@ =~ %r{asdf})]').on(@object)
400
663
  end
401
664
 
402
- def test_regex
403
- assert_equal [], JsonPath.new('$..book[?(@.author =~ /herman/)]').on(@object)
665
+ def test_regex_flags
404
666
  assert_equal [
405
667
  @object['store']['book'][2],
406
668
  @object['store']['book'][4],
407
669
  @object['store']['book'][5],
408
670
  @object['store']['book'][6]
409
671
  ], JsonPath.new('$..book[?(@.author =~ /herman|lukyanenko/i)]').on(@object)
410
- assert_equal %w[asdf asdf2], JsonPath.new('$.store.book..tags[?(@ =~ /asdf/)]').on(@object)
672
+ end
673
+
674
+ def test_regex_error
675
+ assert_raises ArgumentError do
676
+ JsonPath.new('$.store.book..tags[?(@ =~ asdf)]').on(@object)
677
+ end
411
678
  end
412
679
 
413
680
  def test_regression_1
@@ -508,6 +775,68 @@ class TestJsonpath < MiniTest::Unit::TestCase
508
775
  assert_equal 'C09C5GYHF', JsonPath.on(json, "$..channels[?(@.is_archived == 'false')].id")[0]
509
776
  end
510
777
 
778
+ def test_quote
779
+ json = {
780
+ channels: [
781
+ {
782
+ name: "King's Speech"
783
+ }
784
+ ]
785
+ }.to_json
786
+
787
+ assert_equal [{ 'name' => "King\'s Speech" }], JsonPath.on(json, "$..channels[?(@.name == 'King\'s Speech')]")
788
+ end
789
+
790
+ def test_curly_brackets
791
+ data = {
792
+ '{data}' => 'data'
793
+ }
794
+ assert_equal ['data'], JsonPath.new('$.{data}').on(data)
795
+ end
796
+
797
+ def test_symbolize
798
+ data = '
799
+ {
800
+ "store": {
801
+ "bicycle": {
802
+ "price": 19.95,
803
+ "color": "red"
804
+ },
805
+ "book": [
806
+ {
807
+ "price": 8.95,
808
+ "category": "reference",
809
+ "title": "Sayings of the Century",
810
+ "author": "Nigel Rees"
811
+ },
812
+ {
813
+ "price": 12.99,
814
+ "category": "fiction",
815
+ "title": "Sword of Honour",
816
+ "author": "Evelyn Waugh"
817
+ },
818
+ {
819
+ "price": 8.99,
820
+ "category": "fiction",
821
+ "isbn": "0-553-21311-3",
822
+ "title": "Moby Dick",
823
+ "author": "Herman Melville",
824
+ "color": "blue"
825
+ },
826
+ {
827
+ "price": 22.99,
828
+ "category": "fiction",
829
+ "isbn": "0-395-19395-8",
830
+ "title": "The Lord of the Rings",
831
+ "author": "Tolkien"
832
+ }
833
+ ]
834
+ }
835
+ }
836
+ '
837
+ assert_equal [{ price: 8.95, category: 'reference', title: 'Sayings of the Century', author: 'Nigel Rees' }, { price: 8.99, category: 'fiction', isbn: '0-553-21311-3', title: 'Moby Dick', author: 'Herman Melville', color: 'blue' }], JsonPath.new('$..book[::2]').on(data, symbolize_keys: true)
838
+ end
839
+
511
840
  def test_changed
512
841
  json =
513
842
  {
@@ -562,6 +891,33 @@ class TestJsonpath < MiniTest::Unit::TestCase
562
891
  assert_equal [true], JsonPath.on(json, broken_path)
563
892
  end
564
893
 
894
+ def test_complex_nested_grouping
895
+ path = "$..book[?((@['author'] == 'Evelyn Waugh' || @['author'] == 'Herman Melville') && (@['price'] == 33 || @['price'] == 9))]"
896
+ assert_equal [@object['store']['book'][2]], JsonPath.new(path).on(@object)
897
+ end
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)
902
+ end
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
+
909
+ def test_runtime_error_frozen_string
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')
911
+ json = '
912
+ {
913
+ "test": "something"
914
+ }
915
+ '.to_json
916
+ assert_raises(ArgumentError, "RuntimeError: character '|' not supported in query") do
917
+ JsonPath.on(json, '$.description|title')
918
+ end
919
+ end
920
+
565
921
  def test_delete_more_items
566
922
  a = { 'itemList' =>
567
923
  [{ 'alfa' => 'beta1' },
@@ -577,7 +933,7 @@ class TestJsonpath < MiniTest::Unit::TestCase
577
933
  { 'alfa' => 'beta11' },
578
934
  { 'alfa' => 'beta12' }] }
579
935
  expected = { 'itemList' => [{ 'alfa' => 'beta1' }] }
580
- assert_equal expected, JsonPath.for(a.to_json).delete('$.itemList[1:11:1]').to_hash
936
+ assert_equal expected, JsonPath.for(a.to_json).delete('$.itemList[1:12:1]').to_hash
581
937
  end
582
938
 
583
939
  def test_delete_more_items_with_stepping
@@ -607,6 +963,277 @@ class TestJsonpath < MiniTest::Unit::TestCase
607
963
  assert_equal expected, JsonPath.for(a.to_json).delete('$.itemList[1:6:2]').to_hash
608
964
  end
609
965
 
966
+ def test_nested_values
967
+ json = '
968
+ {
969
+ "phoneNumbers": [
970
+ [{
971
+ "type" : "iPhone",
972
+ "number": "0123-4567-8888"
973
+ }],
974
+ [{
975
+ "type" : "home",
976
+ "number": "0123-4567-8910"
977
+ }]
978
+ ]
979
+ }
980
+ '.to_json
981
+ assert_equal [[{ 'type' => 'home', 'number' => '0123-4567-8910' }]], JsonPath.on(json, "$.phoneNumbers[?(@[0].type == 'home')]")
982
+ assert_equal [], JsonPath.on(json, "$.phoneNumbers[?(@[2].type == 'home')]")
983
+ json = '
984
+ {
985
+ "phoneNumbers":
986
+ {
987
+ "type" : "iPhone",
988
+ "number": "0123-4567-8888"
989
+ }
990
+ }
991
+ '.to_json
992
+ assert_equal [], JsonPath.on(json, "$.phoneNumbers[?(@[0].type == 'home')]")
993
+ end
994
+
995
+ def test_selecting_multiple_keys_on_hash
996
+ json = '
997
+ {
998
+ "category": "reference",
999
+ "author": "Nigel Rees",
1000
+ "title": "Sayings of the Century",
1001
+ "price": 8.95
1002
+ }
1003
+ '.to_json
1004
+ assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, '$.(category,author)')
1005
+ end
1006
+
1007
+ def test_selecting_multiple_keys_on_sub_hash
1008
+ skip("Failing as the semantics of .(x,y) is unclear")
1009
+ json = '
1010
+ {
1011
+ "book": {
1012
+ "category": "reference",
1013
+ "author": "Nigel Rees",
1014
+ "title": "Sayings of the Century",
1015
+ "price": 8.95
1016
+ }
1017
+ }
1018
+ '.to_json
1019
+ assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, '$.book.(category,author)')
1020
+ end
1021
+
1022
+ def test_selecting_multiple_keys_on_array
1023
+ json = '
1024
+ {
1025
+ "store": {
1026
+ "book": [
1027
+ {
1028
+ "category": "reference",
1029
+ "author": "Nigel Rees",
1030
+ "title": "Sayings of the Century",
1031
+ "price": 8.95
1032
+ },
1033
+ {
1034
+ "category": "fiction",
1035
+ "author": "Evelyn Waugh",
1036
+ "title": "Sword of Honour",
1037
+ "price": 12.99
1038
+ }
1039
+ ]
1040
+ }
1041
+ }
1042
+ '.to_json
1043
+
1044
+ assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }, { 'category' => 'fiction', 'author' => 'Evelyn Waugh' }], JsonPath.on(json, '$.store.book[*](category,author)')
1045
+ end
1046
+
1047
+ def test_selecting_multiple_keys_on_array_with_filter
1048
+ json = '
1049
+ {
1050
+ "store": {
1051
+ "book": [
1052
+ {
1053
+ "category": "reference",
1054
+ "author": "Nigel Rees",
1055
+ "title": "Sayings of the Century",
1056
+ "price": 8.95
1057
+ },
1058
+ {
1059
+ "category": "fiction",
1060
+ "author": "Evelyn Waugh",
1061
+ "title": "Sword of Honour",
1062
+ "price": 12.99
1063
+ }
1064
+ ]
1065
+ }
1066
+ }
1067
+ '.to_json
1068
+
1069
+ assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, "$.store.book[?(@['price'] == 8.95)](category,author)")
1070
+ assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, "$.store.book[?(@['price'] == 8.95)]( category, author )")
1071
+ end
1072
+
1073
+ def test_selecting_multiple_keys_with_filter_with_space_in_catergory
1074
+ json = '
1075
+ {
1076
+ "store": {
1077
+ "book": [
1078
+ {
1079
+ "cate gory": "reference",
1080
+ "author": "Nigel Rees",
1081
+ "title": "Sayings of the Century",
1082
+ "price": 8.95
1083
+ },
1084
+ {
1085
+ "cate gory": "fiction",
1086
+ "author": "Evelyn Waugh",
1087
+ "title": "Sword of Honour",
1088
+ "price": 12.99
1089
+ }
1090
+ ]
1091
+ }
1092
+ }
1093
+ '.to_json
1094
+
1095
+ assert_equal [{ 'cate gory' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, "$.store.book[?(@['price'] == 8.95)]( cate gory, author )")
1096
+ end
1097
+
1098
+ def test_use_symbol_opt
1099
+ json = {
1100
+ store: {
1101
+ book: [
1102
+ {
1103
+ category: "reference",
1104
+ author: "Nigel Rees",
1105
+ title: "Sayings of the Century",
1106
+ price: 8.95
1107
+ },
1108
+ {
1109
+ category: "fiction",
1110
+ author: "Evelyn Waugh",
1111
+ title: "Sword of Honour",
1112
+ price: 12.99
1113
+ }
1114
+ ]
1115
+ }
1116
+ }
1117
+ on = ->(path){ JsonPath.on(json, path, use_symbols: true) }
1118
+ assert_equal ['reference', 'fiction'], on.("$.store.book[*].category")
1119
+ assert_equal ['reference', 'fiction'], on.("$..category")
1120
+ assert_equal ['reference'], on.("$.store.book[?(@['price'] == 8.95)].category")
1121
+ assert_equal [{'category' => 'reference'}], on.("$.store.book[?(@['price'] == 8.95)](category)")
1122
+ end
1123
+
1124
+ def test_object_method_send
1125
+ j = {height: 5, hash: "some_hash"}.to_json
1126
+ hs = JsonPath.new "$..send"
1127
+ assert_equal([], hs.on(j))
1128
+ hs = JsonPath.new "$..hash"
1129
+ assert_equal(["some_hash"], hs.on(j))
1130
+ hs = JsonPath.new "$..send"
1131
+ assert_equal([], hs.on(j))
1132
+ j = {height: 5, send: "should_still_work"}.to_json
1133
+ hs = JsonPath.new "$..send"
1134
+ assert_equal(['should_still_work'], hs.on(j))
1135
+ end
1136
+
1137
+ def test_index_access_by_number
1138
+ data = {
1139
+ '1': 'foo'
1140
+ }
1141
+ assert_equal ['foo'], JsonPath.new('$.1').on(data.to_json)
1142
+ end
1143
+
1144
+ def test_behavior_on_null_and_missing
1145
+ data = {
1146
+ "foo" => nil,
1147
+ "bar" => {
1148
+ "baz" => nil
1149
+ },
1150
+ "bars" => [
1151
+ { "foo" => 12 },
1152
+ { "foo" => nil },
1153
+ { }
1154
+ ]
1155
+ }
1156
+ assert_equal [nil], JsonPath.new('$.foo').on(data)
1157
+ assert_equal [nil], JsonPath.new('$.bar.baz').on(data)
1158
+ assert_equal [], JsonPath.new('$.baz').on(data)
1159
+ assert_equal [], JsonPath.new('$.bar.foo').on(data)
1160
+ assert_equal [12, nil], JsonPath.new('$.bars[*].foo').on(data)
1161
+ end
1162
+
1163
+ def test_default_path_leaf_to_null_opt
1164
+ data = {
1165
+ "foo" => nil,
1166
+ "bar" => {
1167
+ "baz" => nil
1168
+ },
1169
+ "bars" => [
1170
+ { "foo" => 12 },
1171
+ { "foo" => nil },
1172
+ { }
1173
+ ]
1174
+ }
1175
+ assert_equal [nil], JsonPath.new('$.foo', default_path_leaf_to_null: true).on(data)
1176
+ assert_equal [nil], JsonPath.new('$.bar.baz', default_path_leaf_to_null: true).on(data)
1177
+ assert_equal [nil], JsonPath.new('$.baz', default_path_leaf_to_null: true).on(data)
1178
+ assert_equal [nil], JsonPath.new('$.bar.foo', default_path_leaf_to_null: true).on(data)
1179
+ assert_equal [12, nil, nil], JsonPath.new('$.bars[*].foo', default_path_leaf_to_null: true).on(data)
1180
+ end
1181
+
1182
+ def test_raise_max_nesting_error
1183
+ json = {
1184
+ a: {
1185
+ b: {
1186
+ c: {
1187
+ }
1188
+ }
1189
+ }
1190
+ }.to_json
1191
+
1192
+ assert_raises(MultiJson::ParseError) { JsonPath.new('$.a', max_nesting: 1).on(json) }
1193
+ end
1194
+
1195
+ def test_linefeed_in_path_error
1196
+ assert_raises(ArgumentError) { JsonPath.new("$.store\n.book") }
1197
+ end
1198
+
1199
+ def test_with_max_nesting_false
1200
+ json = {
1201
+ a: {
1202
+ b: {
1203
+ c: {
1204
+ }
1205
+ }
1206
+ }
1207
+ }.to_json
1208
+
1209
+ assert_equal [{}], JsonPath.new('$.a.b.c', max_nesting: false).on(json)
1210
+ end
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
+
610
1237
  def example_object
611
1238
  { 'store' => {
612
1239
  'book' => [
@@ -658,7 +1285,37 @@ class TestJsonpath < MiniTest::Unit::TestCase
658
1285
  },
659
1286
  '@id' => 'http://example.org/store/42',
660
1287
  '$meta-data' => 'whatevs',
1288
+ 'Übermorgen' => 'The day after tomorrow',
1289
+ 'Title Case' => 'A title case string',
661
1290
  '_links' => { 'self' => {} }
662
1291
  } }
663
1292
  end
1293
+
1294
+ def test_fetch_all_path
1295
+ data = {
1296
+ "foo" => nil,
1297
+ "bar" => {
1298
+ "baz" => nil
1299
+ },
1300
+ "bars" => [
1301
+ { "foo" => 12 },
1302
+ { "foo" => nil },
1303
+ { }
1304
+ ]
1305
+ }
1306
+ assert_equal ["$", "$.foo", "$.bar", "$.bar.baz", "$.bars", "$.bars[0].foo", "$.bars[0]", "$.bars[1].foo", "$.bars[1]", "$.bars[2]"], JsonPath.fetch_all_path(data)
1307
+ end
1308
+
1309
+
1310
+ def test_extractore_with_dollar_key
1311
+ json = {"test" => {"$" =>"success", "a" => "123"}}
1312
+ assert_equal ["success"], JsonPath.on(json, "$.test.$")
1313
+ assert_equal ["123"], JsonPath.on(json, "$.test.a")
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
664
1321
  end