stripe 1.27.2 → 1.28.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c4d368b987f5a34446fcc2906d9b3431b0e500e5
4
- data.tar.gz: 2253d61edbdf951fe94f3cba720436084a69f49b
3
+ metadata.gz: d356b022d7063f14b899676fdea7cdca23959578
4
+ data.tar.gz: 04e99c26ba15d5cfaeaeb626cae12ea675136be6
5
5
  SHA512:
6
- metadata.gz: 13688baa2544303346cc97936a8df74969c081db6c1d4bd437818064a50d11e766a6dc43d54c46711e37654c9b7d70cd9b504da147b64a4b19928cd9dc3f4634
7
- data.tar.gz: 06f77ce31a7c684ee01b0189b1ec1ee7faba272e1d3b6adfbfe21cc537560595c44a59385e6487d77b7c71ba1948f7f7e132bcfec8d855794da2a6207449a307
6
+ metadata.gz: d3e60ed73189c99a626246686b1dedd62402ad70c97fab4af71488c5c9ed40927981b4272d1ea2b0d10bae5c2577d68dc2406a588f86b4c9dd400619a98b967b
7
+ data.tar.gz: c049b00c65f2cbab92ef02cec7c5604bf637d4bbb1b2dae44d537edbdfdd4285de41bd955f71acf4bf35fd2c866690600698115fcd2600c2a9f9bd3b416fab53
data/.gitignore CHANGED
@@ -2,3 +2,4 @@
2
2
  /Gemfile.lock
3
3
  .rvmrc
4
4
  Gemfile.lock
5
+ tags
data/.travis.yml CHANGED
@@ -19,4 +19,8 @@ matrix:
19
19
  - rvm: jruby-19mode
20
20
  gemfile: gemfiles/yajl.gemfile
21
21
 
22
+ notifications:
23
+ email:
24
+ on_success: never
25
+
22
26
  sudo: false
data/History.txt CHANGED
@@ -1,3 +1,12 @@
1
+ === 1.28.0 2015-10-05
2
+
3
+ * Make StripeObject's #save "upsert"-like; creates an object if new
4
+ * Add #update_attributes to StripeObject for safe mass assignment
5
+ * Properly mass assign attributes on calls to #save
6
+ * Add question mark helpers for boolean fields (e.g. #paid? as well as old #paid)
7
+ * Fix a bug that broke the API for StripeObject initialization
8
+ * Remove use of deprecated URI.escape
9
+
1
10
  === 1.27.2 2015-09-25
2
11
 
3
12
  * Correct the URLs used to fetch Bitcoin transactions.
data/README.rdoc CHANGED
@@ -40,4 +40,14 @@ compromised in transit and alter the code of gems fetched securely over https:
40
40
 
41
41
  == Development
42
42
 
43
- Test cases can be run with: `bundle exec rake test`
43
+ Run all tests:
44
+
45
+ bundle exec rake
46
+
47
+ Run a single test suite:
48
+
49
+ bundle exec ruby -Ilib/ test/stripe/util_test.rb
50
+
51
+ Run a single test:
52
+
53
+ bundle exec ruby -Ilib/ test/stripe/util_test.rb -n /should.convert.names.to.symbols/
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.27.2
1
+ 1.28.0
@@ -27,6 +27,18 @@ module Stripe
27
27
  super(id, opts)
28
28
  end
29
29
 
30
+ def protected_fields
31
+ [:legal_entity]
32
+ end
33
+
34
+ def legal_entity
35
+ self['legal_entity']
36
+ end
37
+
38
+ def legal_entity=(_)
39
+ raise NoMethodError.new('Overridding legal_entity can cause cause serious issues. Instead, set the individual fields of legal_entity like blah.legal_entity.first_name = \'Blah\'')
40
+ end
41
+
30
42
  def deauthorize(client_id, opts={})
31
43
  opts = {:api_base => Stripe.connect_base}.merge(Util.normalize_opts(opts))
32
44
  response, opts = request(:post, '/oauth/deauthorize', { 'client_id' => client_id, 'stripe_user_id' => self.id }, opts)
@@ -1,12 +1,35 @@
1
1
  module Stripe
2
2
  module APIOperations
3
3
  module Update
4
+ # Creates or updates an API resource.
5
+ #
6
+ # If the resource doesn't yet have an assigned ID and the resource is one
7
+ # that can be created, then the method attempts to create the resource.
8
+ # The resource is updated otherwise.
9
+ #
10
+ # ==== Attributes
11
+ #
12
+ # * +params+ - Overrides any parameters in the resource's serialized data
13
+ # and includes them in the create or update. If +:req_url:+ is included
14
+ # in the list, it overrides the update URL used for the create or
15
+ # update.
4
16
  def save(params={})
5
17
  # Let the caller override the URL but avoid serializing it.
6
- req_url = params.delete(:req_url) || url
18
+ req_url = params.delete(:req_url) || save_url
19
+
20
+ # We started unintentionally (sort of) allowing attributes send to
21
+ # +save+ to override values used during the update. So as not to break
22
+ # the API, this makes that official here.
23
+ update_attributes_with_options(params, :raise_error => false)
24
+
25
+ # Now remove any parameters that look like object attributes.
26
+ params = params.reject { |k, _| respond_to?(k) }
27
+
7
28
  values = self.class.serialize_params(self).merge(params)
8
29
 
9
30
  if values.length > 0
31
+ # note that id gets removed here our call to #url above has already
32
+ # generated a uri for this object with an identifier baked in
10
33
  values.delete(:id)
11
34
 
12
35
  response, opts = request(:post, req_url, values)
@@ -14,6 +37,22 @@ module Stripe
14
37
  end
15
38
  self
16
39
  end
40
+
41
+ private
42
+
43
+ def save_url
44
+ # This switch essentially allows us "upsert"-like functionality. If the
45
+ # API resource doesn't have an ID set (suggesting that it's new) and
46
+ # its class responds to .create (which comes from
47
+ # Stripe::APIOperations::Create), then use the URL to create a new
48
+ # resource. Otherwise, generate a URL based on the object's identifier
49
+ # for a normal update.
50
+ if self[:id] == nil && self.class.respond_to?(:create)
51
+ self.class.url
52
+ else
53
+ url
54
+ end
55
+ end
17
56
  end
18
57
  end
19
58
  end
@@ -1,5 +1,6 @@
1
1
  module Stripe
2
2
  class ListObject < StripeObject
3
+ include Enumerable
3
4
  include Stripe::APIOperations::Request
4
5
 
5
6
  def [](k)
@@ -15,6 +16,11 @@ module Stripe
15
16
  self.data.each(&blk)
16
17
  end
17
18
 
19
+ # Returns true if the page object contains no elements.
20
+ def empty?
21
+ self.data.empty?
22
+ end
23
+
18
24
  def retrieve(id, opts={})
19
25
  id, retrieve_params = Util.normalize_id(id)
20
26
  response, opts = request(:get,"#{url}/#{CGI.escape(id)}", retrieve_params, opts)
@@ -11,7 +11,7 @@ module Stripe
11
11
 
12
12
  def initialize(id=nil, opts={})
13
13
  id, @retrieve_params = Util.normalize_id(id)
14
- @opts = opts
14
+ @opts = Util.normalize_opts(opts)
15
15
  @values = {}
16
16
  # This really belongs in APIResource, but not putting it there allows us
17
17
  # to have a unified inspect method
@@ -21,6 +21,7 @@ module Stripe
21
21
  end
22
22
 
23
23
  def self.construct_from(values, opts={})
24
+ values = Stripe::Util.symbolize_names(values)
24
25
  self.new(values[:id]).refresh_from(values, opts)
25
26
  end
26
27
 
@@ -34,25 +35,29 @@ module Stripe
34
35
  end
35
36
 
36
37
  def refresh_from(values, opts, partial=false)
37
- @opts = opts
38
+ @opts = Util.normalize_opts(opts)
38
39
  @original_values = Marshal.load(Marshal.dump(values)) # deep copy
40
+
39
41
  removed = partial ? Set.new : Set.new(@values.keys - values.keys)
40
42
  added = Set.new(values.keys - @values.keys)
43
+
41
44
  # Wipe old state before setting new. This is useful for e.g. updating a
42
45
  # customer, where there is no persistent card parameter. Mark those values
43
46
  # which don't persist as transient
44
47
 
45
48
  instance_eval do
46
49
  remove_accessors(removed)
47
- add_accessors(added)
50
+ add_accessors(added, values)
48
51
  end
52
+
49
53
  removed.each do |k|
50
54
  @values.delete(k)
51
55
  @transient_values.add(k)
52
56
  @unsaved_values.delete(k)
53
57
  end
54
- values.each do |k, v|
55
- @values[k] = Util.convert_to_stripe_object(v, @opts)
58
+
59
+ update_attributes_with_options(values, :opts => opts)
60
+ values.each do |k, _|
56
61
  @transient_values.delete(k)
57
62
  @unsaved_values.delete(k)
58
63
  end
@@ -60,6 +65,11 @@ module Stripe
60
65
  return self
61
66
  end
62
67
 
68
+ # Mass assigns attributes on the model.
69
+ def update_attributes(values)
70
+ update_attributes_with_options(values, {})
71
+ end
72
+
63
73
  def [](k)
64
74
  @values[k.to_sym]
65
75
  end
@@ -85,8 +95,17 @@ module Stripe
85
95
  end
86
96
 
87
97
  def to_hash
98
+ maybe_to_hash = lambda do |value|
99
+ value.respond_to?(:to_hash) ? value.to_hash : value
100
+ end
101
+
88
102
  @values.inject({}) do |acc, (key, value)|
89
- acc[key] = value.respond_to?(:to_hash) ? value.to_hash : value
103
+ acc[key] = case value
104
+ when Array
105
+ value.map(&maybe_to_hash)
106
+ else
107
+ maybe_to_hash.call(value)
108
+ end
90
109
  acc
91
110
  end
92
111
  end
@@ -191,9 +210,15 @@ module Stripe
191
210
  class << self; self; end
192
211
  end
193
212
 
213
+ def protected_fields
214
+ []
215
+ end
216
+
194
217
  def remove_accessors(keys)
218
+ f = protected_fields
195
219
  metaclass.instance_eval do
196
220
  keys.each do |k|
221
+ next if f.include?(k)
197
222
  next if @@permanent_attributes.include?(k)
198
223
  k_eq = :"#{k}="
199
224
  remove_method(k) if method_defined?(k)
@@ -202,9 +227,11 @@ module Stripe
202
227
  end
203
228
  end
204
229
 
205
- def add_accessors(keys)
230
+ def add_accessors(keys, values)
231
+ f = protected_fields
206
232
  metaclass.instance_eval do
207
233
  keys.each do |k|
234
+ next if f.include?(k)
208
235
  next if @@permanent_attributes.include?(k)
209
236
  k_eq = :"#{k}="
210
237
  define_method(k) { @values[k] }
@@ -218,6 +245,11 @@ module Stripe
218
245
  @values[k] = v
219
246
  @unsaved_values.add(k)
220
247
  end
248
+
249
+ if [FalseClass, TrueClass].include?(values[k].class)
250
+ k_bool = :"#{k}?"
251
+ define_method(k_bool) { @values[k] }
252
+ end
221
253
  end
222
254
  end
223
255
  end
@@ -226,7 +258,10 @@ module Stripe
226
258
  # TODO: only allow setting in updateable classes.
227
259
  if name.to_s.end_with?('=')
228
260
  attr = name.to_s[0...-1].to_sym
229
- add_accessors([attr])
261
+
262
+ # the second argument is only required when adding boolean accessors
263
+ add_accessors([attr], {})
264
+
230
265
  begin
231
266
  mth = method(name)
232
267
  rescue NameError
@@ -251,5 +286,36 @@ module Stripe
251
286
  def respond_to_missing?(symbol, include_private = false)
252
287
  @values && @values.has_key?(symbol) || super
253
288
  end
289
+
290
+ # Mass assigns attributes on the model.
291
+ #
292
+ # This is a version of +update_attributes+ that takes some extra options
293
+ # for internal use.
294
+ #
295
+ # ==== Options
296
+ #
297
+ # * +:opts:+ Options for StripeObject like an API key.
298
+ # * +:raise_error:+ Set to false to suppress ArgumentErrors on keys that
299
+ # don't exist.
300
+ def update_attributes_with_options(values, options={})
301
+ # `opts` are StripeObject options
302
+ opts = options.fetch(:opts, {})
303
+ raise_error = options.fetch(:raise_error, true)
304
+
305
+ values.each do |k, v|
306
+ if !@@permanent_attributes.include?(k) && !self.respond_to?(:"#{k}=")
307
+ if raise_error
308
+ raise ArgumentError,
309
+ "#{k} is not an attribute that can be assigned on this object"
310
+ else
311
+ next
312
+ end
313
+ end
314
+
315
+ @values[k] = Util.convert_to_stripe_object(v, opts)
316
+ @unsaved_values.add(k)
317
+ end
318
+ self
319
+ end
254
320
  end
255
321
  end
data/lib/stripe/util.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require "webrick"
2
+
1
3
  module Stripe
2
4
  module Util
3
5
  def self.objects_to_ids(h)
@@ -93,7 +95,10 @@ module Stripe
93
95
  end
94
96
 
95
97
  def self.url_encode(key)
96
- URI.escape(key.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
98
+ # Unfortunately, URI.escape was deprecated. Here we use a method from
99
+ # WEBrick instead given that it's a fairly close approximation (credit to
100
+ # the AWS Ruby SDK for coming up with the technique).
101
+ WEBrick::HTTPUtils.escape(key.to_s).gsub('%5B', '[').gsub('%5D', ']')
97
102
  end
98
103
 
99
104
  def self.flatten_params(params, parent_key=nil)
@@ -1,3 +1,3 @@
1
1
  module Stripe
2
- VERSION = '1.27.2'
2
+ VERSION = '1.28.0'
3
3
  end
@@ -3,26 +3,34 @@ require File.expand_path('../../test_helper', __FILE__)
3
3
  module Stripe
4
4
  class AccountTest < Test::Unit::TestCase
5
5
  should "be retrievable" do
6
- resp = {:email => "test+bindings@stripe.com", :charge_enabled => false, :details_submitted => false}
6
+ resp = make_account({
7
+ :charges_enabled => false,
8
+ :details_submitted => false,
9
+ :email => "test+bindings@stripe.com",
10
+ })
7
11
  @mock.expects(:get).
8
12
  once.
9
13
  with('https://api.stripe.com/v1/account', nil, nil).
10
14
  returns(make_response(resp))
11
15
  a = Stripe::Account.retrieve
12
16
  assert_equal "test+bindings@stripe.com", a.email
13
- assert !a.charge_enabled
17
+ assert !a.charges_enabled
14
18
  assert !a.details_submitted
15
19
  end
16
20
 
17
21
  should "be retrievable via plural endpoint" do
18
- resp = {:email => "test+bindings@stripe.com", :charge_enabled => false, :details_submitted => false}
22
+ resp = make_account({
23
+ :charges_enabled => false,
24
+ :details_submitted => false,
25
+ :email => "test+bindings@stripe.com",
26
+ })
19
27
  @mock.expects(:get).
20
28
  once.
21
29
  with('https://api.stripe.com/v1/accounts/acct_foo', nil, nil).
22
30
  returns(make_response(resp))
23
31
  a = Stripe::Account.retrieve('acct_foo')
24
32
  assert_equal "test+bindings@stripe.com", a.email
25
- assert !a.charge_enabled
33
+ assert !a.charges_enabled
26
34
  assert !a.details_submitted
27
35
  end
28
36
 
@@ -33,6 +41,17 @@ module Stripe
33
41
  Stripe::Account.retrieve('sk_foobar')
34
42
  end
35
43
 
44
+ should "allow access to keys by method" do
45
+ account = Stripe::Account.construct_from(make_account({
46
+ :keys => {
47
+ :publishable => 'publishable-key',
48
+ :secret => 'secret-key',
49
+ }
50
+ }))
51
+ assert_equal 'publishable-key', account.keys.publishable
52
+ assert_equal 'secret-key', account.keys.secret
53
+ end
54
+
36
55
  should "be updatable" do
37
56
  resp = {
38
57
  :id => 'acct_foo',
@@ -58,6 +77,24 @@ module Stripe
58
77
  a.save
59
78
  end
60
79
 
80
+ should 'disallow direct overrides of legal_entity' do
81
+ account = Stripe::Account.construct_from(make_account({
82
+ :keys => {
83
+ :publishable => 'publishable-key',
84
+ :secret => 'secret-key',
85
+ },
86
+ :legal_entity => {
87
+ :first_name => 'Bling'
88
+ }
89
+ }))
90
+
91
+ assert_raise NoMethodError do
92
+ account.legal_entity = {:first_name => 'Blah'}
93
+ end
94
+
95
+ account.legal_entity.first_name = 'Blah'
96
+ end
97
+
61
98
  should "be able to deauthorize an account" do
62
99
  resp = {:id => 'acct_1234', :email => "test+bindings@stripe.com", :charge_enabled => false, :details_submitted => false}
63
100
  @mock.expects(:get).once.returns(make_response(resp))
@@ -545,6 +545,10 @@ module Stripe
545
545
  :id => 'myid',
546
546
  :legal_entity => {
547
547
  :last_name => 'Smith',
548
+ :address => {
549
+ :line1 => "test",
550
+ :city => "San Francisco"
551
+ }
548
552
  }
549
553
  })
550
554
 
@@ -552,12 +556,12 @@ module Stripe
552
556
  "#{Stripe.api_base}/v1/accounts/myid",
553
557
  nil,
554
558
  any_of(
555
- 'legal_entity[first_name]=Bob&legal_entity[last_name]=',
556
- 'legal_entity[last_name]=&legal_entity[first_name]=Bob'
559
+ 'legal_entity[address][line1]=Test2&legal_entity[address][city]=',
560
+ 'legal_entity[address][city]=&legal_entity[address][line1]=Test2'
557
561
  )
558
562
  ).returns(make_response({"id" => "myid"}))
559
563
 
560
- acct.legal_entity = {:first_name => 'Bob'}
564
+ acct.legal_entity.address = {:line1 => 'Test2'}
561
565
  acct.save
562
566
  end
563
567
 
@@ -627,6 +631,31 @@ module Stripe
627
631
 
628
632
  acct.save
629
633
  end
634
+
635
+ should 'should create a new resource when an object without an id is saved' do
636
+ account = Stripe::Account.construct_from({
637
+ :id => nil,
638
+ :display_name => nil,
639
+ })
640
+
641
+ @mock.expects(:post).once.with("#{Stripe.api_base}/v1/accounts", nil, 'display_name=stripe').
642
+ returns(make_response({"id" => "charge_id"}))
643
+
644
+ account.display_name = 'stripe'
645
+ account.save
646
+ end
647
+
648
+ should 'set attributes as part of save' do
649
+ account = Stripe::Account.construct_from({
650
+ :id => nil,
651
+ :display_name => nil,
652
+ })
653
+
654
+ @mock.expects(:post).once.with("#{Stripe.api_base}/v1/accounts", nil, 'display_name=stripe').
655
+ returns(make_response({"id" => "charge_id"}))
656
+
657
+ account.save(:display_name => 'stripe')
658
+ end
630
659
  end
631
660
  end
632
661
  end
@@ -12,5 +12,19 @@ module Stripe
12
12
  assert_equal('/v1/charges', all.url)
13
13
  assert all.data.kind_of?(Array)
14
14
  end
15
+
16
+ should "provide #empty?" do
17
+ object = Stripe::ListObject.construct_from({ :data => [] })
18
+ assert object.empty?
19
+ object = Stripe::ListObject.construct_from({ :data => [{}] })
20
+ refute object.empty?
21
+ end
22
+
23
+ should "provide enumerable functionality" do
24
+ @mock.expects(:get).once.returns(make_response(make_charge_array))
25
+ c = Stripe::Charge.all
26
+ assert c.kind_of?(Stripe::ListObject)
27
+ assert_equal 3, c.count
28
+ end
15
29
  end
16
30
  end
@@ -9,6 +9,12 @@ module Stripe
9
9
  assert !obj.respond_to?(:baz)
10
10
  end
11
11
 
12
+ should "marshal be insensitive to strings vs. symbols when constructin" do
13
+ obj = Stripe::StripeObject.construct_from({ :id => 1, 'name' => 'Stripe' })
14
+ assert_equal 1, obj[:id]
15
+ assert_equal 'Stripe', obj[:name]
16
+ end
17
+
12
18
  should "marshal a stripe object correctly" do
13
19
  obj = Stripe::StripeObject.construct_from({ :id => 1, :name => 'Stripe' }, {:api_key => 'apikey'})
14
20
  m = Marshal.load(Marshal.dump(obj))
@@ -19,10 +25,29 @@ module Stripe
19
25
  end
20
26
 
21
27
  should "recursively call to_hash on its values" do
22
- nested = Stripe::StripeObject.construct_from({ :id => 7, :foo => 'bar' })
23
- obj = Stripe::StripeObject.construct_from({ :id => 1, :nested => nested })
24
- expected_hash = { :id => 1, :nested => { :id => 7, :foo => 'bar' } }
28
+ nested_hash = { :id => 7, :foo => 'bar' }
29
+ nested = Stripe::StripeObject.construct_from(nested_hash)
30
+ obj = Stripe::StripeObject.construct_from({ :id => 1, :nested => nested, :list => [nested] })
31
+ expected_hash = { :id => 1, :nested => nested_hash, :list => [nested_hash] }
25
32
  assert_equal expected_hash, obj.to_hash
26
33
  end
34
+
35
+ should "assign question mark accessors for booleans" do
36
+ obj = Stripe::StripeObject.construct_from({ :id => 1, :bool => true, :not_bool => 'bar' })
37
+ assert obj.respond_to?(:bool?)
38
+ assert obj.bool?
39
+ refute obj.respond_to?(:not_bool?)
40
+ end
41
+
42
+ should "mass assign values with #update_attributes" do
43
+ obj = Stripe::StripeObject.construct_from({ :id => 1, :name => 'Stripe' })
44
+ obj.update_attributes(:name => 'STRIPE')
45
+ assert_equal "STRIPE", obj.name
46
+
47
+ e = assert_raises(ArgumentError) do
48
+ obj.update_attributes(:foo => 'bar')
49
+ end
50
+ assert_equal "foo is not an attribute that can be assigned on this object", e.message
51
+ end
27
52
  end
28
53
  end
data/test/test_data.rb CHANGED
@@ -16,6 +16,14 @@ module Stripe
16
16
  m
17
17
  end
18
18
 
19
+ def make_account(params={})
20
+ {
21
+ :charges_enabled => false,
22
+ :details_submitted => false,
23
+ :email => "test+bindings@stripe.com",
24
+ }.merge(params)
25
+ end
26
+
19
27
  def make_balance(params={})
20
28
  {
21
29
  :pending => [
@@ -315,10 +323,11 @@ module Stripe
315
323
  :customer => 'c_test_customer',
316
324
  :date => 1349738950,
317
325
  :lines => {
318
- "invoiceitems" => [
326
+ :object => 'list',
327
+ :data => [
319
328
  {
320
329
  :id => 'ii_test_invoice_item',
321
- :object => '',
330
+ :object => 'invoiceitem',
322
331
  :livemode => false,
323
332
  :amount => 1000,
324
333
  :currency => 'usd',
@@ -338,7 +347,7 @@ module Stripe
338
347
  :charge => nil,
339
348
  :discount => nil,
340
349
  :ending_balance => nil,
341
- :next_payemnt_attempt => 1349825350,
350
+ :next_payment_attempt => 1349825350,
342
351
  }
343
352
  end
344
353
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stripe
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.27.2
4
+ version: 1.28.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ross Boucher
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-09-25 00:00:00.000000000 Z
12
+ date: 2015-10-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rest-client