stripe 4.10.0 → 5.55.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (258) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +316 -1
  3. data/CODE_OF_CONDUCT.md +77 -0
  4. data/Gemfile +10 -14
  5. data/Makefile +7 -0
  6. data/README.md +186 -62
  7. data/Rakefile +8 -7
  8. data/VERSION +1 -1
  9. data/lib/stripe/api_operations/create.rb +1 -1
  10. data/lib/stripe/api_operations/delete.rb +28 -2
  11. data/lib/stripe/api_operations/list.rb +1 -12
  12. data/lib/stripe/api_operations/nested_resource.rb +38 -28
  13. data/lib/stripe/api_operations/request.rb +81 -9
  14. data/lib/stripe/api_operations/save.rb +8 -7
  15. data/lib/stripe/api_operations/search.rb +19 -0
  16. data/lib/stripe/api_resource.rb +45 -3
  17. data/lib/stripe/api_resource_test_helpers.rb +47 -0
  18. data/lib/stripe/connection_manager.rb +200 -0
  19. data/lib/stripe/error_object.rb +93 -0
  20. data/lib/stripe/errors.rb +31 -10
  21. data/lib/stripe/instrumentation.rb +84 -0
  22. data/lib/stripe/list_object.rb +41 -7
  23. data/lib/stripe/multipart_encoder.rb +131 -0
  24. data/lib/stripe/oauth.rb +8 -6
  25. data/lib/stripe/object_types.rb +119 -0
  26. data/lib/stripe/{account.rb → resources/account.rb} +48 -30
  27. data/lib/stripe/{account_link.rb → resources/account_link.rb} +2 -1
  28. data/lib/stripe/resources/alipay_account.rb +34 -0
  29. data/lib/stripe/{apple_pay_domain.rb → resources/apple_pay_domain.rb} +2 -1
  30. data/lib/stripe/resources/application_fee.rb +14 -0
  31. data/lib/stripe/resources/application_fee_refund.rb +31 -0
  32. data/lib/stripe/{balance.rb → resources/balance.rb} +2 -1
  33. data/lib/stripe/{balance_transaction.rb → resources/balance_transaction.rb} +2 -5
  34. data/lib/stripe/resources/bank_account.rb +43 -0
  35. data/lib/stripe/{issuing/dispute.rb → resources/billing_portal/configuration.rb} +4 -3
  36. data/lib/stripe/resources/billing_portal/session.rb +12 -0
  37. data/lib/stripe/{bitcoin_receiver.rb → resources/bitcoin_receiver.rb} +4 -3
  38. data/lib/stripe/resources/bitcoin_transaction.rb +16 -0
  39. data/lib/stripe/resources/capability.rb +34 -0
  40. data/lib/stripe/{card.rb → resources/card.rb} +13 -4
  41. data/lib/stripe/resources/cash_balance.rb +22 -0
  42. data/lib/stripe/resources/charge.rb +32 -0
  43. data/lib/stripe/resources/checkout/session.rb +27 -0
  44. data/lib/stripe/{country_spec.rb → resources/country_spec.rb} +2 -1
  45. data/lib/stripe/{coupon.rb → resources/coupon.rb} +3 -2
  46. data/lib/stripe/resources/credit_note.rb +33 -0
  47. data/lib/stripe/resources/credit_note_line_item.rb +8 -0
  48. data/lib/stripe/resources/customer.rb +74 -0
  49. data/lib/stripe/resources/customer_balance_transaction.rb +31 -0
  50. data/lib/stripe/resources/discount.rb +8 -0
  51. data/lib/stripe/resources/dispute.rb +22 -0
  52. data/lib/stripe/{ephemeral_key.rb → resources/ephemeral_key.rb} +6 -2
  53. data/lib/stripe/{event.rb → resources/event.rb} +2 -1
  54. data/lib/stripe/{exchange_rate.rb → resources/exchange_rate.rb} +2 -1
  55. data/lib/stripe/resources/file.rb +36 -0
  56. data/lib/stripe/{file_link.rb → resources/file_link.rb} +3 -2
  57. data/lib/stripe/resources/financial_connections/account.rb +31 -0
  58. data/lib/stripe/resources/financial_connections/account_owner.rb +10 -0
  59. data/lib/stripe/resources/financial_connections/account_ownership.rb +10 -0
  60. data/lib/stripe/resources/financial_connections/session.rb +12 -0
  61. data/lib/stripe/resources/funding_instructions.rb +16 -0
  62. data/lib/stripe/resources/identity/verification_report.rb +12 -0
  63. data/lib/stripe/resources/identity/verification_session.rb +35 -0
  64. data/lib/stripe/resources/invoice.rb +83 -0
  65. data/lib/stripe/{invoice_item.rb → resources/invoice_item.rb} +3 -2
  66. data/lib/stripe/{invoice_line_item.rb → resources/invoice_line_item.rb} +2 -1
  67. data/lib/stripe/resources/issuing/authorization.rb +34 -0
  68. data/lib/stripe/resources/issuing/card.rb +25 -0
  69. data/lib/stripe/resources/issuing/card_details.rb +10 -0
  70. data/lib/stripe/{issuing → resources/issuing}/cardholder.rb +3 -2
  71. data/lib/stripe/resources/issuing/dispute.rb +25 -0
  72. data/lib/stripe/{issuing → resources/issuing}/transaction.rb +3 -2
  73. data/lib/stripe/resources/line_item.rb +8 -0
  74. data/lib/stripe/resources/login_link.rb +15 -0
  75. data/lib/stripe/resources/mandate.rb +8 -0
  76. data/lib/stripe/resources/order.rb +33 -0
  77. data/lib/stripe/{order_return.rb → resources/order_return.rb} +2 -1
  78. data/lib/stripe/resources/payment_intent.rb +82 -0
  79. data/lib/stripe/resources/payment_link.rb +23 -0
  80. data/lib/stripe/resources/payment_method.rb +33 -0
  81. data/lib/stripe/resources/payout.rb +33 -0
  82. data/lib/stripe/{person.rb → resources/person.rb} +9 -3
  83. data/lib/stripe/{plan.rb → resources/plan.rb} +2 -1
  84. data/lib/stripe/resources/price.rb +21 -0
  85. data/lib/stripe/resources/product.rb +22 -0
  86. data/lib/stripe/resources/promotion_code.rb +12 -0
  87. data/lib/stripe/resources/quote.rb +105 -0
  88. data/lib/stripe/resources/radar/early_fraud_warning.rb +12 -0
  89. data/lib/stripe/{radar → resources/radar}/value_list.rb +3 -2
  90. data/lib/stripe/{radar → resources/radar}/value_list_item.rb +3 -2
  91. data/lib/stripe/{recipient.rb → resources/recipient.rb} +3 -6
  92. data/lib/stripe/{recipient_transfer.rb → resources/recipient_transfer.rb} +1 -1
  93. data/lib/stripe/resources/refund.rb +42 -0
  94. data/lib/stripe/{reporting → resources/reporting}/report_run.rb +3 -2
  95. data/lib/stripe/{reporting → resources/reporting}/report_type.rb +3 -2
  96. data/lib/stripe/resources/reversal.rb +30 -0
  97. data/lib/stripe/resources/review.rb +21 -0
  98. data/lib/stripe/resources/setup_attempt.rb +10 -0
  99. data/lib/stripe/resources/setup_intent.rb +43 -0
  100. data/lib/stripe/{product.rb → resources/shipping_rate.rb} +4 -4
  101. data/lib/stripe/{sigma → resources/sigma}/scheduled_query_run.rb +3 -2
  102. data/lib/stripe/{sku.rb → resources/sku.rb} +4 -3
  103. data/lib/stripe/resources/source.rb +47 -0
  104. data/lib/stripe/{source_transaction.rb → resources/source_transaction.rb} +2 -1
  105. data/lib/stripe/resources/subscription.rb +35 -0
  106. data/lib/stripe/resources/subscription_item.rb +26 -0
  107. data/lib/stripe/resources/subscription_schedule.rb +33 -0
  108. data/lib/stripe/resources/tax_code.rb +10 -0
  109. data/lib/stripe/resources/tax_id.rb +27 -0
  110. data/lib/stripe/{refund.rb → resources/tax_rate.rb} +3 -2
  111. data/lib/stripe/{terminal/reader.rb → resources/terminal/configuration.rb} +3 -2
  112. data/lib/stripe/resources/terminal/connection_token.rb +12 -0
  113. data/lib/stripe/{terminal → resources/terminal}/location.rb +3 -2
  114. data/lib/stripe/resources/terminal/reader.rb +75 -0
  115. data/lib/stripe/resources/test_helpers/test_clock.rb +25 -0
  116. data/lib/stripe/{three_d_secure.rb → resources/three_d_secure.rb} +2 -1
  117. data/lib/stripe/{token.rb → resources/token.rb} +2 -1
  118. data/lib/stripe/resources/topup.rb +23 -0
  119. data/lib/stripe/resources/transfer.rb +27 -0
  120. data/lib/stripe/resources/usage_record.rb +8 -0
  121. data/lib/stripe/{usage_record_summary.rb → resources/usage_record_summary.rb} +2 -1
  122. data/lib/stripe/{webhook_endpoint.rb → resources/webhook_endpoint.rb} +3 -2
  123. data/lib/stripe/resources.rb +100 -0
  124. data/lib/stripe/search_result_object.rb +86 -0
  125. data/lib/stripe/singleton_api_resource.rb +3 -1
  126. data/lib/stripe/stripe_client.rb +661 -266
  127. data/lib/stripe/stripe_configuration.rb +194 -0
  128. data/lib/stripe/stripe_object.rb +80 -61
  129. data/lib/stripe/stripe_response.rb +87 -27
  130. data/lib/stripe/util.rb +128 -117
  131. data/lib/stripe/version.rb +1 -1
  132. data/lib/stripe/webhook.rb +43 -10
  133. data/lib/stripe.rb +46 -197
  134. data/stripe.gemspec +24 -8
  135. metadata +123 -283
  136. data/.gitattributes +0 -4
  137. data/.github/ISSUE_TEMPLATE.md +0 -5
  138. data/.gitignore +0 -8
  139. data/.rubocop.yml +0 -32
  140. data/.rubocop_todo.yml +0 -50
  141. data/.travis.yml +0 -42
  142. data/lib/stripe/alipay_account.rb +0 -27
  143. data/lib/stripe/application_fee.rb +0 -23
  144. data/lib/stripe/application_fee_refund.rb +0 -22
  145. data/lib/stripe/bank_account.rb +0 -32
  146. data/lib/stripe/bitcoin_transaction.rb +0 -15
  147. data/lib/stripe/charge.rb +0 -84
  148. data/lib/stripe/checkout/session.rb +0 -11
  149. data/lib/stripe/customer.rb +0 -90
  150. data/lib/stripe/dispute.rb +0 -19
  151. data/lib/stripe/file.rb +0 -37
  152. data/lib/stripe/invoice.rb +0 -48
  153. data/lib/stripe/issuer_fraud_record.rb +0 -9
  154. data/lib/stripe/issuing/authorization.rb +0 -22
  155. data/lib/stripe/issuing/card.rb +0 -18
  156. data/lib/stripe/issuing/card_details.rb +0 -9
  157. data/lib/stripe/login_link.rb +0 -11
  158. data/lib/stripe/order.rb +0 -31
  159. data/lib/stripe/payment_intent.rb +0 -26
  160. data/lib/stripe/payment_method.rb +0 -23
  161. data/lib/stripe/payout.rb +0 -20
  162. data/lib/stripe/reversal.rb +0 -22
  163. data/lib/stripe/review.rb +0 -14
  164. data/lib/stripe/source.rb +0 -38
  165. data/lib/stripe/subscription.rb +0 -25
  166. data/lib/stripe/subscription_item.rb +0 -17
  167. data/lib/stripe/subscription_schedule.rb +0 -32
  168. data/lib/stripe/subscription_schedule_revision.rb +0 -25
  169. data/lib/stripe/terminal/connection_token.rb +0 -11
  170. data/lib/stripe/topup.rb +0 -16
  171. data/lib/stripe/transfer.rb +0 -23
  172. data/lib/stripe/usage_record.rb +0 -14
  173. data/test/api_stub_helpers.rb +0 -1
  174. data/test/openapi/README.md +0 -9
  175. data/test/stripe/account_external_accounts_operations_test.rb +0 -69
  176. data/test/stripe/account_link_test.rb +0 -18
  177. data/test/stripe/account_login_links_operations_test.rb +0 -21
  178. data/test/stripe/account_persons_operations_test.rb +0 -70
  179. data/test/stripe/account_test.rb +0 -256
  180. data/test/stripe/alipay_account_test.rb +0 -37
  181. data/test/stripe/api_operations_test.rb +0 -81
  182. data/test/stripe/api_resource_test.rb +0 -526
  183. data/test/stripe/apple_pay_domain_test.rb +0 -33
  184. data/test/stripe/application_fee_refund_test.rb +0 -37
  185. data/test/stripe/application_fee_refunds_operations_test.rb +0 -56
  186. data/test/stripe/application_fee_test.rb +0 -14
  187. data/test/stripe/balance_test.rb +0 -13
  188. data/test/stripe/bank_account_test.rb +0 -36
  189. data/test/stripe/charge_test.rb +0 -59
  190. data/test/stripe/checkout/session_test.rb +0 -41
  191. data/test/stripe/country_spec_test.rb +0 -20
  192. data/test/stripe/coupon_test.rb +0 -51
  193. data/test/stripe/customer_card_test.rb +0 -42
  194. data/test/stripe/customer_sources_operations_test.rb +0 -64
  195. data/test/stripe/customer_test.rb +0 -115
  196. data/test/stripe/dispute_test.rb +0 -42
  197. data/test/stripe/ephemeral_key_test.rb +0 -86
  198. data/test/stripe/errors_test.rb +0 -20
  199. data/test/stripe/exchange_rate_test.rb +0 -20
  200. data/test/stripe/file_link_test.rb +0 -41
  201. data/test/stripe/file_test.rb +0 -73
  202. data/test/stripe/file_upload_test.rb +0 -76
  203. data/test/stripe/invoice_item_test.rb +0 -55
  204. data/test/stripe/invoice_line_item_test.rb +0 -8
  205. data/test/stripe/invoice_test.rb +0 -161
  206. data/test/stripe/issuer_fraud_record_test.rb +0 -20
  207. data/test/stripe/issuing/authorization_test.rb +0 -50
  208. data/test/stripe/issuing/card_test.rb +0 -53
  209. data/test/stripe/issuing/cardholder_test.rb +0 -53
  210. data/test/stripe/issuing/dispute_test.rb +0 -45
  211. data/test/stripe/issuing/transaction_test.rb +0 -48
  212. data/test/stripe/list_object_test.rb +0 -156
  213. data/test/stripe/login_link_test.rb +0 -37
  214. data/test/stripe/oauth_test.rb +0 -88
  215. data/test/stripe/order_return_test.rb +0 -21
  216. data/test/stripe/order_test.rb +0 -57
  217. data/test/stripe/payment_intent_test.rb +0 -80
  218. data/test/stripe/payment_method_test.rb +0 -66
  219. data/test/stripe/payout_test.rb +0 -50
  220. data/test/stripe/person_test.rb +0 -46
  221. data/test/stripe/plan_test.rb +0 -92
  222. data/test/stripe/product_test.rb +0 -49
  223. data/test/stripe/radar/value_list_item_test.rb +0 -38
  224. data/test/stripe/radar/value_list_test.rb +0 -51
  225. data/test/stripe/recipient_test.rb +0 -49
  226. data/test/stripe/refund_test.rb +0 -39
  227. data/test/stripe/reporting/report_run_test.rb +0 -33
  228. data/test/stripe/reporting/report_type_test.rb +0 -22
  229. data/test/stripe/reversal_test.rb +0 -43
  230. data/test/stripe/review_test.rb +0 -27
  231. data/test/stripe/sigma/scheduled_query_run_test.rb +0 -22
  232. data/test/stripe/sku_test.rb +0 -50
  233. data/test/stripe/source_test.rb +0 -86
  234. data/test/stripe/source_transaction_test.rb +0 -19
  235. data/test/stripe/stripe_client_test.rb +0 -823
  236. data/test/stripe/stripe_object_test.rb +0 -525
  237. data/test/stripe/stripe_response_test.rb +0 -49
  238. data/test/stripe/subscription_item_test.rb +0 -53
  239. data/test/stripe/subscription_schedule_revision_test.rb +0 -37
  240. data/test/stripe/subscription_schedule_revisions_operations_test.rb +0 -35
  241. data/test/stripe/subscription_schedule_test.rb +0 -64
  242. data/test/stripe/subscription_test.rb +0 -60
  243. data/test/stripe/terminal/connection_token_test.rb +0 -16
  244. data/test/stripe/terminal/location_test.rb +0 -58
  245. data/test/stripe/terminal/reader_test.rb +0 -52
  246. data/test/stripe/three_d_secure_test.rb +0 -23
  247. data/test/stripe/topup_test.rb +0 -54
  248. data/test/stripe/transfer_reversals_operations_test.rb +0 -57
  249. data/test/stripe/transfer_test.rb +0 -43
  250. data/test/stripe/usage_record_summary_test.rb +0 -19
  251. data/test/stripe/usage_record_test.rb +0 -28
  252. data/test/stripe/util_test.rb +0 -402
  253. data/test/stripe/webhook_endpoint_test.rb +0 -42
  254. data/test/stripe/webhook_test.rb +0 -96
  255. data/test/stripe_mock.rb +0 -77
  256. data/test/stripe_test.rb +0 -63
  257. data/test/test_data.rb +0 -61
  258. data/test/test_helper.rb +0 -73
@@ -0,0 +1,194 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stripe
4
+ # Configurable options:
5
+ #
6
+ # =ca_bundle_path=
7
+ # The location of a file containing a bundle of CA certificates. By default
8
+ # the library will use an included bundle that can successfully validate
9
+ # Stripe certificates.
10
+ #
11
+ # =log_level=
12
+ # When set prompts the library to log some extra information to $stdout and
13
+ # $stderr about what it's doing. For example, it'll produce information about
14
+ # requests, responses, and errors that are received. Valid log levels are
15
+ # `debug` and `info`, with `debug` being a little more verbose in places.
16
+ #
17
+ # Use of this configuration is only useful when `.logger` is _not_ set. When
18
+ # it is, the decision what levels to print is entirely deferred to the logger.
19
+ #
20
+ # =logger=
21
+ # The logger should support the same interface as the `Logger` class that's
22
+ # part of Ruby's standard library (hint, anything in `Rails.logger` will
23
+ # likely be suitable).
24
+ #
25
+ # If `.logger` is set, the value of `.log_level` is ignored. The decision on
26
+ # what levels to print is entirely deferred to the logger.
27
+ class StripeConfiguration
28
+ attr_accessor :api_key
29
+ attr_accessor :api_version
30
+ attr_accessor :client_id
31
+ attr_accessor :enable_telemetry
32
+ attr_accessor :logger
33
+ attr_accessor :stripe_account
34
+
35
+ attr_reader :api_base
36
+ attr_reader :uploads_base
37
+ attr_reader :connect_base
38
+ attr_reader :ca_bundle_path
39
+ attr_reader :log_level
40
+ attr_reader :initial_network_retry_delay
41
+ attr_reader :max_network_retries
42
+ attr_reader :max_network_retry_delay
43
+ attr_reader :open_timeout
44
+ attr_reader :read_timeout
45
+ attr_reader :write_timeout
46
+ attr_reader :proxy
47
+ attr_reader :verify_ssl_certs
48
+
49
+ def self.setup
50
+ new.tap do |instance|
51
+ yield(instance) if block_given?
52
+ end
53
+ end
54
+
55
+ # Create a new config based off an existing one. This is useful when the
56
+ # caller wants to override the global configuration
57
+ def reverse_duplicate_merge(hash)
58
+ dup.tap do |instance|
59
+ hash.each do |option, value|
60
+ instance.public_send("#{option}=", value)
61
+ end
62
+ end
63
+ end
64
+
65
+ def initialize
66
+ @ca_bundle_path = Stripe::DEFAULT_CA_BUNDLE_PATH
67
+ @enable_telemetry = true
68
+ @verify_ssl_certs = true
69
+
70
+ @max_network_retries = 0
71
+ @initial_network_retry_delay = 0.5
72
+ @max_network_retry_delay = 2
73
+
74
+ @open_timeout = 30
75
+ @read_timeout = 80
76
+ @write_timeout = 30
77
+
78
+ @api_base = "https://api.stripe.com"
79
+ @connect_base = "https://connect.stripe.com"
80
+ @uploads_base = "https://files.stripe.com"
81
+ end
82
+
83
+ def log_level=(val)
84
+ # Backwards compatibility for values that we briefly allowed
85
+ if val == "debug"
86
+ val = Stripe::LEVEL_DEBUG
87
+ elsif val == "info"
88
+ val = Stripe::LEVEL_INFO
89
+ end
90
+
91
+ levels = [Stripe::LEVEL_INFO, Stripe::LEVEL_DEBUG, Stripe::LEVEL_ERROR]
92
+
93
+ if !val.nil? && !levels.include?(val)
94
+ raise ArgumentError,
95
+ "log_level should only be set to `nil`, `debug` or `info`"
96
+ end
97
+ @log_level = val
98
+ end
99
+
100
+ def max_network_retries=(val)
101
+ @max_network_retries = val.to_i
102
+ end
103
+
104
+ def max_network_retry_delay=(val)
105
+ @max_network_retry_delay = val.to_i
106
+ end
107
+
108
+ def initial_network_retry_delay=(val)
109
+ @initial_network_retry_delay = val.to_i
110
+ end
111
+
112
+ def open_timeout=(open_timeout)
113
+ @open_timeout = open_timeout
114
+ StripeClient.clear_all_connection_managers(config: self)
115
+ end
116
+
117
+ def read_timeout=(read_timeout)
118
+ @read_timeout = read_timeout
119
+ StripeClient.clear_all_connection_managers(config: self)
120
+ end
121
+
122
+ def write_timeout=(write_timeout)
123
+ unless Net::HTTP.instance_methods.include?(:write_timeout=)
124
+ raise NotImplementedError
125
+ end
126
+
127
+ @write_timeout = write_timeout
128
+ StripeClient.clear_all_connection_managers(config: self)
129
+ end
130
+
131
+ def proxy=(proxy)
132
+ @proxy = proxy
133
+ StripeClient.clear_all_connection_managers(config: self)
134
+ end
135
+
136
+ def verify_ssl_certs=(verify_ssl_certs)
137
+ @verify_ssl_certs = verify_ssl_certs
138
+ StripeClient.clear_all_connection_managers(config: self)
139
+ end
140
+
141
+ def uploads_base=(uploads_base)
142
+ @uploads_base = uploads_base
143
+ StripeClient.clear_all_connection_managers(config: self)
144
+ end
145
+
146
+ def connect_base=(connect_base)
147
+ @connect_base = connect_base
148
+ StripeClient.clear_all_connection_managers(config: self)
149
+ end
150
+
151
+ def api_base=(api_base)
152
+ @api_base = api_base
153
+ StripeClient.clear_all_connection_managers(config: self)
154
+ end
155
+
156
+ def ca_bundle_path=(path)
157
+ @ca_bundle_path = path
158
+
159
+ # empty this field so a new store is initialized
160
+ @ca_store = nil
161
+
162
+ StripeClient.clear_all_connection_managers(config: self)
163
+ end
164
+
165
+ # A certificate store initialized from the the bundle in #ca_bundle_path and
166
+ # which is used to validate TLS on every request.
167
+ #
168
+ # This was added to the give the gem "pseudo thread safety" in that it seems
169
+ # when initiating many parallel requests marshaling the certificate store is
170
+ # the most likely point of failure (see issue #382). Any program attempting
171
+ # to leverage this pseudo safety should make a call to this method (i.e.
172
+ # `Stripe.ca_store`) in their initialization code because it marshals lazily
173
+ # and is itself not thread safe.
174
+ def ca_store
175
+ @ca_store ||= begin
176
+ store = OpenSSL::X509::Store.new
177
+ store.add_file(ca_bundle_path)
178
+ store
179
+ end
180
+ end
181
+
182
+ def enable_telemetry?
183
+ enable_telemetry
184
+ end
185
+
186
+ # Generates a deterministic key to identify configuration objects with
187
+ # identical configuration values.
188
+ def key
189
+ instance_variables
190
+ .collect { |variable| instance_variable_get(variable) }
191
+ .join
192
+ end
193
+ end
194
+ end
@@ -4,7 +4,7 @@ module Stripe
4
4
  class StripeObject
5
5
  include Enumerable
6
6
 
7
- @@permanent_attributes = Set.new([:id])
7
+ @@permanent_attributes = Set.new([:id]) # rubocop:disable Style/ClassVars
8
8
 
9
9
  # The default :id method is deprecated and isn't useful to us
10
10
  undef :id if method_defined?(:id)
@@ -93,10 +93,12 @@ module Stripe
93
93
  # considered to be equal if they have the same set of values and each one
94
94
  # of those values is the same.
95
95
  def ==(other)
96
- other.is_a?(StripeObject) && @values == other.instance_variable_get(:@values)
96
+ other.is_a?(StripeObject) &&
97
+ @values == other.instance_variable_get(:@values)
97
98
  end
98
99
 
99
- # Hash equality. As with `#==`, we consider two equivalent Stripe objects equal.
100
+ # Hash equality. As with `#==`, we consider two equivalent Stripe objects
101
+ # equal.
100
102
  def eql?(other)
101
103
  # Defer to the implementation on `#==`.
102
104
  self == other
@@ -121,21 +123,10 @@ module Stripe
121
123
 
122
124
  def inspect
123
125
  id_string = respond_to?(:id) && !id.nil? ? " id=#{id}" : ""
124
- "#<#{self.class}:0x#{object_id.to_s(16)}#{id_string}> JSON: " + JSON.pretty_generate(@values)
126
+ "#<#{self.class}:0x#{object_id.to_s(16)}#{id_string}> JSON: " +
127
+ JSON.pretty_generate(@values)
125
128
  end
126
129
 
127
- # Re-initializes the object based on a hash of values (usually one that's
128
- # come back from an API call). Adds or removes value accessors as necessary
129
- # and updates the state of internal data.
130
- #
131
- # Please don't use this method. If you're trying to do mass assignment, try
132
- # #initialize_from instead.
133
- def refresh_from(values, opts, partial = false)
134
- initialize_from(values, opts, partial)
135
- end
136
- extend Gem::Deprecate
137
- deprecate :refresh_from, "#update_attributes", 2016, 1
138
-
139
130
  # Mass assigns attributes on the model.
140
131
  #
141
132
  # This is a version of +update_attributes+ that takes some extra options
@@ -144,7 +135,8 @@ module Stripe
144
135
  # ==== Attributes
145
136
  #
146
137
  # * +values+ - Hash of values to use to update the current attributes of
147
- # the object.
138
+ # the object. If you are on ruby 2.7 or higher make sure to wrap in curly
139
+ # braces to be ruby 3 compatible.
148
140
  # * +opts+ - Options for +StripeObject+ like an API key that will be reused
149
141
  # on subsequent API calls.
150
142
  #
@@ -162,12 +154,12 @@ module Stripe
162
154
  end
163
155
  end
164
156
 
165
- def [](k)
166
- @values[k.to_sym]
157
+ def [](key)
158
+ @values[key.to_sym]
167
159
  end
168
160
 
169
- def []=(k, v)
170
- send(:"#{k}=", v)
161
+ def []=(key, value)
162
+ send(:"#{key}=", value)
171
163
  end
172
164
 
173
165
  def keys
@@ -178,17 +170,20 @@ module Stripe
178
170
  @values.values
179
171
  end
180
172
 
181
- def to_json(*_a)
173
+ def to_json(*_opts)
174
+ # TODO: pass opts to JSON.generate?
182
175
  JSON.generate(@values)
183
176
  end
184
177
 
185
- def as_json(*a)
186
- @values.as_json(*a)
178
+ def as_json(*opts)
179
+ @values.as_json(*opts)
187
180
  end
188
181
 
189
182
  def to_hash
190
183
  maybe_to_hash = lambda do |value|
191
- value && value.respond_to?(:to_hash) ? value.to_hash : value
184
+ return nil if value.nil?
185
+
186
+ value.respond_to?(:to_hash) ? value.to_hash : value
192
187
  end
193
188
 
194
189
  @values.each_with_object({}) do |(key, value), acc|
@@ -251,10 +246,11 @@ module Stripe
251
246
  # values within in that its parent StripeObject doesn't know about.
252
247
  #
253
248
  unsaved = @unsaved_values.include?(k)
254
- if options[:force] || unsaved || v.is_a?(StripeObject)
255
- update_hash[k.to_sym] =
256
- serialize_params_value(@values[k], @original_values[k], unsaved, options[:force], key: k)
257
- end
249
+ next unless options[:force] || unsaved || v.is_a?(StripeObject)
250
+
251
+ update_hash[k.to_sym] = serialize_params_value(
252
+ @values[k], @original_values[k], unsaved, options[:force], key: k
253
+ )
258
254
  end
259
255
 
260
256
  # a `nil` that makes it out of `#serialize_params_value` signals an empty
@@ -264,16 +260,6 @@ module Stripe
264
260
  update_hash
265
261
  end
266
262
 
267
- class << self
268
- # This class method has been deprecated in favor of the instance method
269
- # of the same name.
270
- def serialize_params(obj, options = {})
271
- obj.serialize_params(options)
272
- end
273
- extend Gem::Deprecate
274
- deprecate :serialize_params, "#serialize_params", 2016, 9
275
- end
276
-
277
263
  # A protected field is one that doesn't get an accessor assigned to it
278
264
  # (i.e. `obj.public = ...`) and one which is not allowed to be updated via
279
265
  # the class level `Model.update(id, { ... })`.
@@ -281,18 +267,38 @@ module Stripe
281
267
  []
282
268
  end
283
269
 
284
- protected
285
-
286
- def metaclass
270
+ # When designing APIs, we now make a conscious effort server-side to avoid
271
+ # naming fields after important built-ins in various languages (e.g. class,
272
+ # method, etc.).
273
+ #
274
+ # However, a long time ago we made the mistake (either consciously or by
275
+ # accident) of initializing our `metadata` fields as instances of
276
+ # `StripeObject`, and metadata can have a wide range of different keys
277
+ # defined in it. This is somewhat a convenient in that it allows users to
278
+ # access data like `obj.metadata.my_field`, but is almost certainly not
279
+ # worth the cost.
280
+ #
281
+ # Naming metadata fields bad things like `class` causes `initialize_from`
282
+ # to produce strange results, so we ban known offenders here.
283
+ #
284
+ # In a future major version we should consider leaving `metadata` as a hash
285
+ # and forcing people to access it with `obj.metadata[:my_field]` because
286
+ # the potential for trouble is just too high. For now, reserve names.
287
+ RESERVED_FIELD_NAMES = [
288
+ :class,
289
+ ].freeze
290
+
291
+ protected def metaclass
287
292
  class << self; self; end
288
293
  end
289
294
 
290
- def remove_accessors(keys)
295
+ protected def remove_accessors(keys)
291
296
  # not available in the #instance_eval below
292
297
  protected_fields = self.class.protected_fields
293
298
 
294
299
  metaclass.instance_eval do
295
300
  keys.each do |k|
301
+ next if RESERVED_FIELD_NAMES.include?(k)
296
302
  next if protected_fields.include?(k)
297
303
  next if @@permanent_attributes.include?(k)
298
304
 
@@ -313,7 +319,7 @@ module Stripe
313
319
  #
314
320
  # Here we swallow that error and issue a warning so at least
315
321
  # the program doesn't crash.
316
- $stderr.puts("WARNING: Unable to remove method `#{method_name}`; " \
322
+ warn("WARNING: Unable to remove method `#{method_name}`; " \
317
323
  "if custom, please consider renaming to a name that doesn't " \
318
324
  "collide with an API property name.")
319
325
  end
@@ -322,12 +328,13 @@ module Stripe
322
328
  end
323
329
  end
324
330
 
325
- def add_accessors(keys, values)
331
+ protected def add_accessors(keys, values)
326
332
  # not available in the #instance_eval below
327
333
  protected_fields = self.class.protected_fields
328
334
 
329
335
  metaclass.instance_eval do
330
336
  keys.each do |k|
337
+ next if RESERVED_FIELD_NAMES.include?(k)
331
338
  next if protected_fields.include?(k)
332
339
  next if @@permanent_attributes.include?(k)
333
340
 
@@ -359,7 +366,11 @@ module Stripe
359
366
  end
360
367
  end
361
368
 
362
- def method_missing(name, *args)
369
+ # Disabling the cop because it's confused by the fact that the methods are
370
+ # protected, but we do define `#respond_to_missing?` just below. Hopefully
371
+ # this is fixed in more recent Rubocop versions.
372
+ # rubocop:disable Style/MissingRespondToMissing
373
+ protected def method_missing(name, *args)
363
374
  # TODO: only allow setting in updateable classes.
364
375
  if name.to_s.end_with?("=")
365
376
  attr = name.to_s[0...-1].to_sym
@@ -375,7 +386,9 @@ module Stripe
375
386
  begin
376
387
  mth = method(name)
377
388
  rescue NameError
378
- raise NoMethodError, "Cannot set #{attr} on this object. HINT: you can't set: #{@@permanent_attributes.to_a.join(', ')}"
389
+ raise NoMethodError,
390
+ "Cannot set #{attr} on this object. HINT: you can't set: " \
391
+ "#{@@permanent_attributes.to_a.join(', ')}"
379
392
  end
380
393
  return mth.call(args[0])
381
394
  elsif @values.key?(name)
@@ -385,16 +398,22 @@ module Stripe
385
398
  begin
386
399
  super
387
400
  rescue NoMethodError => e
388
- # If we notice the accessed name if our set of transient values we can
401
+ # If we notice the accessed name of our set of transient values we can
389
402
  # give the user a slightly more helpful error message. If not, just
390
403
  # raise right away.
391
404
  raise unless @transient_values.include?(name)
392
405
 
393
- raise NoMethodError, e.message + ". HINT: The '#{name}' attribute was set in the past, however. It was then wiped when refreshing the object with the result returned by Stripe's API, probably as a result of a save(). The attributes currently available on this object are: #{@values.keys.join(', ')}"
406
+ raise NoMethodError,
407
+ e.message + ". HINT: The '#{name}' attribute was set in the " \
408
+ "past, however. It was then wiped when refreshing the object " \
409
+ "with the result returned by Stripe's API, probably as a " \
410
+ "result of a save(). The attributes currently available on " \
411
+ "this object are: #{@values.keys.join(', ')}"
394
412
  end
395
413
  end
414
+ # rubocop:enable Style/MissingRespondToMissing
396
415
 
397
- def respond_to_missing?(symbol, include_private = false)
416
+ protected def respond_to_missing?(symbol, include_private = false)
398
417
  @values && @values.key?(symbol) || super
399
418
  end
400
419
 
@@ -410,7 +429,7 @@ module Stripe
410
429
  # * +:opts:+ Options for StripeObject like an API key.
411
430
  # * +:partial:+ Indicates that the re-initialization should not attempt to
412
431
  # remove accessors.
413
- def initialize_from(values, opts, partial = false)
432
+ protected def initialize_from(values, opts, partial = false)
414
433
  @opts = Util.normalize_opts(opts)
415
434
 
416
435
  # the `#send` is here so that we can keep this method private
@@ -420,8 +439,8 @@ module Stripe
420
439
  added = Set.new(values.keys - @values.keys)
421
440
 
422
441
  # Wipe old state before setting new. This is useful for e.g. updating a
423
- # customer, where there is no persistent card parameter. Mark those values
424
- # which don't persist as transient
442
+ # customer, where there is no persistent card parameter. Mark those
443
+ # values which don't persist as transient
425
444
 
426
445
  remove_accessors(removed)
427
446
  add_accessors(added, values)
@@ -441,7 +460,8 @@ module Stripe
441
460
  self
442
461
  end
443
462
 
444
- def serialize_params_value(value, original, unsaved, force, key: nil)
463
+ protected def serialize_params_value(value, original, unsaved, force,
464
+ key: nil)
445
465
  if value.nil?
446
466
  ""
447
467
 
@@ -516,11 +536,9 @@ module Stripe
516
536
  end
517
537
  end
518
538
 
519
- private
520
-
521
539
  # Produces a deep copy of the given object including support for arrays,
522
540
  # hashes, and StripeObjects.
523
- def self.deep_copy(obj)
541
+ private_class_method def self.deep_copy(obj)
524
542
  case obj
525
543
  when Array
526
544
  obj.map { |e| deep_copy(e) }
@@ -540,9 +558,8 @@ module Stripe
540
558
  obj
541
559
  end
542
560
  end
543
- private_class_method :deep_copy
544
561
 
545
- def dirty_value!(value)
562
+ private def dirty_value!(value)
546
563
  case value
547
564
  when Array
548
565
  value.map { |v| dirty_value!(v) }
@@ -553,12 +570,14 @@ module Stripe
553
570
 
554
571
  # Returns a hash of empty values for all the values that are in the given
555
572
  # StripeObject.
556
- def empty_values(obj)
573
+ private def empty_values(obj)
557
574
  values = case obj
558
575
  when Hash then obj
559
576
  when StripeObject then obj.instance_variable_get(:@values)
560
577
  else
561
- raise ArgumentError, "#empty_values got unexpected object type: #{obj.class.name}"
578
+ raise ArgumentError,
579
+ "#empty_values got unexpected object type: " \
580
+ "#{obj.class.name}"
562
581
  end
563
582
 
564
583
  values.each_with_object({}) do |(k, _), update|
@@ -1,16 +1,54 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Stripe
4
- # StripeResponse encapsulates some vitals of a response that came back from
5
- # the Stripe API.
6
- class StripeResponse
7
- # The data contained by the HTTP body of the response deserialized from
8
- # JSON.
9
- attr_accessor :data
4
+ # Headers provides an access wrapper to an API response's header data. It
5
+ # mainly exists so that we don't need to expose the entire
6
+ # `Net::HTTPResponse` object while still getting some of its benefits like
7
+ # case-insensitive access to header names and flattening of header values.
8
+ class StripeResponseHeaders
9
+ # Initializes a Headers object from a Net::HTTP::HTTPResponse object.
10
+ def self.from_net_http(resp)
11
+ new(resp.to_hash)
12
+ end
10
13
 
11
- # The raw HTTP body of the response.
12
- attr_accessor :http_body
14
+ # `hash` is expected to be a hash mapping header names to arrays of
15
+ # header values. This is the default format generated by calling
16
+ # `#to_hash` on a `Net::HTTPResponse` object because headers can be
17
+ # repeated multiple times. Using `#[]` will collapse values down to just
18
+ # the first.
19
+ def initialize(hash)
20
+ if !hash.is_a?(Hash) ||
21
+ !hash.keys.all? { |n| n.is_a?(String) } ||
22
+ !hash.values.all? { |a| a.is_a?(Array) } ||
23
+ !hash.values.all? { |a| a.all? { |v| v.is_a?(String) } }
24
+ raise ArgumentError,
25
+ "expect hash to be a map of string header names to arrays of " \
26
+ "header values"
27
+ end
13
28
 
29
+ @hash = {}
30
+
31
+ # This shouldn't be strictly necessary because `Net::HTTPResponse` will
32
+ # produce a hash with all headers downcased, but do it anyway just in
33
+ # case an object of this class was constructed manually.
34
+ #
35
+ # Also has the effect of duplicating the hash, which is desirable for a
36
+ # little extra object safety.
37
+ hash.each do |k, v|
38
+ @hash[k.downcase] = v
39
+ end
40
+ end
41
+
42
+ def [](name)
43
+ values = @hash[name.downcase]
44
+ if values && values.count > 1
45
+ warn("Duplicate header values for `#{name}`; returning only first")
46
+ end
47
+ values ? values.first : nil
48
+ end
49
+ end
50
+
51
+ module StripeResponseBase
14
52
  # A Hash of the HTTP headers of the response.
15
53
  attr_accessor :http_headers
16
54
 
@@ -20,30 +58,52 @@ module Stripe
20
58
  # The Stripe request ID of the response.
21
59
  attr_accessor :request_id
22
60
 
23
- # Initializes a StripeResponse object from a Hash like the kind returned as
24
- # part of a Faraday exception.
25
- #
26
- # This may throw JSON::ParserError if the response body is not valid JSON.
27
- def self.from_faraday_hash(http_resp)
28
- resp = StripeResponse.new
29
- resp.data = JSON.parse(http_resp[:body], symbolize_names: true)
30
- resp.http_body = http_resp[:body]
31
- resp.http_headers = http_resp[:headers]
32
- resp.http_status = http_resp[:status]
33
- resp.request_id = http_resp[:headers]["Request-Id"]
34
- resp
61
+ def self.populate_for_net_http(resp, http_resp)
62
+ resp.http_headers = StripeResponseHeaders.from_net_http(http_resp)
63
+ resp.http_status = http_resp.code.to_i
64
+ resp.request_id = http_resp["request-id"]
35
65
  end
66
+ end
36
67
 
37
- # Initializes a StripeResponse object from a Faraday HTTP response object.
38
- #
39
- # This may throw JSON::ParserError if the response body is not valid JSON.
40
- def self.from_faraday_response(http_resp)
68
+ # StripeResponse encapsulates some vitals of a response that came back from
69
+ # the Stripe API.
70
+ class StripeResponse
71
+ include StripeResponseBase
72
+ # The data contained by the HTTP body of the response deserialized from
73
+ # JSON.
74
+ attr_accessor :data
75
+
76
+ # The raw HTTP body of the response.
77
+ attr_accessor :http_body
78
+
79
+ # Initializes a StripeResponse object from a Net::HTTP::HTTPResponse
80
+ # object.
81
+ def self.from_net_http(http_resp)
41
82
  resp = StripeResponse.new
42
83
  resp.data = JSON.parse(http_resp.body, symbolize_names: true)
43
84
  resp.http_body = http_resp.body
44
- resp.http_headers = http_resp.headers
45
- resp.http_status = http_resp.status
46
- resp.request_id = http_resp.headers["Request-Id"]
85
+ StripeResponseBase.populate_for_net_http(resp, http_resp)
86
+ resp
87
+ end
88
+ end
89
+
90
+ # We have to alias StripeResponseHeaders to StripeResponse::Headers, as this
91
+ # class used to be embedded within StripeResponse and we want to be backwards
92
+ # compatible.
93
+ StripeResponse::Headers = StripeResponseHeaders
94
+
95
+ # StripeHeadersOnlyResponse includes only header-related vitals of the
96
+ # response. This is used for streaming requests where the response was read
97
+ # directly in a block and we explicitly don't want to store the body of the
98
+ # response in memory.
99
+ class StripeHeadersOnlyResponse
100
+ include StripeResponseBase
101
+
102
+ # Initializes a StripeHeadersOnlyResponse object from a
103
+ # Net::HTTP::HTTPResponse object.
104
+ def self.from_net_http(http_resp)
105
+ resp = StripeHeadersOnlyResponse.new
106
+ StripeResponseBase.populate_for_net_http(resp, http_resp)
47
107
  resp
48
108
  end
49
109
  end