stripe 3.3.2 → 3.4.1

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.
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