paypoint-blue 0.3.0 → 0.4.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: 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