shellopts 2.0.0.pre.14 → 2.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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.ruby-version +1 -1
  4. data/README.md +201 -267
  5. data/TODO +37 -5
  6. data/doc/format.rb +95 -0
  7. data/doc/grammar.txt +27 -0
  8. data/doc/syntax.rb +110 -0
  9. data/doc/syntax.txt +10 -0
  10. data/lib/ext/array.rb +62 -0
  11. data/lib/ext/forward_to.rb +15 -0
  12. data/lib/ext/lcs.rb +34 -0
  13. data/lib/shellopts/analyzer.rb +130 -0
  14. data/lib/shellopts/ansi.rb +8 -0
  15. data/lib/shellopts/args.rb +25 -15
  16. data/lib/shellopts/argument_type.rb +139 -0
  17. data/lib/shellopts/dump.rb +158 -0
  18. data/lib/shellopts/formatter.rb +292 -92
  19. data/lib/shellopts/grammar.rb +375 -0
  20. data/lib/shellopts/interpreter.rb +103 -0
  21. data/lib/shellopts/lexer.rb +175 -0
  22. data/lib/shellopts/parser.rb +293 -0
  23. data/lib/shellopts/program.rb +279 -0
  24. data/lib/shellopts/renderer.rb +227 -0
  25. data/lib/shellopts/stack.rb +7 -0
  26. data/lib/shellopts/token.rb +44 -0
  27. data/lib/shellopts/version.rb +1 -1
  28. data/lib/shellopts.rb +359 -3
  29. data/main +1180 -0
  30. data/shellopts.gemspec +8 -14
  31. metadata +86 -41
  32. data/lib/ext/algorithm.rb +0 -14
  33. data/lib/ext/ruby_env.rb +0 -8
  34. data/lib/shellopts/ast/command.rb +0 -112
  35. data/lib/shellopts/ast/dump.rb +0 -28
  36. data/lib/shellopts/ast/option.rb +0 -15
  37. data/lib/shellopts/ast/parser.rb +0 -106
  38. data/lib/shellopts/constants.rb +0 -88
  39. data/lib/shellopts/exceptions.rb +0 -21
  40. data/lib/shellopts/grammar/analyzer.rb +0 -76
  41. data/lib/shellopts/grammar/command.rb +0 -87
  42. data/lib/shellopts/grammar/dump.rb +0 -56
  43. data/lib/shellopts/grammar/lexer.rb +0 -56
  44. data/lib/shellopts/grammar/option.rb +0 -55
  45. data/lib/shellopts/grammar/parser.rb +0 -78
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f1e9e2f138c476cb6af3184dd5e43f8a0f82108d05e4170491c5c46dfb547627
4
- data.tar.gz: 9990bee10ffe5c6c5db537a416f366ed70c4577a8a3a07658281d9485225d438
3
+ metadata.gz: 6f6c85f64a45ee82fb4abdafd5d36358f8f7a202d9179a670cc86d307813b4a9
4
+ data.tar.gz: 0a5e262777d044fe3afea501b3d94a8c44f89d4703924c619bfbbf2326e22a95
5
5
  SHA512:
6
- metadata.gz: 5a57589ccaf3b2f516727cd6e7b066044d13a49d2c5280a478de162e42574e1eca03c2b013133d9b0ce50b4ac037fef15d12a01f5893b32ec6132d03c121e08f
7
- data.tar.gz: bc338066a99d6470bd434d26cf994159ec926c4eb7f3a7d1d8b358303d5850bcdf058b56447ebf6c581bb2295de2d5f57f5637db5ab82fbd47ba618b8988afe6
6
+ metadata.gz: 34d0eb7f8d15ba2726b062c9f16e36bf0b2649690e4b6487e8b68ce442436100a67928eb47d3896961281e78f77f9252f66f407ce2dafd652fae65d85c229c3d
7
+ data.tar.gz: 9fc0e55ccde0175fea950a4cdd4f4dd385123e2e89c6ecfde8b4a1d0c6502054394322b2c673a96adfaabbbeaeee95d642034a8f545620286c8b795dc6da2436
data/.gitignore CHANGED
@@ -1,7 +1,6 @@
1
1
  /.bundle/
2
2
  /.yardoc
3
3
  /_yardoc/
4
- /doc/
5
4
  /rdoc/
6
5
  /pkg/
7
6
  /spec/reports/
@@ -27,3 +26,5 @@ tt.*
27
26
  s
28
27
  s.*
29
28
 
29
+ # Ignore temporary directory
30
+ /spec/tmpdir/
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- ruby-2.6.6
1
+ ruby-2.7.1
data/README.md CHANGED
@@ -1,345 +1,289 @@
1
1
  # Shellopts
2
2
 
3
- `ShellOpts` is a simple Linux command line parsing libray that covers most modern use
4
- cases incl. sub-commands. Options and commands are specified using a
5
- getopt(1)-like string that is interpreted by the library to process the command
6
- line
3
+ `ShellOpts` is a command line processing library. It supports short
4
+ and long options and subcommands, and has built-in help and error messages
5
+
7
6
 
8
7
  ## Usage
9
8
 
10
- The following program accepts the options -a or --all, --count, --file, and -v
11
- or --verbose. It expects `--count` to have an optional integer argument,
12
- `--file` to have a mandatory argument, and allows `-v` and `--verbose` to be
13
- repeated:
9
+ ShellOpts use a string to specify legal options and documentation. The
10
+ following program accepts the options --alpha and --beta with an argument. -a
11
+ and -b are option aliases:
14
12
 
15
13
  ```ruby
16
-
17
- # Define options
18
- USAGE = "a,all count=#? file= +v,verbose -- FILE..."
19
-
20
- # Define default values
21
- all = false
22
- count = nil
23
- file = nil
24
- verbosity_level = 0
25
-
26
- # Process command line and return remaining non-option arguments
27
- args = ShellOpts.process(USAGE, ARGV) do |opt, arg|
28
- case opt
29
- when '-a', '--all'; all = true
30
- when '--count'; count = arg || 42
31
- when '--file'; file = arg # never nil
32
- when '-v, '--verbose'; verbosity_level += 1
33
- else
34
- fail "Internal Error: Unmatched option: '#{opt}'"
35
- end
36
- end
37
-
38
- # Process remaining command line arguments
39
- args.each { |arg| ... }
40
- ```
41
-
42
- Note that the `else` clause catches legal but unhandled options; it is not an
43
- user error. It typically happens because of a missing or misspelled option name
44
- in the `when` clauses
14
+ require 'shellopts'
45
15
 
46
- If there is an error in the command line options, the program will exit with
47
- status 1 and print an error message and a short usage description on standard
48
- error
16
+ SPEC = "-a,alpha -b,beta=VAL -- ARG1 ARG2"
49
17
 
50
- ## Processing
18
+ opts, args = ShellOpts.process(SPEC, ARGV)
51
19
 
52
- `ShellOpts.process` compiles a usage definition string into a grammar and use
53
- that to parse the command line. If given a block, the block is called with a
54
- name/value pair for each option or command and return a list of the remaining
55
- non-option arguments
20
+ alpha = opts.alpha? # True if -a or --alpha are present
21
+ beta = opts.beta # The value of the -b or --beta option
56
22
 
57
- ```ruby
58
- args = ShellOpts.process(USAGE, ARGV) do |opt, arg|
59
- case opt
60
- when ...
61
- end
62
- end
63
23
  ```
64
24
 
65
- This calls the block for each option in the same order as on the command line
66
- and return the remaining non-option args. It also sets up the `ShellOpts.error` and
67
- `ShellOpts.fail` methods. Please note that you need to call `ShellOpts.reset`
68
- if you want to process another command line
69
-
70
- If `ShellOpts.process` is called without a block it returns a
71
- `ShellOpts::ShellOpts` object. It can be used to process more than one command
72
- line at a time and to inspect the grammar and AST
73
-
74
25
  ```ruby
75
- shellopts = ShellOpts.process(USAGE, ARGV) # Returns a ShellOpts::ShellOpts object
76
- shellopts.each { |opt, arg| ... } # Access options
77
- args = shellopts.args # Access remaining arguments
78
- shellopts.error "Something went wrong" # Emit an error message and exit
79
26
  ```
80
27
 
81
- ## Usage string
28
+ ShellOpts also allow multi-line definitions with comments that are used as part
29
+ of help messages
82
30
 
83
- A usage string, typically named `USAGE`, is a list of option and command
84
- definitions separated by whitespace. It can span multiple lines. A double
85
- dash (`--`) marks the end of the definition, anything after that is not
86
- interpreted but copied verbatim in error messages
31
+ ```ruby
32
+ require 'shellopts'
87
33
 
88
- The general [syntax](https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form) is
34
+ SPEC = %(
35
+ -a,alpha @ Brief comment for -a and --alpha options
36
+ -b,beta=VAL
37
+ @ Alternative style of brief comment
38
+ -- ARG1 ARG2
39
+ )
89
40
 
90
- ```EBNF
91
- options { command options } [ "--" anything ]
41
+ opts, args = ShellOpts.process(SPEC, ARGV)
42
+ ShellOpts::ShellOpts.brief
92
43
  ```
93
44
 
94
- ## Options
45
+ prints
95
46
 
96
- An option is defined by a list of comma-separated names optionally prefixed by a
97
- `+` and/or followed by a `=` and a set of flags. The syntax is
47
+ ```
48
+ Usage
49
+ main --alpha --beta=VAL ARG1 ARG2
98
50
 
99
- ```EBNF
100
- [ "+" ] name-list [ "=" [ "#" | "$" ] [ label ] [ "?" ] ]
51
+ Options
52
+ -a, --alpha Brief comment for -a and --alpha options
53
+ -b, --beta=VAL Alternative style of brief comment
101
54
  ```
102
55
 
103
- #### Flags
56
+ There is also a `ShellOpts.help` method that prints a more detailed
57
+ documentation, and a `ShellOpts.usage` method that prints a compact usage
58
+ string
104
59
 
105
- There are the following flags:
60
+ If there is an error in the command line options, the program will exit with
61
+ status 1 and print an error message and usage on standard error. If there is
62
+ an error in the specification, a message to the developer with the origin of
63
+ the error is printed on standard error
106
64
 
107
- |Flag|Effect|
108
- |---|---|
109
- |+|Repeated option (prefix)|
110
- |=|Argument. Mandatory unless `?` is also used|
111
- |#|Integer argument|
112
- |$|Floating point argument|
113
- |?|Optional argument|
65
+ ## Processing
114
66
 
115
- #### Repeated options
67
+ `ShellOpts.process` creates a `ShellOpts::ShellOpts` object and use it to
68
+ compile the specification and process the command line. It returns a tuple of a
69
+ Program object and an array of the remaining arguments
116
70
 
117
- Options are unique by default and the user will get an error if an option is
118
- used more than once. You can tell the parser to allow several instances of the
119
- same option by prefixing the option names with a `+`. A typical use case is to
120
- let the user repeat a 'verbose' option to increase verbosity: `+v,verbose`
121
- allows `-vvv` or `--verbose --verbose --verbose`. `ShellOpts::process` yields
122
- an entry for each usage so should handle repeated options like this
71
+ The Program object has accessor methods for each defined option and sub-command
72
+ to check presence and return an optional argument. Given the options "--alpha
73
+ --beta=ARG" then the following accessor methods are available:
123
74
 
124
75
  ```ruby
125
- verbosity_level = 0
76
+ # Returns true if the option is present and false otherwise
77
+ opts.alpha?()
78
+ opts.beta?()
126
79
 
127
- args = ShellOpts.process(USAGE, ARGV) do |opt, arg|
128
- case opt
129
- when '-v', '--verbose'; verbosity_level += 1
130
- # other options
131
- end
132
- end
80
+ # Returns the argument of the beta option or nil if missing
81
+ opts.beta()
133
82
  ```
134
83
 
135
- #### Option names
84
+ Given the commands "cmd1! cmd2!" the following methods are available:
136
85
 
137
- Option names are a comma-separated list of names. Names can consist of one or more
138
- ASCII letters (a-zA-Z), digits, underscores ('\_') and dashes ('-'). A name
139
- can't start with a dash, though
86
+ ```ruby
87
+ # Returns the sub-command object or nil if not present
88
+ opts.cmd1!
89
+ opts.cmd2!
90
+
91
+ opts.subcommand! # Returns the sub-command object or nil if not present
92
+ opts.subcommand # Returns the sub-command's identifier (eg. :cmd1!)
93
+ ```
140
94
 
141
- Names that are one character long are considered 'short options' and are
142
- prefixed with a single dash on the command line (eg. '-a'). Names with two or
143
- more characters are 'long options' and are used with two dashes (eg. '--all').
144
- Note that short and long names handles arguments differently
95
+ It is used like this
145
96
 
146
- Examples:
147
- ```
148
- a # -a
149
- all # --all
150
- a,all # -a or --all
151
- r,R,recursive # -r, -R, or --recursive
97
+ ```ruby
98
+ case opts.subcommand
99
+ when :cmd1
100
+ # opts.cmd1 is defined here
101
+ when :cmd2
102
+ # opts.cmd2 is defined here
103
+ end
104
+ end
152
105
  ```
153
106
 
154
- #### Option argument
107
+ Sub-commands have options and even sub-sub-commands of their own. They can be
108
+ nested to any depth (which is not recommended, btw.)
155
109
 
156
- An option that takes an an argument is declared with a `=` after the name list.
157
- By default the type of an option is a `String` but a integer argument can be
158
- specified by the `#` flag and a float argument by the `$` flag.
110
+ The module methods `::usage`, `::brief`, and `::help` prints documentation with
111
+ increasing detail. `::usage` lists the options and commands without any comments,
112
+ `::brief` includes source text that starts with a '@', and `::help` the full
113
+ documentation in a man-page like format. Example
159
114
 
160
- You can label a option value that will be used in help texts and error
161
- messages. A usage string like `file=FILE` will be displayed as `--file=FILE`
162
- and `file=FILE?` like `--file[=FILE]`. If no label is given, `INT` will be used
163
- for integer arguments, `FLOAT` for floating point, and else `ARG`
115
+ ```ruby
116
+ SPEC = "-h --help"
117
+ opts, args = ShellOpts.process(SPEC, ARGV)
118
+
119
+ if opts.h?
120
+ ShellOpts.brief
121
+ exit
122
+ elsif opts.help?
123
+ ShellOpts.help
124
+ exit
125
+ end
126
+ ```
164
127
 
165
- Arguments are mandatory by default but can be made optional by suffixing a `?`
128
+ The module methods `::error` and `::failure` are used to report errors in a common
129
+ format and then terminate the program with status 1. `::error` is used to report
130
+ errors that the user can correct and prints a usage description as a reminder.
131
+ `::failure` is used to report errors within the program so the usage descriptionn
132
+ is not printed:
166
133
 
167
- ## Commands
134
+ ```ruby
135
+ SPEC = "--var=VAR"
136
+ opts, args = ShellOpts.process(SPEC, ARGV)
168
137
 
169
- Sub-commands (like `git clone`) are defined by a name (or a dot-separated list
170
- of names) followed by an exclamation mark. All options following a command are
171
- local to that command. It is not possible to 'reset' this behaviour so global
172
- options should always come before the first command. Nested commands are
173
- specified using a dot-separated "path" to the nested sub-command
138
+ # --var is a mandatory 'option'
139
+ opts.var? or error "Missing --var 'option'"
174
140
 
175
- Examples
176
- ```
177
- g,global clone! t,template=
178
- g,global clone! t,template= clone.list! v,verbose
141
+ # later during processing
142
+ condition or failure "Memory overflow"
179
143
  ```
180
144
 
181
- The last example could be called like `program -g clone list -v`. You may split
182
- the usage string to improve readability:
183
145
 
184
- ```
185
- g,global
186
- clone! t,template=
187
- clone.list! v,verbose
188
- ```
146
+ ## Specification
189
147
 
190
- #### Command processing
148
+ The specification is possibly multi-line string, typically named `SPEC`, that
149
+ is a mix of option or command definitions and related documentation.
150
+ Indentation is used to nest the elements and '@' is used to tag an option or
151
+ command with a brief description
191
152
 
192
- Commands are treated like options but with a value that is an array of options (and
193
- sub-commands) to the command:
153
+ The specifiction is parsed line-by-line: Lines matching and initial '-', or
154
+ '--' are considered option definitions and lines starting with a word
155
+ immediately followed by an exclamation mark is a command definition (like 'cmd!
156
+ ...'). Text following a '@' (except in paragraphs) is a brief comment, the rest
157
+ is paragraphs
194
158
 
195
- ```ruby
196
- USAGE = "a cmd! b c"
197
-
198
- args = ShellOpts.process(USAGE, ARGV) { |opt, arg|
199
- case opt
200
- when '-a'; # Handle -a
201
- when 'cmd'
202
- arg.each { |opt, arg|
203
- case opt
204
- when '-b'; # Handle -b
205
- when '-c'; # Handle -c
206
- end
207
- }
208
- end
209
- }
210
159
  ```
160
+ -a,alpha @ Brief comment for -a and --alpha options
161
+ Longer description of the option that is used by `::help`
211
162
 
212
- ## Parsing
163
+ cmd!
164
+ @ Alternative style of brief comment
213
165
 
214
- Parsing of the command line follows the UNIX traditions for short and long
215
- options. Short options are one letter long and prefixed by a `-`. Short options
216
- can be grouped so that `-abc` is the same as `-a -b -c`. Long options are
217
- prefixed with a `--` and can't be grouped
166
+ Longer description of the command
167
+ ```
218
168
 
219
- Mandatory arguments to short options can be separated by a whitespace (`-f
220
- /path/to/file`) but optional arguments needs to come immediately after the
221
- option: `-f/path/to/file`. Long options also allow a space separator for
222
- mandatory arguments but use `=` to separate the option from optional arguments:
223
- `--file=/path/to/file`
169
+ Text starting with '--' follow by a blank character is a free-text description
170
+ of the command-line arguments. It is not parsed but used in documentation and
171
+ error messages:
224
172
 
225
- Examples
173
+ ```ruby
174
+ SPEC = "-a cmd! -- ARG1 ARG2"
226
175
  ```
227
- f= # -farg or -f arg
228
- f=? # -farg
229
176
 
230
- file= # --file=arg or --file arg
231
- file=? # --file=arg
232
- ```
177
+ ## Options
233
178
 
234
- #### Error handling
179
+ The general syntax for options is
235
180
 
236
- If the command line is invalid, it's a user error and the program exits with
237
- status 1 and prints an error message on STDERR
181
+ ```
182
+ <prefix><optionlist>[=argspec][?]
183
+ ```
238
184
 
239
- If there is an error in the usage string, ShellOpts raises a
240
- `ShellOpts::CompileError`. Note that this exception signals an error by the
241
- application developer and shouldn't be catched. If there is an internal error
242
- in the library, a ShellOpts::InternalError is raised and you should look for a
243
- newer version of `ShellOpts` or file a bug-report
185
+ The option list is a comma-separated list of option names. It is prefixed with
186
+ a '-' if the option list starts with a short option name and '--' if the option
187
+ list starts with a long name. '-' and '--' can be replaced with '+' or '++' to
188
+ indicate that the option can be repeated
244
189
 
245
- All ShellOpt exceptions derive from ShellOpt::Error
190
+ ```
191
+ -a,alpha @ -a and --alpha
192
+ ++beta @ --beta, can be repeated
193
+ --gamma=ARG? @ --gamma, takes an optional argument
194
+ ```
246
195
 
247
- #### Error handling methods
248
196
 
249
- ShellOpts provides two methods that can be used by the application to
250
- generate error messages in the style of ShellOpts: `ShellOpts.error` and
251
- `ShellOpts.fail`. Both write an error message on STDERR and terminates the
252
- program with status 1.
197
+ An option argument has a name and a type. The type can be specified as '#'
198
+ (integer), '$' (float), or as a comma-separated list of allowed values. It can
199
+ also be defined by a keyword that expects a file or directory argument:
253
200
 
254
- `error` is intended to respond to user errors (like giving a file name that
255
- doesn't exist) and prints a short usage summary to remind the user:
201
+ | Keyword | Type |
202
+ | --------- | ---- |
203
+ | FILE | A file if present or in an existing directory if not |
204
+ | DIR | A directory if present or in an existing directory if not |
205
+ | PATH | Either a FILE or DIR |
206
+ | EFILE | An existing file |
207
+ | EDIR | An existing directory |
208
+ | EPATH | Either an EFILE or EDIR |
209
+ | NFILE | A new file |
210
+ | NDIR | A new directory |
211
+ | NPATH | A new file or directory |
256
212
 
257
- ```
258
- <PROGRAM>: <MESSAGE>
259
- Usage: <PROGRAM> <USAGE>
260
- ```
261
- The usage string is a prettyfied version of the usage definition given to
262
- ShellOpts
213
+ By default the option name is inferred from the type but it can be specified explicitly by separating it from the type with a ':'. Examples:
263
214
 
264
- `fail` is used to report that something is wrong with the assumptions about the
265
- system (eg. disk full) and omits the usage summary
266
215
  ```
267
- <PROGRAM>: <MESSAGE>
216
+ -a=# @ -a takes an integer argument
217
+ -b=MONEY:$ @ -b takes a float argument. Is shown as '-b=MONEY' in messages
218
+ -c=red,blue,green @ -c takes one of the listed words
219
+ -d=FILE @ Fails if file exists and is not a file
220
+ -d=EDIR @ Fails if directory doesn't exist or is not a directory
221
+ -d=INPUT:EFILE @ Takes and existing file. Shown as '-d=INPUT' in messages
268
222
  ```
269
223
 
270
- The methods are defined as instance methods on `ShellOpts::ShellOpts` and as
271
- class methods on `ShellOpts`. They can also be included in the global scope by
272
- `include ShellOpts::Utils`
224
+ ## Commands
273
225
 
274
- #### Usage string
226
+ Commands are specified as lines starting with the name of the command
227
+ immediately followed by a '!' like `cmd!`. Commands can have options and even
228
+ subcommands of their own, in the multi-line format they're indented under the
229
+ command line like this
275
230
 
276
- The error handling methods prints a prettified version of the usage string
277
- given to `ShellOpts.parse`. The usage string can be overridden by assigning to
278
- `ShellOpts.usage`. A typical use case is when you want to split the usage
279
- description over multiple lines:
231
+ ```
232
+ -a @ Program level option
233
+ cmd!
234
+ -b @ Command level option
235
+ subcmd!
236
+ -c @ Sub-command level option
237
+ ```
280
238
 
281
- ```ruby
239
+ In single-line format, subcommands are specified by prefixing the supercommand's name:
282
240
 
283
- USAGE="long-and-complex-usage-string"
284
- ShellOpts.usage = <<~EOD
285
- usage explanation
286
- split over
287
- multiple lines
288
- EOD
289
241
  ```
290
-
291
- Note that this only affects the module-level `ShellOpts.error` method and not
292
- object-level `ShellOpts::ShellOpts#error` method. This is considered a bug and
293
- will fixed at some point
242
+ -a cmd! -b cmd.subcmd! -c
243
+ ```
294
244
 
295
245
  ## Example
296
246
 
297
- The rm(1) command could be implemented like this
247
+ The rm(1) command could be specified like this:
248
+
298
249
  ```ruby
299
250
 
300
251
  require 'shellopts'
301
252
 
302
253
  # Define options
303
- USAGE = %{
304
- f,force i I interactive=WHEN? r,R,recusive d,dir
305
- one-file-system no-preserve-root preserve-root
306
- v,verbose help version
307
- }
308
-
309
- # Define defaults
310
- force = false
311
- prompt = false
312
- prompt_once = false
313
- interactive = false
314
- interactive_when = nil
315
- recursive = false
316
- remove_empty_dirs = false
317
- one_file_system = false
318
- preserve_root = true
319
- verbose = false
320
-
321
- # Process command line
322
- args = ShellOpts.process(USAGE, ARGV) { |opt, arg|
323
- case opt
324
- when '-f', '--force'; force = true
325
- when '-i'; prompt = true
326
- when '-I'; prompt_once = true
327
- when '--interactive'; interactive = true; interactive_when = arg
328
- when '-r', '-R', '--recursive'; recursive = true
329
- when '-d', '--dir'; remove_empty_dirs = true
330
- when '--one-file-system'; one_file_system = true
331
- when '--preserve-root'; preserve_root = true
332
- when '--no-preserve-root'; preserve_root = false
333
- when '--verbose'; verbose = true
334
- when '--help'; print_help; exit
335
- when '--version'; puts VERSION; exit
336
- end
337
- end
254
+ SPEC = %(
255
+ -f,force @ ignore nonexisten files and arguments, never prompt
256
+ -i @ prompt before every removal
338
257
 
339
- # Remaining arguments are files or directories
340
- files = args
341
- ```
258
+ -I
259
+ @ prompt once
260
+
261
+ prompt once before removing more than three files, or when removing
262
+ recursively; less intrusive than -i, while still giving protection
263
+ against most mistakes
264
+
265
+ --interactive=WHEN:never,once,always
266
+ @ prompt according to WHEN
342
267
 
268
+ prompt according to WHEN: never, once (-I), or always (-i); without WHEN, prompt always
269
+
270
+ --one-file-system
271
+ @ stay on fuile system
272
+
273
+ when removing a hierarchy recursively, skip any directory that is on a file system different from
274
+ that of the corresponding command line argument
275
+
276
+ --no-preserve-root @ do not treat '/' specially
277
+ --preserve-root @ do not remove '/' (default)
278
+ -r,R,recursive @ remove directories and their contents recursively
279
+ -d,dir @ remove empty directories
280
+ -v,verbose @ explain what is being done
281
+ --help @ display this help and exit
282
+ --version @ output version information and exit
283
+
284
+ -- FILE...
285
+ )
286
+ ```
343
287
 
344
288
  ## See also
345
289
 
@@ -378,16 +322,6 @@ release a new version, update the version number in `version.rb`, and then run
378
322
  git commits and tags, and push the `.gem` file to
379
323
  [rubygems.org](https://rubygems.org).
380
324
 
381
- ## Implementation
382
-
383
- FIXME
384
- # ShellOpts is a library for parsing command line options and commands. It
385
- # consists of the interface module {ShellOpts}, the implementation class
386
- # {ShellOpts::ShellOpts} and the representation classes
387
- # {ShellOpts::OptionsHash} and {ShellOpts::OptionsStruct}.
388
- # {ShellOpts::Messenger} is used for error messages
389
-
390
-
391
325
  ## Contributing
392
326
 
393
327
  Bug reports and pull requests are welcome on GitHub at
data/TODO CHANGED
@@ -1,8 +1,16 @@
1
- o Somehow escape comments where a line starts with an option name
2
- o 'help' should list commands in declaration order
3
- o 'help' should use all levels by default
4
- o 'help' should always include top-level options (try setting levels: 10 and
5
- see top-level options are gone
1
+
2
+ o Ignore all text after ' # ' (doesn't conflict with option flag)
3
+ o Command aliases
4
+ o Add user-defined setions
5
+ o Add a SOURCE section with link to git repo
6
+ o Bullet-lists
7
+ o Allow a USAGE section (and NAME)
8
+ o Find source in code an adjust line number in error messages
9
+ o Rename line and char to lineno and charno
10
+ o Client-defined argument types
11
+ o Rename Expr -> ?
12
+ o Find clean(er) procedural object model
13
+ o Allow assignment to options (this makes practical stuff easier)
6
14
  o Special handling of --help arguments so that '--help command' is possible
7
15
  o Support for paging of help:
8
16
  begin
@@ -14,3 +22,27 @@ o Support for paging of help:
14
22
  file.close
15
23
  end
16
24
 
25
+ + Bold text output
26
+ + Recursive format of commands
27
+ + Rename Compiler -> Interpreter
28
+
29
+
30
+ OLD
31
+
32
+ o Fix that it is near unsable when the user doesn't do 'include ShellOpts'
33
+ o Subcommands can be parsed as well:
34
+ opts, args = Shellopts.process(OPTIONS, ARGV)
35
+ ...
36
+ opts, command = opts.process
37
+ case command
38
+ when ...
39
+ end
40
+ o 'help' should list commands in declaration order
41
+ o 'help' should use all levels by default
42
+ o 'help' should always include top-level options (try setting levels: 10 and
43
+ see top-level options are gone
44
+ o A ShellOpts#shift command that makes it possible for Array#expect to emit
45
+ relevant error messages
46
+
47
+ + Somehow escape comments where a line starts with an option name
48
+ + Parse and check enumeration arguments ('--debug=tokens|ast|idr|...')