stripe 3.3.2 → 3.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +20 -0
  4. data/.rubocop_todo.yml +62 -0
  5. data/.travis.yml +1 -1
  6. data/Gemfile +19 -12
  7. data/History.txt +10 -0
  8. data/README.md +5 -1
  9. data/Rakefile +8 -5
  10. data/VERSION +1 -1
  11. data/bin/stripe-console +2 -2
  12. data/lib/stripe.rb +72 -74
  13. data/lib/stripe/account.rb +15 -17
  14. data/lib/stripe/alipay_account.rb +10 -7
  15. data/lib/stripe/api_operations/create.rb +1 -1
  16. data/lib/stripe/api_operations/delete.rb +1 -1
  17. data/lib/stripe/api_operations/list.rb +2 -2
  18. data/lib/stripe/api_operations/request.rb +5 -12
  19. data/lib/stripe/api_operations/save.rb +6 -6
  20. data/lib/stripe/api_resource.rb +7 -9
  21. data/lib/stripe/apple_pay_domain.rb +2 -2
  22. data/lib/stripe/application_fee.rb +5 -5
  23. data/lib/stripe/application_fee_refund.rb +5 -5
  24. data/lib/stripe/balance.rb +1 -1
  25. data/lib/stripe/balance_transaction.rb +2 -2
  26. data/lib/stripe/bank_account.rb +7 -7
  27. data/lib/stripe/bitcoin_receiver.rb +4 -2
  28. data/lib/stripe/bitcoin_transaction.rb +3 -1
  29. data/lib/stripe/card.rb +5 -5
  30. data/lib/stripe/charge.rb +18 -18
  31. data/lib/stripe/country_spec.rb +2 -2
  32. data/lib/stripe/coupon.rb +1 -1
  33. data/lib/stripe/customer.rb +23 -23
  34. data/lib/stripe/dispute.rb +3 -3
  35. data/lib/stripe/ephemeral_key.rb +4 -4
  36. data/lib/stripe/errors.rb +4 -4
  37. data/lib/stripe/event.rb +1 -1
  38. data/lib/stripe/file_upload.rb +5 -5
  39. data/lib/stripe/invoice.rb +7 -7
  40. data/lib/stripe/invoice_item.rb +1 -1
  41. data/lib/stripe/invoice_line_item.rb +1 -1
  42. data/lib/stripe/list_object.rb +14 -18
  43. data/lib/stripe/login_link.rb +3 -3
  44. data/lib/stripe/oauth.rb +15 -13
  45. data/lib/stripe/order.rb +5 -5
  46. data/lib/stripe/order_return.rb +1 -1
  47. data/lib/stripe/payout.rb +3 -3
  48. data/lib/stripe/plan.rb +1 -1
  49. data/lib/stripe/product.rb +1 -1
  50. data/lib/stripe/recipient.rb +3 -2
  51. data/lib/stripe/recipient_transfer.rb +1 -2
  52. data/lib/stripe/refund.rb +1 -1
  53. data/lib/stripe/reversal.rb +5 -5
  54. data/lib/stripe/singleton_api_resource.rb +3 -3
  55. data/lib/stripe/sku.rb +1 -1
  56. data/lib/stripe/source.rb +13 -10
  57. data/lib/stripe/stripe_client.rb +149 -169
  58. data/lib/stripe/stripe_object.rb +77 -76
  59. data/lib/stripe/subscription.rb +5 -5
  60. data/lib/stripe/subscription_item.rb +2 -2
  61. data/lib/stripe/three_d_secure.rb +1 -1
  62. data/lib/stripe/token.rb +1 -1
  63. data/lib/stripe/transfer.rb +3 -3
  64. data/lib/stripe/util.rb +77 -62
  65. data/lib/stripe/version.rb +1 -1
  66. data/lib/stripe/webhook.rb +14 -10
  67. data/stripe.gemspec +14 -14
  68. data/test/stripe/account_test.rb +69 -81
  69. data/test/stripe/alipay_account_test.rb +19 -1
  70. data/test/stripe/api_operations_test.rb +7 -7
  71. data/test/stripe/api_resource_test.rb +224 -260
  72. data/test/stripe/apple_pay_domain_test.rb +8 -8
  73. data/test/stripe/application_fee_refund_test.rb +8 -8
  74. data/test/stripe/application_fee_test.rb +3 -3
  75. data/test/stripe/balance_test.rb +2 -2
  76. data/test/stripe/bank_account_test.rb +9 -11
  77. data/test/stripe/charge_test.rb +11 -11
  78. data/test/stripe/country_spec_test.rb +4 -4
  79. data/test/stripe/coupon_test.rb +10 -10
  80. data/test/stripe/customer_card_test.rb +11 -15
  81. data/test/stripe/customer_test.rb +26 -27
  82. data/test/stripe/dispute_test.rb +8 -8
  83. data/test/stripe/ephemeral_key_test.rb +14 -14
  84. data/test/stripe/errors_test.rb +2 -2
  85. data/test/stripe/file_upload_test.rb +26 -28
  86. data/test/stripe/invoice_item_test.rb +14 -14
  87. data/test/stripe/invoice_line_item_test.rb +1 -1
  88. data/test/stripe/invoice_test.rb +37 -37
  89. data/test/stripe/list_object_test.rb +60 -76
  90. data/test/stripe/login_link_test.rb +14 -14
  91. data/test/stripe/oauth_test.rb +42 -50
  92. data/test/stripe/order_return_test.rb +5 -5
  93. data/test/stripe/order_test.rb +12 -12
  94. data/test/stripe/payout_test.rb +9 -9
  95. data/test/stripe/plan_test.rb +9 -9
  96. data/test/stripe/product_test.rb +8 -8
  97. data/test/stripe/recipient_test.rb +9 -10
  98. data/test/stripe/refund_test.rb +9 -9
  99. data/test/stripe/reversal_test.rb +10 -10
  100. data/test/stripe/sku_test.rb +8 -8
  101. data/test/stripe/source_test.rb +14 -16
  102. data/test/stripe/stripe_client_test.rb +235 -266
  103. data/test/stripe/stripe_object_test.rb +163 -147
  104. data/test/stripe/stripe_response_test.rb +4 -3
  105. data/test/stripe/subscription_item_test.rb +11 -11
  106. data/test/stripe/subscription_test.rb +14 -14
  107. data/test/stripe/three_d_secure_test.rb +2 -2
  108. data/test/stripe/transfer_test.rb +8 -8
  109. data/test/stripe/util_test.rb +59 -57
  110. data/test/stripe/webhook_test.rb +18 -16
  111. data/test/stripe_test.rb +4 -4
  112. data/test/test_data.rb +26 -26
  113. data/test/test_helper.rb +29 -25
  114. metadata +6 -10
  115. data/test/stripe/bitcoin_receiver_test.rb +0 -67
  116. data/test/stripe/bitcoin_transaction_test.rb +0 -19
  117. data/test/stripe/recipient_card_test.rb +0 -44
@@ -5,11 +5,9 @@ module Stripe
5
5
  @@permanent_attributes = Set.new([:id])
6
6
 
7
7
  # The default :id method is deprecated and isn't useful to us
8
- if method_defined?(:id)
9
- undef :id
10
- end
8
+ undef :id if method_defined?(:id)
11
9
 
12
- def initialize(id=nil, opts={})
10
+ def initialize(id = nil, opts = {})
13
11
  id, @retrieve_params = Util.normalize_id(id)
14
12
  @opts = Util.normalize_opts(opts)
15
13
  @original_values = {}
@@ -21,11 +19,11 @@ module Stripe
21
19
  @values[:id] = id if id
22
20
  end
23
21
 
24
- def self.construct_from(values, opts={})
22
+ def self.construct_from(values, opts = {})
25
23
  values = Stripe::Util.symbolize_names(values)
26
24
 
27
25
  # work around protected #initialize_from for now
28
- self.new(values[:id]).send(:initialize_from, values, opts)
26
+ new(values[:id]).send(:initialize_from, values, opts)
29
27
  end
30
28
 
31
29
  # Determines the equality of two Stripe objects. Stripe objects are
@@ -42,13 +40,13 @@ module Stripe
42
40
  @values.fetch(:deleted, false)
43
41
  end
44
42
 
45
- def to_s(*args)
43
+ def to_s(*_args)
46
44
  JSON.pretty_generate(to_hash)
47
45
  end
48
46
 
49
47
  def inspect
50
- id_string = (self.respond_to?(:id) && !self.id.nil?) ? " id=#{self.id}" : ""
51
- "#<#{self.class}:0x#{self.object_id.to_s(16)}#{id_string}> JSON: " + JSON.pretty_generate(@values)
48
+ id_string = respond_to?(:id) && !id.nil? ? " id=#{id}" : ""
49
+ "#<#{self.class}:0x#{object_id.to_s(16)}#{id_string}> JSON: " + JSON.pretty_generate(@values)
52
50
  end
53
51
 
54
52
  # Re-initializes the object based on a hash of values (usually one that's
@@ -57,11 +55,11 @@ module Stripe
57
55
  #
58
56
  # Please don't use this method. If you're trying to do mass assignment, try
59
57
  # #initialize_from instead.
60
- def refresh_from(values, opts, partial=false)
58
+ def refresh_from(values, opts, partial = false)
61
59
  initialize_from(values, opts, partial)
62
60
  end
63
61
  extend Gem::Deprecate
64
- deprecate :refresh_from, "#update_attributes", 2016, 01
62
+ deprecate :refresh_from, "#update_attributes", 2016, 1
65
63
 
66
64
  # Mass assigns attributes on the model.
67
65
  #
@@ -108,7 +106,7 @@ module Stripe
108
106
  @values.values
109
107
  end
110
108
 
111
- def to_json(*a)
109
+ def to_json(*_a)
112
110
  JSON.generate(@values)
113
111
  end
114
112
 
@@ -121,14 +119,13 @@ module Stripe
121
119
  value.respond_to?(:to_hash) ? value.to_hash : value
122
120
  end
123
121
 
124
- @values.inject({}) do |acc, (key, value)|
122
+ @values.each_with_object({}) do |(key, value), acc|
125
123
  acc[key] = case value
126
124
  when Array
127
125
  value.map(&maybe_to_hash)
128
126
  else
129
127
  maybe_to_hash.call(value)
130
128
  end
131
- acc
132
129
  end
133
130
  end
134
131
 
@@ -136,27 +133,13 @@ module Stripe
136
133
  @values.each(&blk)
137
134
  end
138
135
 
139
- def _dump(level)
140
- # The StripeClient instance in @opts is not serializable and is not
141
- # really a property of the StripeObject, so we exclude it when
142
- # dumping
143
- opts = @opts.clone
144
- opts.delete(:client)
145
- Marshal.dump([@values, opts])
146
- end
147
-
148
- def self._load(args)
149
- values, opts = Marshal.load(args)
150
- construct_from(values, opts)
151
- end
152
-
153
136
  # Sets all keys within the StripeObject as unsaved so that they will be
154
137
  # included with an update when #serialize_params is called. This method is
155
138
  # also recursive, so any StripeObjects contained as values or which are
156
139
  # values in a tenant array are also marked as dirty.
157
140
  def dirty!
158
141
  @unsaved_values = Set.new(@values.keys)
159
- @values.each do |k, v|
142
+ @values.each_value do |v|
160
143
  dirty_value!(v)
161
144
  end
162
145
  end
@@ -182,7 +165,7 @@ module Stripe
182
165
 
183
166
  # a `nil` that makes it out of `#serialize_params_value` signals an empty
184
167
  # value that we shouldn't appear in the serialized form of the object
185
- update_hash.reject! { |_, v| v == nil }
168
+ update_hash.reject! { |_, v| v.nil? }
186
169
 
187
170
  update_hash
188
171
  end
@@ -197,8 +180,6 @@ module Stripe
197
180
  deprecate :serialize_params, "#serialize_params", 2016, 9
198
181
  end
199
182
 
200
- protected
201
-
202
183
  # A protected field is one that doesn't get an accessor assigned to it
203
184
  # (i.e. `obj.public = ...`) and one which is not allowed to be updated via
204
185
  # the class level `Model.update(id, { ... })`.
@@ -206,6 +187,8 @@ module Stripe
206
187
  []
207
188
  end
208
189
 
190
+ protected
191
+
209
192
  def metaclass
210
193
  class << self; self; end
211
194
  end
@@ -221,9 +204,7 @@ module Stripe
221
204
 
222
205
  # Remove methods for the accessor's reader and writer.
223
206
  [k, :"#{k}=", :"#{k}?"].each do |method_name|
224
- if method_defined?(method_name)
225
- remove_method(method_name)
226
- end
207
+ remove_method(method_name) if method_defined?(method_name)
227
208
  end
228
209
  end
229
210
  end
@@ -241,10 +222,9 @@ module Stripe
241
222
  define_method(k) { @values[k] }
242
223
  define_method(:"#{k}=") do |v|
243
224
  if v == ""
244
- raise ArgumentError.new(
245
- "You cannot set #{k} to an empty string. " \
225
+ raise ArgumentError, "You cannot set #{k} to an empty string. " \
246
226
  "We interpret empty strings as nil in requests. " \
247
- "You may set (object).#{k} = nil to delete the property.")
227
+ "You may set (object).#{k} = nil to delete the property."
248
228
  end
249
229
  @values[k] = Util.convert_to_stripe_object(v, @opts)
250
230
  dirty_value!(@values[k])
@@ -260,7 +240,7 @@ module Stripe
260
240
 
261
241
  def method_missing(name, *args)
262
242
  # TODO: only allow setting in updateable classes.
263
- if name.to_s.end_with?('=')
243
+ if name.to_s.end_with?("=")
264
244
  attr = name.to_s[0...-1].to_sym
265
245
 
266
246
  # Pull out the assigned value. This is only used in the case of a
@@ -269,31 +249,32 @@ module Stripe
269
249
  val = args.first
270
250
 
271
251
  # the second argument is only required when adding boolean accessors
272
- add_accessors([attr], { attr => val })
252
+ add_accessors([attr], attr => val)
273
253
 
274
254
  begin
275
255
  mth = method(name)
276
256
  rescue NameError
277
- raise NoMethodError.new("Cannot set #{attr} on this object. HINT: you can't set: #{@@permanent_attributes.to_a.join(', ')}")
257
+ raise NoMethodError, "Cannot set #{attr} on this object. HINT: you can't set: #{@@permanent_attributes.to_a.join(', ')}"
278
258
  end
279
259
  return mth.call(args[0])
280
- else
281
- return @values[name] if @values.has_key?(name)
260
+ elsif @values.key?(name)
261
+ return @values[name]
282
262
  end
283
263
 
284
264
  begin
285
265
  super
286
266
  rescue NoMethodError => e
287
- if @transient_values.include?(name)
288
- raise NoMethodError.new(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(', ')}")
289
- else
290
- raise
291
- end
267
+ # If we notice the accessed name if our set of transient values we can
268
+ # give the user a slightly more helpful error message. If not, just
269
+ # raise right away.
270
+ raise unless @transient_values.include?(name)
271
+
272
+ 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(', ')}"
292
273
  end
293
274
  end
294
275
 
295
276
  def respond_to_missing?(symbol, include_private = false)
296
- @values && @values.has_key?(symbol) || super
277
+ @values && @values.key?(symbol) || super
297
278
  end
298
279
 
299
280
  # Re-initializes the object based on a hash of values (usually one that's
@@ -308,9 +289,11 @@ module Stripe
308
289
  # * +:opts:+ Options for StripeObject like an API key.
309
290
  # * +:partial:+ Indicates that the re-initialization should not attempt to
310
291
  # remove accessors.
311
- def initialize_from(values, opts, partial=false)
292
+ def initialize_from(values, opts, partial = false)
312
293
  @opts = Util.normalize_opts(opts)
313
- @original_values = Marshal.load(Marshal.dump(values)) # deep copy
294
+
295
+ # the `#send` is here so that we can keep this method private
296
+ @original_values = self.class.send(:deep_copy, values)
314
297
 
315
298
  removed = partial ? Set.new : Set.new(@values.keys - values.keys)
316
299
  added = Set.new(values.keys - @values.keys)
@@ -328,8 +311,8 @@ module Stripe
328
311
  @unsaved_values.delete(k)
329
312
  end
330
313
 
331
- update_attributes(values, opts, :dirty => false)
332
- values.each do |k, _|
314
+ update_attributes(values, opts, dirty: false)
315
+ values.each_key do |k|
333
316
  @transient_values.delete(k)
334
317
  @unsaved_values.delete(k)
335
318
  end
@@ -338,9 +321,8 @@ module Stripe
338
321
  end
339
322
 
340
323
  def serialize_params_value(value, original, unsaved, force, key: nil)
341
- case true
342
- when value == nil
343
- ''
324
+ if value.nil?
325
+ ""
344
326
 
345
327
  # The logic here is that essentially any object embedded in another
346
328
  # object that had a `type` is actually an API resource of a different
@@ -364,10 +346,10 @@ module Stripe
364
346
  # We throw an error if a property was set explicitly but we can't do
365
347
  # anything with it because the integration is probably not working as the
366
348
  # user intended it to.
367
- when value.is_a?(APIResource) && !value.save_with_parent
349
+ elsif value.is_a?(APIResource) && !value.save_with_parent
368
350
  if !unsaved
369
351
  nil
370
- elsif value.respond_to?(:id) && value.id != nil
352
+ elsif value.respond_to?(:id) && !value.id.nil?
371
353
  value
372
354
  else
373
355
  raise ArgumentError, "Cannot save property `#{key}` containing " \
@@ -375,15 +357,11 @@ module Stripe
375
357
  "not marked as `save_with_parent`."
376
358
  end
377
359
 
378
- when value.is_a?(Array)
360
+ elsif value.is_a?(Array)
379
361
  update = value.map { |v| serialize_params_value(v, nil, true, force) }
380
362
 
381
363
  # This prevents an array that's unchanged from being resent.
382
- if update != serialize_params_value(original, nil, true, force)
383
- update
384
- else
385
- nil
386
- end
364
+ update if update != serialize_params_value(original, nil, true, force)
387
365
 
388
366
  # Handle a Hash for now, but in the long run we should be able to
389
367
  # eliminate all places where hashes are stored as values internally by
@@ -395,11 +373,11 @@ module Stripe
395
373
  # existing array being held by a StripeObject. This could happen for
396
374
  # example by appending a new hash onto `additional_owners` for an
397
375
  # account.
398
- when value.is_a?(Hash)
376
+ elsif value.is_a?(Hash)
399
377
  Util.convert_to_stripe_object(value, @opts).serialize_params
400
378
 
401
- when value.is_a?(StripeObject)
402
- update = value.serialize_params(:force => force)
379
+ elsif value.is_a?(StripeObject)
380
+ update = value.serialize_params(force: force)
403
381
 
404
382
  # If the entire object was replaced, then we need blank each field of
405
383
  # the old object that held a value. The new serialized values will
@@ -415,6 +393,30 @@ module Stripe
415
393
 
416
394
  private
417
395
 
396
+ # Produces a deep copy of the given object including support for arrays,
397
+ # hashes, and StripeObjects.
398
+ def self.deep_copy(obj)
399
+ case obj
400
+ when Array
401
+ obj.map { |e| deep_copy(e) }
402
+ when Hash
403
+ obj.each_with_object({}) do |(k, v), copy|
404
+ copy[k] = deep_copy(v)
405
+ copy
406
+ end
407
+ when StripeObject
408
+ StripeObject.construct_from(
409
+ deep_copy(obj.instance_variable_get(:@values)),
410
+ obj.instance_variable_get(:@opts).select do |k, _v|
411
+ Util::OPTS_COPYABLE.include?(k)
412
+ end
413
+ )
414
+ else
415
+ obj
416
+ end
417
+ end
418
+ private_class_method :deep_copy
419
+
418
420
  def dirty_value!(value)
419
421
  case value
420
422
  when Array
@@ -428,15 +430,14 @@ module Stripe
428
430
  # StripeObject.
429
431
  def empty_values(obj)
430
432
  values = case obj
431
- when Hash then obj
432
- when StripeObject then obj.instance_variable_get(:@values)
433
- else
434
- raise ArgumentError, "#empty_values got unexpected object type: #{obj.class.name}"
435
- end
436
-
437
- values.inject({}) do |update, (k, _)|
438
- update[k] = ''
439
- update
433
+ when Hash then obj
434
+ when StripeObject then obj.instance_variable_get(:@values)
435
+ else
436
+ raise ArgumentError, "#empty_values got unexpected object type: #{obj.class.name}"
437
+ end
438
+
439
+ values.each_with_object({}) do |(k, _), update|
440
+ update[k] = ""
440
441
  end
441
442
  end
442
443
  end
@@ -5,21 +5,21 @@ module Stripe
5
5
  include Stripe::APIOperations::Save
6
6
  include Stripe::APIOperations::Delete
7
7
 
8
- OBJECT_NAME = 'subscription'
8
+ OBJECT_NAME = "subscription".freeze
9
9
 
10
10
  save_nested_resource :source
11
11
 
12
12
  def delete_discount
13
13
  _, opts = request(:delete, discount_url)
14
- initialize_from({ :discount => nil }, opts, true)
14
+ initialize_from({ discount: nil }, opts, true)
15
15
  end
16
16
 
17
- def self.update(id, params={}, opts={})
17
+ def self.update(id, params = {}, opts = {})
18
18
  params[:items] = Util.array_to_hash(params[:items]) if params[:items]
19
19
  super(id, params, opts)
20
20
  end
21
21
 
22
- def self.create(params={}, opts={})
22
+ def self.create(params = {}, opts = {})
23
23
  params[:items] = Util.array_to_hash(params[:items]) if params[:items]
24
24
  super(params, opts)
25
25
  end
@@ -27,7 +27,7 @@ module Stripe
27
27
  private
28
28
 
29
29
  def discount_url
30
- resource_url + '/discount'
30
+ resource_url + "/discount"
31
31
  end
32
32
  end
33
33
  end
@@ -5,10 +5,10 @@ module Stripe
5
5
  extend Stripe::APIOperations::List
6
6
  include Stripe::APIOperations::Save
7
7
 
8
- OBJECT_NAME = 'subscription_item'
8
+ OBJECT_NAME = "subscription_item".freeze
9
9
 
10
10
  def self.resource_url
11
- '/v1/subscription_items'
11
+ "/v1/subscription_items"
12
12
  end
13
13
  end
14
14
  end
@@ -2,7 +2,7 @@ module Stripe
2
2
  class ThreeDSecure < APIResource
3
3
  extend Stripe::APIOperations::Create
4
4
 
5
- OBJECT_NAME = 'three_d_secure'
5
+ OBJECT_NAME = "three_d_secure".freeze
6
6
 
7
7
  def self.resource_url
8
8
  "/v1/3d_secure"
data/lib/stripe/token.rb CHANGED
@@ -2,6 +2,6 @@ module Stripe
2
2
  class Token < APIResource
3
3
  extend Stripe::APIOperations::Create
4
4
 
5
- OBJECT_NAME = 'token'
5
+ OBJECT_NAME = "token".freeze
6
6
  end
7
7
  end
@@ -4,15 +4,15 @@ module Stripe
4
4
  extend Stripe::APIOperations::Create
5
5
  include Stripe::APIOperations::Save
6
6
 
7
- OBJECT_NAME = 'transfer'
7
+ OBJECT_NAME = "transfer".freeze
8
8
 
9
9
  def cancel
10
- resp, api_key = self.request(:post, cancel_url)
10
+ resp, api_key = request(:post, cancel_url)
11
11
  initialize_from(resp.data, api_key)
12
12
  end
13
13
 
14
14
  def cancel_url
15
- resource_url + '/cancel'
15
+ resource_url + "/cancel"
16
16
  end
17
17
  end
18
18
  end
data/lib/stripe/util.rb CHANGED
@@ -2,6 +2,22 @@ require "cgi"
2
2
 
3
3
  module Stripe
4
4
  module Util
5
+ # Options that a user is allowed to specify.
6
+ OPTS_USER_SPECIFIED = Set[
7
+ :api_key,
8
+ :idempotency_key,
9
+ :stripe_account,
10
+ :stripe_version
11
+ ].freeze
12
+
13
+ # Options that should be copyable from one StripeObject to another
14
+ # including options that may be internal.
15
+ OPTS_COPYABLE = (OPTS_USER_SPECIFIED + Set[:api_base]).freeze
16
+
17
+ # Options that should be persisted between API requests. This includes
18
+ # client, which is an object containing an HTTP client to reuse.
19
+ OPTS_KEYS_TO_PERSIST = (OPTS_USER_SPECIFIED + Set[:client]).freeze
20
+
5
21
  def self.objects_to_ids(h)
6
22
  case h
7
23
  when APIResource
@@ -91,25 +107,25 @@ module Stripe
91
107
 
92
108
  def self.log_error(message, data = {})
93
109
  if !Stripe.logger.nil? ||
94
- !Stripe.log_level.nil? && Stripe.log_level <= Stripe::LEVEL_ERROR
110
+ !Stripe.log_level.nil? && Stripe.log_level <= Stripe::LEVEL_ERROR
95
111
  log_internal(message, data, color: :cyan,
96
- level: Stripe::LEVEL_ERROR, logger: Stripe.logger, out: $stderr)
112
+ level: Stripe::LEVEL_ERROR, logger: Stripe.logger, out: $stderr)
97
113
  end
98
114
  end
99
115
 
100
116
  def self.log_info(message, data = {})
101
117
  if !Stripe.logger.nil? ||
102
- !Stripe.log_level.nil? && Stripe.log_level <= Stripe::LEVEL_INFO
118
+ !Stripe.log_level.nil? && Stripe.log_level <= Stripe::LEVEL_INFO
103
119
  log_internal(message, data, color: :cyan,
104
- level: Stripe::LEVEL_INFO, logger: Stripe.logger, out: $stdout)
120
+ level: Stripe::LEVEL_INFO, logger: Stripe.logger, out: $stdout)
105
121
  end
106
122
  end
107
123
 
108
124
  def self.log_debug(message, data = {})
109
125
  if !Stripe.logger.nil? ||
110
- !Stripe.log_level.nil? && Stripe.log_level <= Stripe::LEVEL_DEBUG
126
+ !Stripe.log_level.nil? && Stripe.log_level <= Stripe::LEVEL_DEBUG
111
127
  log_internal(message, data, color: :blue,
112
- level: Stripe::LEVEL_DEBUG, logger: Stripe.logger, out: $stdout)
128
+ level: Stripe::LEVEL_DEBUG, logger: Stripe.logger, out: $stdout)
113
129
  end
114
130
  end
115
131
 
@@ -117,13 +133,12 @@ module Stripe
117
133
  # This is nominally equivalent to File.readable?, but that can
118
134
  # report incorrect results on some more oddball filesystems
119
135
  # (such as AFS)
120
- begin
121
- File.open(file) { |f| }
122
- rescue
123
- false
124
- else
125
- true
126
- end
136
+
137
+ File.open(file) { |f| }
138
+ rescue StandardError
139
+ false
140
+ else
141
+ true
127
142
  end
128
143
 
129
144
  def self.symbolize_names(object)
@@ -131,7 +146,11 @@ module Stripe
131
146
  when Hash
132
147
  new_hash = {}
133
148
  object.each do |key, value|
134
- key = (key.to_sym rescue key) || key
149
+ key = (begin
150
+ key.to_sym
151
+ rescue StandardError
152
+ key
153
+ end) || key
135
154
  new_hash[key] = symbolize_names(value)
136
155
  end
137
156
  new_hash
@@ -147,8 +166,8 @@ module Stripe
147
166
  # involves escaping special characters from parameter keys and values (e.g.
148
167
  # `&`).
149
168
  def self.encode_parameters(params)
150
- Util.flatten_params(params).
151
- map { |k,v| "#{url_encode(k)}=#{url_encode(v)}" }.join('&')
169
+ Util.flatten_params(params)
170
+ .map { |k, v| "#{url_encode(k)}=#{url_encode(v)}" }.join("&")
152
171
  end
153
172
 
154
173
  # Transforms an array into a hash with integer keys. Used for a small
@@ -158,7 +177,7 @@ module Stripe
158
177
  case array
159
178
  when Array
160
179
  hash = {}
161
- array.each_with_index { |v,i| hash[i.to_s] = v }
180
+ array.each_with_index { |v, i| hash[i.to_s] = v }
162
181
  hash
163
182
  else
164
183
  array
@@ -173,16 +192,16 @@ module Stripe
173
192
  # Don't use strict form encoding by changing the square bracket control
174
193
  # characters back to their literals. This is fine by the server, and
175
194
  # makes these parameter strings easier to read.
176
- gsub('%5B', '[').gsub('%5D', ']')
195
+ gsub("%5B", "[").gsub("%5D", "]")
177
196
  end
178
197
 
179
- def self.flatten_params(params, parent_key=nil)
198
+ def self.flatten_params(params, parent_key = nil)
180
199
  result = []
181
200
 
182
201
  # do not sort the final output because arrays (and arrays of hashes
183
202
  # especially) can be order sensitive, but do sort incoming parameters
184
203
  params.each do |key, value|
185
- calculated_key = parent_key ? "#{parent_key}[#{key}]" : "#{key}"
204
+ calculated_key = parent_key ? "#{parent_key}[#{key}]" : key.to_s
186
205
  if value.is_a?(Hash)
187
206
  result += flatten_params(value, calculated_key)
188
207
  elsif value.is_a?(Array)
@@ -211,7 +230,7 @@ module Stripe
211
230
  end
212
231
 
213
232
  def self.normalize_id(id)
214
- if id.kind_of?(Hash) # overloaded id
233
+ if id.is_a?(Hash) # overloaded id
215
234
  params_hash = id.dup
216
235
  id = params_hash.delete(:id)
217
236
  else
@@ -225,22 +244,22 @@ module Stripe
225
244
  def self.normalize_opts(opts)
226
245
  case opts
227
246
  when String
228
- {:api_key => opts}
247
+ { api_key: opts }
229
248
  when Hash
230
- check_api_key!(opts.fetch(:api_key)) if opts.has_key?(:api_key)
249
+ check_api_key!(opts.fetch(:api_key)) if opts.key?(:api_key)
231
250
  opts.clone
232
251
  else
233
- raise TypeError.new('normalize_opts expects a string or a hash')
252
+ raise TypeError, "normalize_opts expects a string or a hash"
234
253
  end
235
254
  end
236
255
 
237
256
  def self.check_string_argument!(key)
238
- raise TypeError.new("argument must be a string") unless key.is_a?(String)
257
+ raise TypeError, "argument must be a string" unless key.is_a?(String)
239
258
  key
240
259
  end
241
260
 
242
261
  def self.check_api_key!(key)
243
- raise TypeError.new("api_key must be a string") unless key.is_a?(String)
262
+ raise TypeError, "api_key must be a string" unless key.is_a?(String)
244
263
  key
245
264
  end
246
265
 
@@ -250,15 +269,14 @@ module Stripe
250
269
  # certain key values when the user could have set them with a variety of
251
270
  # diffent naming schemes.
252
271
  def self.normalize_headers(headers)
253
- headers.inject({}) do |new_headers, (k, v)|
272
+ headers.each_with_object({}) do |(k, v), new_headers|
254
273
  if k.is_a?(Symbol)
255
- k = titlecase_parts(k.to_s.gsub("_", "-"))
274
+ k = titlecase_parts(k.to_s.tr("_", "-"))
256
275
  elsif k.is_a?(String)
257
276
  k = titlecase_parts(k)
258
277
  end
259
278
 
260
279
  new_headers[k] = v
261
- new_headers
262
280
  end
263
281
  end
264
282
 
@@ -279,22 +297,24 @@ module Stripe
279
297
 
280
298
  res = 0
281
299
  b.each_byte { |byte| res |= byte ^ l.shift }
282
- res == 0
300
+ res.zero?
283
301
  end
284
302
 
285
- private
303
+ #
304
+ # private
305
+ #
286
306
 
287
307
  COLOR_CODES = {
288
- :black => 0, :light_black => 60,
289
- :red => 1, :light_red => 61,
290
- :green => 2, :light_green => 62,
291
- :yellow => 3, :light_yellow => 63,
292
- :blue => 4, :light_blue => 64,
293
- :magenta => 5, :light_magenta => 65,
294
- :cyan => 6, :light_cyan => 66,
295
- :white => 7, :light_white => 67,
296
- :default => 9
297
- }
308
+ black: 0, light_black: 60,
309
+ red: 1, light_red: 61,
310
+ green: 2, light_green: 62,
311
+ yellow: 3, light_yellow: 63,
312
+ blue: 4, light_blue: 64,
313
+ magenta: 5, light_magenta: 65,
314
+ cyan: 6, light_cyan: 66,
315
+ white: 7, light_white: 67,
316
+ default: 9,
317
+ }.freeze
298
318
  private_constant :COLOR_CODES
299
319
 
300
320
  # We use a pretty janky version of form encoding (Rack's) that supports
@@ -317,16 +337,16 @@ module Stripe
317
337
  def self.check_array_of_maps_start_keys!(arr)
318
338
  expected_key = nil
319
339
  arr.each do |item|
320
- return if !item.is_a?(Hash)
321
- return if item.count == 0
340
+ break unless item.is_a?(Hash)
341
+ break if item.count.zero?
322
342
 
323
343
  first_key = item.first[0]
324
344
 
325
345
  if expected_key
326
346
  if expected_key != first_key
327
347
  raise ArgumentError,
328
- "All maps nested in an array should start with the same key " +
329
- "(expected starting key '#{expected_key}', got '#{first_key}')"
348
+ "All maps nested in an array should start with the same key " \
349
+ "(expected starting key '#{expected_key}', got '#{first_key}')"
330
350
  end
331
351
  else
332
352
  expected_key = first_key
@@ -362,34 +382,29 @@ module Stripe
362
382
  # TODO: Make these named required arguments when we drop support for Ruby
363
383
  # 2.0.
364
384
  def self.log_internal(message, data = {}, color: nil, level: nil, logger: nil, out: nil)
365
- data_str = data.select { |k,v| !v.nil? }.
366
- map { |(k,v)|
367
- "%s=%s" % [
368
- colorize(k, color, !out.nil? && out.isatty),
369
- wrap_logfmt_value(v)
370
- ]
371
- }.join(" ")
385
+ data_str = data.reject { |_k, v| v.nil? }
386
+ .map do |(k, v)|
387
+ format("%s=%s", colorize(k, color, !out.nil? && out.isatty), wrap_logfmt_value(v))
388
+ end.join(" ")
372
389
 
373
390
  if !logger.nil?
374
391
  # the library's log levels are mapped to the same values as the
375
392
  # standard library's logger
376
393
  logger.log(level,
377
- "message=%s %s" % [wrap_logfmt_value(message), data_str])
394
+ format("message=%s %s", wrap_logfmt_value(message), data_str))
378
395
  elsif out.isatty
379
- out.puts "%s %s %s" %
380
- [colorize(level_name(level)[0, 4].upcase, color, out.isatty), message, data_str]
396
+ out.puts format("%s %s %s", colorize(level_name(level)[0, 4].upcase, color, out.isatty), message, data_str)
381
397
  else
382
- out.puts "message=%s level=%s %s" %
383
- [wrap_logfmt_value(message), level_name(level), data_str]
398
+ out.puts format("message=%s level=%s %s", wrap_logfmt_value(message), level_name(level), data_str)
384
399
  end
385
400
  end
386
401
  private_class_method :log_internal
387
402
 
388
403
  def self.titlecase_parts(s)
389
- s.split("-").
390
- select { |p| p != "" }.
391
- map { |p| p[0].upcase + p[1..-1].downcase }.
392
- join("-")
404
+ s.split("-")
405
+ .reject { |p| p == "" }
406
+ .map { |p| p[0].upcase + p[1..-1].downcase }
407
+ .join("-")
393
408
  end
394
409
  private_class_method :titlecase_parts
395
410
 
@@ -406,7 +421,7 @@ module Stripe
406
421
  if %r{[^\w\-/]} =~ val
407
422
  # If the string contains any special characters, escape any double
408
423
  # quotes it has, remove newlines, and wrap the whole thing in quotes.
409
- %{"%s"} % val.gsub('"', '\"').gsub("\n", "")
424
+ format(%("%s"), val.gsub('"', '\"').delete("\n"))
410
425
  else
411
426
  # Otherwise use the basic value if it looks like a standard set of
412
427
  # characters (and allow a few special characters like hyphens, and