json_p3 0.3.0 → 0.3.2
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
- checksums.yaml.gz.sig +0 -0
- data/.rubocop.yml +1 -1
- data/.ruby-version +1 -0
- data/CHANGELOG.md +10 -0
- data/README.md +7 -1
- data/lib/json_p3/filter.rb +36 -3
- data/lib/json_p3/lexer.rb +1 -1
- data/lib/json_p3/node.rb +3 -1
- data/lib/json_p3/parser.rb +3 -3
- data/lib/json_p3/patch.rb +10 -2
- data/lib/json_p3/selector.rb +1 -1
- data/lib/json_p3/serialize.rb +13 -0
- data/lib/json_p3/unescape.rb +1 -1
- data/lib/json_p3/version.rb +1 -1
- data/sig/json_p3.rbs +13 -7
- data.tar.gz.sig +0 -0
- metadata +5 -3
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: afd5de1be45132d6071616dc7aa21425dc3d9beaed525315f017b343b434a42f
|
4
|
+
data.tar.gz: 19f0fc51ac0f8680e47808beda7f206ea9d911b33ebebaccb5803cd7bcd012c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c6458e2fc86fa09988edbc032ad434cca4125f1d6a368e2f8e37e79e65b80fb404d12a3ec9dfb42ef007dbfc2977a4492814c9a8d689900921e2cfa885b6c11
|
7
|
+
data.tar.gz: 54580931a9a37165dcbb10f8a240c8142a8de013cbc9e76776f59a5f60b43743f98db65daae7d85968d61a6eda1983df26f9ae8d8aaf1571b3a45106236a8ed1
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/.rubocop.yml
CHANGED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.3.6
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## [0.3.2] - 2025-01-29
|
2
|
+
|
3
|
+
- Fix normalized string representations of node locations as returned by `JSONPathNode.path`.
|
4
|
+
- Fix canonical string representations of instances of `JSONPath`, as returned by `to_s`.
|
5
|
+
- Fixed filter queries with multiple bracketed segments. Previously we were failing to tokenize queries like `$[?@[0][0]]`. See [#15](https://github.com/jg-rp/ruby-json-p3/issues/15).
|
6
|
+
|
7
|
+
## [0.3.1] - 2024-12-05
|
8
|
+
|
9
|
+
- Fix JSON Patch `move` and `copy` operations when using the special JSON Pointer token `-`.
|
10
|
+
|
1
11
|
## [0.3.0] - 2024-11-25
|
2
12
|
|
3
13
|
- Implement JSON Pointer and Relative JSON Pointer
|
data/README.md
CHANGED
@@ -474,6 +474,12 @@ Print memory usage to the terminal.
|
|
474
474
|
bundle exec ruby performance/memory_profile.rb
|
475
475
|
```
|
476
476
|
|
477
|
-
###
|
477
|
+
### Notes to self
|
478
|
+
|
479
|
+
#### Build
|
480
|
+
|
481
|
+
`bundle exec rake release` and `bundle exec rake build` will look for `gem-private_key.pem` and `gem-public_cert.pem` in `~/.gem`.
|
482
|
+
|
483
|
+
#### TruffleRuby
|
478
484
|
|
479
485
|
On macOS Sonoma using MacPorts and `rbenv`, `LIBYAML_PREFIX=/opt/local/lib` is needed to install TruffleRuby and when executing any `bundle` command.
|
data/lib/json_p3/filter.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "json"
|
4
3
|
require_relative "function"
|
4
|
+
require_relative "serialize"
|
5
5
|
|
6
6
|
module JSONP3 # rubocop:disable Style/Documentation
|
7
7
|
# Base class for all filter expression nodes.
|
@@ -33,7 +33,7 @@ module JSONP3 # rubocop:disable Style/Documentation
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def to_s
|
36
|
-
@expression
|
36
|
+
to_canonical_string(@expression, Precedence::LOWEST)
|
37
37
|
end
|
38
38
|
|
39
39
|
def ==(other)
|
@@ -47,6 +47,39 @@ module JSONP3 # rubocop:disable Style/Documentation
|
|
47
47
|
def hash
|
48
48
|
[@expression, @token].hash
|
49
49
|
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
class Precedence
|
54
|
+
LOWEST = 1
|
55
|
+
LOGICAL_OR = 3
|
56
|
+
LOGICAL_AND = 4
|
57
|
+
PREFIX = 7
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_canonical_string(expression, parent_precedence)
|
61
|
+
if expression.instance_of? LogicalAndExpression
|
62
|
+
left = to_canonical_string(expression.left, Precedence::LOGICAL_AND)
|
63
|
+
right = to_canonical_string(expression.right, Precedence::LOGICAL_AND)
|
64
|
+
expr = "#{left} && #{right}"
|
65
|
+
return parent_precedence >= Precedence::LOGICAL_AND ? "(#{expr})" : expr
|
66
|
+
end
|
67
|
+
|
68
|
+
if expression.instance_of? LogicalOrExpression
|
69
|
+
left = to_canonical_string(expression.left, Precedence::LOGICAL_OR)
|
70
|
+
right = to_canonical_string(expression.right, Precedence::LOGICAL_OR)
|
71
|
+
expr = "#{left} || #{right}"
|
72
|
+
return parent_precedence >= Precedence::LOGICAL_OR ? "(#{expr})" : expr
|
73
|
+
end
|
74
|
+
|
75
|
+
if expression.instance_of? LogicalNotExpression
|
76
|
+
operand = to_canonical_string(expression.expression, Precedence::PREFIX)
|
77
|
+
expr = "!#{operand}"
|
78
|
+
return parent_precedence > Precedence::PREFIX ? `(#{expr})` : expr
|
79
|
+
end
|
80
|
+
|
81
|
+
expression.to_s
|
82
|
+
end
|
50
83
|
end
|
51
84
|
|
52
85
|
# Base class for expression literals.
|
@@ -85,7 +118,7 @@ module JSONP3 # rubocop:disable Style/Documentation
|
|
85
118
|
# A double or single quoted string literal.
|
86
119
|
class StringLiteral < FilterExpressionLiteral
|
87
120
|
def to_s
|
88
|
-
|
121
|
+
JSONP3.canonical_string(@value)
|
89
122
|
end
|
90
123
|
end
|
91
124
|
|
data/lib/json_p3/lexer.rb
CHANGED
@@ -209,7 +209,7 @@ module JSONP3 # rubocop:disable Style/Documentation
|
|
209
209
|
case c
|
210
210
|
when "]"
|
211
211
|
emit(:token_rbracket, "]")
|
212
|
-
return
|
212
|
+
return :lex_segment
|
213
213
|
when ""
|
214
214
|
error "unclosed bracketed selection"
|
215
215
|
return nil
|
data/lib/json_p3/node.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "serialize"
|
4
|
+
|
3
5
|
module JSONP3
|
4
6
|
# A JSON-like value and its location.
|
5
7
|
class JSONPathNode
|
@@ -19,7 +21,7 @@ module JSONP3
|
|
19
21
|
# Return the normalized path to this node.
|
20
22
|
# @return [String] the normalized path.
|
21
23
|
def path
|
22
|
-
segments = @location.flatten.map { |i| i.is_a?(String) ? "[
|
24
|
+
segments = @location.flatten.map { |i| i.is_a?(String) ? "[#{JSONP3.canonical_string(i)}]" : "[#{i}]" }
|
23
25
|
"$#{segments.join}"
|
24
26
|
end
|
25
27
|
|
data/lib/json_p3/parser.rb
CHANGED
@@ -116,7 +116,7 @@ module JSONP3
|
|
116
116
|
end
|
117
117
|
end
|
118
118
|
|
119
|
-
def parse_bracketed_selection(stream)
|
119
|
+
def parse_bracketed_selection(stream)
|
120
120
|
stream.expect(:token_lbracket)
|
121
121
|
segment_token = stream.next
|
122
122
|
|
@@ -245,7 +245,7 @@ module JSONP3
|
|
245
245
|
FilterSelector.new(@env, token, FilterExpression.new(token, expression))
|
246
246
|
end
|
247
247
|
|
248
|
-
def parse_filter_expression(stream, precedence = Precedence::LOWEST) # rubocop:disable Metrics/
|
248
|
+
def parse_filter_expression(stream, precedence = Precedence::LOWEST) # rubocop:disable Metrics/CyclomaticComplexity
|
249
249
|
left = case stream.peek.type
|
250
250
|
when :token_double_quote_string, :token_single_quote_string
|
251
251
|
token = stream.next
|
@@ -313,7 +313,7 @@ module JSONP3
|
|
313
313
|
end
|
314
314
|
end
|
315
315
|
|
316
|
-
def parse_function_expression(stream)
|
316
|
+
def parse_function_expression(stream)
|
317
317
|
token = stream.next
|
318
318
|
args = [] # : Array[Expression]
|
319
319
|
|
data/lib/json_p3/patch.rb
CHANGED
@@ -220,7 +220,11 @@ module JSONP3
|
|
220
220
|
|
221
221
|
# Write the source value to the destination.
|
222
222
|
if dest_parent.is_a?(Array)
|
223
|
-
|
223
|
+
if dest_target == "-"
|
224
|
+
dest_parent << source_obj
|
225
|
+
else
|
226
|
+
dest_parent[dest_target.to_i] = source_obj
|
227
|
+
end
|
224
228
|
elsif dest_parent.is_a?(Hash)
|
225
229
|
dest_parent[dest_target] = source_obj
|
226
230
|
end
|
@@ -267,7 +271,11 @@ module JSONP3
|
|
267
271
|
|
268
272
|
# Write the source value to the destination.
|
269
273
|
if dest_parent.is_a?(Array)
|
270
|
-
|
274
|
+
if dest_target == "-"
|
275
|
+
dest_parent << source_obj
|
276
|
+
else
|
277
|
+
dest_parent.insert(dest_target.to_i, deep_copy(source_obj))
|
278
|
+
end
|
271
279
|
elsif dest_parent.is_a?(Hash)
|
272
280
|
dest_parent[dest_target] = deep_copy(source_obj)
|
273
281
|
else
|
data/lib/json_p3/selector.rb
CHANGED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
module JSONP3 # rubocop:disable Style/Documentation
|
6
|
+
TRANS = { "\\\"" => "\"", "'" => "\\'" }.freeze
|
7
|
+
|
8
|
+
# Return _value_ formatted as a canonical string literal.
|
9
|
+
# @param value [String]
|
10
|
+
def self.canonical_string(value)
|
11
|
+
"'#{(JSON.dump(value)[1..-2] || raise).gsub(/('|\\")/, TRANS)}'"
|
12
|
+
end
|
13
|
+
end
|
data/lib/json_p3/unescape.rb
CHANGED
@@ -6,7 +6,7 @@ module JSONP3 # rubocop:disable Style/Documentation
|
|
6
6
|
# @param quote [String] one of '"' or "'".
|
7
7
|
# @param token [Token]
|
8
8
|
# @return [String] A new string without escape sequences.
|
9
|
-
def self.unescape_string(value, quote, token)
|
9
|
+
def self.unescape_string(value, quote, token)
|
10
10
|
unescaped = String.new(encoding: "UTF-8")
|
11
11
|
index = 0
|
12
12
|
length = value.length
|
data/lib/json_p3/version.rb
CHANGED
data/sig/json_p3.rbs
CHANGED
@@ -126,7 +126,7 @@ module JSONP3
|
|
126
126
|
|
127
127
|
def initialize: (Token token) -> void
|
128
128
|
|
129
|
-
# Evaluate the filter
|
129
|
+
# Evaluate the filter expression in the given context.
|
130
130
|
def evaluate: (FilterContext _context) -> untyped
|
131
131
|
end
|
132
132
|
|
@@ -147,6 +147,10 @@ module JSONP3
|
|
147
147
|
alias eql? ==
|
148
148
|
|
149
149
|
def hash: () -> Integer
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def to_canonical_string: (Expression expression, Integer parent_precedence) -> String
|
150
154
|
end
|
151
155
|
|
152
156
|
# Base class for expression literals.
|
@@ -394,7 +398,7 @@ module JSONP3
|
|
394
398
|
# @return [Array<Token>]
|
395
399
|
def self.tokenize: (String query) -> Array[Token]
|
396
400
|
|
397
|
-
# JSONPath query
|
401
|
+
# JSONPath query expression lexical scanner.
|
398
402
|
#
|
399
403
|
# @see tokenize
|
400
404
|
class Lexer
|
@@ -428,7 +432,7 @@ module JSONP3
|
|
428
432
|
# Generate a new token with the given type.
|
429
433
|
# @param token_type [Symbol] one of the constants defined on the _Token_ class.
|
430
434
|
# @param value [String | nil] a the token's value, if it is known, otherwise the
|
431
|
-
# value will be sliced from @query. This is a performance
|
435
|
+
# value will be sliced from @query. This is a performance optimization.
|
432
436
|
def emit: (token_t token_type, ?untyped value) -> void
|
433
437
|
|
434
438
|
def next: () -> String
|
@@ -488,7 +492,7 @@ module JSONP3
|
|
488
492
|
|
489
493
|
# @param value [JSON-like] the value at this node.
|
490
494
|
# @param location [Array<String | Integer | Array<String | Integer>>] the sequence of
|
491
|
-
# names and/or
|
495
|
+
# names and/or indices leading to _value_ in _root_.
|
492
496
|
# @param root [JSON-like] the root value containing _value_ at _location_.
|
493
497
|
def initialize: (untyped value, Array[location_element] location, untyped root) -> void
|
494
498
|
|
@@ -498,7 +502,7 @@ module JSONP3
|
|
498
502
|
|
499
503
|
# Return a new node that is a child of this node.
|
500
504
|
# @param value the JSON-like value at the new node.
|
501
|
-
# @param key [Integer, String] the array index or hash key
|
505
|
+
# @param key [Integer, String] the array index or hash key associated with _value_.
|
502
506
|
def new_child: (untyped value, String | Integer key) -> JSONPathNode
|
503
507
|
|
504
508
|
def to_s: () -> ::String
|
@@ -926,7 +930,7 @@ module JSONP3
|
|
926
930
|
# @param value [String]
|
927
931
|
# @param quote [String] one of '"' or "'".
|
928
932
|
# @param token [Token]
|
929
|
-
# @return [String] A new string without escape
|
933
|
+
# @return [String] A new string without escape sequences.
|
930
934
|
def self.unescape_string: (String value, String quote, Token token) -> String
|
931
935
|
|
932
936
|
def self.decode_hex_char: (untyped value, untyped index, Token token) -> ::Array[untyped]
|
@@ -938,6 +942,8 @@ module JSONP3
|
|
938
942
|
def self.low_surrogate?: (untyped code_point) -> untyped
|
939
943
|
|
940
944
|
def self.code_point_to_string: (untyped code_point, Token token) -> untyped
|
945
|
+
|
946
|
+
def self.canonical_string: (untyped String) -> ::String
|
941
947
|
end
|
942
948
|
|
943
949
|
module JSONP3
|
@@ -1162,7 +1168,7 @@ module JSONP3
|
|
1162
1168
|
class OpRemove < Op
|
1163
1169
|
@pointer: JSONPointer
|
1164
1170
|
|
1165
|
-
# @param
|
1171
|
+
# @param pointer [JSONPointer]
|
1166
1172
|
def initialize: (JSONPointer pointer) -> void
|
1167
1173
|
|
1168
1174
|
def name: () -> "remove"
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json_p3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Prior
|
@@ -36,7 +36,7 @@ cert_chain:
|
|
36
36
|
6dM18fnfBc3yA4KI7AO8UAmRkTscMYV6f/K4YZR6ZYCNWRpY7rkg+arhf05aoSQf
|
37
37
|
vn9bO1bzwdnG
|
38
38
|
-----END CERTIFICATE-----
|
39
|
-
date:
|
39
|
+
date: 2025-01-29 00:00:00.000000000 Z
|
40
40
|
dependencies: []
|
41
41
|
description: JSONPath following RFC 9535
|
42
42
|
email:
|
@@ -46,6 +46,7 @@ extensions: []
|
|
46
46
|
extra_rdoc_files: []
|
47
47
|
files:
|
48
48
|
- ".rubocop.yml"
|
49
|
+
- ".ruby-version"
|
49
50
|
- ".yardopts"
|
50
51
|
- CHANGELOG.md
|
51
52
|
- LICENCE
|
@@ -73,6 +74,7 @@ files:
|
|
73
74
|
- lib/json_p3/pointer.rb
|
74
75
|
- lib/json_p3/segment.rb
|
75
76
|
- lib/json_p3/selector.rb
|
77
|
+
- lib/json_p3/serialize.rb
|
76
78
|
- lib/json_p3/token.rb
|
77
79
|
- lib/json_p3/unescape.rb
|
78
80
|
- lib/json_p3/version.rb
|
@@ -106,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
106
108
|
- !ruby/object:Gem::Version
|
107
109
|
version: '0'
|
108
110
|
requirements: []
|
109
|
-
rubygems_version: 3.5.
|
111
|
+
rubygems_version: 3.5.22
|
110
112
|
signing_key:
|
111
113
|
specification_version: 4
|
112
114
|
summary: 'JSONPath: Query Expressions for JSON in Ruby'
|
metadata.gz.sig
CHANGED
Binary file
|