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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +20 -0
- data/.rubocop_todo.yml +62 -0
- data/.travis.yml +1 -1
- data/Gemfile +19 -12
- data/History.txt +10 -0
- data/README.md +5 -1
- data/Rakefile +8 -5
- data/VERSION +1 -1
- data/bin/stripe-console +2 -2
- data/lib/stripe.rb +72 -74
- data/lib/stripe/account.rb +15 -17
- data/lib/stripe/alipay_account.rb +10 -7
- data/lib/stripe/api_operations/create.rb +1 -1
- data/lib/stripe/api_operations/delete.rb +1 -1
- data/lib/stripe/api_operations/list.rb +2 -2
- data/lib/stripe/api_operations/request.rb +5 -12
- data/lib/stripe/api_operations/save.rb +6 -6
- data/lib/stripe/api_resource.rb +7 -9
- data/lib/stripe/apple_pay_domain.rb +2 -2
- data/lib/stripe/application_fee.rb +5 -5
- data/lib/stripe/application_fee_refund.rb +5 -5
- data/lib/stripe/balance.rb +1 -1
- data/lib/stripe/balance_transaction.rb +2 -2
- data/lib/stripe/bank_account.rb +7 -7
- data/lib/stripe/bitcoin_receiver.rb +4 -2
- data/lib/stripe/bitcoin_transaction.rb +3 -1
- data/lib/stripe/card.rb +5 -5
- data/lib/stripe/charge.rb +18 -18
- data/lib/stripe/country_spec.rb +2 -2
- data/lib/stripe/coupon.rb +1 -1
- data/lib/stripe/customer.rb +23 -23
- data/lib/stripe/dispute.rb +3 -3
- data/lib/stripe/ephemeral_key.rb +4 -4
- data/lib/stripe/errors.rb +4 -4
- data/lib/stripe/event.rb +1 -1
- data/lib/stripe/file_upload.rb +5 -5
- data/lib/stripe/invoice.rb +7 -7
- data/lib/stripe/invoice_item.rb +1 -1
- data/lib/stripe/invoice_line_item.rb +1 -1
- data/lib/stripe/list_object.rb +14 -18
- data/lib/stripe/login_link.rb +3 -3
- data/lib/stripe/oauth.rb +15 -13
- data/lib/stripe/order.rb +5 -5
- data/lib/stripe/order_return.rb +1 -1
- data/lib/stripe/payout.rb +3 -3
- data/lib/stripe/plan.rb +1 -1
- data/lib/stripe/product.rb +1 -1
- data/lib/stripe/recipient.rb +3 -2
- data/lib/stripe/recipient_transfer.rb +1 -2
- data/lib/stripe/refund.rb +1 -1
- data/lib/stripe/reversal.rb +5 -5
- data/lib/stripe/singleton_api_resource.rb +3 -3
- data/lib/stripe/sku.rb +1 -1
- data/lib/stripe/source.rb +13 -10
- data/lib/stripe/stripe_client.rb +149 -169
- data/lib/stripe/stripe_object.rb +77 -76
- data/lib/stripe/subscription.rb +5 -5
- data/lib/stripe/subscription_item.rb +2 -2
- data/lib/stripe/three_d_secure.rb +1 -1
- data/lib/stripe/token.rb +1 -1
- data/lib/stripe/transfer.rb +3 -3
- data/lib/stripe/util.rb +77 -62
- data/lib/stripe/version.rb +1 -1
- data/lib/stripe/webhook.rb +14 -10
- data/stripe.gemspec +14 -14
- data/test/stripe/account_test.rb +69 -81
- data/test/stripe/alipay_account_test.rb +19 -1
- data/test/stripe/api_operations_test.rb +7 -7
- data/test/stripe/api_resource_test.rb +224 -260
- data/test/stripe/apple_pay_domain_test.rb +8 -8
- data/test/stripe/application_fee_refund_test.rb +8 -8
- data/test/stripe/application_fee_test.rb +3 -3
- data/test/stripe/balance_test.rb +2 -2
- data/test/stripe/bank_account_test.rb +9 -11
- data/test/stripe/charge_test.rb +11 -11
- data/test/stripe/country_spec_test.rb +4 -4
- data/test/stripe/coupon_test.rb +10 -10
- data/test/stripe/customer_card_test.rb +11 -15
- data/test/stripe/customer_test.rb +26 -27
- data/test/stripe/dispute_test.rb +8 -8
- data/test/stripe/ephemeral_key_test.rb +14 -14
- data/test/stripe/errors_test.rb +2 -2
- data/test/stripe/file_upload_test.rb +26 -28
- data/test/stripe/invoice_item_test.rb +14 -14
- data/test/stripe/invoice_line_item_test.rb +1 -1
- data/test/stripe/invoice_test.rb +37 -37
- data/test/stripe/list_object_test.rb +60 -76
- data/test/stripe/login_link_test.rb +14 -14
- data/test/stripe/oauth_test.rb +42 -50
- data/test/stripe/order_return_test.rb +5 -5
- data/test/stripe/order_test.rb +12 -12
- data/test/stripe/payout_test.rb +9 -9
- data/test/stripe/plan_test.rb +9 -9
- data/test/stripe/product_test.rb +8 -8
- data/test/stripe/recipient_test.rb +9 -10
- data/test/stripe/refund_test.rb +9 -9
- data/test/stripe/reversal_test.rb +10 -10
- data/test/stripe/sku_test.rb +8 -8
- data/test/stripe/source_test.rb +14 -16
- data/test/stripe/stripe_client_test.rb +235 -266
- data/test/stripe/stripe_object_test.rb +163 -147
- data/test/stripe/stripe_response_test.rb +4 -3
- data/test/stripe/subscription_item_test.rb +11 -11
- data/test/stripe/subscription_test.rb +14 -14
- data/test/stripe/three_d_secure_test.rb +2 -2
- data/test/stripe/transfer_test.rb +8 -8
- data/test/stripe/util_test.rb +59 -57
- data/test/stripe/webhook_test.rb +18 -16
- data/test/stripe_test.rb +4 -4
- data/test/test_data.rb +26 -26
- data/test/test_helper.rb +29 -25
- metadata +6 -10
- data/test/stripe/bitcoin_receiver_test.rb +0 -67
- data/test/stripe/bitcoin_transaction_test.rb +0 -19
- data/test/stripe/recipient_card_test.rb +0 -44
data/lib/stripe/stripe_object.rb
CHANGED
@@ -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
|
-
|
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(*
|
43
|
+
def to_s(*_args)
|
46
44
|
JSON.pretty_generate(to_hash)
|
47
45
|
end
|
48
46
|
|
49
47
|
def inspect
|
50
|
-
id_string =
|
51
|
-
"#<#{self.class}:0x#{
|
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,
|
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(*
|
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.
|
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.
|
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
|
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.
|
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],
|
252
|
+
add_accessors([attr], attr => val)
|
273
253
|
|
274
254
|
begin
|
275
255
|
mth = method(name)
|
276
256
|
rescue NameError
|
277
|
-
raise NoMethodError
|
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
|
-
|
281
|
-
return @values[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
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
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.
|
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
|
-
|
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, :
|
332
|
-
values.
|
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
|
-
|
342
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
376
|
+
elsif value.is_a?(Hash)
|
399
377
|
Util.convert_to_stripe_object(value, @opts).serialize_params
|
400
378
|
|
401
|
-
|
402
|
-
update = value.serialize_params(:
|
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
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
values.
|
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
|
data/lib/stripe/subscription.rb
CHANGED
@@ -5,21 +5,21 @@ module Stripe
|
|
5
5
|
include Stripe::APIOperations::Save
|
6
6
|
include Stripe::APIOperations::Delete
|
7
7
|
|
8
|
-
OBJECT_NAME =
|
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({ :
|
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 +
|
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 =
|
8
|
+
OBJECT_NAME = "subscription_item".freeze
|
9
9
|
|
10
10
|
def self.resource_url
|
11
|
-
|
11
|
+
"/v1/subscription_items"
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
data/lib/stripe/token.rb
CHANGED
data/lib/stripe/transfer.rb
CHANGED
@@ -4,15 +4,15 @@ module Stripe
|
|
4
4
|
extend Stripe::APIOperations::Create
|
5
5
|
include Stripe::APIOperations::Save
|
6
6
|
|
7
|
-
OBJECT_NAME =
|
7
|
+
OBJECT_NAME = "transfer".freeze
|
8
8
|
|
9
9
|
def cancel
|
10
|
-
resp, api_key =
|
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 +
|
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
|
-
|
110
|
+
!Stripe.log_level.nil? && Stripe.log_level <= Stripe::LEVEL_ERROR
|
95
111
|
log_internal(message, data, color: :cyan,
|
96
|
-
|
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
|
-
|
118
|
+
!Stripe.log_level.nil? && Stripe.log_level <= Stripe::LEVEL_INFO
|
103
119
|
log_internal(message, data, color: :cyan,
|
104
|
-
|
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
|
-
|
126
|
+
!Stripe.log_level.nil? && Stripe.log_level <= Stripe::LEVEL_DEBUG
|
111
127
|
log_internal(message, data, color: :blue,
|
112
|
-
|
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
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
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 = (
|
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
|
-
|
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(
|
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}]" :
|
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.
|
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
|
-
{:
|
247
|
+
{ api_key: opts }
|
229
248
|
when Hash
|
230
|
-
check_api_key!(opts.fetch(:api_key)) if opts.
|
249
|
+
check_api_key!(opts.fetch(:api_key)) if opts.key?(:api_key)
|
231
250
|
opts.clone
|
232
251
|
else
|
233
|
-
raise TypeError
|
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
|
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
|
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.
|
272
|
+
headers.each_with_object({}) do |(k, v), new_headers|
|
254
273
|
if k.is_a?(Symbol)
|
255
|
-
k = titlecase_parts(k.to_s.
|
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
|
300
|
+
res.zero?
|
283
301
|
end
|
284
302
|
|
285
|
-
|
303
|
+
#
|
304
|
+
# private
|
305
|
+
#
|
286
306
|
|
287
307
|
COLOR_CODES = {
|
288
|
-
:
|
289
|
-
:
|
290
|
-
:
|
291
|
-
:
|
292
|
-
:
|
293
|
-
:
|
294
|
-
:
|
295
|
-
:
|
296
|
-
:
|
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
|
-
|
321
|
-
|
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
|
-
|
329
|
-
|
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.
|
366
|
-
|
367
|
-
|
368
|
-
|
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
|
-
|
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
|
-
|
391
|
-
|
392
|
-
|
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
|
-
%
|
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
|