stripe 1.7.0 → 1.7.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 (48) hide show
  1. data/.gitignore +2 -0
  2. data/.travis.yml +8 -0
  3. data/CONTRIBUTORS +3 -0
  4. data/Gemfile +2 -0
  5. data/Gemfile.lock +34 -0
  6. data/History.txt +68 -0
  7. data/LICENSE +21 -0
  8. data/README.rdoc +28 -0
  9. data/Rakefile +9 -0
  10. data/VERSION +1 -0
  11. data/gemfiles/default-with-activesupport.gemfile +3 -0
  12. data/gemfiles/default-with-activesupport.gemfile.lock +39 -0
  13. data/gemfiles/json.gemfile +4 -0
  14. data/gemfiles/json.gemfile.lock +41 -0
  15. data/gemfiles/yajl.gemfile +4 -0
  16. data/gemfiles/yajl.gemfile.lock +41 -0
  17. data/lib/stripe.rb +62 -500
  18. data/lib/stripe/account.rb +4 -0
  19. data/lib/stripe/api_operations/create.rb +16 -0
  20. data/lib/stripe/api_operations/delete.rb +11 -0
  21. data/lib/stripe/api_operations/list.rb +16 -0
  22. data/lib/stripe/api_operations/update.rb +15 -0
  23. data/lib/stripe/api_resource.rb +33 -0
  24. data/lib/stripe/charge.rb +29 -0
  25. data/lib/stripe/coupon.rb +7 -0
  26. data/lib/stripe/customer.rb +51 -0
  27. data/lib/stripe/errors/api_connection_error.rb +4 -0
  28. data/lib/stripe/errors/api_error.rb +4 -0
  29. data/lib/stripe/errors/authentication_error.rb +4 -0
  30. data/lib/stripe/errors/card_error.rb +11 -0
  31. data/lib/stripe/errors/invalid_request_error.rb +10 -0
  32. data/lib/stripe/errors/stripe_error.rb +20 -0
  33. data/lib/stripe/event.rb +5 -0
  34. data/lib/stripe/invoice.rb +16 -0
  35. data/lib/stripe/invoice_item.rb +8 -0
  36. data/lib/stripe/json.rb +21 -0
  37. data/lib/stripe/plan.rb +8 -0
  38. data/lib/stripe/singleton_api_resource.rb +20 -0
  39. data/lib/stripe/stripe_object.rb +150 -0
  40. data/lib/stripe/token.rb +5 -0
  41. data/lib/stripe/transfer.rb +16 -0
  42. data/lib/stripe/util.rb +103 -0
  43. data/lib/stripe/version.rb +1 -1
  44. data/stripe.gemspec +28 -0
  45. data/test/test_helper.rb +175 -0
  46. data/test/test_stripe.rb +472 -0
  47. data/test/test_stripe_with_active_support.rb +3 -0
  48. metadata +54 -7
@@ -0,0 +1,4 @@
1
+ module Stripe
2
+ class Account < SingletonAPIResource
3
+ end
4
+ end
@@ -0,0 +1,16 @@
1
+ module Stripe
2
+ module APIOperations
3
+ module Create
4
+ module ClassMethods
5
+ def create(params={}, api_key=nil)
6
+ response, api_key = Stripe.request(:post, self.url, api_key, params)
7
+ Util.convert_to_stripe_object(response, api_key)
8
+ end
9
+ end
10
+
11
+ def self.included(base)
12
+ base.extend(ClassMethods)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,11 @@
1
+ module Stripe
2
+ module APIOperations
3
+ module Delete
4
+ def delete
5
+ response, api_key = Stripe.request(:delete, url, @api_key)
6
+ refresh_from(response, api_key)
7
+ self
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ module Stripe
2
+ module APIOperations
3
+ module List
4
+ module ClassMethods
5
+ def all(filters={}, api_key=nil)
6
+ response, api_key = Stripe.request(:get, url, api_key, filters)
7
+ Util.convert_to_stripe_object(response, api_key)
8
+ end
9
+ end
10
+
11
+ def self.included(base)
12
+ base.extend(ClassMethods)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ module Stripe
2
+ module APIOperations
3
+ module Update
4
+ def save
5
+ if @unsaved_values.length > 0
6
+ values = {}
7
+ @unsaved_values.each { |k| values[k] = @values[k] }
8
+ response, api_key = Stripe.request(:post, url, @api_key, values)
9
+ refresh_from(response, api_key)
10
+ end
11
+ self
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,33 @@
1
+ module Stripe
2
+ class APIResource < StripeObject
3
+ def self.class_name
4
+ self.name.split('::')[-1]
5
+ end
6
+
7
+ def self.url()
8
+ if self == APIResource
9
+ raise NotImplementedError.new('APIResource is an abstract class. You should perform actions on its subclasses (Charge, Customer, etc.)')
10
+ end
11
+ "/#{CGI.escape(class_name.downcase)}s"
12
+ end
13
+
14
+ def url
15
+ unless id = self['id']
16
+ raise InvalidRequestError.new("Could not determine which URL to request: #{self.class} instance has invalid ID: #{id.inspect}", 'id')
17
+ end
18
+ "#{self.class.url}/#{CGI.escape(id)}"
19
+ end
20
+
21
+ def refresh
22
+ response, api_key = Stripe.request(:get, url, @api_key)
23
+ refresh_from(response, api_key)
24
+ self
25
+ end
26
+
27
+ def self.retrieve(id, api_key=nil)
28
+ instance = self.new(id, api_key)
29
+ instance.refresh
30
+ instance
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,29 @@
1
+ module Stripe
2
+ class Charge < APIResource
3
+ include Stripe::APIOperations::List
4
+ include Stripe::APIOperations::Create
5
+ include Stripe::APIOperations::Update
6
+
7
+ def refund(params={})
8
+ response, api_key = Stripe.request(:post, refund_url, @api_key, params)
9
+ refresh_from(response, api_key)
10
+ self
11
+ end
12
+
13
+ def capture(params={})
14
+ response, api_key = Stripe.request(:post, capture_url, @api_key, params)
15
+ refresh_from(response, api_key)
16
+ self
17
+ end
18
+
19
+ private
20
+
21
+ def refund_url
22
+ url + '/refund'
23
+ end
24
+
25
+ def capture_url
26
+ url + '/capture'
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,7 @@
1
+ module Stripe
2
+ class Coupon < APIResource
3
+ include Stripe::APIOperations::Create
4
+ include Stripe::APIOperations::Delete
5
+ include Stripe::APIOperations::List
6
+ end
7
+ end
@@ -0,0 +1,51 @@
1
+ module Stripe
2
+ class Customer < APIResource
3
+ include Stripe::APIOperations::Create
4
+ include Stripe::APIOperations::Delete
5
+ include Stripe::APIOperations::Update
6
+ include Stripe::APIOperations::List
7
+
8
+ def add_invoice_item(params)
9
+ InvoiceItem.create(params.merge(:customer => id), @api_key)
10
+ end
11
+
12
+ def invoices
13
+ Invoice.all({ :customer => id }, @api_key)
14
+ end
15
+
16
+ def invoice_items
17
+ InvoiceItem.all({ :customer => id }, @api_key)
18
+ end
19
+
20
+ def charges
21
+ Charge.all({ :customer => id }, @api_key)
22
+ end
23
+
24
+ def cancel_subscription(params={})
25
+ response, api_key = Stripe.request(:delete, subscription_url, @api_key, params)
26
+ refresh_from({ :subscription => response }, api_key, true)
27
+ subscription
28
+ end
29
+
30
+ def update_subscription(params)
31
+ response, api_key = Stripe.request(:post, subscription_url, @api_key, params)
32
+ refresh_from({ :subscription => response }, api_key, true)
33
+ subscription
34
+ end
35
+
36
+ def delete_discount
37
+ Stripe.request(:delete, discount_url, @api_key)
38
+ refresh_from({ :discount => nil }, api_key, true)
39
+ end
40
+
41
+ private
42
+
43
+ def discount_url
44
+ url + '/discount'
45
+ end
46
+
47
+ def subscription_url
48
+ url + '/subscription'
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,4 @@
1
+ module Stripe
2
+ class APIConnectionError < StripeError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Stripe
2
+ class APIError < StripeError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Stripe
2
+ class AuthenticationError < StripeError
3
+ end
4
+ end
@@ -0,0 +1,11 @@
1
+ module Stripe
2
+ class CardError < StripeError
3
+ attr_reader :param, :code
4
+
5
+ def initialize(message, param, code, http_status=nil, http_body=nil, json_body=nil)
6
+ super(message, http_status, http_body, json_body)
7
+ @param = param
8
+ @code = code
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ module Stripe
2
+ class InvalidRequestError < StripeError
3
+ attr_accessor :param
4
+
5
+ def initialize(message, param, http_status=nil, http_body=nil, json_body=nil)
6
+ super(message, http_status, http_body, json_body)
7
+ @param = param
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,20 @@
1
+ module Stripe
2
+ class StripeError < StandardError
3
+ attr_reader :message
4
+ attr_reader :http_status
5
+ attr_reader :http_body
6
+ attr_reader :json_body
7
+
8
+ def initialize(message=nil, http_status=nil, http_body=nil, json_body=nil)
9
+ @message = message
10
+ @http_status = http_status
11
+ @http_body = http_body
12
+ @json_body = json_body
13
+ end
14
+
15
+ def to_s
16
+ status_string = @http_status.nil? ? "" : "(Status #{@http_status}) "
17
+ "#{status_string}#{@message}"
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,5 @@
1
+ module Stripe
2
+ class Event < APIResource
3
+ include Stripe::APIOperations::List
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ module Stripe
2
+ class Invoice < APIResource
3
+ include Stripe::APIOperations::List
4
+
5
+ def self.upcoming(params)
6
+ response, api_key = Stripe.request(:get, upcoming_url, @api_key, params)
7
+ Util.convert_to_stripe_object(response, api_key)
8
+ end
9
+
10
+ private
11
+
12
+ def self.upcoming_url
13
+ url + '/upcoming'
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,8 @@
1
+ module Stripe
2
+ class InvoiceItem < APIResource
3
+ include Stripe::APIOperations::List
4
+ include Stripe::APIOperations::Create
5
+ include Stripe::APIOperations::Delete
6
+ include Stripe::APIOperations::Update
7
+ end
8
+ end
@@ -0,0 +1,21 @@
1
+ module Stripe
2
+ module JSON
3
+ if MultiJson.respond_to?(:dump)
4
+ def self.dump(*args)
5
+ MultiJson.dump(*args)
6
+ end
7
+
8
+ def self.load(*args)
9
+ MultiJson.load(*args)
10
+ end
11
+ else
12
+ def self.dump(*args)
13
+ MultiJson.encode(*args)
14
+ end
15
+
16
+ def self.load(*args)
17
+ MultiJson.decode(*args)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,8 @@
1
+ module Stripe
2
+ class Plan < APIResource
3
+ include Stripe::APIOperations::Create
4
+ include Stripe::APIOperations::Delete
5
+ include Stripe::APIOperations::List
6
+ include Stripe::APIOperations::Update
7
+ end
8
+ end
@@ -0,0 +1,20 @@
1
+ module Stripe
2
+ class SingletonAPIResource < APIResource
3
+ def self.url()
4
+ if self == SingletonAPIResource
5
+ raise NotImplementedError.new('SingletonAPIResource is an abstract class. You should perform actions on its subclasses (Account, etc.)')
6
+ end
7
+ "/#{CGI.escape(class_name.downcase)}"
8
+ end
9
+
10
+ def url
11
+ self.class.url
12
+ end
13
+
14
+ def self.retrieve(api_key=nil)
15
+ instance = self.new(nil, api_key)
16
+ instance.refresh
17
+ instance
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,150 @@
1
+ module Stripe
2
+ class StripeObject
3
+ include Enumerable
4
+
5
+ attr_accessor :api_key
6
+ @@permanent_attributes = Set.new([:api_key])
7
+
8
+ # The default :id method is deprecated and isn't useful to us
9
+ if method_defined?(:id)
10
+ undef :id
11
+ end
12
+
13
+ def initialize(id=nil, api_key=nil)
14
+ @api_key = api_key
15
+ @values = {}
16
+ # This really belongs in APIResource, but not putting it there allows us
17
+ # to have a unified inspect method
18
+ @unsaved_values = Set.new
19
+ @transient_values = Set.new
20
+ self.id = id if id
21
+ end
22
+
23
+ def self.construct_from(values, api_key=nil)
24
+ obj = self.new(values[:id], api_key)
25
+ obj.refresh_from(values, api_key)
26
+ obj
27
+ end
28
+
29
+ def to_s(*args)
30
+ Stripe::JSON.dump(@values, :pretty => true)
31
+ end
32
+
33
+ def inspect()
34
+ id_string = (self.respond_to?(:id) && !self.id.nil?) ? " id=#{self.id}" : ""
35
+ "#<#{self.class}:0x#{self.object_id.to_s(16)}#{id_string}> JSON: " + Stripe::JSON.dump(@values, :pretty => true)
36
+ end
37
+
38
+ def refresh_from(values, api_key, partial=false)
39
+ @api_key = api_key
40
+
41
+ removed = partial ? Set.new : Set.new(@values.keys - values.keys)
42
+ added = Set.new(values.keys - @values.keys)
43
+ # Wipe old state before setting new. This is useful for e.g. updating a
44
+ # customer, where there is no persistent card parameter. Mark those values
45
+ # which don't persist as transient
46
+
47
+ instance_eval do
48
+ remove_accessors(removed)
49
+ add_accessors(added)
50
+ end
51
+ removed.each do |k|
52
+ @values.delete(k)
53
+ @transient_values.add(k)
54
+ @unsaved_values.delete(k)
55
+ end
56
+ values.each do |k, v|
57
+ @values[k] = Util.convert_to_stripe_object(v, api_key)
58
+ @transient_values.delete(k)
59
+ @unsaved_values.delete(k)
60
+ end
61
+ end
62
+
63
+ def [](k)
64
+ k = k.to_sym if k.kind_of?(String)
65
+ @values[k]
66
+ end
67
+
68
+ def []=(k, v)
69
+ send(:"#{k}=", v)
70
+ end
71
+
72
+ def keys
73
+ @values.keys
74
+ end
75
+
76
+ def values
77
+ @values.values
78
+ end
79
+
80
+ def to_json(*a)
81
+ Stripe::JSON.dump(@values)
82
+ end
83
+
84
+ def as_json(*a)
85
+ @values.as_json(*a)
86
+ end
87
+
88
+ def to_hash
89
+ @values
90
+ end
91
+
92
+ def each(&blk)
93
+ @values.each(&blk)
94
+ end
95
+
96
+ protected
97
+
98
+ def metaclass
99
+ class << self; self; end
100
+ end
101
+
102
+ def remove_accessors(keys)
103
+ metaclass.instance_eval do
104
+ keys.each do |k|
105
+ next if @@permanent_attributes.include?(k)
106
+ k_eq = :"#{k}="
107
+ remove_method(k) if method_defined?(k)
108
+ remove_method(k_eq) if method_defined?(k_eq)
109
+ end
110
+ end
111
+ end
112
+
113
+ def add_accessors(keys)
114
+ metaclass.instance_eval do
115
+ keys.each do |k|
116
+ next if @@permanent_attributes.include?(k)
117
+ k_eq = :"#{k}="
118
+ define_method(k) { @values[k] }
119
+ define_method(k_eq) do |v|
120
+ @values[k] = v
121
+ @unsaved_values.add(k)
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ def method_missing(name, *args)
128
+ # TODO: only allow setting in updateable classes.
129
+ if name.to_s.end_with?('=')
130
+ attr = name.to_s[0...-1].to_sym
131
+ @values[attr] = args[0]
132
+ @unsaved_values.add(attr)
133
+ add_accessors([attr])
134
+ return
135
+ else
136
+ return @values[name] if @values.has_key?(name)
137
+ end
138
+
139
+ begin
140
+ super
141
+ rescue NoMethodError => e
142
+ if @transient_values.include?(name)
143
+ 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(', ')}")
144
+ else
145
+ raise
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end