paystack_sdk 0.0.9 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 49b220e27fe0ec66289af8fbbba9d84e63c3698b5964629293edcc8e31335119
4
- data.tar.gz: 0df4630d49d761fb99371fb020271c515153dcbf3f784ac6c6bf543dc63a0634
3
+ metadata.gz: 7771d8c6ca4931f237e71c171c7507cfcd9ca5b6159974ee4a4a37d3d667a0e7
4
+ data.tar.gz: e2c83863b81cd30f7fed5380f145ccfa283a25ea334a30e33cb86170636f0b50
5
5
  SHA512:
6
- metadata.gz: 15748f65a44c87b7a2b679642c3a46c8aa9f7db1841f964975e0929d30dfcdf52a4979a74289085717927452b81806c3c364c362a9cf15416db75baf25b5db43
7
- data.tar.gz: 0e242f0b20e9475d4eb23fff2f6979007d104223f0d681701da99f9aa2635644c9bad41ce23878605dd3583eee38e3535703347a351d7995f078922b1c081798
6
+ metadata.gz: aeeef1dcbfd223247142cfa6ee3ffb85624f2cc392ba5a993f9224ab5a4166273f386b1bf4a6fc4d0571dd30b3a626f08a1d0234cbe3808124e350c88228bebb
7
+ data.tar.gz: f8af0ecc7ef80cd7cfd0ab4858365bdce1b244115402869e5b1b29e3a6018816f19224ed0df2483d2fd732d6babd12a75764f4c324cdc55ee32bc35212d83654
data/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.0] - 2025-06-26
4
+
5
+ ### Changed
6
+
7
+ #### Error Handling Strategy
8
+
9
+ - **BREAKING**: Clarified error handling approach - the SDK now consistently follows a two-tier error handling strategy:
10
+ - **Validation errors** (missing/invalid input data) are thrown as exceptions immediately before API calls
11
+ - **API response errors** (business logic, not found, etc.) are returned as unsuccessful Response objects
12
+ - Updated documentation to clearly explain when exceptions are thrown vs. when to check `response.success?`
13
+
14
+ #### Test Infrastructure
15
+
16
+ - **BREAKING**: Standardized all test specifications to use connection doubles instead of Faraday-specific mocks
17
+ - Updated test pattern across all resource specs to use `instance_double("PaystackSdk::Connection")` for better framework independence
18
+ - All tests now follow consistent mocking pattern with `PaystackSdk::Response.new()` expectations
19
+
20
+ #### Documentation
21
+
22
+ - Enhanced README with comprehensive error handling examples
23
+ - Added validation error examples showing `MissingParamError`, `InvalidFormatError`, and `InvalidValueError`
24
+ - Updated Quick Start guide to demonstrate proper exception handling
25
+ - Clarified the difference between input validation (exceptions) and API response handling (Response objects)
26
+
27
+ ### Improved
28
+
29
+ - Better separation of concerns between input validation and API error handling
30
+ - More consistent test suite that's not tied to specific HTTP client implementation
31
+ - Clearer developer experience with predictable error handling patterns
32
+
3
33
  ## [0.0.9] - 2025-06-26
4
34
 
5
35
  ### Added
data/README.md CHANGED
@@ -69,13 +69,19 @@ params = {
69
69
  currency: "NGN"
70
70
  }
71
71
 
72
- response = paystack.transactions.initiate(params)
72
+ begin
73
+ response = paystack.transactions.initiate(params)
73
74
 
74
- if response.success?
75
- puts "Visit this URL to complete payment: #{response.authorization_url}"
76
- puts "Transaction reference: #{response.reference}"
77
- else
78
- puts "Error: #{response.error_message}"
75
+ if response.success?
76
+ puts "Visit this URL to complete payment: #{response.authorization_url}"
77
+ puts "Transaction reference: #{response.reference}"
78
+ else
79
+ puts "Error: #{response.error_message}"
80
+ end
81
+ rescue PaystackSdk::MissingParamError => e
82
+ puts "Missing required data: #{e.message}"
83
+ rescue PaystackSdk::InvalidFormatError => e
84
+ puts "Invalid data format: #{e.message}"
79
85
  end
80
86
 
81
87
  # Create a customer
@@ -85,12 +91,16 @@ customer_params = {
85
91
  last_name: "Doe"
86
92
  }
87
93
 
88
- customer_response = paystack.customers.create(customer_params)
94
+ begin
95
+ customer_response = paystack.customers.create(customer_params)
89
96
 
90
- if customer_response.success?
91
- puts "Customer created: #{customer_response.data.customer_code}"
92
- else
93
- puts "Error: #{customer_response.error_message}"
97
+ if customer_response.success?
98
+ puts "Customer created: #{customer_response.data.customer_code}"
99
+ else
100
+ puts "Error: #{customer_response.error_message}"
101
+ end
102
+ rescue PaystackSdk::ValidationError => e
103
+ puts "Validation error: #{e.message}"
94
104
  end
95
105
  ```
96
106
 
@@ -98,6 +108,55 @@ end
98
108
 
99
109
  The SDK handles API responses that use string keys (as returned by Paystack) and provides seamless access through both string and symbol notation. All response data maintains the original string key format from the API while offering convenient dot notation access.
100
110
 
111
+ ### Error Handling
112
+
113
+ The SDK uses a two-tier error handling approach:
114
+
115
+ 1. **Validation Errors** (thrown as exceptions) - for missing or invalid input data
116
+ 2. **API Response Errors** (returned as unsuccessful Response objects) - for API-level issues
117
+
118
+ #### Input Validation
119
+
120
+ The SDK validates your parameters **before** making API calls and throws exceptions immediately for data issues:
121
+
122
+ ```ruby
123
+ begin
124
+ # This will throw an exception before making any API call
125
+ response = paystack.transactions.initiate({amount: 1000}) # Missing required email
126
+ rescue PaystackSdk::MissingParamError => e
127
+ puts "Fix your data: #{e.message}"
128
+ end
129
+ ```
130
+
131
+ #### API Response Handling
132
+
133
+ All successful API calls return a `Response` object that you can check for success:
134
+
135
+ ```ruby
136
+ response = paystack.transactions.initiate(valid_params)
137
+
138
+ if response.success?
139
+ puts "Transaction created: #{response.authorization_url}"
140
+ else
141
+ puts "Transaction failed: #{response.error_message}"
142
+
143
+ # Get detailed error information
144
+ error_details = response.error_details
145
+ puts "Status code: #{error_details[:status_code]}"
146
+ puts "Error message: #{error_details[:message]}"
147
+ end
148
+ ```
149
+
150
+ **Note**: The SDK raises exceptions for:
151
+
152
+ - **Validation errors** - when required parameters are missing or have invalid formats
153
+ - **Authentication errors** (401) - usually configuration issues
154
+ - **Rate limiting** (429) - requires retry logic
155
+ - **Server errors** (5xx) - Paystack infrastructure issues
156
+ - **Network errors** - connection failures
157
+
158
+ All other API errors (resource not found, business logic errors, etc.) are returned as unsuccessful Response objects.
159
+
101
160
  ## Usage
102
161
 
103
162
  ### Client Initialization
@@ -457,19 +516,19 @@ total_count = original.dig("meta", "total")
457
516
  current_page = original.dig("meta", "page")
458
517
  ```
459
518
 
460
- #### Error Handling
519
+ #### Exception Handling
461
520
 
462
521
  The SDK provides specific error classes for different types of failures, making it easier to handle errors appropriately:
463
522
 
464
523
  ```ruby
465
524
  begin
466
525
  response = paystack.transactions.verify(reference: "invalid_reference")
467
- rescue PaystackSdk::ResourceNotFoundError => e
468
- puts "Resource not found: #{e.message}"
469
526
  rescue PaystackSdk::AuthenticationError => e
470
527
  puts "Authentication failed: #{e.message}"
471
- rescue PaystackSdk::ValidationError => e
472
- puts "Validation error: #{e.message}"
528
+ rescue PaystackSdk::RateLimitError => e
529
+ puts "Rate limit exceeded. Retry after: #{e.retry_after} seconds"
530
+ rescue PaystackSdk::ServerError => e
531
+ puts "Server error: #{e.message}"
473
532
  rescue PaystackSdk::APIError => e
474
533
  puts "API error: #{e.message}"
475
534
  rescue PaystackSdk::Error => e
@@ -507,6 +566,41 @@ The SDK includes several specific error classes:
507
566
  - **`PaystackSdk::RateLimitError`** - Rate limiting encountered
508
567
  - **`PaystackSdk::ServerError`** - Server errors (5xx responses)
509
568
 
569
+ ##### Validation Error Examples
570
+
571
+ The SDK validates your input data **before** making API calls and will throw exceptions immediately if required data is missing or incorrectly formatted:
572
+
573
+ ```ruby
574
+ # Missing required parameter
575
+ begin
576
+ paystack.transactions.initiate({amount: 1000}) # Missing email
577
+ rescue PaystackSdk::MissingParamError => e
578
+ puts e.message # => "Missing required parameter: email"
579
+ end
580
+
581
+ # Invalid format
582
+ begin
583
+ paystack.transactions.initiate({
584
+ email: "invalid-email", # Not a valid email format
585
+ amount: 1000
586
+ })
587
+ rescue PaystackSdk::InvalidFormatError => e
588
+ puts e.message # => "Invalid format for Email. Expected format: valid email address"
589
+ end
590
+
591
+ # Invalid value
592
+ begin
593
+ paystack.customers.set_risk_action({
594
+ customer: "CUS_123",
595
+ risk_action: "invalid_action" # Not in allowed values
596
+ })
597
+ rescue PaystackSdk::InvalidValueError => e
598
+ puts e.message # => "Invalid value for risk_action: must be one of [default, allow, deny]"
599
+ end
600
+ ```
601
+
602
+ These validation errors are thrown immediately and prevent the API call from being made, helping you catch data issues early in development.
603
+
510
604
  ## Advanced Usage
511
605
 
512
606
  ### Environment Variables
@@ -6,6 +6,7 @@ require_relative "resources/transfer_recipients"
6
6
  require_relative "resources/transfers"
7
7
  require_relative "resources/banks"
8
8
  require_relative "resources/verification"
9
+ require_relative "resources/charges"
9
10
  require_relative "utils/connection_utils"
10
11
 
11
12
  module PaystackSdk
@@ -121,5 +122,19 @@ module PaystackSdk
121
122
  def verification
122
123
  @verification ||= Resources::Verification.new(@connection)
123
124
  end
125
+
126
+ # Provides access to the `Charges` resource.
127
+ #
128
+ # @return [PaystackSdk::Resources::Charges] An instance of the
129
+ # `Charges` resource.
130
+ #
131
+ # @example
132
+ # ```ruby
133
+ # charges = client.charges
134
+ # response = charges.mobile_money(payload)
135
+ # ```
136
+ def charges
137
+ @charges ||= Resources::Charges.new(@connection)
138
+ end
124
139
  end
125
140
  end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module PaystackSdk
6
+ module Resources
7
+ # The `Charges` resource exposes helpers for initiating and managing charges
8
+ # through alternative payment channels such as Mobile Money.
9
+ #
10
+ # At the moment the SDK focuses on supporting the Mobile Money channel which
11
+ # requires posting to the `/charge` endpoint with the customer's email,
12
+ # amount, currency, and the provider specific `mobile_money` payload.
13
+ class Charges < PaystackSdk::Resources::Base
14
+ MOBILE_MONEY_PROVIDERS = %w[mtn atl vod mpesa orange wave].freeze
15
+
16
+ # Initiates a Mobile Money payment.
17
+ #
18
+ # @param payload [Hash] The payload containing charge details.
19
+ # @option payload [String] :email Customer's email address (required)
20
+ # @option payload [Integer] :amount Amount in the lowest currency unit (required)
21
+ # @option payload [String] :currency ISO currency code (default: GHS)
22
+ # @option payload [String] :reference Optional reference supplied by the merchant
23
+ # @option payload [String] :callback_url Optional callback URL for Paystack to redirect to
24
+ # @option payload [Hash] :metadata Optional metadata to attach to the transaction
25
+ # @option payload [Hash] :mobile_money The mobile money details (required)
26
+ # - :phone [String] Customer's mobile money phone number (required)
27
+ # - :provider [String] Mobile money provider code (required)
28
+ #
29
+ # @return [PaystackSdk::Response] The wrapped API response.
30
+ # @raise [PaystackSdk::ValidationError] If the payload is invalid.
31
+ def mobile_money(payload)
32
+ validate_mobile_money_payload!(payload)
33
+
34
+ normalized_payload = normalize_mobile_money_provider(payload)
35
+ response = @connection.post("/charge", normalized_payload)
36
+ handle_response(response)
37
+ end
38
+
39
+ # Submits an OTP for authorising a pending Mobile Money charge (e.g. Vodafone).
40
+ #
41
+ # @param payload [Hash] Payload containing the OTP and charge reference.
42
+ # @option payload [String] :otp The OTP supplied by the customer (required)
43
+ # @option payload [String] :reference The charge reference returned from initiation (required)
44
+ #
45
+ # @return [PaystackSdk::Response] The wrapped API response.
46
+ # @raise [PaystackSdk::ValidationError] If the payload is invalid.
47
+ def submit_otp(payload)
48
+ validate_fields!(
49
+ payload: payload,
50
+ validations: {
51
+ otp: {type: :string, required: true},
52
+ reference: {type: :reference, required: true}
53
+ }
54
+ )
55
+
56
+ response = @connection.post("/charge/submit_otp", payload)
57
+ handle_response(response)
58
+ end
59
+
60
+ private
61
+
62
+ def validate_mobile_money_payload!(payload)
63
+ validate_fields!(
64
+ payload: payload,
65
+ validations: {
66
+ email: {type: :email, required: true},
67
+ amount: {type: :positive_integer, required: true},
68
+ currency: {type: :currency, required: false},
69
+ reference: {type: :reference, required: false},
70
+ callback_url: {required: false},
71
+ metadata: {required: false},
72
+ mobile_money: {required: true}
73
+ }
74
+ )
75
+
76
+ mobile_money = payload[:mobile_money] || payload["mobile_money"]
77
+ validate_hash!(input: mobile_money, name: "mobile_money")
78
+
79
+ phone = mobile_money[:phone] || mobile_money["phone"]
80
+ validate_presence!(value: phone, name: "mobile_money phone")
81
+
82
+ provider = mobile_money[:provider] || mobile_money["provider"]
83
+ validate_mobile_money_provider!(provider)
84
+ end
85
+
86
+ def validate_mobile_money_provider!(provider)
87
+ normalized = provider&.to_s&.downcase
88
+ validate_allowed_values!(
89
+ value: normalized,
90
+ allowed_values: MOBILE_MONEY_PROVIDERS,
91
+ name: "mobile_money provider",
92
+ allow_nil: false
93
+ )
94
+ end
95
+
96
+ def normalize_mobile_money_provider(payload)
97
+ mm = payload[:mobile_money] || payload["mobile_money"] || {}
98
+ provider = mm[:provider] || mm["provider"]
99
+ normalized_provider = provider&.to_s&.downcase
100
+ # Avoid mutating the caller's payload
101
+ payload.merge(mobile_money: mm.merge(provider: normalized_provider))
102
+ end
103
+ end
104
+ end
105
+ end
@@ -68,13 +68,9 @@ module PaystackSdk
68
68
  validate_positive_integer!(value: per_page, name: "per_page", allow_nil: true)
69
69
  validate_positive_integer!(value: page, name: "page", allow_nil: true)
70
70
 
71
- if params[:from]
72
- validate_date_format!(date_str: params[:from], name: "from")
73
- end
71
+ validate_date_format!(date_str: params[:from], name: "from") if params[:from]
74
72
 
75
- if params[:to]
76
- validate_date_format!(date_str: params[:to], name: "to")
77
- end
73
+ validate_date_format!(date_str: params[:to], name: "to") if params[:to]
78
74
 
79
75
  query_params = {perPage: per_page, page: page}.merge(params)
80
76
  response = @connection.get("customer", query_params)
@@ -63,11 +63,11 @@ module PaystackSdk
63
63
  # Initializes a new Response object
64
64
  #
65
65
  # @param response [Faraday::Response, Hash, Array] The raw API response or data
66
- # @raise [PaystackSdk::APIError] If the API returns an error response
67
66
  # @raise [PaystackSdk::AuthenticationError] If authentication fails (401)
68
- # @raise [PaystackSdk::ResourceNotFoundError] If resource is not found (404 or 400 with not found message)
69
67
  # @raise [PaystackSdk::RateLimitError] If rate limit is exceeded (429)
70
68
  # @raise [PaystackSdk::ServerError] If server returns 5xx error
69
+ # @note API-level errors (4xx except 401) are returned as unsuccessful Response objects
70
+ # rather than raised as exceptions. Use response.success? to check for errors.
71
71
  def initialize(response)
72
72
  if response.is_a?(Faraday::Response)
73
73
  @status_code = response.status
@@ -79,20 +79,23 @@ module PaystackSdk
79
79
  case @status_code
80
80
  when 200..299
81
81
  @success = true
82
- when 400
83
- handle_400_response
84
- when 401
85
- raise AuthenticationError.new
86
- when 404
87
- handle_404_response
82
+ when 400..499
83
+ # Client errors - return unsuccessful response for user to handle
84
+ @success = false
85
+ @error_message = @api_message || "Client error"
86
+
87
+ # Still raise for authentication issues as these are usually config problems
88
+ raise AuthenticationError.new(@api_message || "Authentication failed") if @status_code == 401
88
89
  when 429
90
+ # Rate limiting - raise as users need to implement retry logic
89
91
  retry_after = response.headers["Retry-After"]
90
92
  raise RateLimitError.new(retry_after || 30)
91
93
  when 500..599
94
+ # Server errors - raise as these indicate Paystack infrastructure issues
92
95
  raise ServerError.new(@status_code, @api_message)
93
96
  else
94
97
  @success = false
95
- raise APIError.new(@api_message || "Paystack API Error")
98
+ @error_message = @api_message || "Unknown error"
96
99
  end
97
100
  elsif response.is_a?(Response)
98
101
  @success = response.success?
@@ -120,6 +123,26 @@ module PaystackSdk
120
123
  @success
121
124
  end
122
125
 
126
+ # Check if the response failed
127
+ #
128
+ # @return [Boolean] true if the API request failed
129
+ def failed?
130
+ !@success
131
+ end
132
+
133
+ # Get error information if the request failed
134
+ #
135
+ # @return [Hash] Hash containing error details, or empty hash if successful
136
+ def error_details
137
+ return {} if success?
138
+
139
+ {
140
+ status_code: @status_code,
141
+ message: @error_message || @api_message,
142
+ raw_response: @body
143
+ }.compact
144
+ end
145
+
123
146
  # Returns the original response body
124
147
  # This is useful for debugging or accessing raw data
125
148
  #
@@ -186,7 +209,7 @@ module PaystackSdk
186
209
  # @yield [key, value] For hashes, passes each key-value pair
187
210
  # @yield [value] For arrays, passes each item
188
211
  # @return [Response, Enumerator] Self for chaining or Enumerator if no block given
189
- def each(&block)
212
+ def each
190
213
  return enum_for(:each) unless block_given?
191
214
 
192
215
  if @raw_data.is_a?(Hash)
@@ -206,7 +229,7 @@ module PaystackSdk
206
229
  # @return [Integer] The number of items
207
230
  # @!method empty?
208
231
  # @return [Boolean] Whether the collection is empty
209
- [:size, :length, :count, :empty?].each do |method_name|
232
+ %i[size length count empty?].each do |method_name|
210
233
  define_method(method_name) do
211
234
  @raw_data.send(method_name) if @raw_data.respond_to?(method_name)
212
235
  end
@@ -217,9 +240,10 @@ module PaystackSdk
217
240
  # @return [Object, Response] The first item, wrapped if necessary
218
241
  # @!method last
219
242
  # @return [Object, Response] The last item, wrapped if necessary
220
- [:first, :last].each do |method_name|
243
+ %i[first last].each do |method_name|
221
244
  define_method(method_name) do
222
245
  return nil unless @raw_data.is_a?(Array)
246
+
223
247
  wrap_value(@raw_data.send(method_name))
224
248
  end
225
249
  end
@@ -236,9 +260,7 @@ module PaystackSdk
236
260
 
237
261
  # First try to get identifier from the message
238
262
  message = body["message"].to_s.downcase
239
- if message =~ /with (id|code|reference|email): ([^\s]+)/i
240
- return $2
241
- end
263
+ return ::Regexp.last_match(2) if message =~ /with (id|code|reference|email): ([^\s]+)/i
242
264
 
243
265
  # If not found in message, try to extract from error code
244
266
  if body["code"]&.match?(/^(transaction|customer)_/)
@@ -263,6 +285,7 @@ module PaystackSdk
263
285
  # @return [Hash, Array, nil] The data from the response
264
286
  def extract_data_from_body(body)
265
287
  return body unless body.is_a?(Hash)
288
+
266
289
  body["data"] || body
267
290
  end
268
291
 
@@ -284,28 +307,15 @@ module PaystackSdk
284
307
  end
285
308
  end
286
309
 
287
- def handle_400_response
288
- if @body["code"]&.end_with?("_not_found") ||
289
- @api_message&.match?(/not found|cannot find|does not exist/i)
290
- resource_type = determine_resource_type
291
- meta_info = @body["meta"]&.dig("nextStep")
292
- message = @api_message
293
- message = "#{message}\nHint: #{meta_info}" if meta_info
294
- raise ResourceNotFoundError.new(resource_type, message)
295
- else
296
- @success = false
297
- raise APIError.new(@api_message || "Paystack API Error")
298
- end
299
- end
310
+ def determine_resource_type
311
+ return "Unknown" unless @body.is_a?(Hash) && @body["code"]
300
312
 
301
- def handle_404_response
302
- resource_type = determine_resource_type
303
- raise ResourceNotFoundError.new(resource_type, @api_message)
304
- end
313
+ if @body["code"].include?("_")
314
+ parts = @body["code"].to_s.split("_")
315
+ return parts.last if parts.last != "not_found"
316
+ end
305
317
 
306
- def determine_resource_type
307
- resource = @body["code"].split("_").first
308
- resource.capitalize
318
+ "unknown"
309
319
  end
310
320
  end
311
321
  end
@@ -37,9 +37,9 @@ module PaystackSdk
37
37
  # @param name [String] Name of the parameter for error messages
38
38
  # @raise [PaystackSdk::InvalidFormatError] If input is not a hash
39
39
  def validate_hash!(input:, name: "Payload")
40
- unless input.is_a?(Hash)
41
- raise PaystackSdk::InvalidFormatError.new(name, "Hash")
42
- end
40
+ return if input.is_a?(Hash)
41
+
42
+ raise PaystackSdk::InvalidFormatError.new(name, "Hash")
43
43
  end
44
44
 
45
45
  # Validates that required parameters are present in a payload.
@@ -53,10 +53,10 @@ module PaystackSdk
53
53
  !payload.key?(param) && !payload.key?(param.to_s)
54
54
  end
55
55
 
56
- unless missing_params.empty?
57
- param = missing_params.first
58
- raise PaystackSdk::MissingParamError.new(param)
59
- end
56
+ return if missing_params.empty?
57
+
58
+ param = missing_params.first
59
+ raise PaystackSdk::MissingParamError.new(param)
60
60
  end
61
61
 
62
62
  # Validates that a value is present (not nil or empty).
@@ -91,9 +91,9 @@ module PaystackSdk
91
91
  # @param name [String] Name of the parameter for error messages
92
92
  # @raise [PaystackSdk::InvalidFormatError] If reference format is invalid
93
93
  def validate_reference_format!(reference:, name: "Reference")
94
- unless reference.to_s.match?(/^[a-zA-Z0-9._=-]+$/)
95
- raise PaystackSdk::InvalidFormatError.new(name, "alphanumeric characters and the following: -, ., =")
96
- end
94
+ return if reference.to_s.match?(/^[a-zA-Z0-9._=-]+$/)
95
+
96
+ raise PaystackSdk::InvalidFormatError.new(name, "alphanumeric characters and the following: -, ., =")
97
97
  end
98
98
 
99
99
  # Validates a date string format.
@@ -106,6 +106,7 @@ module PaystackSdk
106
106
  def validate_date_format!(date_str:, name: "Date", allow_nil: true)
107
107
  if date_str.nil?
108
108
  raise PaystackSdk::MissingParamError.new(name) unless allow_nil
109
+
109
110
  return
110
111
  end
111
112
 
@@ -136,13 +137,14 @@ module PaystackSdk
136
137
  def validate_allowed_values!(value:, allowed_values:, name: "Parameter", allow_nil: true)
137
138
  if value.nil?
138
139
  raise PaystackSdk::MissingParamError.new(name) unless allow_nil
140
+
139
141
  return
140
142
  end
141
143
 
142
- unless allowed_values.include?(value)
143
- allowed_list = allowed_values.join(", ")
144
- raise PaystackSdk::InvalidValueError.new(name, "must be one of: #{allowed_list}")
145
- end
144
+ return if allowed_values.include?(value)
145
+
146
+ allowed_list = allowed_values.join(", ")
147
+ raise PaystackSdk::InvalidValueError.new(name, "must be one of: #{allowed_list}")
146
148
  end
147
149
 
148
150
  # Validates an email format.
@@ -154,12 +156,13 @@ module PaystackSdk
154
156
  def validate_email!(email:, name: "Email", allow_nil: false)
155
157
  if email.nil?
156
158
  raise PaystackSdk::MissingParamError.new(name) unless allow_nil
159
+
157
160
  return
158
161
  end
159
162
 
160
- unless email.to_s.match?(/\A[^@\s]+@[^@\s]+\.[^@\s]+\z/)
161
- raise PaystackSdk::InvalidFormatError.new(name, "valid email address")
162
- end
163
+ return if email.to_s.match?(/\A[^@\s]+@[^@\s]+\.[^@\s]+\z/)
164
+
165
+ raise PaystackSdk::InvalidFormatError.new(name, "valid email address")
163
166
  end
164
167
 
165
168
  # Validates a currency code format.
@@ -171,12 +174,13 @@ module PaystackSdk
171
174
  def validate_currency!(currency:, name: "Currency", allow_nil: true)
172
175
  if currency.nil?
173
176
  raise PaystackSdk::MissingParamError.new(name) unless allow_nil
177
+
174
178
  return
175
179
  end
176
180
 
177
- unless currency.to_s.match?(/\A[A-Z]{3}\z/)
178
- raise PaystackSdk::InvalidFormatError.new(name, "3-letter ISO code (e.g., NGN, USD, GHS)")
179
- end
181
+ return if currency.to_s.match?(/\A[A-Z]{3}\z/)
182
+
183
+ raise PaystackSdk::InvalidFormatError.new(name, "3-letter ISO code (e.g., NGN, USD, GHS)")
180
184
  end
181
185
 
182
186
  # Validates multiple fields at once.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PaystackSdk
4
- VERSION = "0.0.9"
4
+ VERSION = "0.1.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paystack_sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maxwell Nana Forson (theLazyProgrammer)
@@ -24,75 +24,75 @@ dependencies:
24
24
  - !ruby/object:Gem::Version
25
25
  version: 2.13.1
26
26
  - !ruby/object:Gem::Dependency
27
- name: rspec
27
+ name: debug
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '3.13'
32
+ version: 1.9.0
33
33
  type: :development
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '3.13'
39
+ version: 1.9.0
40
40
  - !ruby/object:Gem::Dependency
41
- name: standard
41
+ name: irb
42
42
  requirement: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: 1.49.0
46
+ version: 1.15.1
47
47
  type: :development
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: 1.49.0
53
+ version: 1.15.1
54
54
  - !ruby/object:Gem::Dependency
55
- name: irb
55
+ name: rake
56
56
  requirement: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: 1.15.1
60
+ version: 13.2.1
61
61
  type: :development
62
62
  prerelease: false
63
63
  version_requirements: !ruby/object:Gem::Requirement
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: 1.15.1
67
+ version: 13.2.1
68
68
  - !ruby/object:Gem::Dependency
69
- name: rake
69
+ name: rspec
70
70
  requirement: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: 13.2.1
74
+ version: '3.13'
75
75
  type: :development
76
76
  prerelease: false
77
77
  version_requirements: !ruby/object:Gem::Requirement
78
78
  requirements:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: 13.2.1
81
+ version: '3.13'
82
82
  - !ruby/object:Gem::Dependency
83
- name: debug
83
+ name: standard
84
84
  requirement: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - "~>"
87
87
  - !ruby/object:Gem::Version
88
- version: 1.9.0
88
+ version: 1.49.0
89
89
  type: :development
90
90
  prerelease: false
91
91
  version_requirements: !ruby/object:Gem::Requirement
92
92
  requirements:
93
93
  - - "~>"
94
94
  - !ruby/object:Gem::Version
95
- version: 1.9.0
95
+ version: 1.49.0
96
96
  description: |
97
97
  The `paystack_sdk` gem provides a simple and intuitive interface for
98
98
  interacting with Paystack's payment gateway API. It allows developers to
@@ -117,6 +117,7 @@ files:
117
117
  - lib/paystack_sdk/client.rb
118
118
  - lib/paystack_sdk/resources/banks.rb
119
119
  - lib/paystack_sdk/resources/base.rb
120
+ - lib/paystack_sdk/resources/charges.rb
120
121
  - lib/paystack_sdk/resources/customers.rb
121
122
  - lib/paystack_sdk/resources/transactions.rb
122
123
  - lib/paystack_sdk/resources/transfer_recipients.rb