json_mend 0.1.2 → 0.1.3

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: 85624e37a002e82e9edcb6d7fffe16799429e75389662d8059e9e89f8b6f14d8
4
- data.tar.gz: 19309bc419b6f4481193e140eea31c2d24153ee87265cf2f4e2ecca1f0421bf4
3
+ metadata.gz: 96e37cada4ab9945473f6a49b1d57a24c7822dceb0e6402847d129827686202a
4
+ data.tar.gz: b497489826f674239f601203e237ee7358c7305475a2f1a43d37e465d04ce875
5
5
  SHA512:
6
- metadata.gz: 85aa783092d768f3ff9543e2de2b59b0bbfe7a285e7d5db91bfb3d5c12dab233d2735f6f605ede6cab701b5085bc740332e91d93fddb90f9361b1033e0edf57e
7
- data.tar.gz: 75d3dc3b22f72748fe5b21f916ba930a04bd03aaea0d9aca8126ce38b2fdf9cfae9ad38c33f35a7c4e0c39ee7784b79df06d60772bcdd062e529372cc1bbd733
6
+ metadata.gz: 641ef79051d205ed61c16b9d6deb5f755d41bfb74f3958ac5b1910e2770ac3df2ccdf7e971ba6d44222e7a71de51078b3964da957b44bf70898db13a798ad239
7
+ data.tar.gz: 605ec12dc272c8b1ce7526c8dcf53748e148a58957e6eca9ebf13133ac7f56db46a56161db03227790ddf5c064a582440a3dc02d33bb117f808e536d910f55fe
data/.rubocop.yml CHANGED
@@ -7,19 +7,19 @@ AllCops:
7
7
  SuggestExtensions: false
8
8
 
9
9
  Metrics/AbcSize:
10
- Max: 60
10
+ Max: 65
11
11
 
12
12
  Metrics/ClassLength:
13
- Max: 800
13
+ Max: 820
14
14
 
15
15
  Metrics/CyclomaticComplexity:
16
- Max: 30
16
+ Max: 35
17
17
 
18
18
  Metrics/MethodLength:
19
- Max: 70
19
+ Max: 80
20
20
 
21
21
  Metrics/PerceivedComplexity:
22
- Max: 32
22
+ Max: 35
23
23
 
24
24
  Metrics/BlockNesting:
25
25
  Max: 5
@@ -222,8 +222,10 @@ module JsonMend
222
222
  # Parses the key of an object, including the special logic for merging dangling arrays.
223
223
  # Returns [key, was_array_merged_flag]
224
224
  def parse_object_key(object)
225
+ char = peek_char
226
+
225
227
  # First, check for and handle the dangling array merge logic.
226
- if try_to_merge_dangling_array(object)
228
+ if char == '[' && try_to_merge_dangling_array(object)
227
229
  return [nil, true, false] # Signal that an array was merged.
228
230
  end
229
231
 
@@ -231,7 +233,7 @@ module JsonMend
231
233
  @context.push(:object_key)
232
234
  is_bracketed = false
233
235
 
234
- if peek_char == '['
236
+ if char == '['
235
237
  @scanner.getch # Consume '['
236
238
  arr = parse_array
237
239
  key = arr.first.to_s
@@ -355,7 +357,7 @@ module JsonMend
355
357
  char = prepare_string_parsing
356
358
 
357
359
  # A valid string can only start with a valid quote or, in our case, with a literal
358
- while !@scanner.eos? && !STRING_DELIMITERS.include?(char) && !char.match?(/[\p{L}0-9]/)
360
+ while !@scanner.eos? && !STRING_DELIMITERS.include?(char) && !char.match?(/[\p{L}0-9$_-]/)
359
361
  return '' if TERMINATORS_STRING_GUESSED.include?(char)
360
362
 
361
363
  @scanner.getch
@@ -434,7 +436,7 @@ module JsonMend
434
436
  when '“'
435
437
  lstring_delimiter = '“'
436
438
  rstring_delimiter = '”'
437
- when /[\p{L}0-9]/
439
+ when /[\p{L}0-9$_-]/
438
440
  # Could be a boolean/null, but not if it's an object key.
439
441
  if BOOLEAN_OR_NULL_CHARS.include?(char.downcase) && !current_context?(:object_key)
440
442
  # parse_literal is non-destructive if it fails to match.
@@ -509,6 +511,17 @@ module JsonMend
509
511
  unmatched_delimiter = false
510
512
  # --- Main Parsing Loop ---
511
513
  while !@scanner.eos? && char != rstring_delimiter
514
+ # Fast-path for unquoted keys (e.g. { key: val })
515
+ # consumes a chunk of valid identifier characters at once
516
+ if missing_quotes && current_context?(:object_key)
517
+ chunk = @scanner.scan(/[a-zA-Z0-9_$-]+/)
518
+ if chunk
519
+ string_parts << chunk
520
+ char = peek_char
521
+ next
522
+ end
523
+ end
524
+
512
525
  break if context_termination_reached?(
513
526
  char:,
514
527
  missing_quotes:
@@ -1170,16 +1183,29 @@ module JsonMend
1170
1183
 
1171
1184
  # Peeks the next character without advancing the scanner
1172
1185
  def peek_char(offset = 0)
1173
- return @scanner.check(/./m) if offset.zero?
1186
+ # Handle the common 0-offset case
1187
+ if offset.zero?
1188
+ # peek(1) returns the next BYTE, not character
1189
+ byte_str = @scanner.peek(1)
1190
+ return nil if byte_str.empty?
1191
+
1192
+ # Fast path: If it's a standard ASCII char (0-127), return it directly.
1193
+ # This avoids the regex overhead for standard JSON characters ({, [, ", etc).
1194
+ return byte_str if byte_str.getbyte(0) < 128
1195
+
1196
+ # Slow path: If it's a multibyte char (e.g. “), use regex to match the full character.
1197
+ return @scanner.check(/./m)
1198
+ end
1174
1199
 
1200
+ # For offsets > 0, we must scan to skip correctly (as characters can be variable width)
1175
1201
  saved_pos = @scanner.pos
1176
- c = nil
1202
+ res = nil
1177
1203
  (offset + 1).times do
1178
- c = @scanner.getch
1179
- break if c.nil?
1204
+ res = @scanner.getch
1205
+ break if res.nil?
1180
1206
  end
1181
1207
  @scanner.pos = saved_pos
1182
- c
1208
+ res
1183
1209
  end
1184
1210
 
1185
1211
  def current_context?(value)
@@ -1192,7 +1218,7 @@ module JsonMend
1192
1218
 
1193
1219
  # Checks if the character signifies the start of a string or literal
1194
1220
  def string_start?(char)
1195
- STRING_DELIMITERS.include?(char) || char&.match?(/\p{L}/)
1221
+ STRING_DELIMITERS.include?(char) || char&.match?(/[\p{L}$_]/)
1196
1222
  end
1197
1223
 
1198
1224
  # Checks if the character signifies the start of a number
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JsonMend
4
- VERSION = '0.1.2'
4
+ VERSION = '0.1.3'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json_mend
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oleksii Vasyliev