neverbounce-cli 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +8 -0
  3. data/.gitignore +21 -0
  4. data/.rspec +4 -0
  5. data/.rubocop.yml +1161 -0
  6. data/.travis.yml +27 -0
  7. data/.yardopts +2 -0
  8. data/Gemfile +19 -0
  9. data/Gemfile.lock +60 -0
  10. data/LICENSE +9 -0
  11. data/README.md +138 -0
  12. data/exe/nb-account-info +5 -0
  13. data/exe/nb-jobs-create +5 -0
  14. data/exe/nb-jobs-delete +5 -0
  15. data/exe/nb-jobs-download +5 -0
  16. data/exe/nb-jobs-parse +5 -0
  17. data/exe/nb-jobs-results +5 -0
  18. data/exe/nb-jobs-search +5 -0
  19. data/exe/nb-jobs-start +5 -0
  20. data/exe/nb-jobs-status +5 -0
  21. data/exe/nb-single-check +5 -0
  22. data/lib/never_bounce/cli/feature/basic_initialize.rb +20 -0
  23. data/lib/never_bounce/cli/feature/eigencache.rb +47 -0
  24. data/lib/never_bounce/cli/feature/envars/examples_mapper.rb +38 -0
  25. data/lib/never_bounce/cli/feature/envars/item.rb +41 -0
  26. data/lib/never_bounce/cli/feature/envars.rb +82 -0
  27. data/lib/never_bounce/cli/feature/igetset.rb +41 -0
  28. data/lib/never_bounce/cli/feature/require_attr.rb +25 -0
  29. data/lib/never_bounce/cli/script/account_info.rb +85 -0
  30. data/lib/never_bounce/cli/script/base.rb +101 -0
  31. data/lib/never_bounce/cli/script/error.rb +16 -0
  32. data/lib/never_bounce/cli/script/feature/requires_job_id.rb +28 -0
  33. data/lib/never_bounce/cli/script/feature/uses_pagination.rb +45 -0
  34. data/lib/never_bounce/cli/script/jobs_create/supplied_input_parser.rb +48 -0
  35. data/lib/never_bounce/cli/script/jobs_create.rb +157 -0
  36. data/lib/never_bounce/cli/script/jobs_delete.rb +55 -0
  37. data/lib/never_bounce/cli/script/jobs_download.rb +44 -0
  38. data/lib/never_bounce/cli/script/jobs_parse.rb +73 -0
  39. data/lib/never_bounce/cli/script/jobs_results.rb +105 -0
  40. data/lib/never_bounce/cli/script/jobs_search.rb +135 -0
  41. data/lib/never_bounce/cli/script/jobs_start.rb +73 -0
  42. data/lib/never_bounce/cli/script/jobs_status.rb +96 -0
  43. data/lib/never_bounce/cli/script/manifest.rb +22 -0
  44. data/lib/never_bounce/cli/script/meaningful.rb +233 -0
  45. data/lib/never_bounce/cli/script/request_maker.rb +169 -0
  46. data/lib/never_bounce/cli/script/single_check.rb +146 -0
  47. data/lib/never_bounce/cli/script/table.rb +43 -0
  48. data/lib/never_bounce/cli/user_config/file_content.rb +66 -0
  49. data/lib/never_bounce/cli/user_config.rb +51 -0
  50. data/lib/never_bounce/cli/version.rb +4 -0
  51. data/lib/neverbounce-cli.rb +3 -0
  52. data/neverbounce-cli.gemspec +24 -0
  53. data/spec/lib/never_bounce/cli/feature/basic_initialize_spec.rb +26 -0
  54. data/spec/lib/never_bounce/cli/feature/eigencache_spec.rb +28 -0
  55. data/spec/lib/never_bounce/cli/feature/envars/examples_mapper_spec.rb +26 -0
  56. data/spec/lib/never_bounce/cli/feature/envars/item_spec.rb +9 -0
  57. data/spec/lib/never_bounce/cli/feature/envars_spec.rb +55 -0
  58. data/spec/lib/never_bounce/cli/feature/igetset_spec.rb +45 -0
  59. data/spec/lib/never_bounce/cli/feature/require_attr_spec.rb +25 -0
  60. data/spec/lib/never_bounce/cli/script/account_info_spec.rb +65 -0
  61. data/spec/lib/never_bounce/cli/script/base_spec.rb +56 -0
  62. data/spec/lib/never_bounce/cli/script/feature/requires_job_id_spec.rb +17 -0
  63. data/spec/lib/never_bounce/cli/script/feature/uses_pagination_spec.rb +21 -0
  64. data/spec/lib/never_bounce/cli/script/jobs_create/supplied_input_parser_spec.rb +35 -0
  65. data/spec/lib/never_bounce/cli/script/jobs_create_spec.rb +118 -0
  66. data/spec/lib/never_bounce/cli/script/jobs_delete_spec.rb +33 -0
  67. data/spec/lib/never_bounce/cli/script/jobs_download_spec.rb +37 -0
  68. data/spec/lib/never_bounce/cli/script/jobs_parse_spec.rb +45 -0
  69. data/spec/lib/never_bounce/cli/script/jobs_results_spec.rb +40 -0
  70. data/spec/lib/never_bounce/cli/script/jobs_search_spec.rb +59 -0
  71. data/spec/lib/never_bounce/cli/script/jobs_start_spec.rb +45 -0
  72. data/spec/lib/never_bounce/cli/script/jobs_status_spec.rb +37 -0
  73. data/spec/lib/never_bounce/cli/script/manifest_spec.rb +6 -0
  74. data/spec/lib/never_bounce/cli/script/meaningful_spec.rb +93 -0
  75. data/spec/lib/never_bounce/cli/script/request_maker_spec.rb +67 -0
  76. data/spec/lib/never_bounce/cli/script/single_check_spec.rb +94 -0
  77. data/spec/lib/never_bounce/cli/script/spec_helper.rb +59 -0
  78. data/spec/lib/never_bounce/cli/script/table_spec.rb +6 -0
  79. data/spec/lib/never_bounce/cli/user_config/file_content_spec.rb +43 -0
  80. data/spec/lib/never_bounce/cli/user_config_spec.rb +12 -0
  81. data/spec/lib/never_bounce/cli_spec.rb +6 -0
  82. data/spec/spec_helper.rb +51 -0
  83. metadata +193 -0
@@ -0,0 +1,48 @@
1
+
2
+ require "never_bounce/cli/feature/basic_initialize"
3
+
4
+ require_relative "../jobs_create"
5
+
6
+ module NeverBounce; module CLI; module Script; class JobsCreate
7
+ # The parser for <tt>SUPPLIED_INPUT=</tt> environment variable.
8
+ # @see #process
9
+ # @see CLI::Feature::BasicInitialize
10
+ class SuppliedInputParser
11
+ CLI::Feature::BasicInitialize.load(self)
12
+
13
+ attr_writer :separator
14
+
15
+ # @return [Regexp]
16
+ def separator
17
+ @separator ||= /[;,\n]/
18
+ end
19
+
20
+ #---------------------------------------
21
+
22
+ # Process content, return parsed structure.
23
+ #
24
+ # NOTE: The parser doesn't validate e-mail addresses.
25
+ #
26
+ # process("alice@isp.com Alice Roberts;bob.smith@gmail.com Bob Smith")
27
+ # # => [["alice@isp.com", "Alice Roberts"], ["bob.smith@gmail.com", "Bob Smith"]]
28
+ #
29
+ # @return [Array<email, name>]
30
+ def process(content)
31
+ # NOTE: Keep it stage-procedural for easier debugging.
32
+ chunks = content.split(separator).map(&:strip).reject(&:empty?)
33
+
34
+ out = chunks.map do |chunk|
35
+ if (chunk =~ /^(.+?)\s+(.+)$/)
36
+ [$1, $2]
37
+ else
38
+ [chunk, ""]
39
+ end
40
+ end
41
+
42
+ out.empty? and raise ArgumentError, "Empty content"
43
+
44
+ out
45
+ end
46
+ alias_method :[], :process
47
+ end
48
+ end; end; end; end
@@ -0,0 +1,157 @@
1
+
2
+ require "neverbounce"
3
+
4
+ require_relative "request_maker"
5
+
6
+ module NeverBounce; module CLI; module Script
7
+ class JobsCreate < RequestMaker
8
+ require_relative "jobs_create/supplied_input_parser"
9
+
10
+ attr_writer :auto_parse, :auto_start, :filename, :input, :input_location, :now, :remote_input, :run_sample, :supplied_input, :supplied_input_array, :supplied_input_parser
11
+
12
+ envar "AUTO_PARSE", "Start parsing the job immediately after creation", ["y", "n"]
13
+ envar "FILENAME", "Original CSV filename", [{default: "YYYYMMDD-HHMMSS.csv"}, "My data.csv"]
14
+ envar "REMOTE_INPUT", "Remote URL with CSV of e-mails to verify", ["http://site.com/emails.csv"]
15
+ envar "SUPPLIED_INPUT", "List of e-mails to verify", ["alice@isp.com Alice Roberts;bob.smith@gmail.com Bob Smith"]
16
+ envar (k = "AUTO_START"), *SHARED_ENVARS[k]
17
+ envar (k = "RUN_SAMPLE"), *SHARED_ENVARS[k]
18
+
19
+ # @return [true]
20
+ # @return [false]
21
+ # @return [nil]
22
+ def auto_parse
23
+ igetset(:auto_parse) do
24
+ if env.has_key?(k = "AUTO_PARSE")
25
+ env_truthy?(k)
26
+ end
27
+ end
28
+ end
29
+
30
+ # @return [true]
31
+ # @return [false]
32
+ # @return [nil]
33
+ def auto_start
34
+ igetset(:auto_start) do
35
+ if env.has_key?(k = "AUTO_START")
36
+ env_truthy?(k)
37
+ end
38
+ end
39
+ end
40
+
41
+ def filename
42
+ igetset(:filename) { env["FILENAME"] || now.strftime("%Y%m%d-%H%M%S.csv") }
43
+ end
44
+
45
+ # @return [String] An URL if remote input.
46
+ # @return [Array] An array of e-mails if supplied input.
47
+ def input
48
+ input_location # Touch for sanity/completeness checks etc.
49
+ remote_input || supplied_input_array
50
+ end
51
+
52
+ # @return [String] <tt>"remote_url"</tt> or <tt>"supplied"</tt>
53
+ def input_location
54
+ @input_location ||= begin
55
+ # Sanity check.
56
+ raise UsageError, "`REMOTE_INPUT` and `SUPPLIED_INPUT` can't both be given" if remote_input? && supplied_input?
57
+
58
+ if remote_input?
59
+ "remote_url"
60
+ elsif supplied_input?
61
+ "supplied"
62
+ else
63
+ raise UsageError, "Input not given, use `REMOTE_INPUT=` or `SUPPLIED_INPUT=`"
64
+ end
65
+ end
66
+ end
67
+
68
+ def now
69
+ @now ||= Time.now
70
+ end
71
+
72
+ def remote_input
73
+ igetset(:remote_input) { env["REMOTE_INPUT"] }
74
+ end
75
+
76
+ def remote_input?
77
+ !!remote_input
78
+ end
79
+
80
+ # @return [true]
81
+ # @return [false]
82
+ # @return [nil]
83
+ def run_sample
84
+ igetset(:run_sample) do
85
+ if env.has_key?(k = "RUN_SAMPLE")
86
+ env_truthy?(k)
87
+ end
88
+ end
89
+ end
90
+
91
+ def supplied_input
92
+ igetset(:supplied_input) { env["SUPPLIED_INPUT"] }
93
+ end
94
+
95
+ def supplied_input?
96
+ !!supplied_input
97
+ end
98
+
99
+ def supplied_input_array
100
+ @supplied_input_array ||= require_attr(:supplied_input_parser)[require_attr(:supplied_input)]
101
+ end
102
+
103
+ def supplied_input_parser
104
+ @supplied_input_parser ||= SuppliedInputParser.new
105
+ end
106
+
107
+ # An <tt>API::Request::JobsCreate</tt>.
108
+ # @!attribute request
109
+ # @return [Object]
110
+ def request
111
+ @request ||= API::Request::JobsCreate.new({
112
+ api_key: api_key,
113
+ auto_parse: auto_parse,
114
+ auto_start: auto_start,
115
+ filename: filename,
116
+ input: input,
117
+ input_location: input_location,
118
+ run_sample: run_sample,
119
+ })
120
+ end
121
+
122
+ #--------------------------------------- Manifest
123
+
124
+ # @!attribute manifest
125
+ # @return [Manifest]
126
+ def manifest
127
+ @manifest ||= Manifest.new(
128
+ name: "nb-jobs-create",
129
+ function: "Create a job",
130
+ cmdline: "[options] [VAR1=value] [VAR2=value] ...",
131
+ )
132
+ end
133
+
134
+ #--------------------------------------- Main
135
+
136
+ # @return [Integer]
137
+ def slim_main
138
+ "Response".tap do |label|
139
+ headings = [
140
+ ["JobId", :job_id],
141
+
142
+ ["ExecTime", :execution_time, :right],
143
+ ]
144
+
145
+ table = Table.new(
146
+ headings: headings.map { |ar| ar[0] },
147
+ rows: [headings.map { |ar| get_table_value(response, ar) }],
148
+ ).align!(headings)
149
+
150
+ stdout.puts "\n#{label}:"
151
+ stdout.puts table
152
+ end
153
+
154
+ 0
155
+ end
156
+ end
157
+ end; end; end
@@ -0,0 +1,55 @@
1
+
2
+ require "neverbounce"
3
+
4
+ require "never_bounce/cli/script/feature/requires_job_id"
5
+
6
+ require_relative "request_maker"
7
+
8
+ module NeverBounce; module CLI; module Script
9
+ class JobsDelete < RequestMaker
10
+ Script::Feature::RequiresJobId.load(self)
11
+
12
+ # An <tt>API::Request::JobsDelete</tt>.
13
+ # @!attribute request
14
+ # @return [Object]
15
+ def request
16
+ @request ||= API::Request::JobsDelete.new({
17
+ api_key: api_key,
18
+ job_id: job_id,
19
+ })
20
+ end
21
+
22
+ #--------------------------------------- Manifest
23
+
24
+ # @!attribute manifest
25
+ # @return [Manifest]
26
+ def manifest
27
+ @manifest ||= Manifest.new(
28
+ name: "nb-jobs-delete",
29
+ function: "Delete a job",
30
+ cmdline: "[options] [VAR1=value] [VAR2=value] ...",
31
+ )
32
+ end
33
+
34
+ #--------------------------------------- Main
35
+
36
+ # @return [Integer]
37
+ def slim_main
38
+ "Response".tap do |label|
39
+ headings = [
40
+ ["ExecTime", :execution_time, :right],
41
+ ]
42
+
43
+ table = Table.new(
44
+ headings: headings.map { |ar| ar[0] },
45
+ rows: [headings.map { |ar| get_table_value(response, ar) }],
46
+ ).align!(headings)
47
+
48
+ stdout.puts "\n#{label}:"
49
+ stdout.puts table
50
+ end
51
+
52
+ 0
53
+ end
54
+ end
55
+ end; end; end
@@ -0,0 +1,44 @@
1
+
2
+ require "neverbounce"
3
+
4
+ require "never_bounce/cli/script/feature/requires_job_id"
5
+
6
+ require_relative "request_maker"
7
+
8
+ module NeverBounce; module CLI; module Script
9
+ class JobsDownload < RequestMaker
10
+ Script::Feature::RequiresJobId.load(self)
11
+
12
+ # An <tt>API::Request::JobsDownload</tt>.
13
+ # @!attribute request
14
+ # @return [Object]
15
+ def request
16
+ @request ||= API::Request::JobsDownload.new({
17
+ api_key: api_key,
18
+ job_id: job_id,
19
+ })
20
+ end
21
+
22
+ #--------------------------------------- Manifest
23
+
24
+ # @!attribute manifest
25
+ # @return [Manifest]
26
+ def manifest
27
+ @manifest ||= Manifest.new(
28
+ name: "nb-jobs-download",
29
+ function: "Download job results as CSV",
30
+ cmdline: "[options] [VAR1=value] [VAR2=value] ...",
31
+ )
32
+ end
33
+
34
+ #--------------------------------------- Main
35
+
36
+ # @return [Integer]
37
+ def slim_main
38
+ # Print CSV as is.
39
+ stdout.puts server_raw
40
+
41
+ 0
42
+ end
43
+ end
44
+ end; end; end
@@ -0,0 +1,73 @@
1
+
2
+ require "neverbounce"
3
+
4
+ require "never_bounce/cli/script/feature/requires_job_id"
5
+
6
+ require_relative "request_maker"
7
+
8
+ module NeverBounce; module CLI; module Script
9
+ class JobsParse < RequestMaker
10
+ Script::Feature::RequiresJobId.load(self)
11
+
12
+ attr_writer :auto_start
13
+
14
+ envar (k = "AUTO_START"), *SHARED_ENVARS[k]
15
+
16
+ # @return [true]
17
+ # @return [false]
18
+ # @return [nil]
19
+ def auto_start
20
+ igetset(:auto_start) do
21
+ if env.has_key?(k = "AUTO_START")
22
+ env_truthy?(k)
23
+ end
24
+ end
25
+ end
26
+
27
+ # An <tt>API::Request::JobsParse</tt>.
28
+ # @!attribute request
29
+ # @return [Object]
30
+ def request
31
+ @request ||= API::Request::JobsParse.new({
32
+ api_key: api_key,
33
+ auto_start: auto_start,
34
+ job_id: job_id,
35
+ })
36
+ end
37
+
38
+ #--------------------------------------- Manifest
39
+
40
+ # @!attribute manifest
41
+ # @return [Manifest]
42
+ def manifest
43
+ @manifest ||= Manifest.new(
44
+ name: "nb-jobs-parse",
45
+ function: "Issue a job parse command to the server",
46
+ cmdline: "[options] [VAR1=value] [VAR2=value] ...",
47
+ )
48
+ end
49
+
50
+ #--------------------------------------- Main
51
+
52
+ # @return [Integer]
53
+ def slim_main
54
+ "Response".tap do |label|
55
+ headings = [
56
+ ["QueueId", :queue_id],
57
+
58
+ ["ExecTime", :execution_time, :right],
59
+ ]
60
+
61
+ table = Table.new(
62
+ headings: headings.map { |ar| ar[0] },
63
+ rows: [headings.map { |ar| get_table_value(response, ar) }],
64
+ ).align!(headings)
65
+
66
+ stdout.puts "\n#{label}:"
67
+ stdout.puts table
68
+ end
69
+
70
+ 0
71
+ end
72
+ end
73
+ end; end; end
@@ -0,0 +1,105 @@
1
+
2
+ require "neverbounce"
3
+
4
+ require "never_bounce/cli/script/feature/requires_job_id"
5
+ require "never_bounce/cli/script/feature/uses_pagination"
6
+
7
+ require_relative "request_maker"
8
+
9
+ module NeverBounce; module CLI; module Script
10
+ class JobsResults < RequestMaker
11
+ Script::Feature::RequiresJobId.load(self)
12
+ Script::Feature::UsesPagination.load(self)
13
+
14
+ # An <tt>API::Request::JobsResults</tt>.
15
+ # @!attribute request
16
+ # @return [Object]
17
+ def request
18
+ @request ||= API::Request::JobsResults.new({
19
+ api_key: api_key,
20
+ job_id: job_id,
21
+ page: page,
22
+ per_page: per_page,
23
+ })
24
+ end
25
+
26
+ #--------------------------------------- Manifest
27
+
28
+ # @!attribute manifest
29
+ # @return [Manifest]
30
+ def manifest
31
+ @manifest ||= Manifest.new(
32
+ name: "nb-jobs-results",
33
+ function: "Get job execution results",
34
+ cmdline: "[options] [VAR1=value] [VAR2=value] ...",
35
+ )
36
+ end
37
+
38
+ #--------------------------------------- Main
39
+
40
+ # @return [Integer]
41
+ def slim_main
42
+ "Response".tap do |label|
43
+ headings = [
44
+ ["nPages", :total_pages, :right],
45
+ ["nResults", :total_results, :right],
46
+
47
+ ["ExecTime", :execution_time, :right],
48
+ ]
49
+
50
+ table = Table.new(
51
+ headings: headings.map { |ar| ar[0] },
52
+ rows: [headings.map { |ar| get_table_value(response, ar) }],
53
+ ).align!(headings)
54
+
55
+ stdout.puts "\n#{label}:"
56
+ stdout.puts table
57
+ end
58
+
59
+ "Query".tap do |label|
60
+ headings = [
61
+ ["JobId", :job_id, :right],
62
+ ["Page", :page, :right],
63
+ ["PerPage", :items_per_page, :right],
64
+ ]
65
+
66
+ table = Table.new(
67
+ headings: headings.map { |ar| ar[0] },
68
+ rows: [headings.map { |ar| get_table_value(response.query, ar) }],
69
+ ).align!(headings)
70
+
71
+ stdout.puts "\n#{label}:"
72
+ stdout.puts table
73
+ end
74
+
75
+ "Results".tap do |label|
76
+ headings = [
77
+ ["Email", :email],
78
+ ["Result", :result, :center],
79
+
80
+ [
81
+ "Flags",
82
+ ->(r) { r.flags.sort.join("\n") },
83
+ ],
84
+
85
+ ["SuggCorr", :suggested_correction],
86
+ ]
87
+
88
+ table = Table.new(
89
+ headings: headings.map { |ar| ar[0] },
90
+ rows: response.items.map do |r|
91
+ headings.map do |ar|
92
+ get_table_value(r, ar)
93
+ end
94
+ end,
95
+ ).align!(headings)
96
+
97
+ stdout.puts "\n#{label}:"
98
+ stdout.puts table
99
+ end
100
+
101
+
102
+ 0
103
+ end
104
+ end
105
+ end; end; end