paypoint-blue 0.3.0 → 0.4.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: 82b114473871861140e8796d61ac85a852a273d2
4
- data.tar.gz: 1034d197286e603f13b8f5b409db165c89ce5edb
3
+ metadata.gz: 0720906c714d8425e8af2ea0bf97a877740caccf
4
+ data.tar.gz: 8e3711213ea3b1db72eaeeb28a76f60b860ff902
5
5
  SHA512:
6
- metadata.gz: 721d6ef451f97773e72f2fef33a9895d9a0c624ac527ffad46320e14928d23814f2a29a6ea30c33233b780a67f39b08161e59d9dfeaeb6c60f1141321af5f85d
7
- data.tar.gz: 041fdf89fdf82280b6459a32f1d7a0992d28d3a4b2f2057b4ed316d01854fe8a9cfb598e1a0a201484382fe79ad531af1b15e376259f64dbbafce2259eaf40e9
6
+ metadata.gz: 0eefb28d9180465c528f689e926944210120c67d53c2131ca3000ce5a361a4138dda564e493d82b4e031bcb7c7f12090eb1706a10a94eb2dae4063a7f1e13eeb
7
+ data.tar.gz: 8a694c43a0bf2dd305ce6ff9fbc29168452b1b10b4c17a751c5cb88bd33890442f0a11f700f903cae09b97bac750ee5e938f2506b3c14be3b38b31adbe59e721
data/.overcommit.yml ADDED
@@ -0,0 +1,11 @@
1
+ PreCommit:
2
+ ALL:
3
+ quiet: false
4
+
5
+ RuboCop:
6
+ enabled: yes
7
+ on_warn: fail # Treat all warnings as failures
8
+
9
+ CommitMsg:
10
+ TextWidth:
11
+ enabled: yes
data/.rubocop.yml ADDED
@@ -0,0 +1,45 @@
1
+ AllCops:
2
+ Include:
3
+ - "**/Gemfile"
4
+ Exclude:
5
+ - "bin/*"
6
+ - "support/**/*"
7
+ - "vendor/**/*"
8
+
9
+ ### Style ######################################################################
10
+
11
+ Style/AlignHash:
12
+ EnforcedHashRocketStyle: table
13
+ EnforcedColonStyle: table
14
+
15
+ Style/AlignParameters:
16
+ EnforcedStyle: with_fixed_indentation
17
+
18
+ Style/AndOr:
19
+ EnforcedStyle: conditionals
20
+
21
+ Style/BlockDelimiters:
22
+ EnforcedStyle: line_count_based
23
+
24
+ Style/IndentHash:
25
+ EnforcedStyle: consistent
26
+
27
+ Style/MultilineOperationIndentation:
28
+ EnforcedStyle: indented
29
+
30
+ Style/StringLiterals:
31
+ EnforcedStyle: double_quotes
32
+
33
+ Style/StringLiteralsInInterpolation:
34
+ EnforcedStyle: double_quotes
35
+
36
+ # Not enforcing %i() arrays, because they are too similar to %w() and don't have
37
+ # proper syntax highlighting support for differentiating between them.
38
+ Style/SymbolArray:
39
+ Enabled: false
40
+
41
+ Style/TrailingComma:
42
+ EnforcedStyleForMultiline: comma
43
+
44
+ Style/ClassAndModuleChildren:
45
+ Enabled: false
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in paypoint-blue.gemspec
4
4
  gemspec
@@ -2,24 +2,23 @@ require "paypoint/blue/base"
2
2
 
3
3
  # Client class for the API product.
4
4
  class PayPoint::Blue::API < PayPoint::Blue::Base
5
-
6
5
  ENDPOINTS = {
7
6
  test: "https://api.mite.paypoint.net:2443/acceptor/rest",
8
7
  live: "https://api.paypoint.net/acceptor/rest",
9
8
  }.freeze
10
9
 
11
- shortcut :merchant_ref, 'transaction.merchant_ref'
12
- shortcut :amount, 'transaction.amount'
13
- shortcut :currency, 'transaction.currency'
14
- shortcut :commerce_type, 'transaction.commerce_type'
15
- shortcut :description, 'transaction.description'
16
- shortcut :customer_ref, 'customer.merchant_ref'
17
- shortcut :customer_name, 'customer.display_name'
10
+ shortcut :merchant_ref, "transaction.merchant_ref"
11
+ shortcut :amount, "transaction.amount"
12
+ shortcut :currency, "transaction.currency"
13
+ shortcut :commerce_type, "transaction.commerce_type"
14
+ shortcut :description, "transaction.description"
15
+ shortcut :customer_ref, "customer.merchant_ref"
16
+ shortcut :customer_name, "customer.display_name"
18
17
 
19
- shortcut :pre_auth_callback, 'callbacks.pre_auth_callback.url'
20
- shortcut :post_auth_callback, 'callbacks.post_auth_callback.url'
21
- shortcut :transaction_notification, 'callbacks.transaction_notification.url'
22
- shortcut :expiry_notification, 'callbacks.expiry_notification.url'
18
+ shortcut :pre_auth_callback, "callbacks.pre_auth_callback.url"
19
+ shortcut :post_auth_callback, "callbacks.post_auth_callback.url"
20
+ shortcut :transaction_notification, "callbacks.transaction_notification.url"
21
+ shortcut :expiry_notification, "callbacks.expiry_notification.url"
23
22
 
24
23
  # Test connectivity
25
24
  #
@@ -45,11 +44,9 @@ class PayPoint::Blue::API < PayPoint::Blue::Base
45
44
  #
46
45
  # @return the API response
47
46
  def make_payment(**payload)
48
- payload = build_payload(payload,
49
- defaults: %i[
50
- currency commerce_type pre_auth_callback post_auth_callback
51
- transaction_notification expiry_notification
52
- ]
47
+ payload = build_payload payload, defaults: %i(
48
+ currency commerce_type pre_auth_callback post_auth_callback
49
+ transaction_notification expiry_notification
53
50
  )
54
51
  client.post "transactions/#{inst_id}/payment", payload
55
52
  end
@@ -85,11 +82,9 @@ class PayPoint::Blue::API < PayPoint::Blue::Base
85
82
  #
86
83
  # @return the API response
87
84
  def capture_authorisation(transaction_id, **payload)
88
- payload = build_payload(payload,
89
- defaults: %i[
90
- commerce_type pre_auth_callback post_auth_callback
91
- transaction_notification expiry_notification
92
- ]
85
+ payload = build_payload payload, defaults: %i(
86
+ commerce_type pre_auth_callback post_auth_callback
87
+ transaction_notification expiry_notification
93
88
  )
94
89
  client.post "transactions/#{inst_id}/#{transaction_id}/capture", payload
95
90
  end
@@ -106,11 +101,9 @@ class PayPoint::Blue::API < PayPoint::Blue::Base
106
101
  #
107
102
  # @return the API response
108
103
  def cancel_authorisation(transaction_id, **payload)
109
- payload = build_payload(payload,
110
- defaults: %i[
111
- commerce_type pre_auth_callback post_auth_callback
112
- transaction_notification expiry_notification
113
- ]
104
+ payload = build_payload payload, defaults: %i(
105
+ commerce_type pre_auth_callback post_auth_callback
106
+ transaction_notification expiry_notification
114
107
  )
115
108
  client.post "transactions/#{inst_id}/#{transaction_id}/cancel", payload
116
109
  end
@@ -146,7 +139,7 @@ class PayPoint::Blue::API < PayPoint::Blue::Base
146
139
  # +amount+ or a +transaction+ hash as a keyword argument.
147
140
  #
148
141
  # @example Partial refund
149
- # blue.refund_payment(txn_id, amount: '3.49') # assumes currency set as default
142
+ # blue.refund_payment(txn_id, amount: '3.49') # assumes a default currency
150
143
  #
151
144
  # @applies_defaults
152
145
  # only if amount is set: +:currency+, +:commerce_type+
@@ -158,9 +151,13 @@ class PayPoint::Blue::API < PayPoint::Blue::Base
158
151
  #
159
152
  # @return the API response
160
153
  def refund_payment(transaction_id, **payload)
161
- defaults = %i[ pre_auth_callback post_auth_callback transaction_notification expiry_notification ]
162
- if payload[:amount] || payload[:transaction] && payload[:transaction][:amount]
163
- defaults += %i[currency commerce_type]
154
+ defaults = %i(
155
+ pre_auth_callback post_auth_callback
156
+ transaction_notification expiry_notification
157
+ )
158
+ if payload[:amount] ||
159
+ payload[:transaction] && payload[:transaction][:amount]
160
+ defaults += %i(currency commerce_type)
164
161
  end
165
162
  payload = build_payload(payload, defaults: defaults)
166
163
  client.post "transactions/#{inst_id}/#{transaction_id}/refund", payload
@@ -180,13 +177,10 @@ class PayPoint::Blue::API < PayPoint::Blue::Base
180
177
  #
181
178
  # @return the API response
182
179
  def submit_payout(**payload)
183
- payload = build_payload(payload,
184
- defaults: %i[
185
- currency commerce_type pre_auth_callback post_auth_callback
186
- transaction_notification expiry_notification
187
- ]
180
+ payload = build_payload payload, defaults: %i(
181
+ currency commerce_type pre_auth_callback post_auth_callback
182
+ transaction_notification expiry_notification
188
183
  )
189
184
  client.post "transactions/#{inst_id}/payout", payload
190
185
  end
191
-
192
186
  end
@@ -9,7 +9,6 @@ require "paypoint/blue/faraday_runscope"
9
9
 
10
10
  module PayPoint
11
11
  module Blue
12
-
13
12
  # Abstract base class for the API clients. Takes care of
14
13
  # initializing the Faraday client by setting up middlewares in the
15
14
  # right order.
@@ -25,7 +24,6 @@ module PayPoint
25
24
  #
26
25
  # @abstract
27
26
  class Base
28
-
29
27
  include PayloadBuilder
30
28
 
31
29
  # The Faraday client
@@ -54,23 +52,18 @@ module PayPoint
54
52
  # @option options [String] :runscope when used, all traffic will
55
53
  # pass through the provided {https://www.runscope.com/ Runscope}
56
54
  # bucket, including notification callbacks
57
- def initialize(endpoint:,
58
- inst_id: ENV['BLUE_API_INSTALLATION'],
59
- api_id: ENV['BLUE_API_ID'],
60
- api_password: ENV['BLUE_API_PASSWORD'],
61
- **options)
62
-
63
- @endpoint = get_endpoint_or_override_with(endpoint)
55
+ def initialize(endpoint:, inst_id: ENV["BLUE_API_INSTALLATION"],
56
+ api_id: ENV["BLUE_API_ID"], api_password: ENV["BLUE_API_PASSWORD"],
57
+ **options)
64
58
 
65
- @inst_id = inst_id or raise ArgumentError, 'missing inst_id'
66
- @api_id = api_id or raise ArgumentError, 'missing api_id'
67
- @api_password = api_password or raise ArgumentError, 'missing api_password'
68
-
69
- options[:url] = @endpoint
70
- @options = options
59
+ @endpoint = get_endpoint_or_override_with(endpoint)
60
+ @inst_id = inst_id or fail ArgumentError, "missing inst_id"
61
+ @api_id = api_id or fail ArgumentError, "missing api_id"
62
+ @api_password =
63
+ api_password or fail ArgumentError, "missing api_password"
71
64
 
72
65
  self.defaults = options.delete(:defaults)
73
-
66
+ @options = options.merge url: @endpoint
74
67
  @client = build_client
75
68
  end
76
69
 
@@ -79,14 +72,14 @@ module PayPoint
79
72
  attr_reader :inst_id, :options
80
73
 
81
74
  def get_endpoint_or_override_with(endpoint)
82
- self.class.const_get('ENDPOINTS').fetch(endpoint, endpoint.to_s)
75
+ self.class.const_get("ENDPOINTS").fetch(endpoint, endpoint.to_s)
83
76
  end
84
77
 
85
78
  def client_options
86
79
  options.select { |k, _| Faraday::ConnectionOptions.members.include?(k) }
87
80
  end
88
81
 
89
- def build_client
82
+ def build_client # rubocop:disable AbcSize, MethodLength
90
83
  Faraday.new(client_options) do |f|
91
84
  unless options[:raw]
92
85
  # This extracts the body and discards all other data from the
@@ -101,15 +94,17 @@ module PayPoint
101
94
  f.use PayPoint::Blue::HashKeyConverter
102
95
  end
103
96
  f.response :json, content_type: /\bjson$/
104
- f.response :logger, options[:logger] if options[:logger] || options[:log]
97
+ if options[:logger] || options[:log]
98
+ f.response :logger, options[:logger]
99
+ end
105
100
 
106
101
  # This sends all API traffic through Runscope, including
107
102
  # notifications. It needs to be inserted here before the JSON
108
103
  # request middleware so that it is able to transform
109
104
  # notification URLs too.
110
105
  if options[:runscope]
111
- f.use FaradayRunscope, options[:runscope],
112
- transform_paths: /\A(callbacks|session)\.\w+(Callback|Notification)\.url\Z/
106
+ path_re = /\A(callbacks|session)\.\w+(Callback|Notification)\.url\Z/
107
+ f.use FaradayRunscope, options[:runscope], transform_paths: path_re
113
108
  end
114
109
 
115
110
  f.request :basic_auth, @api_id, @api_password
@@ -1,18 +1,14 @@
1
1
  module PayPoint
2
2
  module Blue
3
-
4
3
  # Faraday middleware which extracts the body from the response
5
4
  # object and returns with just that discarding all other meta
6
5
  # information.
7
6
  class BodyExtractor < Faraday::Middleware
8
-
9
7
  # Extract and return just the body discarding everything else
10
8
  def call(env)
11
9
  response = @app.call(env)
12
10
  response.env[:body]
13
11
  end
14
-
15
12
  end
16
-
17
13
  end
18
14
  end
@@ -1,10 +1,8 @@
1
1
  module PayPoint
2
2
  module Blue
3
-
4
3
  # Abstract error base class
5
4
  # @abstract
6
5
  class Error < StandardError
7
-
8
6
  # the response that caused the error
9
7
  attr_reader :response
10
8
 
@@ -53,8 +51,6 @@ module PayPoint
53
51
 
54
52
  # Specific error class for errors with an +'U'+ outcome code
55
53
  class Suspended < Error; end
56
-
57
54
  end
58
-
59
55
  end
60
56
  end
@@ -1,5 +1,6 @@
1
+ # Faraday middleware for transforming API endpoint urls and certain urls in JSON
2
+ # payloads to be proxied by Runscope for tracking and debugging purposes.
1
3
  class FaradayRunscope < Faraday::Middleware
2
-
3
4
  CUSTOM_PORT = "Runscope-Request-Port".freeze
4
5
 
5
6
  def initialize(app, bucket, transform_paths: false)
@@ -9,10 +10,7 @@ class FaradayRunscope < Faraday::Middleware
9
10
  end
10
11
 
11
12
  def call(env)
12
- if env.url.port != env.url.default_port
13
- env.request_headers[CUSTOM_PORT] = env.url.port.to_s
14
- env.url.port = env.url.default_port
15
- end
13
+ handle_custom_port(env)
16
14
 
17
15
  transform_url env.url
18
16
 
@@ -27,6 +25,12 @@ class FaradayRunscope < Faraday::Middleware
27
25
 
28
26
  attr_accessor :bucket, :transform_paths
29
27
 
28
+ def handle_custom_port(env)
29
+ return if env.url.port == env.url.default_port
30
+ env.request_headers[CUSTOM_PORT] = env.url.port.to_s
31
+ env.url.port = env.url.default_port
32
+ end
33
+
30
34
  def transform_url(url)
31
35
  if url.respond_to?(:host=)
32
36
  url.host = runscope_host(url.host)
@@ -39,10 +43,10 @@ class FaradayRunscope < Faraday::Middleware
39
43
  end
40
44
 
41
45
  def runscope_host(host)
42
- "#{host.gsub('-', '--').tr('.', '-')}-#{bucket}.runscope.net"
46
+ "#{host.gsub("-", "--").tr(".", "-")}-#{bucket}.runscope.net"
43
47
  end
44
48
 
45
- def transform_paths!(enum, path=nil)
49
+ def transform_paths!(enum, path = nil)
46
50
  each_pair(enum) do |key, value|
47
51
  key_path = path ? "#{path}.#{key}" : key.to_s
48
52
  if value.respond_to?(:each_with_index)
@@ -66,9 +70,8 @@ class FaradayRunscope < Faraday::Middleware
66
70
  end
67
71
 
68
72
  def transform_path?(path)
69
- transform_paths.any? do |path_to_transform|
70
- path_to_transform === path
73
+ transform_paths.any? do |path_pattern|
74
+ path_pattern.is_a?(Regexp) ? path =~ path_pattern : path == path_pattern
71
75
  end
72
76
  end
73
-
74
77
  end
@@ -1,11 +1,9 @@
1
1
  module PayPoint
2
2
  module Blue
3
-
4
3
  # Faraday middleware for converting hash keys in the request payload
5
4
  # from snake_case to camelCase and the other way around in the
6
5
  # response.
7
6
  class HashKeyConverter < Faraday::Middleware
8
-
9
7
  # Convert hash keys to camelCase in the request and to snake_case
10
8
  # in the response
11
9
  def call(env)
@@ -15,7 +13,8 @@ module PayPoint
15
13
 
16
14
  @app.call(env).on_complete do |response_env|
17
15
  if response_env.body.is_a?(Enumerable)
18
- response_env.body = Utils.snakecase_and_symbolize_keys(response_env.body)
16
+ response_env.body =
17
+ Utils.snakecase_and_symbolize_keys(response_env.body)
19
18
  end
20
19
  end
21
20
  end
@@ -4,26 +4,26 @@ require "paypoint/blue/base"
4
4
 
5
5
  # Client class for the Hosted product.
6
6
  class PayPoint::Blue::Hosted < PayPoint::Blue::Base
7
-
8
7
  ENDPOINTS = {
9
8
  test: "https://hosted.mite.paypoint.net/hosted/rest",
10
- live: "https://hosted.paypoint.net/hosted/rest"
9
+ live: "https://hosted.paypoint.net/hosted/rest",
11
10
  }.freeze
12
11
 
13
- shortcut :merchant_ref, 'transaction.merchant_reference'
14
- shortcut :amount, 'transaction.money.amount.fixed'
15
- shortcut :currency, 'transaction.money.currency'
16
- shortcut :commerce_type, 'transaction.commerce_type'
17
- shortcut :description, 'transaction.description'
18
- shortcut :customer_ref, 'customer.identity.merchant_customer_id'
19
- shortcut :customer_name, 'customer.details.name'
20
- shortcut :return_url, 'session.return_url.url'
21
- shortcut :restore_url, 'session.restore_url.url'
22
- shortcut :skin, 'session.skin'
12
+ shortcut :merchant_ref, "transaction.merchant_reference"
13
+ shortcut :amount, "transaction.money.amount.fixed"
14
+ shortcut :currency, "transaction.money.currency"
15
+ shortcut :commerce_type, "transaction.commerce_type"
16
+ shortcut :description, "transaction.description"
17
+ shortcut :customer_ref, "customer.identity.merchant_customer_id"
18
+ shortcut :customer_name, "customer.details.name"
19
+ shortcut :return_url, "session.return_url.url"
20
+ shortcut :cancel_url, "session.cancel_url.url"
21
+ shortcut :restore_url, "session.restore_url.url"
22
+ shortcut :skin, "session.skin"
23
23
 
24
- shortcut :pre_auth_callback, 'session.pre_auth_callback.url'
25
- shortcut :post_auth_callback, 'session.post_auth_callback.url'
26
- shortcut :transaction_notification, 'session.transaction_notification.url'
24
+ shortcut :pre_auth_callback, "session.pre_auth_callback.url"
25
+ shortcut :post_auth_callback, "session.post_auth_callback.url"
26
+ shortcut :transaction_notification, "session.transaction_notification.url"
27
27
 
28
28
  extend Forwardable
29
29
 
@@ -58,19 +58,18 @@ class PayPoint::Blue::Hosted < PayPoint::Blue::Base
58
58
  # @api_url https://developer.paypoint.com/payments/docs/#payments/make_a_payment
59
59
  #
60
60
  # @applies_defaults
61
- # +:currency+, +:commerce_type+, +:return_url+, +:restore_url+, +:skin+,
62
- # +:pre_auth_callback+, +:post_auth_callback+, +:transaction_notification+
61
+ # +:currency+, +:commerce_type+, +:return_url+, +:cancel_url+,
62
+ # +:restore_url+, +:skin+, +:pre_auth_callback+, +:post_auth_callback+,
63
+ # +:transaction_notification+
63
64
  #
64
65
  # @param [Hash] payload the payload is made up of the keyword
65
66
  # arguments passed to the method
66
67
  #
67
68
  # @return the API response
68
69
  def make_payment(**payload)
69
- payload = build_payload(payload,
70
- defaults: %i[
71
- currency commerce_type return_url restore_url skin
72
- pre_auth_callback post_auth_callback transaction_notification
73
- ]
70
+ payload = build_payload payload, defaults: %i(
71
+ currency commerce_type return_url cancel_url restore_url skin
72
+ pre_auth_callback post_auth_callback transaction_notification
74
73
  )
75
74
  client.post "sessions/#{inst_id}/payments", build_payload(payload)
76
75
  end
@@ -97,21 +96,19 @@ class PayPoint::Blue::Hosted < PayPoint::Blue::Base
97
96
  # @api_url https://developer.paypoint.com/payments/docs/#payments/submit_a_payout
98
97
  #
99
98
  # @applies_defaults
100
- # +:currency+, +:commerce_type+, +:return_url+, +:restore_url+, +:skin+,
101
- # +:pre_auth_callback+, +:post_auth_callback+, +:transaction_notification+
99
+ # +:currency+, +:commerce_type+, +:return_url+, +:cancel_url+,
100
+ # +:restore_url+, +:skin+, +:pre_auth_callback+, +:post_auth_callback+,
101
+ # +:transaction_notification+
102
102
  #
103
103
  # @param [Hash] payload the payload is made up of the keyword
104
104
  # arguments passed to the method
105
105
  #
106
106
  # @return the API response
107
107
  def submit_payout(**payload)
108
- payload = build_payload(payload,
109
- defaults: %i[
110
- currency commerce_type return_url restore_url skin
111
- pre_auth_callback post_auth_callback transaction_notification
112
- ]
108
+ payload = build_payload payload, defaults: %i(
109
+ currency commerce_type return_url cancel_url restore_url skin
110
+ pre_auth_callback post_auth_callback transaction_notification
113
111
  )
114
112
  client.post "sessions/#{inst_id}/payouts", build_payload(payload)
115
113
  end
116
-
117
114
  end
@@ -1,15 +1,14 @@
1
1
  module PayPoint
2
2
  module Blue
3
-
4
3
  # Provides helper methods for payload construction used throughout
5
4
  # the API. It allows definition of payload shortcuts and default
6
5
  # values.
7
6
  module PayloadBuilder
8
-
9
7
  def self.included(base)
10
8
  base.extend ClassMethods
11
9
  end
12
10
 
11
+ # Class level methods for PayloadBuilder.
13
12
  module ClassMethods
14
13
  def shortcuts
15
14
  @shortcuts ||= {}
@@ -23,10 +22,12 @@ module PayPoint
23
22
  # to commonly used paths.
24
23
  #
25
24
  # @example Define and use a shortcut
26
- # PayPoint::Blue::Hosted.shortcut :amount, 'transaction.money.amount.fixed'
27
- # blue.make_payment(amount: '3.49', ...)
25
+ # class PayPoint::Blue::Hosted
26
+ # shortcut :amount, "transaction.money.amount.fixed"
27
+ # end
28
+ # blue.make_payment(amount: "3.49", ...)
28
29
  # # this will be turned into
29
- # # { transaction: { money: { amount: { fixed: '3.49' } } } }
30
+ # # { transaction: { money: { amount: { fixed: "3.49" } } } }
30
31
  #
31
32
  # @param [Symbol] key the shortcut key
32
33
  # @param [String] path a path into the payload with segments
@@ -55,20 +56,7 @@ module PayPoint
55
56
  # that should be applied to this payload
56
57
  def build_payload(payload, defaults: [])
57
58
  apply_defaults(payload, defaults)
58
- payload.keys.each do |key|
59
- if path = self.class.shortcut(key)
60
- value = payload.delete(key)
61
- segments = path.split('.').map(&:to_sym)
62
- leaf = segments.pop
63
- leaf_parent = segments.reduce(payload) {|h,k| h[k] ||= {}}
64
- leaf_parent[leaf] ||= value
65
-
66
- if key =~ /_(?:callback|notification)\Z/
67
- leaf_parent[:format] ||= "REST_JSON"
68
- end
69
- end
70
- end
71
- payload
59
+ expand_shortcuts(payload)
72
60
  end
73
61
 
74
62
  private
@@ -77,14 +65,33 @@ module PayPoint
77
65
  return unless defaults
78
66
 
79
67
  defaults.each do |key, value|
80
- if applicable_defaults.include?(key) && !payload.has_key?(key)
68
+ if applicable_defaults.include?(key) && !payload.key?(key)
81
69
  payload[key] = interpolate_values(value, payload)
82
70
  end
83
71
  end
84
72
  end
85
73
 
86
74
  def interpolate_values(value, payload)
87
- value.gsub(/%(\w+)%/) {|m| payload[$1.to_sym] || m}
75
+ value.gsub(/%(\w+)%/) { |m| payload[Regexp.last_match(1).to_sym] || m }
76
+ end
77
+
78
+ def expand_shortcuts(payload)
79
+ payload.keys.each do |key|
80
+ next unless (path = self.class.shortcut(key))
81
+ expand_shortcut(payload, key, path)
82
+ end
83
+ payload
84
+ end
85
+
86
+ def expand_shortcut(payload, key, path)
87
+ value = payload.delete(key)
88
+ segments = path.split(".").map(&:to_sym)
89
+ leaf = segments.pop
90
+ leaf_parent = segments.reduce(payload) { |a, e| a[e] ||= {} }
91
+ leaf_parent[leaf] ||= value
92
+
93
+ callback_re = /_(?:callback|notification)\Z/
94
+ leaf_parent[:format] ||= "REST_JSON" if key =~ callback_re
88
95
  end
89
96
  end
90
97
  end
@@ -2,10 +2,8 @@ require "paypoint/blue/error"
2
2
 
3
3
  module PayPoint
4
4
  module Blue
5
-
6
5
  # Faraday response middleware for handling various error scenarios
7
6
  class RaiseErrors < Faraday::Response::Middleware
8
-
9
7
  # Raise an error if the response outcome signifies a failure or
10
8
  # the HTTP status code is 400 or greater.
11
9
  #
@@ -18,20 +16,12 @@ module PayPoint
18
16
  def on_complete(env)
19
17
  outcome = fetch_outcome(env)
20
18
  if outcome
21
- case outcome[:reason_code]
22
- when /^S/ then return
23
- when /^V/ then raise Error::Validation, response_values(env)
24
- when /^A/ then raise Error::Auth, response_values(env)
25
- when /^C/ then raise Error::Cancelled, response_values(env)
26
- when /^X/ then raise Error::External, response_values(env)
27
- when /^U/ then raise Error::Suspended, response_values(env)
28
- else
29
- raise Error::Client, response_values(env)
30
- end
19
+ return if outcome[:reason_code] =~ /^S/
20
+ fail error_from_outcome(outcome[:reason_code], response_values(env))
31
21
  elsif not_found?(env)
32
- raise Error::NotFound, response_values(env)
22
+ fail Error::NotFound, response_values(env)
33
23
  elsif client_error?(env)
34
- raise Error::Client, response_values(env)
24
+ fail Error::Client, response_values(env)
35
25
  end
36
26
  end
37
27
 
@@ -49,11 +39,23 @@ module PayPoint
49
39
  env.body.is_a?(Hash) && env.body[:outcome]
50
40
  end
51
41
 
42
+ def error_from_outcome(code, response_values)
43
+ case code
44
+ when /^V/ then Error::Validation.new(response_values)
45
+ when /^A/ then Error::Auth.new(response_values)
46
+ when /^C/ then Error::Cancelled.new(response_values)
47
+ when /^X/ then Error::External.new(response_values)
48
+ when /^U/ then Error::Suspended.new(response_values)
49
+ else
50
+ Error::Client.new(response_values)
51
+ end
52
+ end
53
+
52
54
  def response_values(env)
53
55
  {
54
56
  status: env.status,
55
57
  headers: env.response_headers,
56
- body: env.body
58
+ body: env.body,
57
59
  }
58
60
  end
59
61
  end
@@ -1,17 +1,17 @@
1
1
  module PayPoint
2
2
  module Blue
3
+ # Miscellaneous helper methods used in multiple places.
3
4
  module Utils
4
-
5
- extend self
5
+ module_function
6
6
 
7
7
  def snakecase_and_symbolize_keys(hash)
8
8
  case hash
9
9
  when Hash
10
- hash.each_with_object({}) do |(key, value), snakified|
10
+ hash.each_with_object({},) do |(key, value), snakified|
11
11
  snakified[snakecase(key)] = snakecase_and_symbolize_keys(value)
12
12
  end
13
13
  when Enumerable
14
- hash.map {|v| snakecase_and_symbolize_keys(v)}
14
+ hash.map { |v| snakecase_and_symbolize_keys(v) }
15
15
  else
16
16
  hash
17
17
  end
@@ -20,11 +20,11 @@ module PayPoint
20
20
  def camelcase_and_symbolize_keys(hash)
21
21
  case hash
22
22
  when Hash
23
- hash.each_with_object({}) do |(key, value), camelized|
23
+ hash.each_with_object({},) do |(key, value), camelized|
24
24
  camelized[camelcase(key)] = camelcase_and_symbolize_keys(value)
25
25
  end
26
26
  when Enumerable
27
- hash.map {|v| camelcase_and_symbolize_keys(v)}
27
+ hash.map { |v| camelcase_and_symbolize_keys(v) }
28
28
  else
29
29
  hash
30
30
  end
@@ -42,10 +42,9 @@ module PayPoint
42
42
 
43
43
  def camelcase(original)
44
44
  string = original.is_a?(Symbol) ? original.to_s : original.dup
45
- string.gsub!(/_([a-z\d]*)/) { $1.capitalize }
45
+ string.gsub!(/_([a-z\d]*)/) { Regexp.last_match(1).capitalize }
46
46
  string.to_sym
47
47
  end
48
-
49
48
  end
50
49
  end
51
50
  end
@@ -1,5 +1,5 @@
1
1
  module PayPoint
2
- module Blue
3
- VERSION = "0.3.0"
2
+ module Blue # rubocop:disable Documentation
3
+ VERSION = "0.4.0"
4
4
  end
5
5
  end
data/lib/paypoint/blue.rb CHANGED
@@ -4,8 +4,8 @@ require "paypoint/blue/hosted"
4
4
  require "paypoint/blue/utils"
5
5
 
6
6
  module PayPoint
7
+ # Top level module with helper methods.
7
8
  module Blue
8
-
9
9
  # Creates a client for the PayPoint Blue API product
10
10
  #
11
11
  # @see PayPoint::Blue::Base#initialize
@@ -27,12 +27,11 @@ module PayPoint
27
27
  def self.parse_payload(json)
28
28
  payload = json.respond_to?(:read) ? json.read : json.to_s
29
29
  if payload.encoding == Encoding::ASCII_8BIT
30
- payload.force_encoding 'iso-8859-1'
30
+ payload.force_encoding "iso-8859-1"
31
31
  end
32
32
  payload = JSON.parse(payload)
33
33
  payload = Utils.snakecase_and_symbolize_keys(payload)
34
34
  Hashie::Mash.new(payload)
35
35
  end
36
-
37
36
  end
38
37
  end
data/support/yard_ext.rb CHANGED
@@ -3,7 +3,7 @@ class ShortcutHandler < YARD::Handlers::Ruby::Base
3
3
  namespace_only
4
4
 
5
5
  def process
6
- unless namespace.docstring.index('== Payload Shortcuts')
6
+ unless namespace.docstring.index("== Payload Shortcuts")
7
7
  namespace.docstring += "\n\n== Payload Shortcuts\n"
8
8
  end
9
9
  shortcut = statement.parameters.first.jump(:ident).source
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paypoint-blue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Laszlo Bacsi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-05-12 00:00:00.000000000 Z
11
+ date: 2015-08-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -158,6 +158,8 @@ extensions: []
158
158
  extra_rdoc_files: []
159
159
  files:
160
160
  - ".gitignore"
161
+ - ".overcommit.yml"
162
+ - ".rubocop.yml"
161
163
  - ".travis.yml"
162
164
  - ".yardopts"
163
165
  - Gemfile