paid 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.txt +6 -0
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/paid.rb +32 -207
- data/lib/paid/account.rb +22 -10
- data/lib/paid/api_list.rb +56 -17
- data/lib/paid/api_method.rb +93 -0
- data/lib/paid/api_resource.rb +130 -8
- data/lib/paid/customer.rb +104 -40
- data/lib/paid/errors/api_connection_error.rb +1 -1
- data/lib/paid/errors/api_error.rb +25 -3
- data/lib/paid/errors/authentication_error.rb +1 -1
- data/lib/paid/errors/paid_error.rb +2 -9
- data/lib/paid/event.rb +28 -17
- data/lib/paid/event_data.rb +10 -0
- data/lib/paid/headers_builder.rb +75 -0
- data/lib/paid/invoice.rb +55 -16
- data/lib/paid/params_builder.rb +26 -0
- data/lib/paid/path_builder.rb +38 -0
- data/lib/paid/plan.rb +38 -13
- data/lib/paid/refund_list.rb +26 -0
- data/lib/paid/requester.rb +97 -0
- data/lib/paid/subscription.rb +47 -16
- data/lib/paid/transaction.rb +64 -16
- data/lib/paid/util.rb +14 -40
- data/paid.gemspec +1 -1
- data/test/paid/{api_class_test.rb → _api_resource_test.rb} +31 -17
- data/test/paid/account_test.rb +3 -3
- data/test/paid/api_list_test.rb +14 -8
- data/test/paid/api_method_test.rb +89 -0
- data/test/paid/customer_test.rb +20 -10
- data/test/paid/event_test.rb +3 -4
- data/test/paid/headers_builder_test.rb +39 -0
- data/test/paid/invoice_test.rb +3 -3
- data/test/paid/params_builder_test.rb +57 -0
- data/test/paid/path_builder_test.rb +67 -0
- data/test/paid/plan_test.rb +3 -3
- data/test/paid/requester_test.rb +86 -0
- data/test/paid/subscription_test.rb +3 -3
- data/test/paid/transaction_test.rb +4 -4
- data/test/paid/util_test.rb +36 -35
- data/test/test_data.rb +9 -2
- data/test/test_helper.rb +14 -14
- metadata +23 -19
- data/lib/paid/api_class.rb +0 -338
- data/lib/paid/api_singleton.rb +0 -5
- data/lib/paid/errors/invalid_request_error.rb +0 -10
- data/test/mock_resource.rb +0 -69
- data/test/paid/api_resource_test.rb +0 -28
- data/test/paid/api_singleton_test.rb +0 -12
- data/test/paid/authentication_test.rb +0 -50
- data/test/paid/status_codes_test.rb +0 -63
data/test/test_helper.rb
CHANGED
@@ -4,29 +4,29 @@ require 'mocha/setup'
|
|
4
4
|
require 'stringio'
|
5
5
|
require 'shoulda'
|
6
6
|
require File.expand_path('../test_data', __FILE__)
|
7
|
-
require File.expand_path('../mock_resource', __FILE__)
|
7
|
+
# require File.expand_path('../mock_resource', __FILE__)
|
8
8
|
|
9
9
|
# monkeypatch request methods
|
10
10
|
module Paid
|
11
|
-
|
12
|
-
|
13
|
-
def self.mock_rest_client=(mock_client)
|
14
|
-
@mock_rest_client = mock_client
|
11
|
+
class << self
|
12
|
+
attr_accessor :mock_rest_client
|
15
13
|
end
|
16
14
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
15
|
+
module Requester
|
16
|
+
def self.request(method, url, params, headers)
|
17
|
+
case method
|
18
|
+
when :get then Paid::mock_rest_client.get(url, headers, params)
|
19
|
+
when :put then Paid::mock_rest_client.put(url, headers, params)
|
20
|
+
when :post then Paid::mock_rest_client.post(url, headers, params)
|
21
|
+
when :delete then Paid::mock_rest_client.delete(url, headers, params)
|
22
|
+
else
|
23
|
+
raise "Invalid method"
|
24
|
+
end
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
class Test::Unit::TestCase
|
29
|
+
class ::Test::Unit::TestCase
|
30
30
|
include Paid::TestData
|
31
31
|
include Mocha
|
32
32
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Calhoun
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-04-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rest-client
|
@@ -118,7 +118,7 @@ dependencies:
|
|
118
118
|
description: Paid is the programmatic way to manage payments. See https://paidapi.com
|
119
119
|
for details.
|
120
120
|
email:
|
121
|
-
-
|
121
|
+
- jon@apibits.com
|
122
122
|
- ryan@paidapi.com
|
123
123
|
executables:
|
124
124
|
- paid-console
|
@@ -139,37 +139,41 @@ files:
|
|
139
139
|
- gemfiles/yajl.gemfile
|
140
140
|
- lib/paid.rb
|
141
141
|
- lib/paid/account.rb
|
142
|
-
- lib/paid/api_class.rb
|
143
142
|
- lib/paid/api_list.rb
|
143
|
+
- lib/paid/api_method.rb
|
144
144
|
- lib/paid/api_resource.rb
|
145
|
-
- lib/paid/api_singleton.rb
|
146
145
|
- lib/paid/customer.rb
|
147
146
|
- lib/paid/errors/api_connection_error.rb
|
148
147
|
- lib/paid/errors/api_error.rb
|
149
148
|
- lib/paid/errors/authentication_error.rb
|
150
|
-
- lib/paid/errors/invalid_request_error.rb
|
151
149
|
- lib/paid/errors/paid_error.rb
|
152
150
|
- lib/paid/event.rb
|
151
|
+
- lib/paid/event_data.rb
|
152
|
+
- lib/paid/headers_builder.rb
|
153
153
|
- lib/paid/invoice.rb
|
154
|
+
- lib/paid/params_builder.rb
|
155
|
+
- lib/paid/path_builder.rb
|
154
156
|
- lib/paid/plan.rb
|
157
|
+
- lib/paid/refund_list.rb
|
158
|
+
- lib/paid/requester.rb
|
155
159
|
- lib/paid/subscription.rb
|
156
160
|
- lib/paid/transaction.rb
|
157
161
|
- lib/paid/util.rb
|
158
162
|
- lib/paid/version.rb
|
159
163
|
- paid.gemspec
|
160
164
|
- tasks/api_test.rb
|
161
|
-
- test/
|
165
|
+
- test/paid/_api_resource_test.rb
|
162
166
|
- test/paid/account_test.rb
|
163
|
-
- test/paid/api_class_test.rb
|
164
167
|
- test/paid/api_list_test.rb
|
165
|
-
- test/paid/
|
166
|
-
- test/paid/api_singleton_test.rb
|
167
|
-
- test/paid/authentication_test.rb
|
168
|
+
- test/paid/api_method_test.rb
|
168
169
|
- test/paid/customer_test.rb
|
169
170
|
- test/paid/event_test.rb
|
171
|
+
- test/paid/headers_builder_test.rb
|
170
172
|
- test/paid/invoice_test.rb
|
173
|
+
- test/paid/params_builder_test.rb
|
174
|
+
- test/paid/path_builder_test.rb
|
171
175
|
- test/paid/plan_test.rb
|
172
|
-
- test/paid/
|
176
|
+
- test/paid/requester_test.rb
|
173
177
|
- test/paid/subscription_test.rb
|
174
178
|
- test/paid/transaction_test.rb
|
175
179
|
- test/paid/util_test.rb
|
@@ -195,23 +199,23 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
195
199
|
version: '0'
|
196
200
|
requirements: []
|
197
201
|
rubyforge_project:
|
198
|
-
rubygems_version: 2.
|
202
|
+
rubygems_version: 2.4.5
|
199
203
|
signing_key:
|
200
204
|
specification_version: 4
|
201
205
|
summary: Ruby bindings for Paid API
|
202
206
|
test_files:
|
203
|
-
- test/
|
207
|
+
- test/paid/_api_resource_test.rb
|
204
208
|
- test/paid/account_test.rb
|
205
|
-
- test/paid/api_class_test.rb
|
206
209
|
- test/paid/api_list_test.rb
|
207
|
-
- test/paid/
|
208
|
-
- test/paid/api_singleton_test.rb
|
209
|
-
- test/paid/authentication_test.rb
|
210
|
+
- test/paid/api_method_test.rb
|
210
211
|
- test/paid/customer_test.rb
|
211
212
|
- test/paid/event_test.rb
|
213
|
+
- test/paid/headers_builder_test.rb
|
212
214
|
- test/paid/invoice_test.rb
|
215
|
+
- test/paid/params_builder_test.rb
|
216
|
+
- test/paid/path_builder_test.rb
|
213
217
|
- test/paid/plan_test.rb
|
214
|
-
- test/paid/
|
218
|
+
- test/paid/requester_test.rb
|
215
219
|
- test/paid/subscription_test.rb
|
216
220
|
- test/paid/transaction_test.rb
|
217
221
|
- test/paid/util_test.rb
|
data/lib/paid/api_class.rb
DELETED
@@ -1,338 +0,0 @@
|
|
1
|
-
module Paid
|
2
|
-
class APIClass
|
3
|
-
attr_accessor :json
|
4
|
-
|
5
|
-
def self.path
|
6
|
-
raise NotImplementedError.new("APIClass is an abstract class. Please refer to its subclasses: #{subclasses}")
|
7
|
-
end
|
8
|
-
|
9
|
-
def path
|
10
|
-
raise NotImplementedError.new("APIClass is an abstract class. Please refer to its subclasses: #{APIClass.subclasses}")
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.api_class_method(name, method, path=nil, opts={})
|
14
|
-
singleton = class << self; self end
|
15
|
-
singleton.send(:define_method, name, api_lambda(name, method, path, opts))
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.api_instance_method(name, method, path=nil, opts={})
|
19
|
-
self.send(:define_method, name, api_lambda(name, method, path, opts))
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.attribute(name, klass=nil)
|
23
|
-
@attribute_names ||= Set.new
|
24
|
-
@attribute_names << name.to_sym
|
25
|
-
|
26
|
-
self.send(:define_method, "#{name}", attribute_get_lambda(name))
|
27
|
-
self.send(:define_method, "#{name}=", attribute_set_lambda(name, klass))
|
28
|
-
end
|
29
|
-
|
30
|
-
def attributes
|
31
|
-
attributes = {}
|
32
|
-
self.class.attribute_names.each do |attr|
|
33
|
-
attributes[attr.to_sym] = self.send(attr)
|
34
|
-
end
|
35
|
-
attributes
|
36
|
-
end
|
37
|
-
|
38
|
-
def non_nil_attributes
|
39
|
-
attributes.select{|k, v| !v.nil? }
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.attribute_names
|
43
|
-
@attribute_names ||= Set.new
|
44
|
-
unless self == APIClass
|
45
|
-
@attribute_names + self.superclass.attribute_names
|
46
|
-
else
|
47
|
-
@attribute_names
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def mark_attribute_changed(attr_name)
|
52
|
-
@changed_attribute_names ||= Set.new
|
53
|
-
@changed_attribute_names << attr_name.to_sym
|
54
|
-
end
|
55
|
-
|
56
|
-
def changed_attribute_names
|
57
|
-
@changed_attribute_names ||= Set.new
|
58
|
-
attributes.each do |key, val|
|
59
|
-
next if @changed_attribute_names.include?(key)
|
60
|
-
if val.is_a?(Array) || val.is_a?(Hash)
|
61
|
-
@changed_attribute_names << key if json[key] != val
|
62
|
-
end
|
63
|
-
end
|
64
|
-
@changed_attribute_names
|
65
|
-
end
|
66
|
-
|
67
|
-
def changed_attributes
|
68
|
-
ret = {}
|
69
|
-
changed_attribute_names.each do |attr|
|
70
|
-
ret[attr] = send(attr)
|
71
|
-
end
|
72
|
-
ret
|
73
|
-
end
|
74
|
-
|
75
|
-
def clear_changed_attributes
|
76
|
-
@changed_attribute_names = Set.new
|
77
|
-
end
|
78
|
-
|
79
|
-
|
80
|
-
def self.changed_lambda
|
81
|
-
# This runs in the context of an instance since it is used in
|
82
|
-
# an api_instance_method
|
83
|
-
lambda do |instance|
|
84
|
-
instance.changed_attributes
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
def initialize(id=nil)
|
89
|
-
refresh_from(id)
|
90
|
-
end
|
91
|
-
|
92
|
-
def self.construct(json={})
|
93
|
-
self.new.refresh_from(json)
|
94
|
-
end
|
95
|
-
|
96
|
-
def refresh_from(json={})
|
97
|
-
unless json.is_a?(Hash)
|
98
|
-
json = { :id => json }
|
99
|
-
end
|
100
|
-
self.json = Util.sorta_deep_clone(json)
|
101
|
-
|
102
|
-
json.each do |k, v|
|
103
|
-
if self.class.attribute_names.include?(k.to_sym)
|
104
|
-
self.send("#{k}=", v)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
clear_changed_attributes
|
108
|
-
self
|
109
|
-
end
|
110
|
-
|
111
|
-
# Alias, but dont declare it as one because we need to use overloaded methods.
|
112
|
-
def construct(json={})
|
113
|
-
refresh_from(json)
|
114
|
-
end
|
115
|
-
|
116
|
-
def self.subclasses
|
117
|
-
return @subclasses ||= Set.new
|
118
|
-
end
|
119
|
-
|
120
|
-
def self.subclass_fetch(name)
|
121
|
-
@subclasses_hash ||= {}
|
122
|
-
if @subclasses_hash.has_key?(name)
|
123
|
-
@subclasses_hash[name]
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
def self.register_subclass(subclass, name=nil)
|
128
|
-
@subclasses ||= Set.new
|
129
|
-
@subclasses << subclass
|
130
|
-
|
131
|
-
unless name.nil?
|
132
|
-
@subclasses_hash ||= {}
|
133
|
-
@subclasses_hash[name] = subclass
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
def inspect
|
138
|
-
id_string = (self.respond_to?(:id) && !self.id.nil?) ? " id=#{self.id}" : ""
|
139
|
-
"#<#{self.class}:0x#{self.object_id.to_s(16)}#{id_string}> JSON: " + JSON.pretty_generate(attributes)
|
140
|
-
end
|
141
|
-
|
142
|
-
def to_json(*a)
|
143
|
-
JSON.generate(attributes)
|
144
|
-
end
|
145
|
-
|
146
|
-
|
147
|
-
private
|
148
|
-
|
149
|
-
def instance_variables_include?(name)
|
150
|
-
if RUBY_VERSION <= '1.9'
|
151
|
-
instance_variables.include?("@#{name}")
|
152
|
-
else
|
153
|
-
instance_variables.include?("@#{name}".to_sym)
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
def self.attribute_get_lambda(name)
|
158
|
-
lambda do
|
159
|
-
unless instance_variables_include?(name)
|
160
|
-
nil
|
161
|
-
else
|
162
|
-
instance_variable_get("@#{name}")
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
def self.attribute_set_lambda(name, klass=nil)
|
168
|
-
lambda do |val|
|
169
|
-
if klass
|
170
|
-
val = klass.construct(val)
|
171
|
-
end
|
172
|
-
instance_variable_set("@#{name}", val)
|
173
|
-
mark_attribute_changed(name)
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
def self.api_lambda(out_name, out_method, out_path=nil, out_opts={})
|
178
|
-
# Path, Opts, and Klass are all optional, so we have to determine
|
179
|
-
# which were provided using the criteria:
|
180
|
-
temp = [out_path, out_opts]
|
181
|
-
out_path = temp.select{ |t| t.is_a?(String) }.first || nil
|
182
|
-
out_opts = temp.select{ |t| t.is_a?(Hash) }.first || {}
|
183
|
-
|
184
|
-
out_arg_names = out_opts[:arguments] || []
|
185
|
-
out_constructor = out_opts[:constructor] || :self
|
186
|
-
out_default_params = out_opts[:default_params] || {}
|
187
|
-
|
188
|
-
lambda do |*args|
|
189
|
-
# Make sure we have clean data
|
190
|
-
constructor = out_constructor
|
191
|
-
method = out_method
|
192
|
-
path = nil
|
193
|
-
path = out_path.dup if out_path
|
194
|
-
arg_names = nil
|
195
|
-
arg_names = out_arg_names.dup if out_arg_names
|
196
|
-
default_params = out_default_params # dont need to dup this since it isn't modified directly
|
197
|
-
|
198
|
-
validate_args(arg_names, *args)
|
199
|
-
arguments = compose_arguments(method, arg_names, *args)
|
200
|
-
composed_path = compose_api_path(path, arguments)
|
201
|
-
unused_args = determine_unused_args(path, arg_names, arguments)
|
202
|
-
arguments[:params] = compose_params(arguments[:params], unused_args, default_params)
|
203
|
-
|
204
|
-
resp = Paid.request(method, composed_path, arguments[:params], arguments[:opts])
|
205
|
-
|
206
|
-
|
207
|
-
puts "Making a call to #{composed_path}"
|
208
|
-
|
209
|
-
if constructor.is_a?(Class)
|
210
|
-
constructor.construct(resp)
|
211
|
-
elsif constructor.is_a?(Proc)
|
212
|
-
constructor.call(resp)
|
213
|
-
elsif constructor.is_a?(Symbol)
|
214
|
-
if constructor == :self
|
215
|
-
self.construct(resp)
|
216
|
-
else
|
217
|
-
raise ArgumentError.new("Invalid constructor. See method definition.")
|
218
|
-
end
|
219
|
-
end
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
|
-
def self.validate_args(arg_names, *args)
|
224
|
-
# Make sure we have valid arguments
|
225
|
-
if args.length > arg_names.length
|
226
|
-
if args.length > arg_names.length + 2 # more than params and opts were included
|
227
|
-
raise ArgumentError.new("Too many arguments")
|
228
|
-
else
|
229
|
-
# Params and opts are allowed, but they must be hashes
|
230
|
-
args[arg_names.length..-1].each do |arg|
|
231
|
-
unless arg.is_a?(Hash) || arg.nil?
|
232
|
-
raise ArgumentError.new("Invalid Param or Opts argument")
|
233
|
-
end
|
234
|
-
end
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
238
|
-
if args.length < arg_names.length
|
239
|
-
missing = arg_names[args.length..-1]
|
240
|
-
raise ArgumentError.new("Missing arguments #{missing}")
|
241
|
-
end
|
242
|
-
end
|
243
|
-
def validate_args(arg_names, *args)
|
244
|
-
self.class.validate_args(arg_names, *args)
|
245
|
-
end
|
246
|
-
|
247
|
-
# Priority: params > unused_args > default_params
|
248
|
-
def self.compose_params(params={}, unused_args={}, default_params={}, this=self)
|
249
|
-
ret = {}
|
250
|
-
|
251
|
-
# Handle the default params
|
252
|
-
if default_params.is_a?(Proc)
|
253
|
-
default_params = default_params.call(this)
|
254
|
-
elsif default_params.is_a?(Symbol)
|
255
|
-
default_params = this.send(default_params)
|
256
|
-
end
|
257
|
-
|
258
|
-
ret.update(default_params || {})
|
259
|
-
ret.update(unused_args || {})
|
260
|
-
ret.update(params || {})
|
261
|
-
ret
|
262
|
-
end
|
263
|
-
def compose_params(params={}, unused_args={}, default_params={})
|
264
|
-
self.class.compose_params(params, unused_args, default_params, self)
|
265
|
-
end
|
266
|
-
|
267
|
-
def self.compose_arguments(method, arg_names, *args)
|
268
|
-
arguments = {}
|
269
|
-
names = arg_names.dup + [:params, :opts]
|
270
|
-
|
271
|
-
names.each_with_index do |k, i|
|
272
|
-
arguments[k] = args[i] if args.length > i
|
273
|
-
end
|
274
|
-
arguments[:params] ||= {}
|
275
|
-
arguments[:opts] ||= {}
|
276
|
-
|
277
|
-
arguments
|
278
|
-
end
|
279
|
-
def compose_arguments(method, arg_names, *args)
|
280
|
-
self.class.compose_arguments(method, arg_names, *args)
|
281
|
-
end
|
282
|
-
|
283
|
-
def self.compose_api_path(path, arguments, this=self)
|
284
|
-
# Setup the path using the following attribute order:
|
285
|
-
# 1. Args passed in
|
286
|
-
# 2. Args on this
|
287
|
-
# 3. Args on this.class
|
288
|
-
ret = (path || this.path).dup
|
289
|
-
if ret.include?(":")
|
290
|
-
missing = Set.new
|
291
|
-
matches = ret.scan(/:([^\/]*)/).flatten.map(&:to_sym)
|
292
|
-
matches.each do |match|
|
293
|
-
value = arguments[match]
|
294
|
-
begin
|
295
|
-
value ||= this.send(match)
|
296
|
-
rescue NoMethodError
|
297
|
-
end
|
298
|
-
begin
|
299
|
-
value ||= this.class.send(match) unless this.class == Class
|
300
|
-
rescue NoMethodError
|
301
|
-
end
|
302
|
-
|
303
|
-
if value.nil?
|
304
|
-
missing << match
|
305
|
-
end
|
306
|
-
|
307
|
-
ret.sub!(match.inspect, "#{value}")
|
308
|
-
end
|
309
|
-
|
310
|
-
unless missing.empty?
|
311
|
-
raise InvalidRequestError.new("Could not determine the full URL to request. Missing the following values: #{missing.to_a.join(', ')}.")
|
312
|
-
end
|
313
|
-
end
|
314
|
-
ret
|
315
|
-
end
|
316
|
-
def compose_api_path(path, arguments)
|
317
|
-
self.class.compose_api_path(path, arguments, self)
|
318
|
-
end
|
319
|
-
|
320
|
-
def self.determine_unused_args(path, arg_names, arguments, this=self)
|
321
|
-
unused = Set.new(arg_names)
|
322
|
-
path ||= this.path
|
323
|
-
if path.include?(":")
|
324
|
-
matches = path.scan(/:([^\/]*)/).flatten.map(&:to_sym)
|
325
|
-
matches.each{ |m| unused.delete(m) }
|
326
|
-
end
|
327
|
-
ret = {}
|
328
|
-
unused.each do |arg_name|
|
329
|
-
ret[arg_name] = arguments[arg_name]
|
330
|
-
end
|
331
|
-
ret
|
332
|
-
end
|
333
|
-
def determine_unused_args(path, arg_names, arguments)
|
334
|
-
self.class.determine_unused_args(path, arg_names, arguments, self)
|
335
|
-
end
|
336
|
-
|
337
|
-
end
|
338
|
-
end
|