trueform 0.1.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 +7 -0
- data/CHANGELOG.md +10 -0
- data/LICENSE +21 -0
- data/README.md +116 -0
- data/lib/trueform/client.rb +211 -0
- data/lib/trueform/error.rb +21 -0
- data/lib/trueform/resources/validations.rb +23 -0
- data/lib/trueform/transport/net_http.rb +30 -0
- data/lib/trueform/validation.rb +91 -0
- data/lib/trueform/version.rb +5 -0
- data/lib/trueform.rb +8 -0
- metadata +55 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: e8c1befd1e0c8f22c56730d0b668a30df78f406bc43dbdde1512a439bf961c10
|
|
4
|
+
data.tar.gz: 6ee4f568e35bf1d11630c31fb3629287c8d78984bbffb419fa4c9a126b9e7bbc
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 40bbe46e945ab6d664cc2fe9f6d4acd277bbed27cecdf7dc2d7f3394537ca2b09a67152fa385abe89ed6e75ea5b2b38575ab49ec1a5a8be74fa3185119f44c54
|
|
7
|
+
data.tar.gz: e97329fe0109144397e5a223d4c1f60ff0b0cb79168be59a5027dd0d8f9262ac95e09a4080f41b6e720c7cec0b92ae4990b30172021479c9e4149105a834eaa1
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the Trueform Ruby SDK are documented here.
|
|
4
|
+
|
|
5
|
+
## [0.1.0] - 2026-08-13
|
|
6
|
+
|
|
7
|
+
- Added the `Trueform::Client` and `validations.create` resource interface.
|
|
8
|
+
- Added immutable validation results with idiomatic predicate methods.
|
|
9
|
+
- Added configurable retries, timeouts, and namespaced errors.
|
|
10
|
+
- Added validation of successful API response shapes.
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Trueform
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Trueform Ruby SDK
|
|
2
|
+
|
|
3
|
+
The official Ruby client for the [Trueform email validation API](https://trueform.cloud/docs/).
|
|
4
|
+
|
|
5
|
+
[Ruby SDK documentation](https://trueform.cloud/docs/ruby/) | [API reference](https://trueform.cloud/docs/api-reference/)
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
Add the gem to your bundle:
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
gem "trueform"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Then run `bundle install`. You can also install it directly with `gem install trueform`.
|
|
16
|
+
|
|
17
|
+
The SDK supports Ruby 3.1 and newer. It has no runtime dependencies and does not require an API key.
|
|
18
|
+
|
|
19
|
+
## Quickstart
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
require "trueform"
|
|
23
|
+
|
|
24
|
+
trueform = Trueform::Client.new
|
|
25
|
+
validation = trueform.validations.create(email: "user@example.com")
|
|
26
|
+
|
|
27
|
+
puts "Email looks good" if validation.deliverable?
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Handle validation results
|
|
31
|
+
|
|
32
|
+
Validation results are immutable Ruby objects with predicate methods:
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
if validation.did_you_mean
|
|
36
|
+
puts "Did you mean #{validation.did_you_mean}?"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
puts "Ask for a permanent email address" if validation.disposable?
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Available values and predicates:
|
|
43
|
+
|
|
44
|
+
- `email`
|
|
45
|
+
- `valid_format?`
|
|
46
|
+
- `freemail?`
|
|
47
|
+
- `disposable?`
|
|
48
|
+
- `mx_records?`
|
|
49
|
+
- `did_you_mean`
|
|
50
|
+
- `deliverable?`
|
|
51
|
+
- `to_h`
|
|
52
|
+
|
|
53
|
+
`deliverable?` is a domain-level verdict. It does not prove that a specific mailbox exists.
|
|
54
|
+
|
|
55
|
+
## Configure the client
|
|
56
|
+
|
|
57
|
+
Timeout values and retry delays use seconds:
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
trueform = Trueform::Client.new(
|
|
61
|
+
timeout: 5,
|
|
62
|
+
max_retries: 2
|
|
63
|
+
)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Override options for one request:
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
validation = trueform.validations.create(
|
|
70
|
+
email: "user@example.com",
|
|
71
|
+
timeout: 2,
|
|
72
|
+
max_retries: 0
|
|
73
|
+
)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The client retries connection failures, timeouts, rate limits, and server errors. A `Retry-After`
|
|
77
|
+
response header controls the delay when present.
|
|
78
|
+
|
|
79
|
+
Use `base_url:` to point the client at a different Trueform-compatible endpoint.
|
|
80
|
+
|
|
81
|
+
## Errors
|
|
82
|
+
|
|
83
|
+
```ruby
|
|
84
|
+
begin
|
|
85
|
+
validation = trueform.validations.create(email: "user@example.com")
|
|
86
|
+
rescue Trueform::RateLimitError => error
|
|
87
|
+
warn "Retry after #{error.retry_after} seconds"
|
|
88
|
+
rescue Trueform::InvalidRequestError => error
|
|
89
|
+
warn error.message
|
|
90
|
+
end
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Exported errors:
|
|
94
|
+
|
|
95
|
+
- `Trueform::Error`
|
|
96
|
+
- `Trueform::APIError`
|
|
97
|
+
- `Trueform::InvalidRequestError`
|
|
98
|
+
- `Trueform::RateLimitError`
|
|
99
|
+
- `Trueform::ConnectionError`
|
|
100
|
+
- `Trueform::TimeoutError`
|
|
101
|
+
|
|
102
|
+
Errors expose `code`, `status`, `request_id`, and `retry_after` when available.
|
|
103
|
+
|
|
104
|
+
## Development
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
bundle install
|
|
108
|
+
bundle exec rake
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a pull request. Report vulnerabilities
|
|
112
|
+
through the process in [SECURITY.md](SECURITY.md).
|
|
113
|
+
|
|
114
|
+
## License
|
|
115
|
+
|
|
116
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "openssl"
|
|
5
|
+
require "time"
|
|
6
|
+
require "timeout"
|
|
7
|
+
require "uri"
|
|
8
|
+
|
|
9
|
+
module Trueform
|
|
10
|
+
class Client
|
|
11
|
+
DEFAULT_BASE_URL = "https://api.trueform.cloud"
|
|
12
|
+
DEFAULT_TIMEOUT = 10
|
|
13
|
+
DEFAULT_MAX_RETRIES = 2
|
|
14
|
+
MAX_RETRY_DELAY = 60
|
|
15
|
+
|
|
16
|
+
attr_reader :validations
|
|
17
|
+
|
|
18
|
+
def initialize(
|
|
19
|
+
base_url: DEFAULT_BASE_URL,
|
|
20
|
+
timeout: DEFAULT_TIMEOUT,
|
|
21
|
+
max_retries: DEFAULT_MAX_RETRIES,
|
|
22
|
+
transport: Transport::NetHTTP.new
|
|
23
|
+
)
|
|
24
|
+
@base_url = normalize_base_url(base_url)
|
|
25
|
+
@timeout = positive_number(timeout, :timeout)
|
|
26
|
+
@max_retries = non_negative_integer(max_retries, :max_retries)
|
|
27
|
+
@transport = transport
|
|
28
|
+
@validations = Resources::Validations.new do |email, timeout: nil, max_retries: nil|
|
|
29
|
+
request(
|
|
30
|
+
method: :post,
|
|
31
|
+
path: "/v1/validations",
|
|
32
|
+
body: {email: email},
|
|
33
|
+
timeout: timeout,
|
|
34
|
+
max_retries: max_retries
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def request(method:, path:, body:, timeout:, max_retries:)
|
|
42
|
+
request_timeout = positive_number(timeout.nil? ? @timeout : timeout, :timeout)
|
|
43
|
+
retries = non_negative_integer(max_retries.nil? ? @max_retries : max_retries, :max_retries)
|
|
44
|
+
attempt = 0
|
|
45
|
+
|
|
46
|
+
begin
|
|
47
|
+
response = perform_request(
|
|
48
|
+
method: method,
|
|
49
|
+
path: path,
|
|
50
|
+
body: body,
|
|
51
|
+
timeout: request_timeout
|
|
52
|
+
)
|
|
53
|
+
parse_response(response)
|
|
54
|
+
rescue Error => error
|
|
55
|
+
raise unless retryable?(error) && attempt < retries
|
|
56
|
+
|
|
57
|
+
sleep(retry_delay(error, attempt))
|
|
58
|
+
attempt += 1
|
|
59
|
+
retry
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def perform_request(method:, path:, body:, timeout:)
|
|
64
|
+
@transport.call(
|
|
65
|
+
method: method,
|
|
66
|
+
uri: URI.parse("#{@base_url}#{path}"),
|
|
67
|
+
headers: {
|
|
68
|
+
"Accept" => "application/json",
|
|
69
|
+
"Content-Type" => "application/json",
|
|
70
|
+
"User-Agent" => "trueform-ruby/#{VERSION}"
|
|
71
|
+
},
|
|
72
|
+
body: JSON.generate(body),
|
|
73
|
+
timeout: timeout
|
|
74
|
+
)
|
|
75
|
+
rescue Timeout::Error => timeout_error
|
|
76
|
+
raise TimeoutError.new(
|
|
77
|
+
"Request timed out after #{timeout} seconds.",
|
|
78
|
+
code: "request_timeout"
|
|
79
|
+
), cause: timeout_error
|
|
80
|
+
rescue OpenSSL::SSL::SSLError, Net::ProtocolError, SocketError, IOError, SystemCallError => connection_error
|
|
81
|
+
raise ConnectionError.new(
|
|
82
|
+
"Unable to connect to the Trueform API.",
|
|
83
|
+
code: "connection_error"
|
|
84
|
+
), cause: connection_error
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def parse_response(response)
|
|
88
|
+
status = Integer(response.code)
|
|
89
|
+
request_id = response["x-request-id"] || response["cf-ray"]
|
|
90
|
+
body = parse_body(response.body, status: status, request_id: request_id)
|
|
91
|
+
|
|
92
|
+
if status.between?(200, 299)
|
|
93
|
+
unless body.is_a?(Hash)
|
|
94
|
+
raise APIError.new(
|
|
95
|
+
"The API returned an invalid JSON response.",
|
|
96
|
+
code: "invalid_response",
|
|
97
|
+
status: status,
|
|
98
|
+
request_id: request_id
|
|
99
|
+
)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
return body
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
raise error_from_response(status, body, response, request_id)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def parse_body(value, status:, request_id:)
|
|
109
|
+
return nil if value.nil? || value.empty?
|
|
110
|
+
|
|
111
|
+
JSON.parse(value)
|
|
112
|
+
rescue JSON::ParserError => error
|
|
113
|
+
return nil unless status.between?(200, 299)
|
|
114
|
+
|
|
115
|
+
raise APIError.new(
|
|
116
|
+
"The API returned an invalid JSON response.",
|
|
117
|
+
code: "invalid_response",
|
|
118
|
+
status: status,
|
|
119
|
+
request_id: request_id
|
|
120
|
+
), cause: error
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def error_from_response(status, body, response, request_id)
|
|
124
|
+
message = if body.is_a?(Hash) && body["error"].is_a?(String)
|
|
125
|
+
body["error"]
|
|
126
|
+
else
|
|
127
|
+
"Request failed with status #{status}."
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
case status
|
|
131
|
+
when 400
|
|
132
|
+
InvalidRequestError.new(
|
|
133
|
+
message,
|
|
134
|
+
code: "invalid_request",
|
|
135
|
+
status: status,
|
|
136
|
+
request_id: request_id
|
|
137
|
+
)
|
|
138
|
+
when 429
|
|
139
|
+
RateLimitError.new(
|
|
140
|
+
message,
|
|
141
|
+
code: "rate_limit",
|
|
142
|
+
status: status,
|
|
143
|
+
request_id: request_id,
|
|
144
|
+
retry_after: parse_retry_after(response["retry-after"])
|
|
145
|
+
)
|
|
146
|
+
else
|
|
147
|
+
APIError.new(
|
|
148
|
+
message,
|
|
149
|
+
code: "api_error",
|
|
150
|
+
status: status,
|
|
151
|
+
request_id: request_id
|
|
152
|
+
)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def parse_retry_after(value)
|
|
157
|
+
return if value.nil? || value.empty?
|
|
158
|
+
|
|
159
|
+
seconds = Float(value, exception: false)
|
|
160
|
+
return [seconds, 0].max if seconds&.finite?
|
|
161
|
+
|
|
162
|
+
[Time.httpdate(value) - Time.now, 0].max
|
|
163
|
+
rescue ArgumentError
|
|
164
|
+
nil
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def retryable?(error)
|
|
168
|
+
return true if error.is_a?(RateLimitError)
|
|
169
|
+
return true if error.is_a?(TimeoutError)
|
|
170
|
+
return true if error.is_a?(ConnectionError) && error.code == "connection_error"
|
|
171
|
+
|
|
172
|
+
error.is_a?(APIError) && (error.status == 408 || error.status.to_i >= 500)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def retry_delay(error, attempt)
|
|
176
|
+
return [error.retry_after, MAX_RETRY_DELAY].min if error.retry_after
|
|
177
|
+
|
|
178
|
+
[0.25 * (2**attempt), 2].min
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def normalize_base_url(value)
|
|
182
|
+
unless value.is_a?(String)
|
|
183
|
+
raise ArgumentError, "base_url must be an HTTP or HTTPS URL"
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
uri = URI.parse(value)
|
|
187
|
+
unless uri.is_a?(URI::HTTP) && uri.host && !uri.query && !uri.fragment
|
|
188
|
+
raise ArgumentError, "base_url must be an HTTP or HTTPS URL"
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
value.sub(%r{/+\z}, "")
|
|
192
|
+
rescue URI::InvalidURIError
|
|
193
|
+
raise ArgumentError, "base_url must be an HTTP or HTTPS URL"
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def positive_number(value, name)
|
|
197
|
+
valid = value.is_a?(Numeric) && value.positive? && (!value.respond_to?(:finite?) || value.finite?)
|
|
198
|
+
raise ArgumentError, "#{name} must be a positive number" unless valid
|
|
199
|
+
|
|
200
|
+
value
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def non_negative_integer(value, name)
|
|
204
|
+
unless value.is_a?(Integer) && value >= 0
|
|
205
|
+
raise ArgumentError, "#{name} must be a non-negative integer"
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
value
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Trueform
|
|
4
|
+
class Error < StandardError
|
|
5
|
+
attr_reader :code, :status, :request_id, :retry_after
|
|
6
|
+
|
|
7
|
+
def initialize(message, code:, status: nil, request_id: nil, retry_after: nil)
|
|
8
|
+
super(message)
|
|
9
|
+
@code = code
|
|
10
|
+
@status = status
|
|
11
|
+
@request_id = request_id
|
|
12
|
+
@retry_after = retry_after
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class APIError < Error; end
|
|
17
|
+
class InvalidRequestError < APIError; end
|
|
18
|
+
class RateLimitError < APIError; end
|
|
19
|
+
class ConnectionError < Error; end
|
|
20
|
+
class TimeoutError < ConnectionError; end
|
|
21
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Trueform
|
|
4
|
+
module Resources
|
|
5
|
+
class Validations
|
|
6
|
+
def initialize(&request)
|
|
7
|
+
@request = request
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def create(email:, **options)
|
|
11
|
+
unless email.is_a?(String) && !email.strip.empty?
|
|
12
|
+
raise InvalidRequestError.new(
|
|
13
|
+
"The email parameter must be a non-empty string.",
|
|
14
|
+
code: "invalid_email"
|
|
15
|
+
)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
response = @request.call(email, **options)
|
|
19
|
+
Validation.from_api_response(response)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
|
|
5
|
+
module Trueform
|
|
6
|
+
module Transport
|
|
7
|
+
class NetHTTP
|
|
8
|
+
def call(method:, uri:, headers:, body:, timeout:)
|
|
9
|
+
request = request_class(method).new(uri)
|
|
10
|
+
headers.each { |name, value| request[name] = value }
|
|
11
|
+
request.body = body
|
|
12
|
+
|
|
13
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
14
|
+
http.use_ssl = uri.scheme == "https"
|
|
15
|
+
http.open_timeout = timeout
|
|
16
|
+
http.read_timeout = timeout
|
|
17
|
+
http.write_timeout = timeout if http.respond_to?(:write_timeout=)
|
|
18
|
+
http.request(request)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def request_class(method)
|
|
24
|
+
return Net::HTTP::Post if method == :post
|
|
25
|
+
|
|
26
|
+
raise ArgumentError, "Unsupported HTTP method: #{method.inspect}"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Trueform
|
|
4
|
+
class Validation
|
|
5
|
+
BOOLEAN_FIELDS = %w[
|
|
6
|
+
is_valid_format
|
|
7
|
+
is_freemail
|
|
8
|
+
is_disposable
|
|
9
|
+
has_mx_records
|
|
10
|
+
is_deliverable
|
|
11
|
+
].freeze
|
|
12
|
+
|
|
13
|
+
attr_reader :email, :did_you_mean
|
|
14
|
+
|
|
15
|
+
def self.from_api_response(value)
|
|
16
|
+
valid = value.is_a?(Hash) &&
|
|
17
|
+
value["email"].is_a?(String) &&
|
|
18
|
+
BOOLEAN_FIELDS.all? { |field| value[field] == true || value[field] == false } &&
|
|
19
|
+
(value["did_you_mean"].nil? || value["did_you_mean"].is_a?(String))
|
|
20
|
+
|
|
21
|
+
unless valid
|
|
22
|
+
raise APIError.new(
|
|
23
|
+
"The API returned an invalid validation response.",
|
|
24
|
+
code: "invalid_response"
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
new(
|
|
29
|
+
email: value["email"],
|
|
30
|
+
valid_format: value["is_valid_format"],
|
|
31
|
+
freemail: value["is_freemail"],
|
|
32
|
+
disposable: value["is_disposable"],
|
|
33
|
+
mx_records: value["has_mx_records"],
|
|
34
|
+
did_you_mean: value["did_you_mean"],
|
|
35
|
+
deliverable: value["is_deliverable"]
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def initialize(email:, valid_format:, freemail:, disposable:, mx_records:, did_you_mean:, deliverable:)
|
|
40
|
+
@email = email.dup.freeze
|
|
41
|
+
@valid_format = valid_format
|
|
42
|
+
@freemail = freemail
|
|
43
|
+
@disposable = disposable
|
|
44
|
+
@mx_records = mx_records
|
|
45
|
+
@did_you_mean = did_you_mean&.dup&.freeze
|
|
46
|
+
@deliverable = deliverable
|
|
47
|
+
freeze
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def valid_format?
|
|
51
|
+
@valid_format
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def freemail?
|
|
55
|
+
@freemail
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def disposable?
|
|
59
|
+
@disposable
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def mx_records?
|
|
63
|
+
@mx_records
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def deliverable?
|
|
67
|
+
@deliverable
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def to_h
|
|
71
|
+
{
|
|
72
|
+
email: @email,
|
|
73
|
+
is_valid_format: @valid_format,
|
|
74
|
+
is_freemail: @freemail,
|
|
75
|
+
is_disposable: @disposable,
|
|
76
|
+
has_mx_records: @mx_records,
|
|
77
|
+
did_you_mean: @did_you_mean,
|
|
78
|
+
is_deliverable: @deliverable
|
|
79
|
+
}
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def ==(other)
|
|
83
|
+
other.is_a?(Validation) && to_h == other.to_h
|
|
84
|
+
end
|
|
85
|
+
alias_method :eql?, :==
|
|
86
|
+
|
|
87
|
+
def hash
|
|
88
|
+
to_h.hash
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
data/lib/trueform.rb
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "trueform/version"
|
|
4
|
+
require_relative "trueform/error"
|
|
5
|
+
require_relative "trueform/validation"
|
|
6
|
+
require_relative "trueform/resources/validations"
|
|
7
|
+
require_relative "trueform/transport/net_http"
|
|
8
|
+
require_relative "trueform/client"
|
metadata
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: trueform
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Trueform
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: A dependency-free Ruby client for validating email addresses with Trueform.
|
|
13
|
+
executables: []
|
|
14
|
+
extensions: []
|
|
15
|
+
extra_rdoc_files: []
|
|
16
|
+
files:
|
|
17
|
+
- CHANGELOG.md
|
|
18
|
+
- LICENSE
|
|
19
|
+
- README.md
|
|
20
|
+
- lib/trueform.rb
|
|
21
|
+
- lib/trueform/client.rb
|
|
22
|
+
- lib/trueform/error.rb
|
|
23
|
+
- lib/trueform/resources/validations.rb
|
|
24
|
+
- lib/trueform/transport/net_http.rb
|
|
25
|
+
- lib/trueform/validation.rb
|
|
26
|
+
- lib/trueform/version.rb
|
|
27
|
+
homepage: https://trueform.cloud/docs/ruby/
|
|
28
|
+
licenses:
|
|
29
|
+
- MIT
|
|
30
|
+
metadata:
|
|
31
|
+
allowed_push_host: https://rubygems.org
|
|
32
|
+
bug_tracker_uri: https://github.com/True-Form-Cloud/trueform-ruby-sdk/issues
|
|
33
|
+
changelog_uri: https://github.com/True-Form-Cloud/trueform-ruby-sdk/blob/main/CHANGELOG.md
|
|
34
|
+
documentation_uri: https://trueform.cloud/docs/ruby/
|
|
35
|
+
homepage_uri: https://trueform.cloud/docs/ruby/
|
|
36
|
+
rubygems_mfa_required: 'true'
|
|
37
|
+
source_code_uri: https://github.com/True-Form-Cloud/trueform-ruby-sdk
|
|
38
|
+
rdoc_options: []
|
|
39
|
+
require_paths:
|
|
40
|
+
- lib
|
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
42
|
+
requirements:
|
|
43
|
+
- - ">="
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '3.1'
|
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
47
|
+
requirements:
|
|
48
|
+
- - ">="
|
|
49
|
+
- !ruby/object:Gem::Version
|
|
50
|
+
version: '0'
|
|
51
|
+
requirements: []
|
|
52
|
+
rubygems_version: 4.0.16
|
|
53
|
+
specification_version: 4
|
|
54
|
+
summary: Official Ruby SDK for the Trueform email validation API
|
|
55
|
+
test_files: []
|