neverbounce-api 1.0.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/.codeclimate.yml +8 -0
- data/.gitignore +21 -0
- data/.rspec +4 -0
- data/.rubocop.yml +1161 -0
- data/.travis.yml +27 -0
- data/.yardopts +2 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +48 -0
- data/LICENSE +9 -0
- data/README.md +235 -0
- data/lib/never_bounce/api/client.rb +259 -0
- data/lib/never_bounce/api/error.rb +21 -0
- data/lib/never_bounce/api/feature/basic_initialize.rb +20 -0
- data/lib/never_bounce/api/feature/eigencache.rb +48 -0
- data/lib/never_bounce/api/feature/igetset.rb +41 -0
- data/lib/never_bounce/api/feature/oattrs.rb +100 -0
- data/lib/never_bounce/api/feature/require_attr.rb +27 -0
- data/lib/never_bounce/api/request/account_info.rb +29 -0
- data/lib/never_bounce/api/request/base.rb +102 -0
- data/lib/never_bounce/api/request/jobs_create.rb +90 -0
- data/lib/never_bounce/api/request/jobs_delete.rb +34 -0
- data/lib/never_bounce/api/request/jobs_download.rb +34 -0
- data/lib/never_bounce/api/request/jobs_parse.rb +55 -0
- data/lib/never_bounce/api/request/jobs_results.rb +53 -0
- data/lib/never_bounce/api/request/jobs_search.rb +57 -0
- data/lib/never_bounce/api/request/jobs_start.rb +47 -0
- data/lib/never_bounce/api/request/jobs_status.rb +37 -0
- data/lib/never_bounce/api/request/single_check.rb +67 -0
- data/lib/never_bounce/api/response/account_info.rb +39 -0
- data/lib/never_bounce/api/response/account_info/job_counts.rb +26 -0
- data/lib/never_bounce/api/response/address_info.rb +43 -0
- data/lib/never_bounce/api/response/base.rb +15 -0
- data/lib/never_bounce/api/response/container.rb +126 -0
- data/lib/never_bounce/api/response/credits_info/base.rb +30 -0
- data/lib/never_bounce/api/response/credits_info/monthly.rb +16 -0
- data/lib/never_bounce/api/response/credits_info/paid.rb +20 -0
- data/lib/never_bounce/api/response/error_message.rb +17 -0
- data/lib/never_bounce/api/response/feature/job_status_fields.rb +68 -0
- data/lib/never_bounce/api/response/feature/job_status_fields/total.rb +46 -0
- data/lib/never_bounce/api/response/jobs_create.rb +10 -0
- data/lib/never_bounce/api/response/jobs_delete.rb +8 -0
- data/lib/never_bounce/api/response/jobs_download.rb +19 -0
- data/lib/never_bounce/api/response/jobs_parse.rb +10 -0
- data/lib/never_bounce/api/response/jobs_results.rb +34 -0
- data/lib/never_bounce/api/response/jobs_results/item.rb +65 -0
- data/lib/never_bounce/api/response/jobs_results/query.rb +20 -0
- data/lib/never_bounce/api/response/jobs_search.rb +33 -0
- data/lib/never_bounce/api/response/jobs_search/query.rb +16 -0
- data/lib/never_bounce/api/response/jobs_search/result.rb +13 -0
- data/lib/never_bounce/api/response/jobs_start.rb +10 -0
- data/lib/never_bounce/api/response/jobs_status.rb +11 -0
- data/lib/never_bounce/api/response/message.rb +32 -0
- data/lib/never_bounce/api/response/single_check.rb +68 -0
- data/lib/never_bounce/api/response/status_message.rb +17 -0
- data/lib/never_bounce/api/response/success_message.rb +12 -0
- data/lib/never_bounce/api/session.rb +141 -0
- data/lib/never_bounce/api/version.rb +4 -0
- data/lib/neverbounce-api.rb +4 -0
- data/lib/neverbounce.rb +3 -0
- data/neverbounce-api.gemspec +20 -0
- data/spec/lib/never_bounce/api/client_spec.rb +199 -0
- data/spec/lib/never_bounce/api/feature/basic_initialize_spec.rb +25 -0
- data/spec/lib/never_bounce/api/feature/eigencache_spec.rb +28 -0
- data/spec/lib/never_bounce/api/feature/igetset_spec.rb +45 -0
- data/spec/lib/never_bounce/api/feature/oattrs_spec.rb +72 -0
- data/spec/lib/never_bounce/api/feature/require_attr_spec.rb +25 -0
- data/spec/lib/never_bounce/api/request/account_info_spec.rb +29 -0
- data/spec/lib/never_bounce/api/request/base_spec.rb +6 -0
- data/spec/lib/never_bounce/api/request/jobs_create_spec.rb +89 -0
- data/spec/lib/never_bounce/api/request/jobs_delete_spec.rb +31 -0
- data/spec/lib/never_bounce/api/request/jobs_download_spec.rb +31 -0
- data/spec/lib/never_bounce/api/request/jobs_parse_spec.rb +44 -0
- data/spec/lib/never_bounce/api/request/jobs_results_spec.rb +42 -0
- data/spec/lib/never_bounce/api/request/jobs_search_spec.rb +40 -0
- data/spec/lib/never_bounce/api/request/jobs_start_spec.rb +44 -0
- data/spec/lib/never_bounce/api/request/jobs_status_spec.rb +31 -0
- data/spec/lib/never_bounce/api/request/single_check_spec.rb +44 -0
- data/spec/lib/never_bounce/api/response/account_info/job_counts_spec.rb +7 -0
- data/spec/lib/never_bounce/api/response/account_info_spec.rb +9 -0
- data/spec/lib/never_bounce/api/response/address_info_spec.rb +7 -0
- data/spec/lib/never_bounce/api/response/base_spec.rb +6 -0
- data/spec/lib/never_bounce/api/response/container_spec.rb +142 -0
- data/spec/lib/never_bounce/api/response/credits_info/base_spec.rb +31 -0
- data/spec/lib/never_bounce/api/response/credits_info/monthly_spec.rb +11 -0
- data/spec/lib/never_bounce/api/response/credits_info/paid_spec.rb +11 -0
- data/spec/lib/never_bounce/api/response/feature/job_status_fields/total_spec.rb +7 -0
- data/spec/lib/never_bounce/api/response/feature/job_status_fields_spec.rb +42 -0
- data/spec/lib/never_bounce/api/response/jobs_create_spec.rb +7 -0
- data/spec/lib/never_bounce/api/response/jobs_delete_spec.rb +7 -0
- data/spec/lib/never_bounce/api/response/jobs_download_spec.rb +7 -0
- data/spec/lib/never_bounce/api/response/jobs_parse_spec.rb +7 -0
- data/spec/lib/never_bounce/api/response/jobs_results/jobs_results_item_spec.rb +7 -0
- data/spec/lib/never_bounce/api/response/jobs_results/jobs_results_query_spec.rb +7 -0
- data/spec/lib/never_bounce/api/response/jobs_results_spec.rb +7 -0
- data/spec/lib/never_bounce/api/response/jobs_search/jobs_search_query_spec.rb +7 -0
- data/spec/lib/never_bounce/api/response/jobs_search/jobs_search_result_spec.rb +7 -0
- data/spec/lib/never_bounce/api/response/jobs_search_spec.rb +7 -0
- data/spec/lib/never_bounce/api/response/jobs_start_spec.rb +7 -0
- data/spec/lib/never_bounce/api/response/jobs_status_spec.rb +7 -0
- data/spec/lib/never_bounce/api/response/single_check_spec.rb +7 -0
- data/spec/lib/never_bounce/api/response/spec_helper.rb +8 -0
- data/spec/lib/never_bounce/api/session_spec.rb +140 -0
- data/spec/lib/never_bounce/api_spec.rb +8 -0
- data/spec/spec_helper.rb +49 -0
- data/spec/spec_support/include_dir_context.rb +22 -0
- data/spec/spec_support/simplecov.rb +18 -0
- metadata +210 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
module NeverBounce; module API
|
|
3
|
+
# Base class for all errors.
|
|
4
|
+
# @abstract
|
|
5
|
+
class Error < StandardError; end
|
|
6
|
+
|
|
7
|
+
# Incorrect attribute usage.
|
|
8
|
+
class AttributeError < Error; end
|
|
9
|
+
|
|
10
|
+
# Data format errors happening in our land.
|
|
11
|
+
class FormatError < Error; end
|
|
12
|
+
|
|
13
|
+
# Something went wrong with the request.
|
|
14
|
+
class RequestError < Error; end
|
|
15
|
+
end; end
|
|
16
|
+
|
|
17
|
+
#
|
|
18
|
+
# Implementation notes:
|
|
19
|
+
#
|
|
20
|
+
# * None of these exceptions should be suppressed in end-user script.
|
|
21
|
+
# Either they must be handled or they should crash the end-user script with a full backtrace.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
module NeverBounce; module API; module Feature
|
|
3
|
+
# Provide the basic method <tt>#initialize</tt> to the owner class.
|
|
4
|
+
# @see InstanceMethods#initialize
|
|
5
|
+
module BasicInitialize
|
|
6
|
+
# @param owner [Class]
|
|
7
|
+
# @return [nil]
|
|
8
|
+
def self.load(owner)
|
|
9
|
+
return if owner < InstanceMethods
|
|
10
|
+
owner.send(:include, InstanceMethods)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module InstanceMethods
|
|
14
|
+
# See source for details.
|
|
15
|
+
def initialize(attrs = {})
|
|
16
|
+
attrs.each { |k, v| public_send("#{k}=", v) }
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end; end; end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
|
|
2
|
+
module NeverBounce; module API; module Feature
|
|
3
|
+
# Eigenclass (singleton class)-based cache which allows to handle "hidden" instance variables.
|
|
4
|
+
# @see InstanceMethods#_cache
|
|
5
|
+
module Eigencache
|
|
6
|
+
# @param owner [Class]
|
|
7
|
+
# @return [nil]
|
|
8
|
+
def self.load(owner)
|
|
9
|
+
return if owner < InstanceMethods
|
|
10
|
+
owner.send(:include, InstanceMethods)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module InstanceMethods
|
|
14
|
+
# Hidden cache.
|
|
15
|
+
#
|
|
16
|
+
# def body
|
|
17
|
+
# _cache[:body] ||= File.read("my-bulky-body.csv")
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
# def body=(v)
|
|
21
|
+
# _cache[:body] = v
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
24
|
+
# @return [Hash]
|
|
25
|
+
def _cache
|
|
26
|
+
if eigen.instance_variable_defined?(k = :@cache)
|
|
27
|
+
eigen.instance_variable_get(k)
|
|
28
|
+
else
|
|
29
|
+
eigen.instance_variable_set(k, {})
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
#---------------------------------------
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
# Object's eigenclass (singleton class).
|
|
37
|
+
# @return [Class]
|
|
38
|
+
def eigen
|
|
39
|
+
class << self; self; end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end; end; end
|
|
44
|
+
|
|
45
|
+
#
|
|
46
|
+
# Implementation notes:
|
|
47
|
+
#
|
|
48
|
+
# * As of Ruby 2.1 `Object#singleton_class` is introduced. We use our own compatible implementation, `eigen`.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
|
|
2
|
+
module NeverBounce; module API; module Feature
|
|
3
|
+
# @see InstanceMethods#igetset
|
|
4
|
+
module Igetset
|
|
5
|
+
# @param owner [Class]
|
|
6
|
+
# @return [nil]
|
|
7
|
+
def self.load(owner)
|
|
8
|
+
return if owner < InstanceMethods
|
|
9
|
+
owner.send(:include, InstanceMethods)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
module InstanceMethods
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
# Get/set an OTF instance variable of any type.
|
|
16
|
+
#
|
|
17
|
+
# Ruby's <tt>||=</tt> works nicely with object instances, but requires special bulky treatment for <tt>nil</tt> and <tt>false</tt>.
|
|
18
|
+
# For example, this will cause a hidden glitch since <tt>==</tt> can evaluate to <tt>false</tt>:
|
|
19
|
+
#
|
|
20
|
+
# @is_verbose ||= begin
|
|
21
|
+
# # This clause will be evaluated *every time* if its value is `false`.
|
|
22
|
+
# ENV["VERBOSE"] == "y"
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
25
|
+
# There's a number of solutions to this problem, all of which involve calling <tt>instance_variable_*</tt> a few times per attribute accessor.
|
|
26
|
+
#
|
|
27
|
+
# <tt>igetset</tt> does this job for you. All you have to do is specify a block to compute the value.
|
|
28
|
+
#
|
|
29
|
+
# igetset(:is_verbose) { ENV["VERBOSE"] == "y" }
|
|
30
|
+
#
|
|
31
|
+
# See source for details.
|
|
32
|
+
def igetset(name, &compute)
|
|
33
|
+
if instance_variable_defined?(k = "@#{name}")
|
|
34
|
+
instance_variable_get(k)
|
|
35
|
+
else
|
|
36
|
+
instance_variable_set(k, compute.call)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end; end; end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
|
|
2
|
+
module NeverBounce; module API; module Feature
|
|
3
|
+
# Declare and manage on-the-fly (OTF) attributes of the class, codenamed "oattrs".
|
|
4
|
+
# @see ClassMethods#oattr
|
|
5
|
+
# @see ClassMethods#oattrs
|
|
6
|
+
# @see InstanceMethods#touch
|
|
7
|
+
module Oattrs
|
|
8
|
+
# @return [nil]
|
|
9
|
+
def self.load(owner)
|
|
10
|
+
return if owner < InstanceMethods
|
|
11
|
+
owner.extend(ClassMethods)
|
|
12
|
+
owner.send(:include, InstanceMethods)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module ClassMethods
|
|
16
|
+
# Return oattrs declared so far, recurse all superclasses.
|
|
17
|
+
#
|
|
18
|
+
# oattrs # => [:first_name, :last_name]
|
|
19
|
+
#
|
|
20
|
+
# @!attribute oattrs
|
|
21
|
+
# @return [Array]
|
|
22
|
+
def oattrs
|
|
23
|
+
@attrs ||= if superclass.respond_to?(m = :oattrs)
|
|
24
|
+
superclass.send(m).dup
|
|
25
|
+
else
|
|
26
|
+
[]
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def oattrs=(ar)
|
|
31
|
+
@oattrs = ar
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Declare an OTF attribute.
|
|
35
|
+
#
|
|
36
|
+
# class Klass
|
|
37
|
+
# oattr :first_name, :writer
|
|
38
|
+
# oattr :goods, :custom
|
|
39
|
+
#
|
|
40
|
+
# def first_name
|
|
41
|
+
# @first_name ||= ENV["FIRST_NAME"]
|
|
42
|
+
# end
|
|
43
|
+
#
|
|
44
|
+
# def goods
|
|
45
|
+
# @goods ||= ...
|
|
46
|
+
#
|
|
47
|
+
# def goods=(ar)
|
|
48
|
+
# @goods = ar
|
|
49
|
+
# ...
|
|
50
|
+
#
|
|
51
|
+
# @return [Symbol] <tt>name</tt>.
|
|
52
|
+
# @see InstanceMethods#touch
|
|
53
|
+
def oattr(name, type)
|
|
54
|
+
case type
|
|
55
|
+
when :custom
|
|
56
|
+
# Do nothing, just register attr below.
|
|
57
|
+
when :writer
|
|
58
|
+
attr_writer name
|
|
59
|
+
else
|
|
60
|
+
raise ArgumentError, "Unknown type: #{type.inspect}"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Register and return.
|
|
64
|
+
name.tap { oattrs << name}
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
module InstanceMethods
|
|
69
|
+
# Load all oattrs by "touching" them.
|
|
70
|
+
#
|
|
71
|
+
# irb> resp = client.jobs_delete(job_id: 353701)
|
|
72
|
+
# => #<NeverBounce::API::Response::ErrorMessage:0x0056245978aec8>
|
|
73
|
+
# irb> resp.touch
|
|
74
|
+
# => #<NeverBounce::API::Response::ErrorMessage:0x0056245978aec8 @message="Invalid job ID 353701", @execution_time=15, @status="general_failure">
|
|
75
|
+
#
|
|
76
|
+
# @return [self]
|
|
77
|
+
def touch
|
|
78
|
+
self.class.oattrs.each do |name|
|
|
79
|
+
v = public_send(name)
|
|
80
|
+
|
|
81
|
+
# Touch recursively. Support simple collections.
|
|
82
|
+
if v.respond_to? :touch
|
|
83
|
+
v.touch
|
|
84
|
+
elsif v.is_a? Array
|
|
85
|
+
v.each { |r| r.touch if r.respond_to? :touch }
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
self
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end; end; end
|
|
94
|
+
|
|
95
|
+
#
|
|
96
|
+
# Implementation notes:
|
|
97
|
+
#
|
|
98
|
+
# * Originally I've used `attr` and `attrs` as method names.
|
|
99
|
+
# Sadly enough, YARD choked on `attr ...` with no reasonable way to work around it and tell it to ignore these statements.
|
|
100
|
+
# That led me to the conclusion that `attr` acts more like a language construct, so I'd rather not override it, but make my own.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
require "never_bounce/api/error"
|
|
3
|
+
|
|
4
|
+
module NeverBounce; module API; module Feature
|
|
5
|
+
# Provide attribute validation method(s) to the owner class.
|
|
6
|
+
# @see InstanceMethods#initialize
|
|
7
|
+
module RequireAttr
|
|
8
|
+
# @param owner [Class]
|
|
9
|
+
# @return [nil]
|
|
10
|
+
def self.load(owner)
|
|
11
|
+
return if owner < InstanceMethods
|
|
12
|
+
owner.send(:include, InstanceMethods)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module InstanceMethods
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
# Require attribute to be set. Return attribute value.
|
|
19
|
+
# @return [mixed]
|
|
20
|
+
def require_attr(name)
|
|
21
|
+
send(name).tap do |_|
|
|
22
|
+
raise AttributeError, "Attribute must be set: #{name}" if _.nil?
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end; end; end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
|
|
2
|
+
require "never_bounce/api/response/account_info"
|
|
3
|
+
|
|
4
|
+
require_relative "base"
|
|
5
|
+
|
|
6
|
+
module NeverBounce; module API; module Request
|
|
7
|
+
class AccountInfo < Base
|
|
8
|
+
# @return [Symbol]
|
|
9
|
+
def self.http_method
|
|
10
|
+
:get
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @return [String]
|
|
14
|
+
def self.path
|
|
15
|
+
"account/info"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @return [Response::AccountInfo]
|
|
19
|
+
def self.response_klass
|
|
20
|
+
Response::AccountInfo
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def to_h
|
|
24
|
+
{
|
|
25
|
+
key: require_attr(:api_key),
|
|
26
|
+
}
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end; end; end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
|
|
2
|
+
require "never_bounce/api/feature/basic_initialize"
|
|
3
|
+
require "never_bounce/api/feature/require_attr"
|
|
4
|
+
|
|
5
|
+
module NeverBounce; module API; module Request
|
|
6
|
+
# @abstract
|
|
7
|
+
# @see API::Feature::BasicInitialize
|
|
8
|
+
class Base
|
|
9
|
+
API::Feature::BasicInitialize.load(self)
|
|
10
|
+
API::Feature::RequireAttr.load(self)
|
|
11
|
+
|
|
12
|
+
# User's API key.
|
|
13
|
+
# @return [String]
|
|
14
|
+
attr_accessor :api_key
|
|
15
|
+
attr_writer :api_url, :headers, :user_agent
|
|
16
|
+
|
|
17
|
+
# Custom API URL. Default is <tt>https://api.neverbounce.com/v4</tt>.
|
|
18
|
+
# @return [String]
|
|
19
|
+
def api_url
|
|
20
|
+
@api_url ||= "https://api.neverbounce.com/v4"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @!attribute headers
|
|
24
|
+
# @return [Array]
|
|
25
|
+
def headers
|
|
26
|
+
{
|
|
27
|
+
"Content-Type" => "application/json",
|
|
28
|
+
"User-Agent" => user_agent,
|
|
29
|
+
}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# <tt>:get</tt>, <tt>:post</tt> or whatever.
|
|
33
|
+
# @abstract
|
|
34
|
+
# @return [Symbol]
|
|
35
|
+
# @return [String]
|
|
36
|
+
def self.http_method
|
|
37
|
+
raise NotImplementedError, "Redefine `self.http_method` in your class: #{self}"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Request path on server, e.g. <tt>"jobs/parse"</tt>.
|
|
41
|
+
# @abstract
|
|
42
|
+
# @return [String]
|
|
43
|
+
def self.path
|
|
44
|
+
raise NotImplementedError, "Redefine `self.path` in your class: #{self}"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# @abstract
|
|
48
|
+
# @return [Class]
|
|
49
|
+
def self.response_klass
|
|
50
|
+
raise NotImplementedError, "Redefine `self.response_klass` in your class: #{self}"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Build arguments for cURL OS command.
|
|
54
|
+
# @return [Array]
|
|
55
|
+
def to_curl
|
|
56
|
+
# NOTE: I consider we should use long options to avoid ambiguity of ones like `-u` etc.
|
|
57
|
+
@curl ||= begin
|
|
58
|
+
ar = [
|
|
59
|
+
"--request", self.class.http_method.to_s.upcase,
|
|
60
|
+
"--url", "#{api_url}/#{self.class.path}",
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
ar += headers.reject { |k,| k == "User-Agent" }.flat_map do |k, v|
|
|
64
|
+
["--header", "#{k}: #{v}"]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
ar += ["--data-binary", to_h.to_json]
|
|
68
|
+
|
|
69
|
+
ar
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Build a <tt>Hash</tt> representation of request data.
|
|
74
|
+
# @abstract
|
|
75
|
+
# @return [Hash]
|
|
76
|
+
def to_h
|
|
77
|
+
raise NotImplementedError, "Redefine `to_h` in your class: #{self.class}"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Build argumentsfor <tt>Httparty</tt> invocation.
|
|
81
|
+
# @return [Array]
|
|
82
|
+
def to_httparty
|
|
83
|
+
[
|
|
84
|
+
self.class.http_method, # E.g. `:get`.
|
|
85
|
+
"#{api_url}/#{self.class.path}",
|
|
86
|
+
{
|
|
87
|
+
body: to_h.to_json,
|
|
88
|
+
headers: headers,
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# @!attribute user_agent
|
|
94
|
+
# @return [String]
|
|
95
|
+
def user_agent
|
|
96
|
+
@user_agent ||= [
|
|
97
|
+
"NeverBounceApi-Ruby/#{API::VERSION} (#{RUBY_PLATFORM})",
|
|
98
|
+
"Ruby/#{RUBY_VERSION} (p #{RUBY_PATCHLEVEL}; rev #{RUBY_REVISION})",
|
|
99
|
+
].join(" ")
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end; end; end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
|
|
2
|
+
require_relative "base"
|
|
3
|
+
|
|
4
|
+
module NeverBounce; module API; module Request
|
|
5
|
+
class JobsCreate < Base
|
|
6
|
+
# @return [Boolean]
|
|
7
|
+
attr_accessor :auto_parse
|
|
8
|
+
|
|
9
|
+
# @return [Boolean]
|
|
10
|
+
attr_accessor :auto_start
|
|
11
|
+
|
|
12
|
+
# @return [String]
|
|
13
|
+
attr_accessor :filename
|
|
14
|
+
|
|
15
|
+
# Input specification.
|
|
16
|
+
# @return [String] URL if <tt>input_location</tt> is <tt>"remote".
|
|
17
|
+
# @return [Array<Array<email, name>>] Structure if <tt>input_location</tt> is "supplied".
|
|
18
|
+
attr_accessor :input
|
|
19
|
+
|
|
20
|
+
# @return [String]
|
|
21
|
+
attr_accessor :input_location
|
|
22
|
+
|
|
23
|
+
# @return [Boolean]
|
|
24
|
+
attr_accessor :run_sample
|
|
25
|
+
|
|
26
|
+
# @return [Symbol]
|
|
27
|
+
def self.http_method
|
|
28
|
+
:post
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @return [String]
|
|
32
|
+
def self.path
|
|
33
|
+
"jobs/create"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @return [Response::JobsCreate]
|
|
37
|
+
def self.response_klass
|
|
38
|
+
Response::JobsCreate
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Return a ready-to-merge mode attributes hash.
|
|
42
|
+
# @return [Hash]
|
|
43
|
+
def mode_h
|
|
44
|
+
@mode_h ||= {}.tap do |_|
|
|
45
|
+
unless (v = auto_start).nil?
|
|
46
|
+
_[:auto_start] = v
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
unless (v = auto_parse).nil?
|
|
50
|
+
_[:auto_parse] = v
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
unless (v = run_sample).nil?
|
|
54
|
+
_[:run_sample] = v
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @return [Hash]
|
|
60
|
+
def to_h
|
|
61
|
+
input = require_attr(:input)
|
|
62
|
+
input_location = require_attr(:input_location)
|
|
63
|
+
|
|
64
|
+
# Validate `input_location` and `input`.
|
|
65
|
+
|
|
66
|
+
if not ["remote_url", "supplied"].include? input_location
|
|
67
|
+
raise AttributeError, "Unknown `input_location`: #{input_location.inspect}"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
if input_location == "supplied"
|
|
71
|
+
raise AttributeError, "Invalid `input` for `input_location` == #{input_location.inspect}: #{input.inspect}" if not input.is_a? Array
|
|
72
|
+
|
|
73
|
+
# Skim through elements of `input`, raise if invalid structure detected, with details.
|
|
74
|
+
input.each do |elem|
|
|
75
|
+
em = [AttributeError, "Invalid `input` element: #{elem.inspect}"]
|
|
76
|
+
raise(*em) unless elem.is_a? Array
|
|
77
|
+
raise(*em) unless elem.map(&:class) == [String, String]
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Result.
|
|
82
|
+
{
|
|
83
|
+
input: input,
|
|
84
|
+
input_location: input_location,
|
|
85
|
+
filename: require_attr(:filename),
|
|
86
|
+
key: require_attr(:api_key),
|
|
87
|
+
}.merge(mode_h)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end; end; end
|