command_line_boss 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/.rspec +3 -0
- data/.rubocop.yml +34 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +34 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/LICENSE.txt +21 -0
- data/README.md +340 -0
- data/Rakefile +90 -0
- data/examples/create_spreadsheet/.gitignore +21 -0
- data/examples/create_spreadsheet/.rspec +3 -0
- data/examples/create_spreadsheet/.rubocop.yml +34 -0
- data/examples/create_spreadsheet/Gemfile +16 -0
- data/examples/create_spreadsheet/README.md +314 -0
- data/examples/create_spreadsheet/Rakefile +50 -0
- data/examples/create_spreadsheet/create_spreadsheet.gemspec +39 -0
- data/examples/create_spreadsheet/exe/create-spreadsheet +28 -0
- data/examples/create_spreadsheet/lib/create_spreadsheet/command_line.rb +221 -0
- data/examples/create_spreadsheet/lib/create_spreadsheet.rb +8 -0
- data/examples/create_spreadsheet/spec/create_spreadsheet/command_line.feature +239 -0
- data/examples/create_spreadsheet/spec/create_spreadsheet/command_line_steps.rb +93 -0
- data/examples/create_spreadsheet/spec/spec_helper.rb +130 -0
- data/examples/readme_example/create-spreadsheet +64 -0
- data/lib/command_line_boss/help_option.rb +82 -0
- data/lib/command_line_boss/logger_options.rb +103 -0
- data/lib/command_line_boss/version.rb +6 -0
- data/lib/command_line_boss.rb +246 -0
- metadata +266 -0
@@ -0,0 +1,246 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
require 'command_line_boss/help_option'
|
7
|
+
require 'command_line_boss/logger_options'
|
8
|
+
require 'command_line_boss/version'
|
9
|
+
|
10
|
+
# Command line interface parser based on OptionsParser
|
11
|
+
#
|
12
|
+
# @api public
|
13
|
+
#
|
14
|
+
class CommandLineBoss
|
15
|
+
# Create a new command line parser
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
# parser = CommandLineParser.new
|
19
|
+
#
|
20
|
+
# @param program_name [String] the name of the program to report in the usage line
|
21
|
+
#
|
22
|
+
# The program name is used in the usage line when the --help option is given.
|
23
|
+
# This is given as an optional argument so that it can be overridden in tests.
|
24
|
+
#
|
25
|
+
def initialize(program_name: $PROGRAM_NAME)
|
26
|
+
@program_name = program_name
|
27
|
+
@parser = OptionParser.new.tap { |p| p.set_program_name(program_name) }
|
28
|
+
@error_messages = []
|
29
|
+
set_defaults if private_methods.include?(:set_defaults)
|
30
|
+
define_options
|
31
|
+
end
|
32
|
+
|
33
|
+
# Parse the command line arguments and return self
|
34
|
+
#
|
35
|
+
# The caller will have to check the {#failed?} to see if there were any errors.
|
36
|
+
#
|
37
|
+
# If there were errors, {#error_messages} will contain the error messages.
|
38
|
+
#
|
39
|
+
# @example
|
40
|
+
# parser = CommandLineParser.new.call(ARGV)
|
41
|
+
#
|
42
|
+
# @param args [Array<String>] the command line arguments
|
43
|
+
#
|
44
|
+
# @return [CommandLineParser] returns self
|
45
|
+
#
|
46
|
+
def parse(args)
|
47
|
+
@args = args.dup
|
48
|
+
parse_options
|
49
|
+
parse_arguments
|
50
|
+
validate if @error_messages.empty?
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
# Parse the command line arguments and return self
|
55
|
+
#
|
56
|
+
# If there were any errors parsing the command line arguments, this method
|
57
|
+
# will output the error messages to stderr and exit the program with a non-zero
|
58
|
+
# status code.
|
59
|
+
#
|
60
|
+
# @example
|
61
|
+
# parser = CommandLineParser.new.parse!(ARGV)
|
62
|
+
#
|
63
|
+
# @param args [Array<String>] the command line arguments
|
64
|
+
#
|
65
|
+
# @raise [SystemExit] if the command line arguments are invalid
|
66
|
+
#
|
67
|
+
# @return [CommandLineParser] returns self
|
68
|
+
#
|
69
|
+
def parse!(args)
|
70
|
+
parse(args)
|
71
|
+
|
72
|
+
if failed?
|
73
|
+
warn error_messages.join("\n")
|
74
|
+
exit 1
|
75
|
+
end
|
76
|
+
|
77
|
+
self
|
78
|
+
end
|
79
|
+
|
80
|
+
# The name of the program to report in the usage line
|
81
|
+
#
|
82
|
+
# The program name is used in the usage line when the --help option is given.
|
83
|
+
# This is given as an optional argument so that it can be overridden in tests.
|
84
|
+
#
|
85
|
+
# @example
|
86
|
+
# options.program_name #=> 'sync_paranoids_milestones'
|
87
|
+
#
|
88
|
+
# @return [String]
|
89
|
+
#
|
90
|
+
attr_reader :program_name
|
91
|
+
|
92
|
+
# The error messages generated by the validation methods
|
93
|
+
#
|
94
|
+
# @example
|
95
|
+
# options.error_messages #=> ["ERROR: The sheet 'Sheet1' was given more than once"]
|
96
|
+
#
|
97
|
+
# @return [Array<String>]
|
98
|
+
#
|
99
|
+
def error_messages = @error_messages.dup.freeze
|
100
|
+
|
101
|
+
# true if the parser encountered no errors
|
102
|
+
#
|
103
|
+
#
|
104
|
+
# @example
|
105
|
+
# options.succeeded? #=> true
|
106
|
+
#
|
107
|
+
# @return [Boolean]
|
108
|
+
#
|
109
|
+
def succeeded? = @error_messages.empty?
|
110
|
+
|
111
|
+
# true if the parser encountered errors
|
112
|
+
#
|
113
|
+
# @example
|
114
|
+
# options.failed? #=> false
|
115
|
+
#
|
116
|
+
# @return [Boolean]
|
117
|
+
#
|
118
|
+
def failed? = !succeeded?
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
# This is how you should add an error message to the error_messages array
|
123
|
+
#
|
124
|
+
# @example
|
125
|
+
# add_error_message("The sheet 'Sheet1' was given more than once")
|
126
|
+
# error_messages #=> ["ERROR: The sheet 'Sheet1' was given more than once"]
|
127
|
+
#
|
128
|
+
# @param message [String] the error message to add
|
129
|
+
#
|
130
|
+
# @return [void]
|
131
|
+
#
|
132
|
+
# @api private
|
133
|
+
#
|
134
|
+
def add_error_message(message)
|
135
|
+
@error_messages << "ERROR: #{message}"
|
136
|
+
end
|
137
|
+
|
138
|
+
# Ensure that any extra args are valid
|
139
|
+
#
|
140
|
+
# This method is expected to add a message to {add_error} if there are
|
141
|
+
# any unexpected arguments.
|
142
|
+
#
|
143
|
+
# For this command line, there should be no extra arguments.
|
144
|
+
#
|
145
|
+
# @return [void]
|
146
|
+
#
|
147
|
+
# @api private
|
148
|
+
#
|
149
|
+
def validate_remaining_args
|
150
|
+
return if args.empty?
|
151
|
+
|
152
|
+
add_error_message("Unexpected arguments: #{args.join(' ')}")
|
153
|
+
end
|
154
|
+
|
155
|
+
# The parse to use to parse the command line arguments
|
156
|
+
#
|
157
|
+
# @return [OptionParser]
|
158
|
+
#
|
159
|
+
# @api private
|
160
|
+
#
|
161
|
+
attr_reader :parser
|
162
|
+
|
163
|
+
# The command line args passed to the parser
|
164
|
+
#
|
165
|
+
# The parser will remove options and their arguments from this array
|
166
|
+
# as it parses them.
|
167
|
+
#
|
168
|
+
# After all options are parsed, this array will contain only the
|
169
|
+
# remaining arguments.
|
170
|
+
#
|
171
|
+
# @return [Array<String>]
|
172
|
+
#
|
173
|
+
# @api private
|
174
|
+
#
|
175
|
+
attr_reader :args
|
176
|
+
|
177
|
+
# Parse the command line arguments using the OptionParser
|
178
|
+
#
|
179
|
+
# The OptionParser will remove options and their arguments from the
|
180
|
+
# `args` array as it parses them. After all options are parsed, `args`
|
181
|
+
# will contain only the remaining arguments.
|
182
|
+
#
|
183
|
+
# @raise [SystemExit] if the command line arguments are invalid
|
184
|
+
#
|
185
|
+
# @return [void]
|
186
|
+
#
|
187
|
+
# @api private
|
188
|
+
#
|
189
|
+
def parse_options
|
190
|
+
parser.parse!(args)
|
191
|
+
rescue OptionParser::ParseError => e
|
192
|
+
add_error_message(e.message)
|
193
|
+
end
|
194
|
+
|
195
|
+
# Parse the arguments that remain after parsing options
|
196
|
+
#
|
197
|
+
# This method is expected to be overridden by subclasses to parse the
|
198
|
+
# remaining arguments. {args} will contain the remaining arguments. This
|
199
|
+
# method should remove any arguments it processes from {args}.
|
200
|
+
#
|
201
|
+
# @return [void]
|
202
|
+
#
|
203
|
+
# @api private
|
204
|
+
#
|
205
|
+
def parse_arguments; end
|
206
|
+
|
207
|
+
VALIDATION_METHOD_REGEXP = /^validate_(.+)$/
|
208
|
+
|
209
|
+
# Validate the command line options and remaining arguments
|
210
|
+
#
|
211
|
+
# Calls all validation methods defined by this class. Validation
|
212
|
+
# methods are private methods that start with `validate_`.
|
213
|
+
#
|
214
|
+
# If validation fails, a validation method is expected to output an error
|
215
|
+
# messages using `warn` and exit the program with a non-zero status code.
|
216
|
+
#
|
217
|
+
# @return [void]
|
218
|
+
#
|
219
|
+
# @api private
|
220
|
+
#
|
221
|
+
def validate
|
222
|
+
private_methods.select { |m| m.to_s.match?(VALIDATION_METHOD_REGEXP) }.each { |m| send(m) }
|
223
|
+
end
|
224
|
+
|
225
|
+
# Set the default values for the command line options
|
226
|
+
#
|
227
|
+
# @return [void]
|
228
|
+
#
|
229
|
+
# @api private
|
230
|
+
#
|
231
|
+
# def set_defaults; end
|
232
|
+
|
233
|
+
DEFINITION_METHOD_REGEXP = /^define_(.+)_option$/
|
234
|
+
|
235
|
+
# Define the command line options
|
236
|
+
#
|
237
|
+
# @return [void]
|
238
|
+
#
|
239
|
+
# @api private
|
240
|
+
#
|
241
|
+
def define_options
|
242
|
+
parser.separator 'Options:'
|
243
|
+
private_methods.select { |m| m.to_s.match?(DEFINITION_METHOD_REGEXP) }.each { |m| send(m) }
|
244
|
+
parser.separator ''
|
245
|
+
end
|
246
|
+
end
|
metadata
ADDED
@@ -0,0 +1,266 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: command_line_boss
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- James Couball
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-07-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler-audit
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.9'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.9'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: create_github_release
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.4'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.4'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: csv
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.3'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: fuubar
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.5'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.5'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '13.2'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '13.2'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.13'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.13'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.64'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.64'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: simplecov
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.22'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0.22'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: simplecov-lcov
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0.8'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0.8'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: turnip
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '4.4'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '4.4'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: redcarpet
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '3.6'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '3.6'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: yard
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - "~>"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0.9'
|
174
|
+
- - ">="
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: 0.9.28
|
177
|
+
type: :development
|
178
|
+
prerelease: false
|
179
|
+
version_requirements: !ruby/object:Gem::Requirement
|
180
|
+
requirements:
|
181
|
+
- - "~>"
|
182
|
+
- !ruby/object:Gem::Version
|
183
|
+
version: '0.9'
|
184
|
+
- - ">="
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: 0.9.28
|
187
|
+
- !ruby/object:Gem::Dependency
|
188
|
+
name: yardstick
|
189
|
+
requirement: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - "~>"
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '0.9'
|
194
|
+
type: :development
|
195
|
+
prerelease: false
|
196
|
+
version_requirements: !ruby/object:Gem::Requirement
|
197
|
+
requirements:
|
198
|
+
- - "~>"
|
199
|
+
- !ruby/object:Gem::Version
|
200
|
+
version: '0.9'
|
201
|
+
description: |
|
202
|
+
Command Line Boss is a convenience layer over OptionsParser. It provides a simple
|
203
|
+
way to define command line options and arguments, and then parse them into an options
|
204
|
+
object.
|
205
|
+
email:
|
206
|
+
- jcouball@yahoo.com
|
207
|
+
executables: []
|
208
|
+
extensions: []
|
209
|
+
extra_rdoc_files: []
|
210
|
+
files:
|
211
|
+
- ".rspec"
|
212
|
+
- ".rubocop.yml"
|
213
|
+
- ".yardopts"
|
214
|
+
- CHANGELOG.md
|
215
|
+
- CODE_OF_CONDUCT.md
|
216
|
+
- LICENSE.txt
|
217
|
+
- README.md
|
218
|
+
- Rakefile
|
219
|
+
- examples/create_spreadsheet/.gitignore
|
220
|
+
- examples/create_spreadsheet/.rspec
|
221
|
+
- examples/create_spreadsheet/.rubocop.yml
|
222
|
+
- examples/create_spreadsheet/Gemfile
|
223
|
+
- examples/create_spreadsheet/README.md
|
224
|
+
- examples/create_spreadsheet/Rakefile
|
225
|
+
- examples/create_spreadsheet/create_spreadsheet.gemspec
|
226
|
+
- examples/create_spreadsheet/exe/create-spreadsheet
|
227
|
+
- examples/create_spreadsheet/lib/create_spreadsheet.rb
|
228
|
+
- examples/create_spreadsheet/lib/create_spreadsheet/command_line.rb
|
229
|
+
- examples/create_spreadsheet/spec/create_spreadsheet/command_line.feature
|
230
|
+
- examples/create_spreadsheet/spec/create_spreadsheet/command_line_steps.rb
|
231
|
+
- examples/create_spreadsheet/spec/spec_helper.rb
|
232
|
+
- examples/readme_example/create-spreadsheet
|
233
|
+
- lib/command_line_boss.rb
|
234
|
+
- lib/command_line_boss/help_option.rb
|
235
|
+
- lib/command_line_boss/logger_options.rb
|
236
|
+
- lib/command_line_boss/version.rb
|
237
|
+
homepage: https://github.com/main-branch/command_line_boss
|
238
|
+
licenses:
|
239
|
+
- MIT
|
240
|
+
metadata:
|
241
|
+
allowed_push_host: https://rubygems.org
|
242
|
+
homepage_uri: https://github.com/main-branch/command_line_boss
|
243
|
+
source_code_uri: https://github.com/main-branch/command_line_boss
|
244
|
+
changelog_uri: https://rubydoc.info/gems/command_line_boss/0.1.0/file/CHANGELOG.md
|
245
|
+
documentation_uri: https://rubydoc.info/gems/command_line_boss/0.1.0
|
246
|
+
rubygems_mfa_required: 'true'
|
247
|
+
post_install_message:
|
248
|
+
rdoc_options: []
|
249
|
+
require_paths:
|
250
|
+
- lib
|
251
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
252
|
+
requirements:
|
253
|
+
- - ">="
|
254
|
+
- !ruby/object:Gem::Version
|
255
|
+
version: 3.1.0
|
256
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
257
|
+
requirements:
|
258
|
+
- - ">="
|
259
|
+
- !ruby/object:Gem::Version
|
260
|
+
version: '0'
|
261
|
+
requirements: []
|
262
|
+
rubygems_version: 3.5.11
|
263
|
+
signing_key:
|
264
|
+
specification_version: 4
|
265
|
+
summary: Command Line Boss is a convenience layer over OptionsParser
|
266
|
+
test_files: []
|