smarter_json 1.2.4 → 1.2.6

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: 1bdfb87113872a6659af0063f196de84f9074b81eedc90ae63445fa6a9f86a0a
4
- data.tar.gz: 1271826d3097455921c7f058710ea42651daa75a0de9438b0f0d581e7abc8b7a
3
+ metadata.gz: d7ded6a0b9872aaa577e5a8381ed69c5eeb89056a05eaa82a253228b1456c2b9
4
+ data.tar.gz: 5fb399f6c8ae40528d521182b02b4e156734c436b70e3cbd662b832ad339f245
5
5
  SHA512:
6
- metadata.gz: 4885f735c132bea79affc74ddb82504c581b722a03f52fbbbaabe27fa818347715bf1753b2fc539fb86991448a3e7987719d679f18210aaab54afbe06ee1d021
7
- data.tar.gz: c9fafa246a337eb025a089e3db4909c596d52b023b5b06291e7f3b8114f225c57ad4e48b4fd742ffd295db1c95e6cd9574e68adc6bba0d9f5a4c8695b0620649
6
+ metadata.gz: 0c87d064c656210698c3fd0307bd2673861105e1be998e0770a6833cc7c7bd9658c329b19c5866d87bb23db11fc2dec13a25b8007417fa634ed2fe6ab4d71624
7
+ data.tar.gz: 959b5022a439414a101285ee4d3480e8ca011c1d9293eac911024f9748b574bda1a108b280d529118b5e572fcd1dd633a9ef4ca89d0bea5e07823135868a5e2c
data/CHANGELOG.md CHANGED
@@ -13,6 +13,22 @@
13
13
  > ⚠️ We discourage the use of `process(input).first` / `process(input)[0]` because it silently drops potential additional documents
14
14
  > Please use `process_one` if you are expecting only one JSON doc, e.g. in API payloads, because it emits on_warning if it finds multiple docs.
15
15
 
16
+ ## 1.2.6 (2026-07-02)
17
+
18
+ RSpec tests: 1,308 → 1,325
19
+
20
+ ### Bug Fixes
21
+
22
+ - **The `:number_overflow` warning now reports the sign of the collapsed value.** A negative number literal beyond Float range (e.g. `-1e400`) collapses to `-Infinity`, but the warning said "collapsed to Infinity" — always on the C path, and for top-level numbers on the pure-Ruby path. Both paths now report the actual collapsed value (`Infinity` or `-Infinity`) in every position, and the warning-parity suite locks them together.
23
+
24
+ ## 1.2.5 (2026-07-01)
25
+
26
+ RSpec tests: 1,282 → 1,308
27
+
28
+ ### New Features
29
+
30
+ - **RFC 7464 JSON Text Sequences are now read natively.** The record separator (`0x1E`) that frames each record is a first-class document separator, so an RS-framed stream parses into its documents without a warning, and bare-scalar records (a number / keyword / string on its own) are read correctly.
31
+
16
32
  ## 1.2.4 (2026-07-01)
17
33
 
18
34
  RSpec tests: 1,268 → 1,282
@@ -649,7 +649,11 @@ static FJ_ALWAYS_INLINE VALUE fj_float_from_parts(fj_state *st, uint64_t m10, in
649
649
  still returned). The Infinity/NaN keywords take separate paths and never get here.
650
650
  Gate isinf on a listening handler (matches the Ruby float_or_warn): no handler ->
651
651
  no point detecting, and it keeps the test off the hot number path. */
652
- if (st->on_warning != Qnil && isinf(d)) fj_warn(st, fj_sym_number_overflow, "number literal out of Float range — collapsed to Infinity");
652
+ if (st->on_warning != Qnil && isinf(d)) {
653
+ fj_warn(st, fj_sym_number_overflow,
654
+ d > 0 ? "number literal out of Float range — collapsed to Infinity"
655
+ : "number literal out of Float range — collapsed to -Infinity");
656
+ }
653
657
  return rb_float_new(d);
654
658
  }
655
659
 
@@ -1624,14 +1628,17 @@ static int fj_implicit_root_ahead(fj_state *st) {
1624
1628
  return result;
1625
1629
  }
1626
1630
 
1627
- /* Between top-level documents, whitespace, comments, AND commas all separate
1628
- * (commas collapse like the in-container lenient-comma rule). A space alone never
1629
- * separates that is handled inside the document by the quoteless run. Mirrors
1630
- * the Ruby Parser#skip_document_separators. */
1631
+ /* Between top-level documents, whitespace, comments, commas, AND the RFC 7464
1632
+ * record separator (0x1E) all separate (commas collapse like the in-container
1633
+ * lenient-comma rule; 0x1E frames each JSON Text Sequence record). A space alone
1634
+ * never separates — that is handled inside the document by the quoteless run.
1635
+ * Mirrors the Ruby Parser#skip_document_separators. */
1631
1636
  static void fj_skip_document_separators(fj_state *st) {
1632
1637
  for (;;) {
1638
+ int b;
1633
1639
  fj_skip_ws_comments(st);
1634
- if (fj_byte(st) != ',') break;
1640
+ b = fj_byte(st);
1641
+ if (b != ',' && b != 0x1E) break;
1635
1642
  fj_advance(st, 1);
1636
1643
  }
1637
1644
  }
@@ -1640,8 +1647,9 @@ static int fj_is_hws(int b) { return b == ' ' || b == '\t' || b == 0x0B || b ==
1640
1647
 
1641
1648
  /* After a top-level value: a self-delimiting value (object / array / string) may be
1642
1649
  * followed by anything, but a bare scalar (number / keyword) must be followed by a
1643
- * real separator — a newline, ',', a comment, or EOF. A space is NOT a separator, so
1644
- * `1 2 3` and `42 "x" true` raise. Mirrors the Ruby Parser#enforce_scalar_boundary. */
1650
+ * real separator — a newline, ',', the RFC 7464 record separator (0x1E), a comment,
1651
+ * or EOF. A space is NOT a separator, so `1 2 3` and `42 "x" true` raise. Mirrors the
1652
+ * Ruby Parser#enforce_scalar_boundary. */
1645
1653
  static void fj_enforce_scalar_boundary(fj_state *st, VALUE value) {
1646
1654
  int b, nx;
1647
1655
  if (RB_TYPE_P(value, T_STRING) || RB_TYPE_P(value, T_HASH) || RB_TYPE_P(value, T_ARRAY)) return;
@@ -1655,7 +1663,7 @@ static void fj_enforce_scalar_boundary(fj_state *st, VALUE value) {
1655
1663
  break;
1656
1664
  }
1657
1665
  b = fj_byte(st);
1658
- if (b == -1 || b == 0x0A || b == 0x0D || b == ',') return;
1666
+ if (b == -1 || b == 0x0A || b == 0x0D || b == ',' || b == 0x1E) return;
1659
1667
  if (b == '#') return;
1660
1668
  if (b == '/') { nx = fj_byte_at(st, 1); if (nx == '/' || nx == '*') return; }
1661
1669
  fj_error(st, "a top-level number or keyword must be followed by a newline, ',', or end of input");
@@ -384,6 +384,7 @@ module SmarterJSON
384
384
  TAB = 0x09
385
385
  LF = 0x0A
386
386
  CR = 0x0D
387
+ RS = 0x1E # RFC 7464 record separator — frames each JSON Text Sequence record
387
388
  end
388
389
 
389
390
  module Framer
@@ -1052,13 +1053,14 @@ module SmarterJSON
1052
1053
  parse_iter(implicit_root_object_ahead?)
1053
1054
  end
1054
1055
 
1055
- # Between top-level documents, whitespace, comments, AND commas all separate
1056
- # (commas collapse like the in-container lenient-comma rule). A space alone never
1057
- # separates that is handled inside the document by the quoteless run, so
1056
+ # Between top-level documents, whitespace, comments, commas, AND the RFC 7464
1057
+ # record separator (0x1E) all separate (commas collapse like the in-container
1058
+ # lenient-comma rule; 0x1E frames each JSON Text Sequence record). A space alone
1059
+ # never separates — that is handled inside the document by the quoteless run, so
1058
1060
  # `1 2 3` is one document (the string "1 2 3") while `1, 2, 3` is three.
1059
1061
  def skip_document_separators
1060
1062
  skip_whitespace_and_comments
1061
- while byte == COMMA
1063
+ while (b = byte) == COMMA || b == RS
1062
1064
  advance(1)
1063
1065
  skip_whitespace_and_comments
1064
1066
  end
@@ -1066,15 +1068,16 @@ module SmarterJSON
1066
1068
 
1067
1069
  # After a top-level value: a self-delimiting value (object / array / quoted string)
1068
1070
  # may be followed by anything (the next document self-delimits), but a bare scalar
1069
- # (number / keyword) must be followed by a real separator — a newline, ',', a
1070
- # comment, or EOF. A space is NOT a separator, so `1 2 3` and `42 "x" true` raise
1071
- # rather than silently splitting; bare top-level words raise in parse_value itself.
1071
+ # (number / keyword) must be followed by a real separator — a newline, ',', the RFC
1072
+ # 7464 record separator (0x1E), a comment, or EOF. A space is NOT a separator, so
1073
+ # `1 2 3` and `42 "x" true` raise rather than silently splitting; bare top-level
1074
+ # words raise in parse_value itself.
1072
1075
  def enforce_scalar_boundary(value)
1073
1076
  return if value.is_a?(String) || value.is_a?(Hash) || value.is_a?(Array)
1074
1077
 
1075
1078
  skip_horizontal_whitespace
1076
1079
  b = byte
1077
- return if b.nil? || b == LF || b == CR || b == COMMA
1080
+ return if b.nil? || b == LF || b == CR || b == COMMA || b == RS
1078
1081
  return if b == HASH || (b == SLASH && ((c = byte_at(1)) == SLASH || c == STAR))
1079
1082
 
1080
1083
  raise error("a top-level number or keyword must be followed by a newline, ',', or end of input")
@@ -1922,6 +1925,7 @@ module SmarterJSON
1922
1925
  # --- numbers (top-level / strict positions) ---
1923
1926
 
1924
1927
  def parse_number
1928
+ token_start = @pos
1925
1929
  negative = false
1926
1930
  signed = false
1927
1931
  if byte == MINUS
@@ -1942,7 +1946,6 @@ module SmarterJSON
1942
1946
  return Float::NAN
1943
1947
  end
1944
1948
 
1945
- int_start = @pos
1946
1949
  had_leading_zero = false
1947
1950
 
1948
1951
  if byte == ZERO
@@ -1998,9 +2001,13 @@ module SmarterJSON
1998
2001
  raise error("invalid number with a leading zero")
1999
2002
  end
2000
2003
 
2001
- slice = @input.byteslice(int_start, @pos - int_start).delete("_")
2002
- value = is_float ? decimal_value(slice) : slice.to_i
2003
- negative ? -value : value
2004
+ # token_start sits BEFORE the sign, so the slice keeps it ("-1e400", not "1e400"):
2005
+ # decimal_value -> float_or_warn sees the signed token, and a negative overflow
2006
+ # warns "collapsed to -Infinity" the same warning numeric_value produces for a
2007
+ # member-position number. String#to_i, String#to_f, and BigDecimal() all parse
2008
+ # the leading sign, so there is no negation step here.
2009
+ slice = @input.byteslice(token_start, @pos - token_start).delete("_")
2010
+ is_float ? decimal_value(slice) : slice.to_i
2004
2011
  end
2005
2012
 
2006
2013
  def hex_digit?(b)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SmarterJSON
4
- VERSION = "1.2.4"
4
+ VERSION = "1.2.6"
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smarter_json
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.4
4
+ version: 1.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tilo Sloboda
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2026-07-01 00:00:00.000000000 Z
10
+ date: 2026-07-03 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: bigdecimal