Module: Stripe::V2TypeCoercion

Defined in:
lib/stripe/v2_type_coercion.rb

Overview

Shared V2 type coercion logic for encoding/decoding values between native Ruby types and their wire representations.

Used by RequestParams (encode: native → wire) and StripeObject (decode: wire → native).

On the response side, composite schemas (:object, :discriminated_union) are effectively no-ops because StripeObject's inner class hierarchy instantiates the correct subclass (which carries its own field_encodings) before coercion runs. The composite cases here exist for request-side use.

Class Method Summary collapse

Class Method Details

.coerce_composite(value, encoding, direction) ⇒ Object

--- composite coercions ---



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/stripe/v2_type_coercion.rb', line 88

module_function def coerce_composite(value, encoding, direction)
  case encoding[:kind]
  when :object
    coerce_object(value, encoding[:fields] || {}, direction)
  when :array
    return value unless value.is_a?(Array)

    value.map { |v| coerce_value(v, encoding[:element], direction: direction) }
  when :nullable
    coerce_value(value, encoding[:inner], direction: direction)
  when :discriminated_union
    coerce_discriminated_union(value, encoding[:discriminator], encoding[:variants] || {}, direction)
  else
    value
  end
end

.coerce_decimal_string(value, direction) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/stripe/v2_type_coercion.rb', line 66

module_function def coerce_decimal_string(value, direction)
  case direction
  when :encode
    case value
    when BigDecimal then value.to_s("F")
    when Integer, Float then value.to_s
    when Array then value.map { |v| coerce_decimal_string(v, direction) }
    else value
    end
  when :decode
    case value
    when String then Kernel.BigDecimal(value)
    when Array then value.map { |v| coerce_decimal_string(v, direction) }
    else value
    end
  else
    Kernel.raise ArgumentError, "unknown direction: #{direction.inspect}"
  end
end

.coerce_discriminated_union(value, discriminator, variants, direction) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/stripe/v2_type_coercion.rb', line 111

module_function def coerce_discriminated_union(value, discriminator, variants, direction)
  return value unless value.is_a?(Hash)

  disc_value = value[discriminator.to_sym] || value[discriminator.to_s]

  # A discriminator that is absent, or present but not name-like, not usable.
  # On encode, that's worth failing on to make sure we don't skip coercion
  # and silently fail to send the correct data types.
  unless disc_value.is_a?(String) || disc_value.is_a?(Symbol)
    return value unless direction == :encode

    Kernel.raise ArgumentError,
                 "Missing or invalid discriminator `#{discriminator}` for a polymorphic " \
                 "parameter. Stripe uses this field to determine the shape of the value, " \
                 "so we cannot encode the request without it. Provide `#{discriminator}:` " \
                 "with one of: #{variants.keys.join(', ')}."
  end

  variant_schema = variants[disc_value.to_sym]
  return value if variant_schema.nil?

  coerce_value(value, variant_schema, direction: direction)
end

.coerce_fields(hash, schema, direction:) ⇒ Object

Coerce all fields in a hash according to a schema map.



35
36
37
38
39
40
41
42
43
# File 'lib/stripe/v2_type_coercion.rb', line 35

module_function def coerce_fields(hash, schema, direction:)
  return hash unless hash.is_a?(Hash)
  return hash if schema.nil? || schema.empty?

  hash.each_with_object({}) do |(k, v), result|
    field_encoding = schema[k.to_sym]
    result[k] = field_encoding ? coerce_value(v, field_encoding, direction: direction) : v
  end
end

.coerce_int64_string(value, direction) ⇒ Object

--- leaf coercions ---



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/stripe/v2_type_coercion.rb', line 47

module_function def coerce_int64_string(value, direction)
  case direction
  when :encode
    case value
    when Integer then value.to_s
    when Array then value.map { |v| coerce_int64_string(v, direction) }
    else value
    end
  when :decode
    case value
    when String then Kernel.Integer(value)
    when Array then value.map { |v| coerce_int64_string(v, direction) }
    else value
    end
  else
    Kernel.raise ArgumentError, "unknown direction: #{direction.inspect}"
  end
end

.coerce_object(value, fields_schema, direction) ⇒ Object



105
106
107
108
109
# File 'lib/stripe/v2_type_coercion.rb', line 105

module_function def coerce_object(value, fields_schema, direction)
  return value unless value.is_a?(Hash)

  coerce_fields(value, fields_schema, direction: direction)
end

.coerce_value(value, encoding, direction:) ⇒ Object

Coerce a single value based on its field encoding schema. direction: :encode (request: native → wire) or :decode (response: wire → native)



19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/stripe/v2_type_coercion.rb', line 19

module_function def coerce_value(value, encoding, direction:)
  return value if value.nil?

  case encoding
  when :int64_string
    coerce_int64_string(value, direction)
  when :decimal_string
    coerce_decimal_string(value, direction)
  when Hash
    coerce_composite(value, encoding, direction)
  else
    value
  end
end