shellopts 0.9.5 → 1.0.1
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 +4 -4
- data/.gitignore +1 -0
- data/README.md +49 -17
- data/TODO +11 -1
- data/bin/mkdoc +11 -6
- data/doc/stylesheet.css +409 -0
- data/lib/shellopts.rb +33 -10
- data/lib/shellopts/version.rb +1 -1
- data/shellopts.gemspec +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3096c35af16a39ffc98b52f02799aa25efa311b20916309496ee33b2a50dcf47
|
4
|
+
data.tar.gz: ebc336b7a5595412d1f705378f24dc6136c17e3257db7ca5ddec021349ec2a88
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d44d80cc028fa9c9a7add7206b6a0f096cc3deb1c7e3f756075171c4ebfb20fdb6246215ec02d8920e9b450ebfcd5355a0c3b4179cc03d7fb4f6f89eea6f3a15
|
7
|
+
data.tar.gz: 5bb562a9806196a6b6594897d3a09b8a1dc70abebf9f51194a6d31c031e86c54e69d1531acbb5ba6d675afb97c12d86ad2da4216af06bdcac8e056430787a97a
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,20 +1,19 @@
|
|
1
1
|
# Shellopts
|
2
2
|
|
3
|
-
`ShellOpts` is a simple command line parsing libray that covers most modern use
|
3
|
+
`ShellOpts` is a simple Linux command line parsing libray that covers most modern use
|
4
4
|
cases incl. sub-commands. Options and commands are specified using a
|
5
5
|
getopt(1)-like string that is interpreted by the library to process the command
|
6
6
|
line
|
7
7
|
|
8
8
|
## Usage
|
9
9
|
|
10
|
-
The following program accepts
|
11
|
-
|
12
|
-
|
13
|
-
|
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:
|
14
14
|
|
15
15
|
```ruby
|
16
|
-
|
17
|
-
|
16
|
+
|
18
17
|
# Define options
|
19
18
|
USAGE = "a,all count=#? file= +v,verbose -- FILE..."
|
20
19
|
|
@@ -36,7 +35,7 @@ args = ShellOpts.process(USAGE, ARGV) do |opt, arg|
|
|
36
35
|
end
|
37
36
|
end
|
38
37
|
|
39
|
-
# Process remaining arguments
|
38
|
+
# Process remaining command line arguments
|
40
39
|
args.each { |arg| ... }
|
41
40
|
```
|
42
41
|
|
@@ -50,10 +49,10 @@ error
|
|
50
49
|
|
51
50
|
## Processing
|
52
51
|
|
53
|
-
`ShellOpts.process` compiles a usage definition string into a grammar and use
|
54
|
-
parse the command line. If given a block, the block is called with a
|
55
|
-
pair for each option or command and return a list of the remaining
|
56
|
-
arguments
|
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
|
57
56
|
|
58
57
|
```ruby
|
59
58
|
args = ShellOpts.process(USAGE, ARGV) do |opt, arg|
|
@@ -74,7 +73,7 @@ line at a time and to inspect the grammar and AST
|
|
74
73
|
|
75
74
|
```ruby
|
76
75
|
shellopts = ShellOpts.process(USAGE, ARGV) # Returns a ShellOpts::ShellOpts object
|
77
|
-
shellopts.each { |opt,
|
76
|
+
shellopts.each { |opt, arg| ... } # Access options
|
78
77
|
args = shellopts.args # Access remaining arguments
|
79
78
|
shellopts.error "Something went wrong" # Emit an error message and exit
|
80
79
|
```
|
@@ -101,6 +100,18 @@ An option is defined by a list of comma-separated names optionally prefixed by a
|
|
101
100
|
[ "+" ] name-list [ "=" [ "#" | "$" ] [ label ] [ "?" ] ]
|
102
101
|
```
|
103
102
|
|
103
|
+
#### Flags
|
104
|
+
|
105
|
+
There are the following flags:
|
106
|
+
|
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|
|
114
|
+
|
104
115
|
#### Repeated options
|
105
116
|
|
106
117
|
Options are unique by default and the user will get an error if an option is
|
@@ -184,11 +195,11 @@ sub-commands) to the command:
|
|
184
195
|
```ruby
|
185
196
|
USAGE = "a cmd! b c"
|
186
197
|
|
187
|
-
args = ShellOpts.process(USAGE, ARGV) { |opt,
|
198
|
+
args = ShellOpts.process(USAGE, ARGV) { |opt, arg|
|
188
199
|
case opt
|
189
200
|
when '-a'; # Handle -a
|
190
201
|
when 'cmd'
|
191
|
-
|
202
|
+
arg.each { |opt, arg|
|
192
203
|
case opt
|
193
204
|
when '-b'; # Handle -b
|
194
205
|
when '-c'; # Handle -c
|
@@ -260,6 +271,27 @@ The methods are defined as instance methods on `ShellOpts::ShellOpts` and as
|
|
260
271
|
class methods on `ShellOpts`. They can also be included in the global scope by
|
261
272
|
`include ShellOpts::Utils`
|
262
273
|
|
274
|
+
#### Usage string
|
275
|
+
|
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:
|
280
|
+
|
281
|
+
```ruby
|
282
|
+
|
283
|
+
USAGE="long-and-complex-usage-string"
|
284
|
+
ShellOpts.usage = <<~EOD
|
285
|
+
usage explanation
|
286
|
+
split over
|
287
|
+
multiple lines
|
288
|
+
EOD
|
289
|
+
```
|
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
|
294
|
+
|
263
295
|
## Example
|
264
296
|
|
265
297
|
The rm(1) command could be implemented like this
|
@@ -287,12 +319,12 @@ preserve_root = true
|
|
287
319
|
verbose = false
|
288
320
|
|
289
321
|
# Process command line
|
290
|
-
args = ShellOpts.process(USAGE, ARGV) { |opt,
|
322
|
+
args = ShellOpts.process(USAGE, ARGV) { |opt, arg|
|
291
323
|
case opt
|
292
324
|
when '-f', '--force'; force = true
|
293
325
|
when '-i'; prompt = true
|
294
326
|
when '-I'; prompt_once = true
|
295
|
-
when '--interactive'; interactive = true; interactive_when =
|
327
|
+
when '--interactive'; interactive = true; interactive_when = arg
|
296
328
|
when '-r', '-R', '--recursive'; recursive = true
|
297
329
|
when '-d', '--dir'; remove_empty_dirs = true
|
298
330
|
when '--one-file-system'; one_file_system = true
|
data/TODO
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
|
2
2
|
TODO
|
3
|
+
o Also allow assignment to usage string for ShellOpts::ShellOpts objects
|
4
|
+
o Create a ShellOpts.args method? It would be useful when processing commands:
|
5
|
+
case opt
|
6
|
+
when "command"
|
7
|
+
call_command_method(ShellOpts.args[1], ShellOpts.args[2])
|
8
|
+
end
|
9
|
+
ShellOpts.args would be a shorthand for ShellOpts.shellopts.args
|
10
|
+
Another option would be to create an argument-processing method:
|
11
|
+
shellopts.argv(2) -> call error if not exactly two arguments else return elements
|
12
|
+
|
3
13
|
o Check on return value from #process block to see if all options was handled:
|
4
14
|
case opt
|
5
15
|
when '-v'; verbose = true # Return value 'true' is ok
|
@@ -11,7 +21,7 @@ TODO
|
|
11
21
|
o Make an official dump method for debug
|
12
22
|
o Make a note that all options are processed at once and not as-you-go
|
13
23
|
o Test that arguments with spaces work
|
14
|
-
o Long version usage strings
|
24
|
+
o Long version usage strings (major release)
|
15
25
|
o Doc: Example of processing of sub-commands and sub-sub-commands
|
16
26
|
|
17
27
|
+ More tests
|
data/bin/mkdoc
CHANGED
@@ -1,10 +1,15 @@
|
|
1
1
|
#!/usr/bin/bash
|
2
2
|
|
3
|
-
|
3
|
+
set -e
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
# Generate github-like page
|
6
|
+
(
|
7
|
+
cd doc
|
8
|
+
{
|
9
|
+
echo '<link rel="stylesheet" type="text/css" href="stylesheet.css">'
|
10
|
+
pandoc ../README.md
|
11
|
+
} >index.html
|
12
|
+
)
|
9
13
|
|
10
|
-
rdoc
|
14
|
+
# Generate rdoc
|
15
|
+
rdoc --output=rdoc --force-output lib
|
data/doc/stylesheet.css
ADDED
@@ -0,0 +1,409 @@
|
|
1
|
+
/*
|
2
|
+
Copyright (c) 2017 Chris Patuzzo
|
3
|
+
https://twitter.com/chrispatuzzo
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
22
|
+
*/
|
23
|
+
|
24
|
+
body {
|
25
|
+
font-family: Helvetica, arial, sans-serif;
|
26
|
+
font-size: 14px;
|
27
|
+
line-height: 1.6;
|
28
|
+
padding-top: 10px;
|
29
|
+
padding-bottom: 10px;
|
30
|
+
background-color: white;
|
31
|
+
padding: 30px;
|
32
|
+
color: #333;
|
33
|
+
}
|
34
|
+
|
35
|
+
body > *:first-child {
|
36
|
+
margin-top: 0 !important;
|
37
|
+
}
|
38
|
+
|
39
|
+
body > *:last-child {
|
40
|
+
margin-bottom: 0 !important;
|
41
|
+
}
|
42
|
+
|
43
|
+
a {
|
44
|
+
color: #4183C4;
|
45
|
+
text-decoration: none;
|
46
|
+
}
|
47
|
+
|
48
|
+
a.absent {
|
49
|
+
color: #cc0000;
|
50
|
+
}
|
51
|
+
|
52
|
+
a.anchor {
|
53
|
+
display: block;
|
54
|
+
padding-left: 30px;
|
55
|
+
margin-left: -30px;
|
56
|
+
cursor: pointer;
|
57
|
+
position: absolute;
|
58
|
+
top: 0;
|
59
|
+
left: 0;
|
60
|
+
bottom: 0;
|
61
|
+
}
|
62
|
+
|
63
|
+
h1, h2, h3, h4, h5, h6 {
|
64
|
+
margin: 20px 0 10px;
|
65
|
+
padding: 0;
|
66
|
+
font-weight: bold;
|
67
|
+
-webkit-font-smoothing: antialiased;
|
68
|
+
cursor: text;
|
69
|
+
position: relative;
|
70
|
+
}
|
71
|
+
|
72
|
+
h2:first-child, h1:first-child, h1:first-child + h2, h3:first-child, h4:first-child, h5:first-child, h6:first-child {
|
73
|
+
margin-top: 0;
|
74
|
+
padding-top: 0;
|
75
|
+
}
|
76
|
+
|
77
|
+
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor {
|
78
|
+
text-decoration: none;
|
79
|
+
}
|
80
|
+
|
81
|
+
h1 tt, h1 code {
|
82
|
+
font-size: inherit;
|
83
|
+
}
|
84
|
+
|
85
|
+
h2 tt, h2 code {
|
86
|
+
font-size: inherit;
|
87
|
+
}
|
88
|
+
|
89
|
+
h3 tt, h3 code {
|
90
|
+
font-size: inherit;
|
91
|
+
}
|
92
|
+
|
93
|
+
h4 tt, h4 code {
|
94
|
+
font-size: inherit;
|
95
|
+
}
|
96
|
+
|
97
|
+
h5 tt, h5 code {
|
98
|
+
font-size: inherit;
|
99
|
+
}
|
100
|
+
|
101
|
+
h6 tt, h6 code {
|
102
|
+
font-size: inherit;
|
103
|
+
}
|
104
|
+
|
105
|
+
h1 {
|
106
|
+
font-size: 28px;
|
107
|
+
color: black;
|
108
|
+
}
|
109
|
+
|
110
|
+
h2 {
|
111
|
+
font-size: 24px;
|
112
|
+
border-bottom: 1px solid #cccccc;
|
113
|
+
color: black;
|
114
|
+
}
|
115
|
+
|
116
|
+
h3 {
|
117
|
+
font-size: 18px;
|
118
|
+
}
|
119
|
+
|
120
|
+
h4 {
|
121
|
+
font-size: 16px;
|
122
|
+
}
|
123
|
+
|
124
|
+
h5 {
|
125
|
+
font-size: 14px;
|
126
|
+
}
|
127
|
+
|
128
|
+
h6 {
|
129
|
+
color: #777777;
|
130
|
+
font-size: 14px;
|
131
|
+
}
|
132
|
+
|
133
|
+
p, blockquote, ul, ol, dl, li, table, pre {
|
134
|
+
margin: 15px 0;
|
135
|
+
}
|
136
|
+
|
137
|
+
hr {
|
138
|
+
border: 0 none;
|
139
|
+
color: #cccccc;
|
140
|
+
height: 4px;
|
141
|
+
padding: 0;
|
142
|
+
}
|
143
|
+
|
144
|
+
body > h2:first-child {
|
145
|
+
margin-top: 0;
|
146
|
+
padding-top: 0;
|
147
|
+
}
|
148
|
+
|
149
|
+
body > h1:first-child {
|
150
|
+
margin-top: 0;
|
151
|
+
padding-top: 0;
|
152
|
+
}
|
153
|
+
|
154
|
+
body > h1:first-child + h2 {
|
155
|
+
margin-top: 0;
|
156
|
+
padding-top: 0;
|
157
|
+
}
|
158
|
+
|
159
|
+
body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child {
|
160
|
+
margin-top: 0;
|
161
|
+
padding-top: 0;
|
162
|
+
}
|
163
|
+
|
164
|
+
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
|
165
|
+
margin-top: 0;
|
166
|
+
padding-top: 0;
|
167
|
+
}
|
168
|
+
|
169
|
+
h1 p, h2 p, h3 p, h4 p, h5 p, h6 p {
|
170
|
+
margin-top: 0;
|
171
|
+
}
|
172
|
+
|
173
|
+
li p.first {
|
174
|
+
display: inline-block;
|
175
|
+
}
|
176
|
+
|
177
|
+
ul, ol {
|
178
|
+
padding-left: 30px;
|
179
|
+
}
|
180
|
+
|
181
|
+
ul :first-child, ol :first-child {
|
182
|
+
margin-top: 0;
|
183
|
+
}
|
184
|
+
|
185
|
+
ul :last-child, ol :last-child {
|
186
|
+
margin-bottom: 0;
|
187
|
+
}
|
188
|
+
|
189
|
+
dl {
|
190
|
+
padding: 0;
|
191
|
+
}
|
192
|
+
|
193
|
+
dl dt {
|
194
|
+
font-size: 14px;
|
195
|
+
font-weight: bold;
|
196
|
+
font-style: italic;
|
197
|
+
padding: 0;
|
198
|
+
margin: 15px 0 5px;
|
199
|
+
}
|
200
|
+
|
201
|
+
dl dt:first-child {
|
202
|
+
padding: 0;
|
203
|
+
}
|
204
|
+
|
205
|
+
dl dt > :first-child {
|
206
|
+
margin-top: 0;
|
207
|
+
}
|
208
|
+
|
209
|
+
dl dt > :last-child {
|
210
|
+
margin-bottom: 0;
|
211
|
+
}
|
212
|
+
|
213
|
+
dl dd {
|
214
|
+
margin: 0 0 15px;
|
215
|
+
padding: 0 15px;
|
216
|
+
}
|
217
|
+
|
218
|
+
dl dd > :first-child {
|
219
|
+
margin-top: 0;
|
220
|
+
}
|
221
|
+
|
222
|
+
dl dd > :last-child {
|
223
|
+
margin-bottom: 0;
|
224
|
+
}
|
225
|
+
|
226
|
+
blockquote {
|
227
|
+
border-left: 4px solid #dddddd;
|
228
|
+
padding: 0 15px;
|
229
|
+
color: #777777;
|
230
|
+
}
|
231
|
+
|
232
|
+
blockquote > :first-child {
|
233
|
+
margin-top: 0;
|
234
|
+
}
|
235
|
+
|
236
|
+
blockquote > :last-child {
|
237
|
+
margin-bottom: 0;
|
238
|
+
}
|
239
|
+
|
240
|
+
table {
|
241
|
+
padding: 0;
|
242
|
+
}
|
243
|
+
table tr {
|
244
|
+
border-top: 1px solid #cccccc;
|
245
|
+
background-color: white;
|
246
|
+
margin: 0;
|
247
|
+
padding: 0;
|
248
|
+
}
|
249
|
+
|
250
|
+
table tr:nth-child(2n) {
|
251
|
+
background-color: #f8f8f8;
|
252
|
+
}
|
253
|
+
|
254
|
+
table tr th {
|
255
|
+
font-weight: bold;
|
256
|
+
border: 1px solid #cccccc;
|
257
|
+
text-align: left;
|
258
|
+
margin: 0;
|
259
|
+
padding: 6px 13px;
|
260
|
+
}
|
261
|
+
|
262
|
+
table tr td {
|
263
|
+
border: 1px solid #cccccc;
|
264
|
+
text-align: left;
|
265
|
+
margin: 0;
|
266
|
+
padding: 6px 13px;
|
267
|
+
}
|
268
|
+
|
269
|
+
table tr th :first-child, table tr td :first-child {
|
270
|
+
margin-top: 0;
|
271
|
+
}
|
272
|
+
|
273
|
+
table tr th :last-child, table tr td :last-child {
|
274
|
+
margin-bottom: 0;
|
275
|
+
}
|
276
|
+
|
277
|
+
img {
|
278
|
+
max-width: 100%;
|
279
|
+
}
|
280
|
+
|
281
|
+
span.frame {
|
282
|
+
display: block;
|
283
|
+
overflow: hidden;
|
284
|
+
}
|
285
|
+
|
286
|
+
span.frame > span {
|
287
|
+
border: 1px solid #dddddd;
|
288
|
+
display: block;
|
289
|
+
float: left;
|
290
|
+
overflow: hidden;
|
291
|
+
margin: 13px 0 0;
|
292
|
+
padding: 7px;
|
293
|
+
width: auto;
|
294
|
+
}
|
295
|
+
|
296
|
+
span.frame span img {
|
297
|
+
display: block;
|
298
|
+
float: left;
|
299
|
+
}
|
300
|
+
|
301
|
+
span.frame span span {
|
302
|
+
clear: both;
|
303
|
+
color: #333333;
|
304
|
+
display: block;
|
305
|
+
padding: 5px 0 0;
|
306
|
+
}
|
307
|
+
|
308
|
+
span.align-center {
|
309
|
+
display: block;
|
310
|
+
overflow: hidden;
|
311
|
+
clear: both;
|
312
|
+
}
|
313
|
+
|
314
|
+
span.align-center > span {
|
315
|
+
display: block;
|
316
|
+
overflow: hidden;
|
317
|
+
margin: 13px auto 0;
|
318
|
+
text-align: center;
|
319
|
+
}
|
320
|
+
|
321
|
+
span.align-center span img {
|
322
|
+
margin: 0 auto;
|
323
|
+
text-align: center;
|
324
|
+
}
|
325
|
+
|
326
|
+
span.align-right {
|
327
|
+
display: block;
|
328
|
+
overflow: hidden;
|
329
|
+
clear: both;
|
330
|
+
}
|
331
|
+
|
332
|
+
span.align-right > span {
|
333
|
+
display: block;
|
334
|
+
overflow: hidden;
|
335
|
+
margin: 13px 0 0;
|
336
|
+
text-align: right;
|
337
|
+
}
|
338
|
+
|
339
|
+
span.align-right span img {
|
340
|
+
margin: 0;
|
341
|
+
text-align: right;
|
342
|
+
}
|
343
|
+
|
344
|
+
span.float-left {
|
345
|
+
display: block;
|
346
|
+
margin-right: 13px;
|
347
|
+
overflow: hidden;
|
348
|
+
float: left;
|
349
|
+
}
|
350
|
+
|
351
|
+
span.float-left span {
|
352
|
+
margin: 13px 0 0;
|
353
|
+
}
|
354
|
+
|
355
|
+
span.float-right {
|
356
|
+
display: block;
|
357
|
+
margin-left: 13px;
|
358
|
+
overflow: hidden;
|
359
|
+
float: right;
|
360
|
+
}
|
361
|
+
|
362
|
+
span.float-right > span {
|
363
|
+
display: block;
|
364
|
+
overflow: hidden;
|
365
|
+
margin: 13px auto 0;
|
366
|
+
text-align: right;
|
367
|
+
}
|
368
|
+
|
369
|
+
code, tt {
|
370
|
+
margin: 0 2px;
|
371
|
+
padding: 0 5px;
|
372
|
+
white-space: nowrap;
|
373
|
+
border: 1px solid #eaeaea;
|
374
|
+
background-color: #f8f8f8;
|
375
|
+
border-radius: 3px;
|
376
|
+
}
|
377
|
+
|
378
|
+
pre code {
|
379
|
+
margin: 0;
|
380
|
+
padding: 0;
|
381
|
+
white-space: pre;
|
382
|
+
border: none;
|
383
|
+
background: transparent;
|
384
|
+
}
|
385
|
+
|
386
|
+
.highlight pre {
|
387
|
+
background-color: #f8f8f8;
|
388
|
+
border: 1px solid #cccccc;
|
389
|
+
font-size: 13px;
|
390
|
+
line-height: 19px;
|
391
|
+
overflow: auto;
|
392
|
+
padding: 6px 10px;
|
393
|
+
border-radius: 3px;
|
394
|
+
}
|
395
|
+
|
396
|
+
pre {
|
397
|
+
background-color: #f8f8f8;
|
398
|
+
border: 1px solid #cccccc;
|
399
|
+
font-size: 13px;
|
400
|
+
line-height: 19px;
|
401
|
+
overflow: auto;
|
402
|
+
padding: 6px 10px;
|
403
|
+
border-radius: 3px;
|
404
|
+
}
|
405
|
+
|
406
|
+
pre code, pre tt {
|
407
|
+
background-color: transparent;
|
408
|
+
border: none;
|
409
|
+
}
|
data/lib/shellopts.rb
CHANGED
@@ -12,6 +12,18 @@ require 'shellopts/utils.rb'
|
|
12
12
|
# name of the program
|
13
13
|
#
|
14
14
|
module ShellOpts
|
15
|
+
# Return the hidden +ShellOpts::ShellOpts+ object (see .process)
|
16
|
+
def self.shellopts()
|
17
|
+
@shellopts
|
18
|
+
end
|
19
|
+
|
20
|
+
# Prettified usage string used by #error and #fail. Default is +usage+ of
|
21
|
+
# the current +ShellOpts::ShellOpts+ object
|
22
|
+
def self.usage() @usage || @shellopts&.usage end
|
23
|
+
|
24
|
+
# Set the usage string
|
25
|
+
def self.usage=(usage) @usage = usage end
|
26
|
+
|
15
27
|
# Process command line options and arguments. #process takes a usage string
|
16
28
|
# defining the options and the array of command line arguments to be parsed
|
17
29
|
# as arguments
|
@@ -72,14 +84,16 @@ module ShellOpts
|
|
72
84
|
# #process saves a hidden {ShellOpts::ShellOpts} class variable used by the
|
73
85
|
# class methods #error and #fail. Call #reset to clear the global object if
|
74
86
|
# you really need to parse more than one command line. Alternatively you can
|
75
|
-
# create +ShellOpts::ShellOpts+ objects yourself and use the object methods
|
76
|
-
# #error and #fail
|
87
|
+
# create +ShellOpts::ShellOpts+ objects yourself and also use the object methods
|
88
|
+
# #error and #fail:
|
77
89
|
#
|
78
90
|
# shellopts = ShellOpts::ShellOpts.new(USAGE, ARGS)
|
79
91
|
# shellopts.each { |name, value| ... }
|
80
92
|
# shellopts.args.each { |arg| ... }
|
81
93
|
# shellopts.error("Something went wrong")
|
82
94
|
#
|
95
|
+
# Use #shellopts to get the hidden +ShellOpts::ShellOpts+ object
|
96
|
+
#
|
83
97
|
def self.process(usage, argv, program_name: PROGRAM, &block)
|
84
98
|
if !block_given?
|
85
99
|
ShellOpts.new(usage, argv, program_name: program_name)
|
@@ -95,15 +109,20 @@ module ShellOpts
|
|
95
109
|
# another command line
|
96
110
|
def self.reset()
|
97
111
|
@shellopts = nil
|
112
|
+
@usage = nil
|
98
113
|
end
|
99
114
|
|
100
115
|
# Print error message and usage string and exit with status 1. It use the
|
101
116
|
# current ShellOpts object if defined. This method should be called in
|
102
117
|
# response to user-errors (eg. specifying an illegal option)
|
118
|
+
#
|
119
|
+
# If there is no current ShellOpts object +error+ will look for USAGE to make
|
120
|
+
# it possible to use +error+ before the command line is processed and also as
|
121
|
+
# a stand-alone error reporting method
|
103
122
|
def self.error(*msgs)
|
104
123
|
program = @shellopts&.program_name || PROGRAM
|
105
|
-
|
106
|
-
emit_and_exit(program, usage, *msgs)
|
124
|
+
usage_string = usage || (defined?(USAGE) && USAGE ? Grammar.compile(PROGRAM, USAGE).usage : nil)
|
125
|
+
emit_and_exit(program, @usage.nil?, usage_string, *msgs)
|
107
126
|
end
|
108
127
|
|
109
128
|
# Print error message and exit with status 1. It use the current ShellOpts
|
@@ -111,7 +130,7 @@ module ShellOpts
|
|
111
130
|
# user-errors but system errors (like disk full)
|
112
131
|
def self.fail(*msgs)
|
113
132
|
program = @shellopts&.program_name || PROGRAM
|
114
|
-
emit_and_exit(program, nil, *msgs)
|
133
|
+
emit_and_exit(program, false, nil, *msgs)
|
115
134
|
end
|
116
135
|
|
117
136
|
# The compilation object
|
@@ -119,7 +138,7 @@ module ShellOpts
|
|
119
138
|
# Name of program
|
120
139
|
attr_reader :program_name
|
121
140
|
|
122
|
-
#
|
141
|
+
# Prettified usage string used by #error and #fail. Shorthand for +grammar.usage+
|
123
142
|
def usage() @grammar.usage end
|
124
143
|
|
125
144
|
# The grammar compiled from the usage string. If #ast is defined, it's
|
@@ -172,13 +191,13 @@ module ShellOpts
|
|
172
191
|
# should be called in response to user-errors (eg. specifying an illegal
|
173
192
|
# option)
|
174
193
|
def error(*msgs)
|
175
|
-
::ShellOpts.emit_and_exit(program_name, usage, msgs)
|
194
|
+
::ShellOpts.emit_and_exit(program_name, true, usage, msgs)
|
176
195
|
end
|
177
196
|
|
178
197
|
# Print error message and exit with status 1. This method should not be
|
179
198
|
# called in response to user-errors but system errors (like disk full)
|
180
199
|
def fail(*msgs)
|
181
|
-
::ShellOpts.emit_and_exit(program_name, nil, msgs)
|
200
|
+
::ShellOpts.emit_and_exit(program_name, false, nil, msgs)
|
182
201
|
end
|
183
202
|
end
|
184
203
|
|
@@ -199,9 +218,13 @@ module ShellOpts
|
|
199
218
|
private
|
200
219
|
@shellopts = nil
|
201
220
|
|
202
|
-
def self.emit_and_exit(program, usage, *msgs)
|
221
|
+
def self.emit_and_exit(program, use_usage, usage, *msgs)
|
203
222
|
$stderr.puts "#{program}: #{msgs.join}"
|
204
|
-
|
223
|
+
if use_usage
|
224
|
+
$stderr.puts "Usage: #{program} #{usage}" if usage
|
225
|
+
else
|
226
|
+
$stderr.puts usage if usage
|
227
|
+
end
|
205
228
|
exit 1
|
206
229
|
end
|
207
230
|
end
|
data/lib/shellopts/version.rb
CHANGED
data/shellopts.gemspec
CHANGED
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
33
33
|
spec.require_paths = ["lib"]
|
34
34
|
|
35
|
-
spec.add_development_dependency "bundler", "~>
|
35
|
+
spec.add_development_dependency "bundler", "~> 2.2.10"
|
36
36
|
spec.add_development_dependency "rake", ">= 12.3.3"
|
37
37
|
spec.add_development_dependency "rspec", "~> 3.0"
|
38
38
|
spec.add_development_dependency "indented_io"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shellopts
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Claus Rasmussen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-08-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 2.2.10
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 2.2.10
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -103,6 +103,7 @@ files:
|
|
103
103
|
- bin/console
|
104
104
|
- bin/mkdoc
|
105
105
|
- bin/setup
|
106
|
+
- doc/stylesheet.css
|
106
107
|
- lib/ext/array.rb
|
107
108
|
- lib/shellopts.rb
|
108
109
|
- lib/shellopts/ast/command.rb
|
@@ -137,8 +138,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
137
138
|
- !ruby/object:Gem::Version
|
138
139
|
version: '0'
|
139
140
|
requirements: []
|
140
|
-
|
141
|
-
rubygems_version: 2.7.6
|
141
|
+
rubygems_version: 3.0.8
|
142
142
|
signing_key:
|
143
143
|
specification_version: 4
|
144
144
|
summary: Parse command line options and arguments
|