payjp 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.rubocop.yml +82 -0
  4. data/.rubocop_todo.yml +35 -0
  5. data/.travis.yml +22 -0
  6. data/CONTRIBUTORS +0 -0
  7. data/Gemfile +8 -0
  8. data/History.txt +0 -0
  9. data/LICENSE +21 -0
  10. data/README.rdoc +43 -0
  11. data/Rakefile +8 -0
  12. data/VERSION +1 -0
  13. data/gemfiles/default-with-activesupport.gemfile +10 -0
  14. data/gemfiles/json.gemfile +12 -0
  15. data/gemfiles/yajl.gemfile +12 -0
  16. data/lib/payjp.rb +279 -0
  17. data/lib/payjp/account.rb +11 -0
  18. data/lib/payjp/api_operations/create.rb +16 -0
  19. data/lib/payjp/api_operations/delete.rb +11 -0
  20. data/lib/payjp/api_operations/list.rb +17 -0
  21. data/lib/payjp/api_operations/request.rb +39 -0
  22. data/lib/payjp/api_operations/update.rb +17 -0
  23. data/lib/payjp/api_resource.rb +35 -0
  24. data/lib/payjp/card.rb +18 -0
  25. data/lib/payjp/charge.rb +27 -0
  26. data/lib/payjp/customer.rb +8 -0
  27. data/lib/payjp/errors/api_connection_error.rb +4 -0
  28. data/lib/payjp/errors/api_error.rb +4 -0
  29. data/lib/payjp/errors/authentication_error.rb +4 -0
  30. data/lib/payjp/errors/card_error.rb +11 -0
  31. data/lib/payjp/errors/invalid_request_error.rb +10 -0
  32. data/lib/payjp/errors/payjp_error.rb +20 -0
  33. data/lib/payjp/event.rb +5 -0
  34. data/lib/payjp/list_object.rb +33 -0
  35. data/lib/payjp/payjp_object.rb +259 -0
  36. data/lib/payjp/plan.rb +8 -0
  37. data/lib/payjp/subscription.rb +37 -0
  38. data/lib/payjp/token.rb +5 -0
  39. data/lib/payjp/transfer.rb +5 -0
  40. data/lib/payjp/util.rb +121 -0
  41. data/lib/payjp/version.rb +3 -0
  42. data/payjp.gemspec +27 -0
  43. data/test/payjp/account_test.rb +17 -0
  44. data/test/payjp/api_resource_test.rb +445 -0
  45. data/test/payjp/charge_test.rb +83 -0
  46. data/test/payjp/customer_card_test.rb +61 -0
  47. data/test/payjp/customer_test.rb +35 -0
  48. data/test/payjp/event_test.rb +26 -0
  49. data/test/payjp/list_object_test.rb +16 -0
  50. data/test/payjp/metadata_test.rb +103 -0
  51. data/test/payjp/payjp_object_test.rb +28 -0
  52. data/test/payjp/plan_test.rb +48 -0
  53. data/test/payjp/subscription_test.rb +58 -0
  54. data/test/payjp/token_test.rb +34 -0
  55. data/test/payjp/transfer_test.rb +34 -0
  56. data/test/payjp/util_test.rb +34 -0
  57. data/test/test_data.rb +291 -0
  58. data/test/test_helper.rb +45 -0
  59. metadata +201 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a3ebefc29e62141f365e3ca15bb11d052229d6fc
4
+ data.tar.gz: 198a11ab68493049c173f512f05d6ac9122bad64
5
+ SHA512:
6
+ metadata.gz: 18b6e0e221ad9d6da678bd12cc5b091b6a824f95e3e0de34841a500ceed0fa25b6ab9724abc834180f39a609f379a181fa347a9a9d930fb5ff26ad8a47dc0002
7
+ data.tar.gz: 58037b77c13b1aa5d2536c0ddced86fc72fc99f6e5e0b6fe2f872efdfab5a60a4e19f67f9dd6e1a04d966cdc872b07fbb50cac3535d2c1d673fa4b5a41308350
@@ -0,0 +1,7 @@
1
+ /payjp-*.gem
2
+ /Gemfile.lock
3
+ .rvmrc
4
+ Gemfile.lock
5
+ .idea/*
6
+ .ruby-version
7
+ pkg/*
@@ -0,0 +1,82 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ Style/PerlBackrefs:
4
+ Enabled: false
5
+
6
+ Style/IndentHash:
7
+ Enabled: false
8
+
9
+ Style/StringLiterals:
10
+ Enabled: false
11
+
12
+ Style/DeprecatedHashMethods:
13
+ Enabled: false
14
+
15
+ Style/RaiseArgs:
16
+ Enabled: false
17
+
18
+ Style/SignalException:
19
+ Enabled: false
20
+
21
+ Style/NumericLiterals:
22
+ MinDigits: 11
23
+
24
+ Style/ClassAndModuleChildren:
25
+ Enabled: false
26
+
27
+ Style/Documentation:
28
+ Enabled: false
29
+
30
+ Metrics/AbcSize:
31
+ Max: 45
32
+
33
+ Metrics/ClassLength:
34
+ Max: 376
35
+
36
+ Metrics/CyclomaticComplexity:
37
+ Max: 16
38
+
39
+ Metrics/LineLength:
40
+ Max: 315
41
+
42
+ Metrics/MethodLength:
43
+ Max: 63
44
+
45
+ Metrics/ModuleLength:
46
+ Max: 265
47
+
48
+ Metrics/ParameterLists:
49
+ Max: 6
50
+
51
+ Metrics/PerceivedComplexity:
52
+ Max: 20
53
+
54
+ Style/GuardClause:
55
+ MinBodyLength: 4
56
+
57
+ Style/FileName:
58
+ Exclude:
59
+ - '**/payjp-console'
60
+
61
+ Style/RescueModifier:
62
+ Enabled: false
63
+
64
+ #######################
65
+ # for ruby 1.8.7
66
+ #######################
67
+ # Configuration parameters: WordRegex.
68
+ Style/WordArray:
69
+ MinSize: 2
70
+
71
+ # Configuration parameters: SupportedStyles, UseHashRocketsWithSymbolValues.
72
+ Style/HashSyntax:
73
+ EnforcedStyle: hash_rockets
74
+
75
+ Style/Lambda:
76
+ Enabled: false
77
+
78
+ Style/EachWithObject:
79
+ Enabled: false
80
+
81
+ Style/DotPosition:
82
+ Enabled: false
@@ -0,0 +1,35 @@
1
+ # This configuration was generated by `rubocop --auto-gen-config`
2
+ # on 2015-06-28 13:48:45 +0900 using RuboCop version 0.32.1.
3
+ # The point is for the user to remove these configuration records
4
+ # one by one as the offenses are removed from the code base.
5
+ # Note that changes in the inspected code, or installation of new
6
+ # versions of RuboCop, may require this file to be generated again.
7
+
8
+ # Offense count: 3
9
+ # Configuration parameters: AllowSafeAssignment.
10
+ Lint/AssignmentInCondition:
11
+ Enabled: false
12
+
13
+ # Offense count: 1
14
+ Lint/ShadowingOuterLocalVariable:
15
+ Enabled: false
16
+
17
+ # Offense count: 3
18
+ # Cop supports --auto-correct.
19
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
20
+ Style/AndOr:
21
+ Enabled: false
22
+
23
+ # Offense count: 32
24
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
25
+ Style/BracesAroundHashParameters:
26
+ Enabled: false
27
+
28
+ # Offense count: 1
29
+ Style/ClassVars:
30
+ Enabled: false
31
+
32
+ # Offense count: 6
33
+ Style/DoubleNegation:
34
+ Enabled: false
35
+
@@ -0,0 +1,22 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 1.8.7
5
+ - 1.9.2
6
+ - 1.9.3
7
+ - 2.0.0
8
+ - 2.1
9
+ - 2.2
10
+ - jruby-19mode
11
+
12
+ gemfile:
13
+ - gemfiles/default-with-activesupport.gemfile
14
+ - gemfiles/json.gemfile
15
+ - gemfiles/yajl.gemfile
16
+
17
+ matrix:
18
+ exclude:
19
+ - rvm: jruby-19mode
20
+ gemfile: gemfiles/yajl.gemfile
21
+
22
+ sudo: false
File without changes
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+ gemspec
3
+
4
+ if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('1.9.3')
5
+ gem 'i18n', '< 0.7'
6
+ gem 'rest-client', '~> 1.6.8'
7
+ gem 'activesupport', '~> 3.2'
8
+ end
File without changes
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2011- Stripe, Inc. (https://stripe.com)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,43 @@
1
+ = PAY.JP for Ruby
2
+
3
+ == Documentation
4
+
5
+ {PAY.JP API Docs}[http://pay.readme.io/v1.0/docs]
6
+
7
+ == Installation
8
+
9
+ You don't need this source code unless you want to modify the gem. If
10
+ you just want to use the Payjp Ruby bindings, you should run:
11
+
12
+ gem install payjp
13
+
14
+ If you want to build the gem from source:
15
+
16
+ gem build payjp.gemspec
17
+
18
+ == Requirements
19
+
20
+ * Ruby 1.8.7 or above. (Ruby 1.8.6 may work if you load
21
+ ActiveSupport.) For Ruby versions before 1.9.2, you'll need to add this to your Gemfile:
22
+
23
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('1.9.2')
24
+ gem 'rest-client', '~> 1.6.8'
25
+ end
26
+
27
+
28
+ * rest-client, json
29
+
30
+ == Bundler
31
+
32
+ If you are installing via bundler, you should be sure to use the https
33
+ rubygems source in your Gemfile, as any gems fetched over http could potentially be
34
+ compromised in transit and alter the code of gems fetched securely over https:
35
+
36
+ source 'https://rubygems.org'
37
+
38
+ gem 'rails'
39
+ gem 'payjp'
40
+
41
+ == Development
42
+
43
+ Test cases can be run with: `bundle exec rake test`
@@ -0,0 +1,8 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ task :default => [:test]
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.pattern = './test/**/*_test.rb'
8
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.2
@@ -0,0 +1,10 @@
1
+ source "https://rubygems.org"
2
+ gemspec :path => File.join(File.dirname(__FILE__), "..")
3
+
4
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('1.9.3')
5
+ gem 'i18n', '< 0.7'
6
+ gem 'rest-client', '~> 1.6.8'
7
+ gem 'activesupport', '~> 3.2'
8
+ else
9
+ gem 'activesupport'
10
+ end
@@ -0,0 +1,12 @@
1
+ source "https://rubygems.org"
2
+ gemspec :path => File.join(File.dirname(__FILE__), "..")
3
+
4
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('1.9.3')
5
+ gem 'i18n', '< 0.7'
6
+ gem 'rest-client', '~> 1.6.8'
7
+ gem 'activesupport', '~> 3.2'
8
+ else
9
+ gem 'activesupport'
10
+ end
11
+
12
+ gem 'json'
@@ -0,0 +1,12 @@
1
+ source "https://rubygems.org"
2
+ gemspec :path => File.join(File.dirname(__FILE__), "..")
3
+
4
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('1.9.3')
5
+ gem 'i18n', '< 0.7'
6
+ gem 'rest-client', '~> 1.6.8'
7
+ gem 'activesupport', '~> 3.2'
8
+ else
9
+ gem 'activesupport'
10
+ end
11
+
12
+ gem 'yajl-ruby'
@@ -0,0 +1,279 @@
1
+ # Payjp Ruby bindings
2
+ # API spec at https://pay.jp/docs/api
3
+ require 'cgi'
4
+ require 'openssl'
5
+ require 'rbconfig'
6
+ require 'set'
7
+ require 'socket'
8
+
9
+ require 'rest-client'
10
+ require 'json'
11
+ require 'base64'
12
+
13
+ # Version
14
+ require 'payjp/version'
15
+
16
+ # API operations
17
+ require 'payjp/api_operations/create'
18
+ require 'payjp/api_operations/update'
19
+ require 'payjp/api_operations/delete'
20
+ require 'payjp/api_operations/list'
21
+ require 'payjp/api_operations/request'
22
+
23
+ # Resources
24
+ require 'payjp/util'
25
+ require 'payjp/payjp_object'
26
+ require 'payjp/api_resource'
27
+ require 'payjp/list_object'
28
+ require 'payjp/account'
29
+ require 'payjp/customer'
30
+ require 'payjp/charge'
31
+ require 'payjp/plan'
32
+ require 'payjp/token'
33
+ require 'payjp/event'
34
+ require 'payjp/transfer'
35
+ require 'payjp/card'
36
+ require 'payjp/subscription'
37
+
38
+ # Errors
39
+ require 'payjp/errors/payjp_error'
40
+ require 'payjp/errors/api_error'
41
+ require 'payjp/errors/api_connection_error'
42
+ require 'payjp/errors/card_error'
43
+ require 'payjp/errors/invalid_request_error'
44
+ require 'payjp/errors/authentication_error'
45
+
46
+ module Payjp
47
+ @api_base = 'https://api.pay.jp'
48
+
49
+ class << self
50
+ attr_accessor :api_key, :api_base, :api_version, :connect_base, :uploads_base
51
+ end
52
+
53
+ def self.api_url(url = '', api_base_url = nil)
54
+ (api_base_url || @api_base) + url
55
+ end
56
+
57
+ def self.request(method, url, api_key, params = {}, headers = {}, api_base_url = nil)
58
+ api_base_url ||= @api_base
59
+
60
+ unless api_key ||= @api_key
61
+ raise AuthenticationError.new('No API key provided. ' \
62
+ 'Set your API key using "Payjp.api_key = <API-KEY>". ' \
63
+ 'You can generate API keys from the Payjp web interface. ' \
64
+ 'See https://pay.jp/api for details, or email support@pay.jp ' \
65
+ 'if you have any questions.')
66
+ end
67
+
68
+ if api_key =~ /\s/
69
+ raise AuthenticationError.new('Your API key is invalid, as it contains ' \
70
+ 'whitespace. (HINT: You can double-check your API key from the ' \
71
+ 'Payjp web interface. See https://pay.jp/api for details, or ' \
72
+ 'email support@pay.jp if you have any questions.)')
73
+ end
74
+
75
+ request_opts = {}
76
+
77
+ params = Util.objects_to_ids(params)
78
+ url = api_url(url, api_base_url)
79
+
80
+ case method.to_s.downcase.to_sym
81
+ when :get, :head, :delete
82
+ # Make params into GET parameters
83
+ url += "#{URI.parse(url).query ? '&' : '?'}#{uri_encode(params)}" if params && params.any?
84
+ payload = nil
85
+ else
86
+ if headers[:content_type] && headers[:content_type] == "multipart/form-data"
87
+ payload = params
88
+ else
89
+ payload = uri_encode(params)
90
+ end
91
+ end
92
+
93
+ request_opts.update(:headers => request_headers(api_key).update(headers),
94
+ :method => method, :open_timeout => 30,
95
+ :payload => payload, :url => url, :timeout => 80)
96
+
97
+ begin
98
+ # $stderr.puts request_opts
99
+
100
+ response = execute_request(request_opts)
101
+ rescue SocketError => e
102
+ handle_restclient_error(e, api_base_url)
103
+ rescue NoMethodError => e
104
+ # Work around RestClient bug
105
+ if e.message =~ /\WRequestFailed\W/
106
+ e = APIConnectionError.new('Unexpected HTTP response code')
107
+ handle_restclient_error(e, api_base_url)
108
+ else
109
+ raise
110
+ end
111
+ rescue RestClient::ExceptionWithResponse => e
112
+ if rcode = e.http_code and rbody = e.http_body
113
+ handle_api_error(rcode, rbody)
114
+ else
115
+ handle_restclient_error(e, api_base_url)
116
+ end
117
+ rescue RestClient::Exception, Errno::ECONNREFUSED => e
118
+ handle_restclient_error(e, api_base_url)
119
+ end
120
+
121
+ [parse(response), api_key]
122
+ end
123
+
124
+ private
125
+
126
+ def self.user_agent
127
+ @uname ||= uname
128
+ lang_version = "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})"
129
+
130
+ {
131
+ :bindings_version => Payjp::VERSION,
132
+ :lang => 'ruby',
133
+ :lang_version => lang_version,
134
+ :platform => RUBY_PLATFORM,
135
+ :engine => defined?(RUBY_ENGINE) ? RUBY_ENGINE : '',
136
+ :publisher => 'payjp',
137
+ :uname => @uname,
138
+ :hostname => Socket.gethostname
139
+ }
140
+ end
141
+
142
+ def self.uname
143
+ if File.exist?('/proc/version')
144
+ File.read('/proc/version').strip
145
+ else
146
+ case RbConfig::CONFIG['host_os']
147
+ when /linux|darwin|bsd|sunos|solaris|cygwin/i
148
+ _uname_uname
149
+ when /mswin|mingw/i
150
+ _uname_ver
151
+ else
152
+ "unknown platform"
153
+ end
154
+ end
155
+ end
156
+
157
+ def self._uname_uname
158
+ (`uname -a 2>/dev/null` || '').strip
159
+ rescue Errno::ENOMEM # couldn't create subprocess
160
+ "uname lookup failed"
161
+ end
162
+
163
+ def self._uname_ver
164
+ (`ver` || '').strip
165
+ rescue Errno::ENOMEM # couldn't create subprocess
166
+ "uname lookup failed"
167
+ end
168
+
169
+ def self.uri_encode(params)
170
+ Util.flatten_params(params).
171
+ map { |k, v| "#{k}=#{Util.url_encode(v)}" }.join('&')
172
+ end
173
+
174
+ def self.request_headers(api_key)
175
+ headers = {
176
+ :user_agent => "Payjp/v1 RubyBindings/#{Payjp::VERSION}",
177
+ :authorization => "Basic #{Base64.encode64("#{api_key}:")}",
178
+ :content_type => 'application/x-www-form-urlencoded'
179
+ }
180
+
181
+ headers[:payjp_version] = api_version if api_version
182
+
183
+ begin
184
+ headers.update(:x_payjp_client_user_agent => JSON.generate(user_agent))
185
+ rescue => e
186
+ headers.update(:x_payjp_client_raw_user_agent => user_agent.inspect,
187
+ :error => "#{e} (#{e.class})")
188
+ end
189
+ end
190
+
191
+ def self.execute_request(opts)
192
+ RestClient::Request.execute(opts)
193
+ end
194
+
195
+ def self.parse(response)
196
+ begin
197
+ # Would use :symbolize_names => true, but apparently there is
198
+ # some library out there that makes symbolize_names not work.
199
+ response = JSON.parse(response.body)
200
+ rescue JSON::ParserError
201
+ raise general_api_error(response.code, response.body)
202
+ end
203
+
204
+ Util.symbolize_names(response)
205
+ end
206
+
207
+ def self.general_api_error(rcode, rbody)
208
+ APIError.new("Invalid response object from API: #{rbody.inspect} " \
209
+ "(HTTP response code was #{rcode})", rcode, rbody)
210
+ end
211
+
212
+ def self.handle_api_error(rcode, rbody)
213
+ begin
214
+ error_obj = JSON.parse(rbody)
215
+ error_obj = Util.symbolize_names(error_obj)
216
+ error = error_obj[:error] or raise PayjpError.new # escape from parsing
217
+
218
+ rescue JSON::ParserError, PayjpError
219
+ raise general_api_error(rcode, rbody)
220
+ end
221
+
222
+ case rcode
223
+ when 400, 404
224
+ raise invalid_request_error error, rcode, rbody, error_obj
225
+ when 401
226
+ raise authentication_error error, rcode, rbody, error_obj
227
+ when 402
228
+ raise card_error error, rcode, rbody, error_obj
229
+ else
230
+ raise api_error error, rcode, rbody, error_obj
231
+ end
232
+ end
233
+
234
+ def self.invalid_request_error(error, rcode, rbody, error_obj)
235
+ InvalidRequestError.new(error[:message], error[:param], rcode,
236
+ rbody, error_obj)
237
+ end
238
+
239
+ def self.authentication_error(error, rcode, rbody, error_obj)
240
+ AuthenticationError.new(error[:message], rcode, rbody, error_obj)
241
+ end
242
+
243
+ def self.card_error(error, rcode, rbody, error_obj)
244
+ CardError.new(error[:message], error[:param], error[:code],
245
+ rcode, rbody, error_obj)
246
+ end
247
+
248
+ def self.api_error(error, rcode, rbody, error_obj)
249
+ APIError.new(error[:message], rcode, rbody, error_obj)
250
+ end
251
+
252
+ def self.handle_restclient_error(e, api_base_url = nil)
253
+ api_base_url = @api_base unless api_base_url
254
+ connection_message = "Please check your internet connection and try again. " \
255
+ "If this problem persists, you should check Payjp's service status at " \
256
+ "https://twitter.com/payjpstatus, or let us know at support@pay.jp."
257
+
258
+ case e
259
+ when RestClient::RequestTimeout
260
+ message = "Could not connect to Payjp (#{api_base_url}). #{connection_message}"
261
+
262
+ when RestClient::ServerBrokeConnection
263
+ message = "The connection to the server (#{api_base_url}) broke before the " \
264
+ "request completed. #{connection_message}"
265
+
266
+ when SocketError
267
+ message = "Unexpected error communicating when trying to connect to Payjp. " \
268
+ "You may be seeing this message because your DNS is not working. " \
269
+ "To check, try running 'host pay.jp' from the command line."
270
+
271
+ else
272
+ message = "Unexpected error communicating with Payjp. " \
273
+ "If this problem persists, let us know at support@pay.jp."
274
+
275
+ end
276
+
277
+ raise APIConnectionError.new(message + "\n\n(Network error: #{e.message})")
278
+ end
279
+ end