Add decimal_string coercion for v1 and v2 API fields#1829
Conversation
bigdecimal was demoted from a default gem to a bundled gem in Ruby 3.4.0. Without declaring it, users on Ruby 3.4.0+ see a deprecation warning and future Ruby versions may raise LoadError entirely. This is stripe-ruby's first runtime dependency. It's required because decimal_string field coercion (added in this branch) loads BigDecimal in stripe_object.rb for all response deserialization. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
…zation
Request-side (RequestParams):
- Add :decimal_string case to coerce_value
- Add coerce_decimal_string private class method: BigDecimal → to_s("F"),
String passthrough, Integer/Float → to_s, Array recursion
Response-side (StripeObject):
- Add self.field_encodings class method defaulting to {}
- In update_attributes, coerce string values to BigDecimal when
field_encodings declares :decimal_string for the field
Both files: require "bigdecimal"
Tests:
- request_params_test.rb: 8 new tests for :decimal_string encoding
- stripe_object_decimal_test.rb: 8 new tests for response coercion
and non-regression
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Committed-By-Agent: claude
There was a problem hiding this comment.
Pull request overview
Adds an explicit runtime dependency on bigdecimal to ensure decimal_string coercion support won’t raise LoadError on Ruby versions where bigdecimal is no longer a default gem (Ruby 3.4+).
Changes:
- Declares
bigdecimalas a runtime dependency in the gemspec. - Documents the Ruby 3.4+ rationale directly in
stripe.gemspec.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
xavdid-stripe
left a comment
There was a problem hiding this comment.
I see the new dependency, but there don't appear to be any of the described changes in this PR?
… v2 resources Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
This one is weird. Here's the change: https://github.com/stripe/stripe-ruby/pull/1829/files#diff-825edb8c5aafbbacf7da7d78303f6c12e6eaa2a2a5333a0360387a88a0d70bfe. It's actually a standard gem that is no longer "bundled" in future versions of Ruby so we need to declare it in the gemspec. |
Why?
The Stripe API uses
decimal_stringfields — high-precision decimal values that travel as JSON strings on the wire (e.g."9.99") to avoid floating-point loss. This PR adds bidirectional coercion so these fields are transparent to SDK users: pass aBigDecimalin, get aBigDecimalback.Coercion fires for both v1 and v2 resources. The codegen-emitted
field_encodingsmetadata drives which fields get coerced; resources without decimal fields are unaffected. This matches other SDK behavior (Java, Go, .NET).What?
Runtime (hand-written):
lib/stripe/request_params.rb: Adds:decimal_stringcase tocoerce_valueand acoerce_decimal_stringprivate method. HandlesBigDecimal,String,Integer,Float, andArrayinputs; usesto_s("F")to produce plain decimal notation (not scientific).lib/stripe/stripe_object.rb: Addsself.field_encodingsclass method and response-side coercion inupdate_attributes— whenfield_encodings[field] == :decimal_string, converts string API values toBigDecimal.stripe.gemspec: Addsbigdecimalas an explicit runtime dependency (demoted from default gem in Ruby 3.4).test/stripe/request_params_test.rbandtest/stripe/stripe_object_decimal_test.rb.Generated:
decimal_stringfields (v1 and v2) now emit afield_encodingsclass method listing those fields.primitiveDecimalTypechanged fromStringtoBigDecimal, so typed params and response types useBigDecimalinstead ofString.Review consideration —
bigdecimalgemspec dependency:This is stripe-ruby's first runtime dependency.
bigdecimalwas a default gem through Ruby 3.3 but was demoted starting in Ruby 3.4.0, so without this declaration users on Ruby 3.4+ would get aLoadError. The gem ships with every supported Ruby version we target (2.7 through JRuby 9.4 and TruffleRuby 25.0), so this is a declaration rather than a new install.See Also
Changelog
decimal_stringfields changed type fromStringtoBigDecimalin both request params and response objects. Code that reads or writes these fields asStringwill need to useBigDecimalinstead. Affected fields across v1 and v2 APIs:fx_ratemetric_tons; Climate::Product:metric_tons_availableunit_amount_decimalquantity_decimal,unit_amount_decimalquantity_decimal,unit_amount_decimalquantity_decimal,unit_cost_decimal,gross_amount_decimal,local_amount_decimal,national_amount_decimalamount_decimal,flat_amount_decimal,unit_amount_decimalunit_amount_decimal,flat_amount_decimal(includingcurrency_optionsandtiers)percent_ownershipunit_amount_decimal,flat_amount_decimal,quantity_decimal(where applicable)