electionbuddy-ruby 0.2.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
  SHA256:
3
- metadata.gz: 609fbcd8ec13547ffc65048afb495236d9eecbe0a787bea74bee39315b3e92c1
4
- data.tar.gz: 35682f5a36ea65fe229f9239cf14335b132e6ef94e7befc79d9e601338262e81
3
+ metadata.gz: 64c0f48e8da4cd5811d86506d945b853e4e284afd8a8041878d680bf46117d4d
4
+ data.tar.gz: b635df1e9e3f7f013c769818e2722f6224de5cea279bd5ad36364a80c6d9d15b
5
5
  SHA512:
6
- metadata.gz: 7cbf3bc35b59210fcf1a8a0e906dafa5112ea801568edc5aee762019edc3dcdc49936087e7c58613657b3d732af42400ea735da644f717e38d89a2e1eb8b074b
7
- data.tar.gz: 7fadf9a933f95c94b949dbec9533bf6c775cc25c16252e30f80d3895ab7c49408e29d01518e034d9d71148e6e258634ce01df6f7d4710625d21cfee4ff9ba431
6
+ metadata.gz: b0dc2ca445cb784a1d72b27c6bcd4a5f0221ea50ca87e577dd301e0603189a11623eb85f9d794005350486efd82ce62bdb40d1492afe5ef536cde58a39fdb060
7
+ data.tar.gz: 4438b38fefa9ebaf8d22d7b57bc71272042bf89eda5dfe459fe29d647fd1c7d0d6141e31c5befe25e7267c5010cf5fad67b7f8ab729ef067b155b68ceed07fea
data/.rubocop.yml CHANGED
@@ -15,4 +15,10 @@ Naming/FileName:
15
15
  - 'lib/electionbuddy-ruby.rb'
16
16
 
17
17
  Metrics/MethodLength:
18
- Max: 15
18
+ Max: 30
19
+
20
+ Metrics/ClassLength:
21
+ Max: 200
22
+
23
+ Layout/LineLength:
24
+ Max: 150
data/.yardopts ADDED
@@ -0,0 +1,10 @@
1
+ --markup markdown
2
+ --markup-provider redcarpet
3
+ --readme README.md
4
+ --title 'ElectionBuddy Ruby'
5
+ --protected
6
+ --private
7
+ lib/**/*.rb
8
+ -
9
+ LICENSE.txt
10
+ CHANGELOG.md
data/CHANGELOG.md CHANGED
@@ -7,9 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
- ## [0.1.0] - 2024-10-29
10
+ ## [0.4.0] - 2024-11-20
11
11
 
12
- - Initial release
12
+ ### Added
13
+
14
+ - Ability to import voters to a vote
15
+ - Automated gem release using GitHub Actions
16
+
17
+ ## [0.3.0] - 2024-11-18
18
+
19
+ ### Added
20
+
21
+ - Added Global configuration for setting the API key using `ElectionBuddy.configure` method
22
+ - Ability to retrieve voter list's validation results
23
+ - Automated gem documentation using YARD and GitHub Pages
24
+
25
+ ### Changed
26
+
27
+ - Update README.md with get validtion results usage instructions
28
+ - Update .rubocop.yml with new rules
29
+ - Enhance code documentation with detailed YARD comments
30
+
31
+ ### Fixed
32
+
33
+ - Fix changelog version ordering
13
34
 
14
35
  ## [0.2.0] - 2024-11-07
15
36
 
@@ -29,7 +50,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
29
50
 
30
51
  - Fix console startup issue caused by incorrect code reference
31
52
 
32
- [unreleased]: https://github.com/electionbuddy/electionbuddy-ruby/compare/v0.2.0...HEAD
53
+ ## [0.1.0] - 2024-10-29
54
+
55
+ - Initial release
56
+
57
+ [unreleased]: https://github.com/electionbuddy/electionbuddy-ruby/compare/v0.4.0...HEAD
58
+ [0.4.0]: https://github.com/electionbuddy/electionbuddy-ruby/compare/v0.3.0...v0.4.0
59
+ [0.3.0]: https://github.com/electionbuddy/electionbuddy-ruby/compare/v0.2.0...v0.3.0
33
60
  [0.2.0]: https://github.com/electionbuddy/electionbuddy-ruby/compare/v0.1.0...v0.2.0
34
61
  [0.1.0]: https://github.com/electionbuddy/electionbuddy-ruby/releases/tag/v0.1.0
35
62
 
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # ElectionBuddy Ruby
2
2
 
3
- A Ruby client for interacting with the ElectionBuddy API.
4
- You can find the API documentation [here](https://api.electionbuddy.com).
3
+ A Ruby client for interacting with the [ElectionBuddy API](https://api.electionbuddy.com).
4
+ Explore the complete documentation at [https://electionbuddy.github.io/electionbuddy-ruby](https://electionbuddy.github.io/electionbuddy-ruby).
5
5
 
6
6
  ## Installation
7
7
 
@@ -21,12 +21,55 @@ gem 'electionbuddy-ruby'
21
21
 
22
22
  ## Usage
23
23
 
24
- Ensure you have an API key from Electionbuddy, and initialize the client as follows:
24
+ Ensure you have an API key from Electionbuddy. You can configure the API key globally or initialize the client directly with the API key.
25
+
26
+ ### Global Configuration
27
+
28
+ #### Example in a Rails application
29
+
30
+ Create an initializer file in `config/initializers/electionbuddy.rb` and add the following code:
31
+
32
+ ```ruby
33
+ ElectionBuddy.configure do |config|
34
+ config.api_key = Rails.application.credentials.electionbuddy[:api_key]
35
+ end
36
+ ```
37
+
38
+ #### Client Initialization
39
+
40
+ You can now initialize the client without passing the API key if it has been configured globally:
25
41
 
26
42
  ```ruby
27
- client = ElectionBuddy::Client.new('your-api-key')
43
+ client = ElectionBuddy::Client.new
28
44
  ```
29
45
 
46
+ Alternatively, you can still pass the API key directly during initialization. If the API key is passed during initialization, it will take precedence over the global configuration.
47
+
48
+ ```ruby
49
+ client = ElectionBuddy::Client.new(api_key: 'your-api-key')
50
+ ```
51
+
52
+ ### Voter List Importation
53
+
54
+ To import a voter list for an election, use the `voter_list.import(vote_id, voters, append_mode: false)` method:
55
+
56
+ ```ruby
57
+ voters = [
58
+ { email: 'voter1@example.com', label: 'Voter One' },
59
+ { email: 'voter2@example.com', label: 'Voter Two' }
60
+ ]
61
+
62
+ import = client.voter_list.import(1, voters, append_mode: false)
63
+
64
+ if import.done?
65
+ puts "Import completed successfully! Identifier: #{import.identifier}"
66
+ else
67
+ puts "Import failed: #{import.error}"
68
+ end
69
+ ```
70
+
71
+ The `append_mode` parameter determines whether the voters should be appended to the existing list (`true`) or replace the existing list (`false`). The default value is `false`.
72
+
30
73
  ### Voter List Validation
31
74
 
32
75
  To validate a voter list, use the `voter_list.validate(vote_id)` method:
@@ -36,14 +79,79 @@ validation = client.voter_list.validate(1)
36
79
 
37
80
  if validation.done?
38
81
  puts "Validation completed successfully! Identifier: #{validation.identifier}"
39
- # "Validation completed successfully! Identifier: ae0a1724-9791-4bb2-8331-6d4e55a9b7c8"
40
82
  else
41
83
  puts "Validation failed: #{validation.error}"
42
- # "Validation failed: Vote: not found"
43
84
  end
44
85
  ```
45
86
 
46
- ### Possible Errors
87
+ ### Get the Validation Result
88
+
89
+ Once you have a validation identifier, you can check the validation results.
90
+
91
+ ```ruby
92
+ begin
93
+ validation_result = client.voter_list.validation_result('ae0a1724-9791-4bb2-8331-6d4e55a9b7c8')
94
+ if validation_result.valid?
95
+ puts "The voter list is valid!"
96
+ else
97
+ puts "The voter list is invalid!"
98
+ puts "Total errors count: #{validation_result.total_errors_count}"
99
+ end
100
+ rescue ElectionBuddy::Error => e
101
+ puts "Something went wrong: #{e.message}"
102
+ end
103
+ ```
104
+
105
+ The voter list validation can have two types of errors:
106
+
107
+ 1. **List-level errors**: Affect the entire voter list (e.g., missing required columns)
108
+ 2. **Line-level errors**: Affect specific lines in the voter list (e.g., invalid email format)
109
+
110
+ #### List-Level Errors
111
+
112
+ List-level errors can be retrieved using the `list_errors` method.
113
+
114
+ ```ruby
115
+ if validation_result.list_errors.any?
116
+ puts "List-level errors:"
117
+ validation_result.list_errors.each do |list_error|
118
+ puts "Error message: #{list_error.error_message}"
119
+ end
120
+ end
121
+ ```
122
+
123
+ #### Line-Level Errors
124
+
125
+ Line-level errors are paginated. You can specify the page number and the number of errors per page.
126
+ If you don't specify the page number and the number of errors per page, the default values are 1 and 10, respectively.
127
+
128
+ ```ruby
129
+ validation_result = client.voter_list.validation_result('ae0a1724-9791-4bb2-8331-6d4e55a9b7c8', page: 2, per_page: 10)
130
+ line_errors = validation_result.line_errors
131
+ puts "There is a total of #{line_errors.total} line-level errors."
132
+ puts "The current page is #{line_errors.page}."
133
+ puts "There are #{line_errors.per_page} errors per page."
134
+ puts "There are #{line_errors.total_pages} pages in total."
135
+ ```
136
+
137
+ PS: The `list_errors` object is always available, regardless of the line-level errors pagination.
138
+
139
+ To iterate over the line-level errors, you can use the following code:
140
+
141
+ ```ruby
142
+ if line_errors.any?
143
+ puts "Line-level errors for page #{line_errors.page}:"
144
+ line_errors.each do |line_error|
145
+ puts "Line identifier: #{line_error.voter_information_line_id}"
146
+ puts "Error messages:"
147
+ line_error.each do |line_error|
148
+ puts "Error messages #{line_error.error_messages}"
149
+ end
150
+ end
151
+ end
152
+ ```
153
+
154
+ ### Possible API Errors
47
155
 
48
156
  The following errors may be raised by the API:
49
157
 
@@ -56,6 +164,17 @@ The following errors may be raised by the API:
56
164
 
57
165
  Each error will raise an `Error` exception with a message detailing the status code and the error message returned by the API.
58
166
 
167
+ ## Documentation
168
+
169
+ The complete documentation for this gem is available at: https://electionbuddy.github.io/electionbuddy-ruby
170
+
171
+ You can also generate the documentation locally using:
172
+
173
+ ```bash
174
+ yard doc
175
+ yard server
176
+ ```
177
+
59
178
  ## Development
60
179
 
61
180
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -1,15 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ElectionBuddy
4
+ # HTTP client for the ElectionBuddy API
5
+ #
6
+ # @example
7
+ # client = Client.new(api_key: "your-api-key")
8
+ # client.voter_list.validate(123)
9
+ #
4
10
  class Client
5
11
  BASE_URL = "https://secure.electionbuddy.com/api/v2"
6
12
 
7
- def initialize(api_key, adapter: Faraday.default_adapter, stubs: nil)
8
- @api_key = api_key
13
+ # @param api_key [String, nil] The API key for authentication (optional if configured globally)
14
+ # @param adapter [Object, nil] The HTTP client adapter to use (optional, defaults to Faraday's default adapter)
15
+ # @param stubs [Object, nil] Test stubs for the adapter (optional)
16
+ def initialize(api_key: nil, adapter: Faraday.default_adapter, stubs: nil)
17
+ @api_key = api_key || ElectionBuddy.configuration.api_key
9
18
  @adapter = adapter
10
19
  @stubs = stubs
11
20
  end
12
21
 
22
+ # Returns the voter list resource for handling voter-related operations
23
+ #
24
+ # @return [VoterListResource] The voter list resource
13
25
  def voter_list
14
26
  VoterListResource.new(connection)
15
27
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ElectionBuddy
4
+ # Configuration options for the ElectionBuddy client
5
+ class Configuration
6
+ # @return [String, nil] The API key used for authentication
7
+ attr_accessor :api_key
8
+ end
9
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ElectionBuddy
4
+ # Represents an importation operation for voter lists
5
+ #
6
+ # @example
7
+ # importation = Importation.new(response)
8
+ # if importation.done?
9
+ # puts "Import successful: #{importation.identifier}"
10
+ # else
11
+ # puts "Import failed: #{importation.error}"
12
+ # end
13
+ #
14
+ class Importation
15
+ # @param response [Hash] The API response containing importation details
16
+ def initialize(response)
17
+ @response = response
18
+ end
19
+
20
+ # Returns the identifier for this importation
21
+ #
22
+ # @return [String] The importation identifier or "Not Available"
23
+ def identifier
24
+ @response["importation_identifier"] || "Not Available"
25
+ end
26
+
27
+ # Checks if the importation completed successfully
28
+ #
29
+ # @return [Boolean] true if importation was successful, false otherwise
30
+ def done?
31
+ @response["error"].nil?
32
+ end
33
+
34
+ # Returns the error message if importation failed
35
+ #
36
+ # @return [String, nil] The formatted error message or nil if importation was successful
37
+ def error
38
+ return nil if done?
39
+
40
+ ErrorFormatter.format(@response["error"])
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ElectionBuddy
4
+ class Validation
5
+ # Represents a single line validation error
6
+ #
7
+ # @example
8
+ # line_error = LineError.new({ "voter_information_line_id" => 123, "errors" => { "email" => ["is invalid"] } })
9
+ # line_error.voter_information_line_id #=> 123
10
+ # line_error.error_messages #=> ["email: is invalid"]
11
+ #
12
+ class LineError
13
+ # @return [Integer] The ID of the voter information line
14
+ attr_reader :voter_information_line_id
15
+
16
+ # @return [Hash] The errors hash containing categories and messages
17
+ attr_reader :errors
18
+
19
+ # @param line_error [Hash] The error hash containing line ID and errors
20
+ def initialize(line_error)
21
+ @voter_information_line_id = line_error["voter_information_line_id"]
22
+ @errors = line_error["errors"]
23
+ end
24
+
25
+ # Returns formatted error messages for each category
26
+ #
27
+ # @return [Array<String>] Array of formatted error messages
28
+ def error_messages
29
+ @errors.map do |(category, messages)|
30
+ "#{category}: #{messages.join(", ")}"
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ElectionBuddy
4
+ class Validation
5
+ # Represents a collection of line-by-line validation errors
6
+ #
7
+ # @example
8
+ # line_errors = LineErrors.new(response)
9
+ # line_errors.total #=> 5
10
+ # line_errors.total_pages #=> 1
11
+ # line_errors.empty? #=> false
12
+ #
13
+ class LineErrors
14
+ include Enumerable
15
+
16
+ # @return [Integer] Total number of validation errors
17
+ attr_reader :total
18
+
19
+ # @return [Integer] Current page number
20
+ attr_reader :page
21
+
22
+ # @return [Integer] Number of items per page
23
+ attr_reader :per_page
24
+
25
+ # @param response [Hash] API response containing validation errors
26
+ def initialize(response)
27
+ @line_errors = response["voter_line_errors"]
28
+ @total = response["meta"]["total"]
29
+ @page = response["meta"]["page"]
30
+ @per_page = response["meta"]["per_page"]
31
+ end
32
+
33
+ # Calculates the total number of pages
34
+ #
35
+ # @return [Integer] Total number of pages
36
+ def total_pages
37
+ (total.to_f / per_page).ceil
38
+ end
39
+
40
+ # Iterates through each line error
41
+ #
42
+ # @return [Enumerator] Collection of line errors
43
+ def each(&block)
44
+ collection.each(&block)
45
+ end
46
+
47
+ # Checks if there are any line errors
48
+ #
49
+ # @return [Boolean] true if no errors exist, false otherwise
50
+ def empty?
51
+ collection.empty?
52
+ end
53
+
54
+ private
55
+
56
+ def collection
57
+ @collection ||= @line_errors.map { |line_error| LineError.new(line_error) }
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ElectionBuddy
4
+ class Validation
5
+ # Represents a single voter list validation error
6
+ #
7
+ # @example
8
+ # error = ListError.new({ "email" => ["is invalid", "is required"] })
9
+ # error.category #=> "email"
10
+ # error.messages #=> ["is invalid", "is required"]
11
+ # error.error_message #=> "email: is invalid, is required"
12
+ #
13
+ class ListError
14
+ # @return [Hash] The raw error data
15
+ attr_reader :error
16
+
17
+ # @return [String] The category of the error
18
+ attr_reader :category
19
+
20
+ # @return [Array<String>] The error messages
21
+ attr_reader :messages
22
+
23
+ # @param error [Hash] The error hash containing category and messages
24
+ def initialize(error)
25
+ @error = error
26
+ @category, @messages = error.first
27
+ end
28
+
29
+ # Returns a formatted error message
30
+ #
31
+ # @return [String] The formatted error message
32
+ def error_message
33
+ "#{category}: #{messages.join(", ")}"
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ElectionBuddy
4
+ class Validation
5
+ # Represents a collection of voter list validation errors
6
+ #
7
+ # @example
8
+ # list_errors = ListErrors.new(response)
9
+ # list_errors.total #=> 2
10
+ # list_errors.empty? #=> false
11
+ #
12
+ class ListErrors
13
+ include Enumerable
14
+
15
+ # @return [Integer] Total number of validation errors
16
+ attr_reader :total
17
+
18
+ # @param response [Hash] API response containing validation errors
19
+ def initialize(response)
20
+ @list_errors = response["voter_list_errors"]
21
+ @total = response["meta"]["total"]
22
+ end
23
+
24
+ # Iterates through each list error
25
+ #
26
+ # @return [Enumerator] Collection of list errors
27
+ def each(&block)
28
+ collection.each(&block)
29
+ end
30
+
31
+ # Checks if there are any list errors
32
+ #
33
+ # @return [Boolean] true if no errors exist, false otherwise
34
+ def empty?
35
+ collection.empty?
36
+ end
37
+
38
+ private
39
+
40
+ def collection
41
+ @collection ||= @list_errors
42
+ .map { |category, messages| { category => messages } }
43
+ .map { |list_error| ListError.new(list_error) }
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ElectionBuddy
4
+ class Validation
5
+ class UnavailableTotalErrorsCount < ElectionBuddy::Error; end
6
+ class UnavailableValidStatus < ElectionBuddy::Error; end
7
+
8
+ Success = ->(data) { { success?: true, data: data } }
9
+ Failure = ->(error) { { success?: false, error: error } }
10
+ private_constant :Success, :Failure
11
+
12
+ # Represents the result of a validation operation
13
+ #
14
+ # @example Check if validation passed
15
+ # result = Result.new(response)
16
+ # result.valid? #=> true
17
+ # result.total_errors_count #=> 0
18
+ #
19
+ # @example Handle validation errors
20
+ # result = Result.new(response)
21
+ # result.valid? #=> false
22
+ # result.total_errors_count #=> 3
23
+ # result.list_errors #=> #<ListErrors @total=1>
24
+ # result.line_errors #=> #<LineErrors @total=2>
25
+ #
26
+ # @example Handle API failures
27
+ # result = Result.new(response)
28
+ # result.valid? #=> raises UnavailableValidStatus
29
+ # result.total_errors_count #=> raises UnavailableTotalErrorsCount
30
+ # result.failure_message #=> "API call has failed - Error: Validation: not found"
31
+ class Result
32
+ # Initializes a new validation result
33
+ #
34
+ # @param response [Hash] The raw response from the validation API
35
+ def initialize(response)
36
+ @result = process_response(response)
37
+ end
38
+
39
+ # Returns the list of validation errors related to the voter list
40
+ # @return [ListErrors, Array] List validation errors or empty array if validation failed
41
+ def list_errors
42
+ return [] unless success?
43
+
44
+ @list_errors ||= ListErrors.new(@result[:data].dig("results", "voter_list_validations"))
45
+ end
46
+
47
+ # Returns the line-by-line validation errors
48
+ # @return [LineErrors, Array] Line validation errors or empty array if validation failed
49
+ def line_errors
50
+ return [] unless success?
51
+
52
+ @line_errors ||= LineErrors.new(@result[:data].dig("results", "voter_lines_validation"))
53
+ end
54
+
55
+ # Returns the total count of all validation errors
56
+ #
57
+ # @return [Integer] Total number of validation errors
58
+ # @raise [UnavailableTotalErrorsCount] if the API call failed
59
+ def total_errors_count
60
+ raise UnavailableTotalErrorsCount, failure_message if failure?
61
+
62
+ list_errors.total + line_errors.total
63
+ end
64
+
65
+ # Indicates if the validation passed without errors
66
+ #
67
+ # @return [Boolean] true if validation passed, false otherwise
68
+ # @raise [UnavailableValidStatus] if the API call failed
69
+ def valid?
70
+ raise UnavailableValidStatus, failure_message if failure?
71
+
72
+ total_errors_count.zero?
73
+ end
74
+
75
+ # Returns the error message if validation failed
76
+ #
77
+ # @return [String, nil] The formatted error message or nil if successful
78
+ def failure_error
79
+ return if success?
80
+
81
+ ::ElectionBuddy::ErrorFormatter.format(@result[:error])
82
+ end
83
+
84
+ # Returns a user-friendly failure message
85
+ #
86
+ # @return [String, nil] The failure message or nil if successful
87
+ def failure_message
88
+ return if success?
89
+
90
+ "API call has failed - Error: #{failure_error}"
91
+ end
92
+
93
+ private
94
+
95
+ def success?
96
+ @result[:success?]
97
+ end
98
+
99
+ def failure?
100
+ !success?
101
+ end
102
+
103
+ def process_response(response)
104
+ if response["error"]
105
+ Failure.call(response["error"])
106
+ else
107
+ Success.call(response)
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -1,19 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ElectionBuddy
4
+ # Represents a validation operation response from the ElectionBuddy API
5
+ # This class handles both successful and failed validation responses
6
+ #
7
+ # @example
8
+ # validation = Validation.new(response_hash)
9
+ # validation.done? #=> true/false
10
+ #
4
11
  class Validation
12
+ # @param response [Hash] The raw API response containing validation details
5
13
  def initialize(response)
6
14
  @response = response
7
15
  end
8
16
 
17
+ # Returns the unique identifier for this validation
18
+ #
19
+ # @return [String] The validation identifier or "Not available" if not present
9
20
  def identifier
10
21
  @response["validation_identifier"] || "Not available"
11
22
  end
12
23
 
24
+ # Checks if the validation completed successfully without errors
25
+ #
26
+ # @return [Boolean] true if validation completed without errors, false otherwise
13
27
  def done?
14
28
  @response["error"].nil?
15
29
  end
16
30
 
31
+ # Returns formatted error message if validation failed
32
+ #
33
+ # @return [String, nil] Formatted error message or nil if validation was successful
17
34
  def error
18
35
  return nil if done?
19
36
 
@@ -1,6 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ElectionBuddy
4
+ # @api public
5
+ # Base error class for ElectionBuddy exceptions
6
+ #
7
+ # @example Raising a custom error
8
+ # raise ElectionBuddy::Error, "Something went wrong"
9
+ #
10
+ # @since 0.1.0
4
11
  class Error < StandardError
5
12
  end
6
13
  end
@@ -1,7 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ElectionBuddy
4
+ # Formats error messages from hash responses
5
+ #
6
+ # @example
7
+ # ErrorFormatter.format({ "email" => ["is invalid", "is required"] })
8
+ # #=> "Email: is invalid, is required"
9
+ #
4
10
  class ErrorFormatter
11
+ # Formats error messages from a hash into a human-readable string
12
+ #
13
+ # @param error_hash [Hash, nil] Hash containing error keys and messages
14
+ # @return [String, nil] Formatted error message or nil if no errors
5
15
  def self.format(error_hash)
6
16
  return if error_hash.nil? || error_hash.empty?
7
17
 
@@ -1,15 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ElectionBuddy
4
+ # Base class for API resources
5
+ #
6
+ # @example
7
+ # class VoterListResource < Resource
8
+ # def validate(vote_id)
9
+ # post_request("/api/v2/votes/voters/validations", vote_id: vote_id)
10
+ # end
11
+ # end
12
+ #
4
13
  class Resource
14
+ # @param connection [Object] The HTTP client connection
5
15
  def initialize(connection)
6
16
  @connection = connection
7
17
  end
8
18
 
19
+ # Makes a GET request to the API
20
+ #
21
+ # @param url [String] The API endpoint URL
22
+ # @param params [Hash] Query parameters
23
+ # @param headers [Hash] Request headers
24
+ # @return [Hash] The API response
9
25
  def get_request(url, params = {}, headers = {}, &block)
10
26
  handle_response(@connection.get(url, params, headers, &block))
11
27
  end
12
28
 
29
+ # Makes a POST request to the API
30
+ #
31
+ # @param url [String] The API endpoint URL
32
+ # @param body [Hash] Request body parameters
33
+ # @param headers [Hash] Request headers
34
+ # @return [Hash] The API response
13
35
  def post_request(url, body = {}, headers = {}, &block)
14
36
  handle_response(@connection.post(url, body, headers, &block))
15
37
  end
@@ -17,7 +39,7 @@ module ElectionBuddy
17
39
  private
18
40
 
19
41
  def handle_response(response)
20
- return response.body if response.success? || response.status == 422
42
+ return response.body if response.success? || [422, 423].include?(response.status)
21
43
 
22
44
  raise_error(response.status, ErrorFormatter.format(response.body))
23
45
  end
@@ -1,11 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ElectionBuddy
4
+ # Handles voter list validation operations
5
+ #
6
+ # @example
7
+ # resource = VoterListResource.new(client)
8
+ # validation = resource.validate(123)
9
+ # result = resource.get_validation_result(validation.identifier)
10
+ #
4
11
  class VoterListResource < Resource
12
+ # Imports voters for a given vote
13
+ #
14
+ # @param vote_id [Integer] The ID of the vote to import voters for
15
+ # @param voters [Array<Hash>] Array of voter data to import
16
+ # @param append_mode [Boolean] Whether to append voters to existing list (default: false)
17
+ # @return [Importation] The importation response
18
+ def import(vote_id, voters, append_mode: false)
19
+ response = post_request("/api/v2/votes/voters/importations", vote_id: vote_id.to_i, voters: voters, append_mode: append_mode)
20
+
21
+ Importation.new(response)
22
+ end
23
+
24
+ # Initiates a validation for a given vote
25
+ #
26
+ # @param vote_id [Integer] The ID of the vote to validate
27
+ # @return [Validation] The validation response
5
28
  def validate(vote_id)
6
29
  response = post_request("/api/v2/votes/voters/validations", vote_id: vote_id.to_i)
7
30
 
8
31
  Validation.new(response)
9
32
  end
33
+
34
+ # Retrieves the validation results
35
+ #
36
+ # @param identifier [String] The validation identifier
37
+ # @param page [Integer, nil] The page number for paginated results (optional, default: 1)
38
+ # @param per_page [Integer, nil] The number of items per page (optional, default: 10)
39
+ # @return [Validation::Result] The validation results
40
+ def get_validation_result(identifier, page: 1, per_page: 10)
41
+ params = { "identifier" => identifier, "page" => page, "per_page" => per_page }
42
+ response = get_request("/api/v2/votes/voters/validations", params)
43
+
44
+ Validation::Result.new(response)
45
+ end
10
46
  end
11
47
  end
@@ -1,5 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ElectionBuddy
4
- VERSION = "0.2.0"
4
+ # Current version of ElectionBuddy gem
5
+ #
6
+ # @api public
7
+ # @return [String] the current version of the gem
8
+ # @example Get current version
9
+ # ElectionBuddy::VERSION #=> "0.4.0"
10
+ VERSION = "0.4.0"
5
11
  end
@@ -10,7 +10,34 @@ require "election_buddy/error"
10
10
  require "election_buddy/resource"
11
11
  require "election_buddy/resources/voter_list_resource"
12
12
  require "election_buddy/entities/validation"
13
+ require "election_buddy/entities/importation"
13
14
  require "election_buddy/error_formatter"
15
+ require "election_buddy/configuration"
16
+ require "election_buddy/entities/validation/result"
17
+ require "election_buddy/entities/validation/line_error"
18
+ require "election_buddy/entities/validation/line_errors"
19
+ require "election_buddy/entities/validation/list_error"
20
+ require "election_buddy/entities/validation/list_errors"
14
21
 
22
+ # ElectionBuddy API client library
23
+ #
24
+ # @api public
25
+ # @example Configure the client
26
+ # ElectionBuddy.configure do |config|
27
+ # config.api_key = 'your-api-key'
28
+ # end
15
29
  module ElectionBuddy
30
+ class << self
31
+ # @return [Configuration] Current configuration
32
+ attr_accessor :configuration
33
+
34
+ # Configures the ElectionBuddy client
35
+ #
36
+ # @yield [config] Configuration instance to be modified
37
+ # @yieldparam [Configuration] config The configuration instance
38
+ def configure
39
+ self.configuration ||= Configuration.new
40
+ yield(configuration)
41
+ end
42
+ end
16
43
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: electionbuddy-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alberto Rocha
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2024-11-07 00:00:00.000000000 Z
12
+ date: 2024-11-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: faraday
@@ -35,13 +35,21 @@ extra_rdoc_files: []
35
35
  files:
36
36
  - ".devcontainer/devcontainer.json"
37
37
  - ".rubocop.yml"
38
+ - ".yardopts"
38
39
  - CHANGELOG.md
39
40
  - LICENSE.txt
40
41
  - README.md
41
42
  - Rakefile
42
43
  - lib/election_buddy.rb
43
44
  - lib/election_buddy/client.rb
45
+ - lib/election_buddy/configuration.rb
46
+ - lib/election_buddy/entities/importation.rb
44
47
  - lib/election_buddy/entities/validation.rb
48
+ - lib/election_buddy/entities/validation/line_error.rb
49
+ - lib/election_buddy/entities/validation/line_errors.rb
50
+ - lib/election_buddy/entities/validation/list_error.rb
51
+ - lib/election_buddy/entities/validation/list_errors.rb
52
+ - lib/election_buddy/entities/validation/result.rb
45
53
  - lib/election_buddy/error.rb
46
54
  - lib/election_buddy/error_formatter.rb
47
55
  - lib/election_buddy/resource.rb
@@ -72,7 +80,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
72
80
  - !ruby/object:Gem::Version
73
81
  version: '0'
74
82
  requirements: []
75
- rubygems_version: 3.5.16
83
+ rubygems_version: 3.2.33
76
84
  signing_key:
77
85
  specification_version: 4
78
86
  summary: Ruby SDK for the ElectionBuddy API.