shellopts 0.9.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 35b358de39fe1966b1f9ad95dd2e92b296e86f122439a0e69d9ca3367005e279
4
- data.tar.gz: 6080ae9b374490c0a39f70a440b65e80a711756646997e2589d059c627c9c12a
3
+ metadata.gz: 4cc3c3ef5b7b13876949b290b9d247c41778eaa38ea01432d5abac47b663478a
4
+ data.tar.gz: bc2c44f163f81d8b51545679e8f8280ac889fbb1f96a7898e5a65fa63d337d4a
5
5
  SHA512:
6
- metadata.gz: 7ac618dcd5a918827b7a57dd8b462352f8f464e844428eac60aabd5c3cca220a89898f3bd1f4abf7e5d8f8dbac9bfb46dfd22c8a1d4baf300683fc2ccbe24630
7
- data.tar.gz: a278e013c2a8e2ec673c4dc8ebb0198a8060e71164a5b3d3d68f48ec5f56009b1d2589f5f069855d640e7c76f50fe7493ea21e2118c331803e1e0ef003e83178
6
+ metadata.gz: d3c501335a899e4b14280cbb14b7f9e8a0d9ef28715760394d8f13ea837d0a5d3d9b91b9d07dcb42a747753e97a10c157ae5c5b20b95804b1746e0ebad7d88c9
7
+ data.tar.gz: 387c888158bbbebe127c6efde55c7bbb14436b7dcb8227cac38e2c9dac85e9a3d956c062e04b86101e28fa0bde4977fefadad4d1a643dd48d9218e5c04558ad2
data/.gitignore CHANGED
@@ -2,6 +2,7 @@
2
2
  /.yardoc
3
3
  /_yardoc/
4
4
  /doc/
5
+ /rdoc/
5
6
  /pkg/
6
7
  /spec/reports/
7
8
  /tmp/
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 `-a` and `--all` that are aliases
11
- for the same option, `--count` that may be given an integer argument but
12
- defaults to 42, `--file` that has a mandatory argument, and `-v` and
13
- `--verbose` that can be repeated to increase the verbosity level
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
- require 'shellopts'
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 that to
54
- parse the command line. If given a block, the block is called with a name/value
55
- pair for each option or command and return a list of the remaining non-option
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, val| ... } # Access options
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,val|
198
+ args = ShellOpts.process(USAGE, ARGV) { |opt, arg|
188
199
  case opt
189
200
  when '-a'; # Handle -a
190
201
  when 'cmd'
191
- opt.each { |opt, val|
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, val|
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 = val
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,12 +1,27 @@
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
+
13
+ o Check on return value from #process block to see if all options was handled:
14
+ case opt
15
+ when '-v'; verbose = true # Return value 'true' is ok
16
+ # Unhandled option means return value is nil
17
+ end
3
18
  o Consolidate some of the 3 variations of #error and #fail
4
19
  o Add a option flag for solitary options (--help)
5
20
  o Make a #to_yaml
6
21
  o Make an official dump method for debug
7
22
  o Make a note that all options are processed at once and not as-you-go
8
23
  o Test that arguments with spaces work
9
- o Long version usage strings
24
+ o Long version usage strings (major release)
10
25
  o Doc: Example of processing of sub-commands and sub-sub-commands
11
26
 
12
27
  + More tests
@@ -55,6 +70,7 @@ LATER
55
70
  o Escape of separator in lists
56
71
  o Handle output of subcommand usage like "cmd1 cmd1.cmd2 cmd2"
57
72
  o Command-specific arguments: clone! o,opt ++ ARG1 ARG2...
73
+ o Hostname and email as basic types
58
74
 
59
75
  ON TO_H BRANCH
60
76
  ShellOpts.process(usage, argv) { |opt,val| ... } => args
data/bin/mkdoc CHANGED
@@ -1,10 +1,15 @@
1
1
  #!/usr/bin/bash
2
2
 
3
- LINK='<link rel="stylesheet" type="text/css" href="stylesheet.css">'
3
+ set -e
4
4
 
5
- {
6
- echo $LINK
7
- pandoc README.md
8
- } >index.html
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 lib
14
+ # Generate rdoc
15
+ rdoc --output=rdoc --force-output lib
@@ -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 instead:
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
- usage = @shellopts&.usage || (defined?(USAGE) && USAGE ? Grammar.compile(PROGRAM, USAGE).usage : nil)
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
- # Usage string. Shorthand for +grammar.usage+
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
- $stderr.puts "Usage: #{program} #{usage}" if usage
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
@@ -27,7 +27,7 @@ module ShellOpts
27
27
 
28
28
  # Initialize a Compiler object. source is the option definition string
29
29
  def initialize(program_name, source)
30
- @program_name, @tokens = program_name, source.split(/\s+/)
30
+ @program_name, @tokens = program_name, source.split(/\s+/).reject(&:empty?)
31
31
 
32
32
  # @commands_by_path is an hash from command-path to Command or Program
33
33
  # object. The top level Program object has nil as its path.
@@ -1,3 +1,3 @@
1
1
  module Shellopts
2
- VERSION = "0.9.3"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -33,7 +33,7 @@ Gem::Specification.new do |spec|
33
33
  spec.require_paths = ["lib"]
34
34
 
35
35
  spec.add_development_dependency "bundler", "~> 1.16"
36
- spec.add_development_dependency "rake", "~> 10.0"
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"
39
39
  spec.add_development_dependency "simplecov"
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.9.3
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Claus Rasmussen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-10-30 00:00:00.000000000 Z
11
+ date: 2020-07-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: 12.3.3
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: 12.3.3
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  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
- rubyforge_project:
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