dentaku 4.0.1 → 4.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8c52e5ed43e8cc6d9ac6f3cf81ae522e408860ab24bf59109bdd97301e0d6e12
4
- data.tar.gz: fa376e35d073d5c0ebce858f96c4c1322ed1bba2a202dc6e41d265c1e5fa24f3
3
+ metadata.gz: 498d10748b47ba3ab1930e2d3df6685d8d557e1e4f7b95a0887952507557325a
4
+ data.tar.gz: a47a69280b8c298a299edbba9758b0dc132fdcceecb055eaa4008c0427d785de
5
5
  SHA512:
6
- metadata.gz: 040e836d96fad9833095285a2d3a9b6b7e7a3c4bffcd84cac9603bc16128308acb719103eb96693cc04910c028265231f72f982658dd34523d3685ac4dea8e7d
7
- data.tar.gz: 66aa9ee21ce77b2d9dd25d44b3a7f1db7212e7776614839d4c92e403ed0d4e5561fee07e28a50eb81c1a886bf889c1ae285c4a89aa78a59910f5636de66159d4
6
+ metadata.gz: '0466598da5b7018075787a018873cc72f4185faa40eabe3596b1666646625d70d29c199a8ac91d5fe0c4436d5b960f5cc9c95efbfe6ff2ea91a4855928074288'
7
+ data.tar.gz: '0440877441b431ffb55da23343fe1fff2271afd6ef4868f86a860927ba26f6e37ffa586514dee83a3c018cea4506615377e092ead2135b1cf39e440006a3a933'
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Change Log
2
2
 
3
+ ## [v4.0.2] 2026-08-02
4
+ - the 4.0.1 guard against arithmetic that rejects a well-typed operand only
5
+ worked on Ruby 3.4+. Ruby 3.2 and 3.3 do not raise for an oversized
6
+ exponent: `Integer#**` warns and returns `Float::INFINITY`, so there was
7
+ nothing to rescue and `Infinity` still leaked out of the non-bang
8
+ `Calculator#evaluate` (#332). Arithmetic now also rejects a non-finite
9
+ result computed from finite operands, so `evaluate` returns `nil` and
10
+ `evaluate!` raises `Dentaku::ArgumentError` on every supported Ruby.
11
+ Operands that are already infinite are passed through unchanged.
12
+
3
13
  ## [v4.0.1] 2026-08-02
4
14
  - parsing no longer executes user functions. The three parse-time operand
5
15
  validators (`Arithmetic`, `Negation`, and the logical combinators) asked
@@ -38,7 +38,7 @@ module Dentaku
38
38
  l = cast(left_value)
39
39
  r = cast(right_value)
40
40
 
41
- begin
41
+ result = begin
42
42
  l.public_send(operator, r)
43
43
  rescue ::TypeError => e
44
44
  # Right cannot be converted to a suitable type for left. e.g. [] + 1
@@ -53,6 +53,27 @@ module Dentaku
53
53
  # promises to return nil rather than raise.
54
54
  raise Dentaku::ArgumentError.for(:invalid_value, actual: r), e.message
55
55
  end
56
+
57
+ validate_result(result, l, r)
58
+ end
59
+
60
+ # Not every Ruby rejects an operation it cannot carry out. Before 3.4,
61
+ # `Integer#**` with an oversized exponent warns and returns
62
+ # Float::INFINITY where 3.4+ raises ArgumentError, and overflowing float
63
+ # arithmetic is silently infinite on every version. Finite operands that
64
+ # produce a non-finite result mean the operation overflowed, so treat it
65
+ # as the same rejection newer Rubies raise -- otherwise Infinity leaks
66
+ # out of Calculator#evaluate, which promises nil on failure (#332).
67
+ def validate_result(result, l, r)
68
+ return result unless nonfinite?(result)
69
+ return result if nonfinite?(l) || nonfinite?(r)
70
+
71
+ raise Dentaku::ArgumentError.for(:invalid_value, actual: r),
72
+ "Result of #{l} #{operator} #{r} is not a finite number"
73
+ end
74
+
75
+ def nonfinite?(val)
76
+ val.is_a?(::Numeric) && val.respond_to?(:finite?) && !val.finite?
56
77
  end
57
78
 
58
79
  def cast(val)
@@ -1,3 +1,3 @@
1
1
  module Dentaku
2
- VERSION = "4.0.1"
2
+ VERSION = "4.0.2"
3
3
  end
@@ -177,9 +177,12 @@ describe Dentaku::AST::Arithmetic do
177
177
  let(:oversized) { "999999999999999 ^ 99999999999999" }
178
178
 
179
179
  it 'wraps the raw Ruby error so it is a Dentaku::Error' do
180
+ # Ruby 3.4+ raises ArgumentError('exponent is too large') and we pass its
181
+ # message through; older Rubies only warn and return Infinity, which the
182
+ # non-finite result guard turns into the equivalent Dentaku error.
180
183
  expect {
181
184
  Dentaku::Calculator.new.evaluate!(oversized)
182
- }.to raise_error(Dentaku::ArgumentError, /exponent is too large/)
185
+ }.to raise_error(Dentaku::ArgumentError, /exponent is too large|is not a finite number/)
183
186
  end
184
187
 
185
188
  it 'is rescuable as Dentaku::Error' do
@@ -209,6 +212,17 @@ describe Dentaku::AST::Arithmetic do
209
212
  expect(Dentaku::Calculator.new.evaluate!("2 ^ 10")).to eq(1024)
210
213
  end
211
214
 
215
+ it 'still evaluates large results that BigDecimal can represent' do
216
+ expect(Dentaku::Calculator.new.evaluate!("1e308 * 10")).to eq(BigDecimal("1e309"))
217
+ end
218
+
219
+ it 'leaves arithmetic alone when an operand is already infinite' do
220
+ calculator = Dentaku::Calculator.new
221
+
222
+ expect(calculator.evaluate!("a + 1", a: Float::INFINITY)).to be_infinite
223
+ expect(calculator.evaluate!("a * 2", a: Float::INFINITY)).to be_infinite
224
+ end
225
+
212
226
  it 'does not swallow Dentaku errors raised by the operation itself' do
213
227
  expect {
214
228
  Dentaku::Calculator.new.evaluate!("1 / 0")
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dentaku
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.1
4
+ version: 4.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Solomon White