opt_parse_builder 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.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.rspec +1 -0
  4. data/.ruby-version +1 -0
  5. data/CHANGELOG.md +5 -0
  6. data/Gemfile +8 -0
  7. data/Gemfile.lock +35 -0
  8. data/LICENSE +23 -0
  9. data/README.md +434 -0
  10. data/Rakefile +13 -0
  11. data/examples/hello_world.rb +20 -0
  12. data/lib/opt_parse_builder.rb +156 -0
  13. data/lib/opt_parse_builder/argument.rb +62 -0
  14. data/lib/opt_parse_builder/argument_builder.rb +193 -0
  15. data/lib/opt_parse_builder/argument_bundle.rb +30 -0
  16. data/lib/opt_parse_builder/argument_bundle_builder.rb +34 -0
  17. data/lib/opt_parse_builder/argument_values.rb +60 -0
  18. data/lib/opt_parse_builder/banner_argument.rb +11 -0
  19. data/lib/opt_parse_builder/constant_argument.rb +16 -0
  20. data/lib/opt_parse_builder/errors.rb +10 -0
  21. data/lib/opt_parse_builder/formats_operand_name.rb +9 -0
  22. data/lib/opt_parse_builder/has_value.rb +21 -0
  23. data/lib/opt_parse_builder/null_argument.rb +4 -0
  24. data/lib/opt_parse_builder/option_argument.rb +33 -0
  25. data/lib/opt_parse_builder/optional_operand_argument.rb +29 -0
  26. data/lib/opt_parse_builder/parser.rb +345 -0
  27. data/lib/opt_parse_builder/parser_builder.rb +17 -0
  28. data/lib/opt_parse_builder/required_operand_argument.rb +32 -0
  29. data/lib/opt_parse_builder/separator_argument.rb +11 -0
  30. data/lib/opt_parse_builder/splat_operand_argument.rb +22 -0
  31. data/lib/opt_parse_builder/stable_sort.rb +13 -0
  32. data/lib/opt_parse_builder/version.rb +6 -0
  33. data/opt_parse_builder.gemspec +35 -0
  34. data/rake/bundler.rake +1 -0
  35. data/rake/default.rake +1 -0
  36. data/rake/rdoc.rake +7 -0
  37. data/rake/spec.rake +3 -0
  38. data/rake/test.rake +2 -0
  39. metadata +126 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 28f64f160f1a3940a3884f5f56ecba366ba6078be1c3032b625f0cded4124259
4
+ data.tar.gz: d81a3b030a5e8b60b97577148c5e91810c7a9125e0f08c6ad01e68f76a0d58ff
5
+ SHA512:
6
+ metadata.gz: d48ea90e1d556a24a649124d33ca1329c743384066da239472c240aec47b9b113785a9e321365b2fac1b4f90ef08e9a370664693c330b326e0a510f666d650d4
7
+ data.tar.gz: 68ccc121fe7a7703f16d2bac471a69abcf0af241a7c85aef53554de9c1609bb464e2a8a5eba3ad1fd39a382d91d5f433cab554e55be6a072347ed96d24fb2f27
@@ -0,0 +1,2 @@
1
+ html
2
+ *.gem
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
@@ -0,0 +1 @@
1
+ ruby-2.7.2
@@ -0,0 +1,5 @@
1
+ # -*- mode: fundamental -*-
2
+
3
+ # Development
4
+
5
+ * Initial release
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ # Specify your gem's dependencies in opt_parse_builder.gemspec
8
+ gemspec
@@ -0,0 +1,35 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ opt_parse_builder (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.4.4)
10
+ rake (13.0.1)
11
+ rspec (3.10.0)
12
+ rspec-core (~> 3.10.0)
13
+ rspec-expectations (~> 3.10.0)
14
+ rspec-mocks (~> 3.10.0)
15
+ rspec-core (3.10.0)
16
+ rspec-support (~> 3.10.0)
17
+ rspec-expectations (3.10.0)
18
+ diff-lcs (>= 1.2.0, < 2.0)
19
+ rspec-support (~> 3.10.0)
20
+ rspec-mocks (3.10.0)
21
+ diff-lcs (>= 1.2.0, < 2.0)
22
+ rspec-support (~> 3.10.0)
23
+ rspec-support (3.10.0)
24
+
25
+ PLATFORMS
26
+ ruby
27
+
28
+ DEPENDENCIES
29
+ bundler (~> 2.1)
30
+ opt_parse_builder!
31
+ rake (~> 13.0)
32
+ rspec (~> 3.10)
33
+
34
+ BUNDLED WITH
35
+ 2.1.4
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Copyright 2020 Wayne Conrad
2
+
3
+ This software is distributed under the [MIT
4
+ License](http://opensource.org/licenses/MIT):
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining
7
+ a copy of this software and associated documentation files (the
8
+ "Software"), to deal in the Software without restriction, including
9
+ without limitation the rights to use, copy, modify, merge, publish,
10
+ distribute, sublicense, and/or sell copies of the Software, and to
11
+ permit persons to whom the Software is furnished to do so, subject to
12
+ the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,434 @@
1
+ # opt_parse_builder
2
+
3
+ A Ruby Gem for processing CLI arguments using optparse. Adds to
4
+ optparse a compact builder-style DSL, operand (positional argument)
5
+ parsing, and composability for sharing argument definitions within a
6
+ suite of commands.
7
+
8
+ Features:
9
+
10
+ * A compact, simple [builder style DSL](#label-Terminology)
11
+
12
+ * Composability - Arguments can be [defined separately from their
13
+ use](#label-Composability), allowing common arguments to be shared
14
+ shared within a suite of programs.
15
+
16
+ * Operand parsing - Adds [parsing of
17
+ operands](#label-Required+Operand)) (aka positional arguments)
18
+
19
+ * Builds on solid ground - Uses tried and true OptParse.
20
+
21
+ * Familiarity - Arguments to OptParse#on are passed through with very
22
+ little change, so you don't have to learn a new syntax for defining
23
+ options.
24
+
25
+ * Not a framework - This library provides _only_ improved argument
26
+ parsing. There is no base class for your program to inherit from,
27
+ no module for it to include, and no imposed structure.
28
+
29
+ * No magic, no surprises - Plain and explicit.
30
+
31
+ * Cohesion - Everything about an argument is defined in one place.
32
+ You don't have to define the argument's help text in one place, the
33
+ default value in another, etc.
34
+
35
+ * Narrow API - Simple and easy to use.
36
+
37
+ * Fully documented - Includes full code documentation and examples.
38
+
39
+ * Stable API - Uses [semantic
40
+ versioning](ttps://semver.org/spec/v2.0.0.html). Promises not to
41
+ break your program without incrementing the major version number.
42
+
43
+ * Programmed simply - Easy to understand and modify.
44
+
45
+ * Fully tested - Extensive unit test suite.
46
+
47
+ # Hello, World
48
+
49
+ It is valuable to provide a simple example which can be modified and
50
+ expanded upon:
51
+
52
+ ```ruby
53
+ require "opt_parse_builder"
54
+
55
+ arg_parser = OptParseBuilder.build_parser do |args|
56
+ args.banner "A simple example"
57
+ args.add do |arg|
58
+ arg.key :path
59
+ arg.required_operand
60
+ end
61
+ args.add do |arg|
62
+ arg.key :verbose
63
+ arg.on "-v", "--verbose", "Be verbose"
64
+ end
65
+ args.separator "Some explanatory text at the bottom"
66
+ end
67
+
68
+ arg_values = arg_parser.parse!
69
+ p arg_values.verbose
70
+ p arg_values.path
71
+ ```
72
+
73
+ # Installation
74
+
75
+ Add this line to your application's Gemfile:
76
+
77
+ ```ruby
78
+ gem 'opt_parse_builder'
79
+ ```
80
+
81
+ And then execute:
82
+
83
+ $ bundle
84
+
85
+ Or install it yourself as:
86
+
87
+ $ gem install opt_parse_builder
88
+
89
+ # Explanation of some features
90
+
91
+ ## Builder style DSL
92
+
93
+ You build an argument parser using a builder style DSL, like this:
94
+
95
+ ```ruby
96
+ arg_parser = OptParseBuilder.build_parser do |args|
97
+ args.add do |arg|
98
+ arg.key :verbose
99
+ arg.on "-v", "--verbose", "Be verbose"
100
+ end
101
+ end
102
+ ```
103
+
104
+ Once built, a parser is normally used like this:
105
+
106
+ arg_values = arg_parser.parse!
107
+
108
+ and argument values retrieved using struct or hash notation:
109
+
110
+ p arg_values.verbose
111
+ p arg_values[:verbose]
112
+
113
+ ## Composability
114
+
115
+ An argument definition can be created separately from its use:
116
+
117
+ ```ruby
118
+ VERBOSE = OptParseBuilder.build_argument do |arg|
119
+ arg.key :verbose
120
+ arg.on "-v", "--verbose", "Print extra output"
121
+ end
122
+
123
+ parser = OptParseBuilder.build_parser do |args|
124
+ args.add VERBOSE
125
+ end
126
+ ```
127
+
128
+ This is especially useful where a suite of programs share some
129
+ arguments in common. Instead of defining common arguments over and
130
+ over, you can define them once and then reuse them in each program:
131
+
132
+ ```ruby
133
+ # common_arguments.rb
134
+
135
+ require "opt_parse_builder"
136
+
137
+ module CommonArguments
138
+ VERBOSE = OptParseBuilder.build_argument do |arg|
139
+ arg.key :verbose
140
+ arg.on "-v", "--verbose", "Print extra output"
141
+ end
142
+ end
143
+ ```
144
+
145
+ ```ruby
146
+ # read_input.rb
147
+
148
+ require_relative "common_arguments"
149
+
150
+ ARG_PARSER = OptParseBuilder.build_parser do |args|
151
+ args.banner "Read and store the input data"
152
+ args.add do |arg|
153
+ arg.key
154
+ arg.required_operand
155
+ end
156
+ args.add CommonArguments::VERBOSE
157
+ end
158
+ ```
159
+
160
+ ```ruby
161
+ # write_report.rb
162
+
163
+ require_relative "common_arguments"
164
+
165
+ ARG_PARSER = OptParseBuilder.build_parser do |args|
166
+ args.banner "Print a report based on data previously read"
167
+ args.add CommonArguments::VERBOSE
168
+ args.add do |arg|
169
+ arg.key :detail
170
+ arg.on "-d", "--detail", "Add the detail section to the report"
171
+ end
172
+ end
173
+ ```
174
+
175
+ When adding a pre-built operand to a parser, you can change change
176
+ it from required to optional:
177
+
178
+ ```
179
+ PATH = OptParseBuilder.build_argument do |arg|
180
+ arg.key :path
181
+ arg.required_operand
182
+ end
183
+
184
+ ARG_PARSER = OptParser.build_parser do |args|
185
+ args.add PATH.optional
186
+ end
187
+ ```
188
+
189
+ or from optional to required:
190
+
191
+ ```
192
+ PATH = OptParseBuilder.build_argument do |arg|
193
+ arg.key :path
194
+ arg.optional_operand
195
+ end
196
+
197
+ ARG_PARSER = OptParser.build_parser do |args|
198
+ args.add PATH.required
199
+ end
200
+ ```
201
+
202
+ # Argument Building Examples
203
+
204
+ Most of these examples use a shorthand where the surrounding code
205
+ is not shown:
206
+
207
+ arg.key = :foo
208
+ arg.on "-f"
209
+
210
+ With the surrounding code, that would be this:
211
+
212
+ parser = OptparserBuilder.new do |args|
213
+ args.add do |arg|
214
+ arg.key = :foo
215
+ arg.on = "-f"
216
+ end
217
+ end
218
+
219
+ or this:
220
+
221
+ arg = OptParseBuilder.build_argument do |arg|
222
+ arg.key = :foo
223
+ arg.on = "-f"
224
+ end
225
+
226
+ ## Null argument
227
+
228
+ A null argument, having no value or visible effect:
229
+
230
+ OptParseBuilder.build_argument do |arg|
231
+ end
232
+
233
+ This has little value to you, but it fell out of the design for
234
+ free, and it is useful in the implementation.
235
+
236
+ ## Banner only
237
+
238
+ An argument with only banner text (but see OptParseBuilder#banner
239
+ for the usual way to do this). "Banner" is how OptParse describes
240
+ text that appears at the top of the --help output.
241
+
242
+ OptParseBuilder.build_argument do |arg|
243
+ arg.banner "Some banner text"
244
+ arg.banner "A second line of banner text"
245
+ arg.banner <<~BANNER
246
+ A third line
247
+ A fourth line
248
+ BANNER
249
+ end
250
+
251
+ Applicable builder methods:
252
+
253
+ * banner
254
+
255
+ Banner text can be added to any argument.
256
+
257
+ ## Separator only
258
+
259
+ An argument with only separator text (but see
260
+ OptParseBuilder#banner for the usual way to do this). "Separator"
261
+ is how OptParse describes text that appears at the bottom of the
262
+ --help output.
263
+
264
+ OptParseBuilder.build_argument do |arg|
265
+ arg.serparator "Separator text"
266
+ arg.serparator "A second line of separator text"
267
+ arg.serparator <<~SERPARATOR
268
+ A third line
269
+ A fourth line
270
+ SERPARATOR
271
+ end
272
+
273
+ Applicable builder methods:
274
+
275
+ * separator
276
+
277
+ Separator text can be added to any argument.
278
+
279
+ ## Constant value
280
+
281
+ An argument with a constant value.
282
+
283
+ OptParseBuilder.build_argument do |arg|
284
+ arg.key :limit
285
+ arg.default 12345
286
+ end
287
+
288
+ Applicable builder methods:
289
+
290
+ * key
291
+ * default
292
+ * banner (optional)
293
+ * separator (optional)
294
+
295
+ This is of limited value, but it fell out of the design for free.
296
+
297
+ ## Simple option
298
+
299
+ A simple option parsed by OptParse:
300
+
301
+ OptParseBuilder.build_argument do |arg|
302
+ arg.key :quiet
303
+ arg.on "-q", "--quiet", "Suppress normal output"
304
+ end
305
+
306
+ Applicable builder methods:
307
+
308
+ * key
309
+ * on
310
+ * default (optional)
311
+ * handler (optional)
312
+ * banner (optional)
313
+ * separator (optional)
314
+
315
+ ## Option with value
316
+
317
+ A value option parsed by OptParse:
318
+
319
+ OptParseBuilder.build_argument do |arg|
320
+ arg.key :iterations
321
+ arg.default 100
322
+ arg.on "-i", "--iterations=N",
323
+ arg.on "Number of iterations (default _DEFAULT_)"
324
+ end
325
+
326
+ Applicable builder methods:
327
+
328
+ * key
329
+ * on
330
+ * default (optional)
331
+ * handler (optional)
332
+ * banner (optional)
333
+ * separator (optional)
334
+
335
+ ## Required Operand
336
+
337
+ A required operand consumes one argument, with an error if there
338
+ isn't one to consume.
339
+
340
+ This example overrides the help name, which is used to describe
341
+ the operand in the --help text. Optional and splat arguments can
342
+ also have a help name override.
343
+
344
+ OptParseBuilder.build_argument do |arg|
345
+ arg.key :group
346
+ arg.required_operand help_name: "resource group"
347
+ arg.optional_operand
348
+ end
349
+
350
+ Applicable builder methods:
351
+
352
+ * key
353
+ * required_operand
354
+ * default (optional)
355
+ * banner (optional)
356
+ * separator (optional)
357
+
358
+ ## Optional operand
359
+
360
+ An optional operand consumes one argument. If there isn't an
361
+ argument to consume, then the value is either nil (if no default
362
+ was specified), or the specified default value.
363
+
364
+ OptParseBuilder.build_argument do |arg|
365
+ arg.key :group_name
366
+ arg.default "main"
367
+ arg.optional_operand
368
+ end
369
+
370
+ Applicable builder methods:
371
+
372
+ * key
373
+ * optional_operand
374
+ * default (optional)
375
+ * banner (optional)
376
+ * separator (optional)
377
+
378
+ ## Splat Operand
379
+
380
+ A "splat" operand consumes all remaining arguments. Its value is
381
+ always an array.
382
+
383
+ OptParseBuilder.build_argument do |arg|
384
+ arg.key :input_path
385
+ arg.optional_operand
386
+ end
387
+
388
+ Applicable builder methods:
389
+
390
+ * key
391
+ * splat_operand
392
+ * default (optional)
393
+ * banner (optional)
394
+ * separator (optional)
395
+
396
+ # Development
397
+
398
+ After checking out the repo, run `bundle` to install dependencies.
399
+ Then run `rake test` to run the tests.
400
+
401
+ To install this gem onto your local machine, run `bundle exec rake
402
+ install`. To release a new version, update the version number in
403
+ `version.rb`, and then run `bundle exec rake release`, which will
404
+ create a git tag for the version, push git commits and tags, and push
405
+ the `.gem` file to [rubygems.org](https://rubygems.org).
406
+
407
+ # Contributing
408
+
409
+ Bug reports and pull requests are welcome on GitHub at
410
+ https://github.com/wconrad/opt_parse_builder.
411
+
412
+ # Terminology
413
+
414
+ These terms are used in this library's code and documentation:
415
+
416
+ * Argument - An option or operand; a single element of ARGV
417
+
418
+ * Option - An argument parsed by optparse, like `-v` or `--size=12`
419
+
420
+ * Switch - An option that is either present or not, like `-v`
421
+
422
+ * Value option - An option with a value, like `--size=12`
423
+
424
+ * Operand - An argument not parsed by optparse, like
425
+ `/path/to/my/file`. Also called a "positional argument."
426
+
427
+ * Required operand - An operand that must be present or an error
428
+ results.
429
+
430
+ * Optional operand - An operand that may be present or not; if not
431
+ present, it receives either `nil` or a default that you set.
432
+
433
+ * Splat operand - An operand that consumes all remaining operands,
434
+ resulting in an array (possibly empty) of strings.