janeway-jsonpath 0.6.0 → 1.0.0

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: 33fc9254c0443121404ced6b9e60c15133111299b8f7052f012fe45d7ad4d281
4
- data.tar.gz: c5a9eea01a8a332343b47328c64991a52fc50292969247433650914c8af727bd
3
+ metadata.gz: 9b4502d1b125c833d8a142b6cbecc1fa01f30aefcfe5f06b8526037c70e0d071
4
+ data.tar.gz: 28b8f3e14cb83b7941d50ac8a4da408e1ff9cdb72cd206fc5dba2e1cc481da97
5
5
  SHA512:
6
- metadata.gz: 0c101d0e02380fc56bd4abc83b5012965e3281aabc3bcce10e7f55c6cff61ba5b825f0d582f95c076234e01d59f07a8db19e6b8984c85e923c780d6f362adc2c
7
- data.tar.gz: e2a762c773653c01415dee8f988b95be53d45da8bb3d1ed6f20817eb333fce00b3c960f9268a2212c929a27582d4c0cdb8e480e3948b2e193974f452b32e526f
6
+ metadata.gz: 4fe6e4fe0daec50df309251916bda911a4eada27274dd817d5b03b90aeaa3fdaae9a7918cd467644df100b3dc3aa192eaffa8d7a25ceed452a47ca35ad059223
7
+ data.tar.gz: eeb8197665932f9ad24c582ced1331c2b8cded6fc7d978477b1fc96f5bff268b68d4461e5a7220e7717a0da252c6b85c429f72b27596ac4ac68cb32bb40f6de0
data/README.md CHANGED
@@ -29,7 +29,7 @@ Install the gem from the command-line:
29
29
  or add it to your Gemfile:
30
30
 
31
31
  ```
32
- gem 'janeway-jsonpath', '~> 0.4.0'
32
+ gem 'janeway-jsonpath', '~> 0.6'
33
33
  ```
34
34
 
35
35
  ### Usage
@@ -15,6 +15,7 @@ module Janeway
15
15
  # $[name1, [1:10]]
16
16
  class ChildSegment < Janeway::AST::Expression
17
17
  extend Forwardable
18
+
18
19
  def_delegators :@value, :size, :first, :last, :each, :map, :empty?
19
20
 
20
21
  # Subsequent expression that modifies the result of this selector list.
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative 'helpers'
3
4
  require_relative 'error'
4
5
 
@@ -37,7 +38,7 @@ module Janeway
37
38
  # @param msg [String]
38
39
  # @return [String]
39
40
  def indented(level, msg)
40
- format('%s%s', (INDENT * level), msg)
41
+ format('%s%s', INDENT * level, msg)
41
42
  end
42
43
 
43
44
  # @param level [Integer]
@@ -56,7 +56,7 @@ module Janeway
56
56
  # Assign the given value at every query match.
57
57
  # @param replacement [Object]
58
58
  # @return [void]
59
- def replace(replacement = :no_replacement_value_was_given, &block)
59
+ def replace(replacement = :no_replacement_value_was_given, &_)
60
60
  if replacement != :no_replacement_value_was_given && block_given?
61
61
  raise Janeway::Error.new('#replace needs either replacement value or block, not both', @query)
62
62
  end
@@ -118,6 +118,15 @@ module Janeway
118
118
  end
119
119
  end
120
120
 
121
+ # Return the normalized path of every query match.
122
+ #
123
+ # @see https://www.rfc-editor.org/rfc/rfc9535.html#name-normalized-paths
124
+ #
125
+ # @return [Array<String>] normalized paths, eg. [ "$['key'][0]"] ]
126
+ def find_paths
127
+ map { |_, _, _, path| path }
128
+ end
129
+
121
130
  private
122
131
 
123
132
  # Find the 'parent' of the object pointed to by the query. For singular query only.
@@ -149,7 +158,7 @@ module Janeway
149
158
  # @param path [String] jsonpath singular query to parent
150
159
  # @yieldparam [Hash] parent object
151
160
  # @yieldparam [String] hash key
152
- def insert_into_hash(hash, key, value, path, &block)
161
+ def insert_into_hash(hash, key, value, path, &_)
153
162
  unless key.is_a?(String) || key.is_a?(Symbol)
154
163
  raise Error.new("cannot use #{key.inspect} as hash key", @query.to_s)
155
164
  end
@@ -172,7 +181,7 @@ module Janeway
172
181
  # @param path [String] jsonpath singular query to parent
173
182
  # @yieldparam [Array] parent object
174
183
  # @yieldparam [Integer] array index
175
- def insert_into_array(array, index, value, path, &block)
184
+ def insert_into_array(array, index, value, path)
176
185
  raise Error.new("cannot use #{index.inspect} as array index", @query.to_s) unless index.is_a?(Integer)
177
186
 
178
187
  if index < array.size
@@ -50,10 +50,6 @@ module Janeway
50
50
  # @param input [Array, Hash] object to be searched
51
51
  # @return [Object]
52
52
  def interpret(input)
53
- unless input.is_a?(Hash) || input.is_a?(Array)
54
- return [] # can't query on any other types, but need to check because a string is also valid json
55
- end
56
-
57
53
  @root.interpret(nil, nil, input, [])
58
54
  rescue StandardError => e
59
55
  # Error during interpretation. Convert it to a Janeway::Error and include the query in the message
@@ -37,7 +37,7 @@ module Janeway
37
37
  end
38
38
  # basic types are ignored, they will be added by one of the above
39
39
 
40
- results.flatten(1).compact
40
+ results.flatten(1)
41
41
  end
42
42
  end
43
43
  end
@@ -28,8 +28,10 @@ module Janeway
28
28
 
29
29
  index = selector.value
30
30
  result = input.fetch(index) # raises IndexError if no such index
31
+ index += input.size if index.negative? # yield positive index for the normalize path
31
32
  return unless @yield_proc.call(input[index], input, path + [index])
32
33
 
34
+ index += input.size if index.negative?
33
35
  input.delete_at(index) # returns nil if deleted value is nil, or if no value was deleted
34
36
  [result]
35
37
  rescue IndexError
@@ -31,7 +31,9 @@ module Janeway
31
31
  result = input.fetch(selector.value) # raises IndexError if no such index
32
32
  return [result] unless @next
33
33
 
34
- @next.interpret(result, input, root, path + [selector.value])
34
+ index = selector.value
35
+ index += input.size if index.negative?
36
+ @next.interpret(result, input, root, path + [index])
35
37
  rescue IndexError
36
38
  []
37
39
  end
data/lib/janeway/lexer.rb CHANGED
@@ -72,6 +72,7 @@ module Janeway
72
72
  end
73
73
 
74
74
  def start_tokenization
75
+ raise err('JSONPath query is empty') if @source.empty?
75
76
  if WHITESPACE.include?(@source[0]) || WHITESPACE.include?(@source[-1])
76
77
  raise err('JSONPath query may not start or end with whitespace')
77
78
  end
@@ -470,6 +471,7 @@ module Janeway
470
471
  end
471
472
 
472
473
  # Lex a member name that is found within dot notation.
474
+ # This name is not delimited and allows a subset of the characters that can appear in a delimited string.
473
475
  #
474
476
  # Recognize keywords and given them the correct type.
475
477
  # @see https://www.rfc-editor.org/rfc/rfc9535.html#section-2.5.1.1-3
@@ -477,6 +479,10 @@ module Janeway
477
479
  # @param ignore_keywords [Boolean]
478
480
  # @return [Token]
479
481
  def lex_member_name_shorthand(ignore_keywords: false)
482
+ # Abort if name is preceded by child_start. Catches non-delimited identifiers in brackets,
483
+ # eg. $["key"] is allowed, but $[key] is not
484
+ raise err('Identifier within brackets must be surrounded by quotes') if @tokens.last&.type == :child_start
485
+
480
486
  consume while name_char?(lookahead)
481
487
  identifier = source[lexeme_start_p..(next_p - 1)]
482
488
  type =
@@ -46,11 +46,18 @@ module Janeway
46
46
  def self.escape_char(char)
47
47
  # Character ranges defined by https://www.rfc-editor.org/rfc/rfc9535.html#section-2.7-8
48
48
  case char.ord
49
- when 0x20..0x26, 0x28..0x5B, 0x5D..0xD7FF, 0xE000..0x10FFFF # normal-unescaped range
50
- char # unescaped
51
- when 0x62, 0x66, 0x6E, 0x72, 0x74, 0x27, 0x5C # normal-escapable range
52
- # backspace, form feed, line feed, carriage return, horizontal tab, apostrophe, backslash
53
- "\\#{char}" # escaped
49
+ # normal-unescaped range
50
+ when 0x20..0x26, 0x28..0x5B, 0x5D..0xD7FF, 0xE000..0x10FFFF then char # unescaped
51
+
52
+ # normal-escapable range
53
+ when 0x08 then '\\b' # backspace
54
+ when 0x0C then '\\f' # form feed
55
+ when 0x0A then '\\n' # line feed / newline
56
+ when 0x0D then '\\r' # carriage return
57
+ when 0x09 then '\\t' # horizontal tab
58
+ when 0x27 then '\\\'' # apostrophe
59
+ when 0x5C then '\\\\' # backslash
60
+
54
61
  else # normal-hexchar range
55
62
  hex_encode_char(char)
56
63
  end
data/lib/janeway/query.rb CHANGED
@@ -90,9 +90,7 @@ module Janeway
90
90
  #
91
91
  # @return [AST::Selector]
92
92
  def pop
93
- unless singular_query?
94
- raise Janeway::Error.new('not allowed to pop from a non-singular query', to_s)
95
- end
93
+ raise Janeway::Error.new('not allowed to pop from a non-singular query', to_s) unless singular_query?
96
94
 
97
95
  # Sever the link to the last selector
98
96
  nodes = node_list
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Janeway
4
4
  # Version for janeway-jsonpath gem
5
- VERSION = '0.6.0'
5
+ VERSION = '1.0.0'
6
6
  end
data/lib/janeway.rb CHANGED
@@ -54,8 +54,8 @@ module Janeway
54
54
  Janeway::Parser.parse(query)
55
55
  end
56
56
 
57
- # Transform a jsonpath singular query into an array of values suitable for
58
- # providing to Hash#dig or Array#dig.
57
+ # Transform a jsonpath singular query into an array of hash keys and/or array
58
+ # indexes suitable for providing to Hash#dig or Array#dig.
59
59
  #
60
60
  # Only singular queries are allowed, meaning queries that contain only name
61
61
  # selectors (ie. hash keys) and index selectors (array indexes.)
@@ -67,6 +67,19 @@ module Janeway
67
67
  # @param jsonpath [String] jsonpath query
68
68
  # @return [Array<String, Integer>]
69
69
  def self.path_to_diggable(jsonpath)
70
- raise NotImplementedError
70
+ raise Janeway::Error.new('Query has nothing to dig', jsonpath) if jsonpath == '$'
71
+
72
+ # Parse query and determine whether it can be converted
73
+ query = parse(jsonpath)
74
+ unless query.singular_query?
75
+ raise Janeway::Error.new('Only a singular query can be converted to dig parameters', jsonpath)
76
+ end
77
+
78
+ # Convert query to a list of name and index selectors
79
+ nodes = query.node_list
80
+ nodes.shift # discard the root identifier
81
+
82
+ # Extract values from selectors
83
+ nodes.map(&:value)
71
84
  end
72
85
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: janeway-jsonpath
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fraser Hanson
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-02-05 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  description: |+
13
13
  JSONPath is a query language for selecting and extracting values from a JSON text.
@@ -116,7 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
116
116
  - !ruby/object:Gem::Version
117
117
  version: '0'
118
118
  requirements: []
119
- rubygems_version: 3.6.2
119
+ rubygems_version: 3.6.9
120
120
  specification_version: 4
121
121
  summary: jsonpath parser which implements the finalized IETF standard of Goessner
122
122
  JSONPath