stripe 1.27.2 → 1.28.0

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