shellopts 0.9.4 → 2.0.0.pre.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 405cc16b5b116eaecfbbf6bc3e7896b473380d710de246fe1d0db8957a0b37ad
4
- data.tar.gz: f455be9f739a91cd3c809670985509a92d91115e92475a7d2c3d4fb46cf22a90
3
+ metadata.gz: e60db3cf5de50dcd106cb0fca007d064e18354278a65207bb167bf8aa63d3433
4
+ data.tar.gz: 85b0108262357d6e5654e725ab12293f51fd2579beb13fa0d910be2200c32310
5
5
  SHA512:
6
- metadata.gz: d148291a8658490359f0e9b4515e384f955bcb95ea81d88965dc6659bd3d6d0c7c46d07772ca7c77470a3e3b5e1b7b0261281d322670fdce90738a992d1ce3e8
7
- data.tar.gz: da6f42af8a1cea71f2f75600200bffbb6c2f3859375cc19ddac137639b1019db7a830723089a419c0266deb3f2b6f4aa5753070b2e8626fe72cf0bd5d5bba5a8
6
+ metadata.gz: 375fe97651622560d786b288217e1a8581d12bbc497dee55b36848597d9410d393a127e86088cfe4ac8f949270d9f6797d6f135f65492f15bb9d4a84bff1ffbc
7
+ data.tar.gz: c69a813e4672d87c6a4da69e0e8086d8acfe54c8506cda64ce6dc36dbc12669cc79c29ffd480c6871937d87491139f4e7448fd35a6d6a7d333451addd6c634a6
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
@@ -346,6 +378,16 @@ release a new version, update the version number in `version.rb`, and then run
346
378
  git commits and tags, and push the `.gem` file to
347
379
  [rubygems.org](https://rubygems.org).
348
380
 
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
+
349
391
  ## Contributing
350
392
 
351
393
  Bug reports and pull requests are welcome on GitHub at
data/TODO CHANGED
@@ -1,5 +1,31 @@
1
1
 
2
2
  TODO
3
+ o Add validation block to ShellOpts class methods
4
+ o Get rid of key_name. Define #name on Grammar::Node instead
5
+ o Define #name to the string name of the option/command without prefixed '--'
6
+ for options. This can cause collisions but they can be avoided using aliases
7
+ o Clean-up
8
+ o Grammar::options -> Grammar::option_multihash
9
+ o Clean-up identifiers etc.
10
+ o Un-multi-izing Grammar::option_multihash and turn it into a regular hash from key to option
11
+ o subcommand vs. command consistency
12
+ o Implement ObjectStruct#key! and ObjectStruct#value! (?)
13
+ o Allow command_alias == nil to suppress the method
14
+ o Raise on non-existing names/keys. Only return nil for declared names/keys that are not present
15
+ o Use hash_tree
16
+ o Also allow assignment to usage string for ShellOpts::ShellOpts objects
17
+ o Create a ShellOpts.args method? It would be useful when processing commands:
18
+ case opt
19
+ when "command"
20
+ call_command_method(ShellOpts.args[1], ShellOpts.args[2])
21
+ end
22
+ ShellOpts.args would be a shorthand for ShellOpts.shellopts.args
23
+ Another option would be to create an argument-processing method:
24
+ shellopts.argv(2) -> call error if not exactly two arguments else return elements
25
+ o Add a ShellOpts.option method:
26
+ file = ShellOpts.option("--file")
27
+ This will only work for options on the outermost level... maybe:
28
+ file = ShellOpts.option("load! --file")
3
29
  o Check on return value from #process block to see if all options was handled:
4
30
  case opt
5
31
  when '-v'; verbose = true # Return value 'true' is ok
@@ -11,7 +37,7 @@ TODO
11
37
  o Make an official dump method for debug
12
38
  o Make a note that all options are processed at once and not as-you-go
13
39
  o Test that arguments with spaces work
14
- o Long version usage strings
40
+ o Long version usage strings (major release)
15
41
  o Doc: Example of processing of sub-commands and sub-sub-commands
16
42
 
17
43
  + More tests
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
@@ -2,208 +2,145 @@ require "shellopts/version"
2
2
 
3
3
  require 'shellopts/compiler.rb'
4
4
  require 'shellopts/parser.rb'
5
+ require 'shellopts/generator.rb'
6
+ require 'shellopts/option_struct.rb'
7
+ require 'shellopts/messenger.rb'
5
8
  require 'shellopts/utils.rb'
6
9
 
7
- # ShellOpts is a library for parsing command line options and sub-commands. The
8
- # library API consists of the methods {ShellOpts.process}, {ShellOpts.error},
9
- # and {ShellOpts.fail} and the result class {ShellOpts::ShellOpts}
10
+ # Name of program. Defined as the basename of the program file
11
+ PROGRAM = File.basename($PROGRAM_NAME)
12
+
13
+ # ShellOpts main Module
14
+ #
15
+ # This module contains methods to process command line options and arguments.
16
+ # ShellOpts keeps a reference in ShellOpts.shellopts to the result of the last
17
+ # command that was processed through its interface and use it as the implicit
18
+ # object of many of its methods. This matches the typical use case where only
19
+ # one command line is ever processed and makes it possible to create class
20
+ # methods that knows about the command like #error and #fail
21
+ #
22
+ # For example; the following process and convert a command line into a struct
23
+ # representation and also sets ShellOpts.shellopts object so that the #error
24
+ # method can print a relevant usage string:
25
+ #
26
+ # USAGE = "a,all f,file=FILE -- ARG1 ARG2"
27
+ # opts, args = ShellOpts.as_struct(USAGE, ARGV)
28
+ # File.exist?(opts.file) or error "Can't find #{opts.file}"
29
+ #
30
+ # The command line is processed through one of the methods #process, #as_array,
31
+ # #as_hash, or #as_struct that returns a [data, args] tuple. The data type
32
+ # depends on the method: #process yields a Idr object that internally serves as
33
+ # the base for the #as_array and #as_hash and #as_struct that converts it into
34
+ # an Array, Hash, or ShellOpts::OptionStruct object. For example:
35
+ #
36
+ # USAGE = "..."
37
+ # ShellOpts.process(USAGE, ARGV)
38
+ # program, args = ShellOpts.as_program(USAGE, ARGV)
39
+ # array, args = ShellOpts.as_array(USAGE, ARGV)
40
+ # hash, args = ShellOpts.as_hash(USAGE, ARGV)
41
+ # struct, args = ShellOpts.as_struct(USAGE, ARGV)
10
42
  #
11
- # ShellOpts inject the constant PROGRAM into the global scope. It contains the
43
+ # ShellOpts can raise the exception CompilerError is there is an error in the
44
+ # USAGE string. If there is an error in the user supplied command line, #error
45
+ # is called instead and the program terminates with exit code 1. ShellOpts
46
+ # raises ConversionError is there is a name collision when converting to the
47
+ # hash or struct representations. Note that CompilerError and ConversionError
48
+ # are caused by misuse of the library and the problem should be corrected by
49
+ # the developer
50
+ #
51
+ # ShellOpts injects the constant PROGRAM into the global scope. It contains the
12
52
  # name of the program
13
53
  #
14
54
  module ShellOpts
15
- # Process command line options and arguments. #process takes a usage string
16
- # defining the options and the array of command line arguments to be parsed
17
- # as arguments
18
- #
19
- # If called with a block, the block is called with name and value of each
20
- # option or command and #process returns a list of remaining command line
21
- # arguments. If called without a block a ShellOpts::ShellOpts object is
22
- # returned
23
- #
24
- # The value of an option is its argument, the value of a command is an array
25
- # of name/value pairs of options and subcommands. Option values are converted
26
- # to the target type (String, Integer, Float) if specified
27
- #
28
- # Example
29
- #
30
- # # Define options
31
- # USAGE = 'a,all g,global +v,verbose h,help save! snapshot f,file=FILE h,help'
32
- #
33
- # # Define defaults
34
- # all = false
35
- # global = false
36
- # verbose = 0
37
- # save = false
38
- # snapshot = false
39
- # file = nil
40
- #
41
- # # Process options
42
- # argv = ShellOpts.process(USAGE, ARGV) do |name, value|
43
- # case name
44
- # when '-a', '--all'; all = true
45
- # when '-g', '--global'; global = value
46
- # when '-v', '--verbose'; verbose += 1
47
- # when '-h', '--help'; print_help(); exit(0)
48
- # when 'save'
49
- # save = true
50
- # value.each do |name, value|
51
- # case name
52
- # when '--snapshot'; snapshot = true
53
- # when '-f', '--file'; file = value
54
- # when '-h', '--help'; print_save_help(); exit(0)
55
- # end
56
- # end
57
- # else
58
- # raise "Not a user error. The developer forgot or misspelled an option"
59
- # end
60
- # end
61
- #
62
- # # Process remaining arguments
63
- # argv.each { |arg| ... }
64
- #
65
- # If an error is encountered while compiling the usage string, a
66
- # +ShellOpts::Compiler+ exception is raised. If the error happens while
67
- # parsing the command line arguments, the program prints an error message and
68
- # exits with status 1. Failed assertions raise a +ShellOpts::InternalError+
69
- # exception
70
- #
71
- # Note that you can't process more than one command line at a time because
72
- # #process saves a hidden {ShellOpts::ShellOpts} class variable used by the
73
- # class methods #error and #fail. Call #reset to clear the global object if
74
- # 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:
77
- #
78
- # shellopts = ShellOpts::ShellOpts.new(USAGE, ARGS)
79
- # shellopts.each { |name, value| ... }
80
- # shellopts.args.each { |arg| ... }
81
- # shellopts.error("Something went wrong")
82
- #
83
- def self.process(usage, argv, program_name: PROGRAM, &block)
84
- if !block_given?
85
- ShellOpts.new(usage, argv, program_name: program_name)
86
- else
87
- @shellopts.nil? or raise InternalError, "ShellOpts class variable already initialized"
88
- @shellopts = ShellOpts.new(usage, argv, program_name: program_name)
89
- @shellopts.each(&block)
90
- @shellopts.args
55
+ # Base class for ShellOpts exceptions
56
+ class Error < RuntimeError; end
57
+
58
+ # Raised when a syntax error is detected in the usage string
59
+ class CompilerError < Error
60
+ def initialize(start, message)
61
+ super(message)
62
+ set_backtrace(caller(start))
91
63
  end
92
64
  end
93
65
 
94
- # Reset the hidden +ShellOpts::ShellOpts+ class variable so that you can process
95
- # another command line
96
- def self.reset()
97
- @shellopts = nil
98
- end
66
+ # Raised when an error is detected during conversion from the Idr to array,
67
+ # hash, or struct
68
+ class ConversionError < Error; end
99
69
 
100
- # Print error message and usage string and exit with status 1. It use the
101
- # current ShellOpts object if defined. This method should be called in
102
- # response to user-errors (eg. specifying an illegal option)
103
- def self.error(*msgs)
104
- 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)
107
- end
70
+ # Raised when an internal error is detected
71
+ class InternalError < Error; end
108
72
 
109
- # Print error message and exit with status 1. It use the current ShellOpts
110
- # object if defined. This method should not be called in response to
111
- # user-errors but system errors (like disk full)
112
- def self.fail(*msgs)
113
- program = @shellopts&.program_name || PROGRAM
114
- emit_and_exit(program, nil, *msgs)
115
- end
73
+ # The current compilation object. It is set by #process
74
+ def self.shellopts() @shellopts end
116
75
 
117
- # The compilation object
118
- class ShellOpts
119
- # Name of program
120
- attr_reader :program_name
121
-
122
- # Usage string. Shorthand for +grammar.usage+
123
- def usage() @grammar.usage end
124
-
125
- # The grammar compiled from the usage string. If #ast is defined, it's
126
- # equal to ast.grammar
127
- attr_reader :grammar
128
-
129
- # The AST resulting from parsing the command line arguments
130
- attr_reader :ast
131
-
132
- # List of remaining non-option command line arguments. Shorthand for ast.arguments
133
- def args() @ast.arguments end
134
-
135
- # Compile a usage string into a grammar and use that to parse command line
136
- # arguments
137
- #
138
- # +usage+ is the usage string, and +argv+ the command line (typically the
139
- # global ARGV array). +program_name+ is the name of the program and is
140
- # used in error messages. It defaults to the basename of the program
141
- #
142
- # Errors in the usage string raise a CompilerError exception. Errors in the
143
- # argv arguments terminates the program with an error message
144
- def initialize(usage, argv, program_name: File.basename($0))
145
- @program_name = program_name
146
- begin
147
- @grammar = Grammar.compile(program_name, usage)
148
- @ast = Ast.parse(@grammar, argv)
149
- rescue Grammar::Compiler::Error => ex
150
- raise CompilerError.new(5, ex.message)
151
- rescue Ast::Parser::Error => ex
152
- error(ex.message)
153
- end
154
- end
76
+ # Process command line and set and return the shellopts compile object
77
+ def self.process(usage, argv, name: self.name, message: nil)
78
+ @shellopts.nil? or reset
79
+ messenger = message && Messenger.new(name, message, format: :custom)
80
+ @shellopts = ShellOpts.new(usage, argv, name: name, messenger: messenger)
81
+ end
155
82
 
156
- # Unroll the AST into a nested array
157
- def to_a
158
- @ast.values
159
- end
83
+ # Return the internal data representation of the command line (Idr::Program).
84
+ # Note that #as_program that the remaning arguments are accessible through
85
+ # the returned object
86
+ def self.as_program(usage, argv, name: self.name, message: nil)
87
+ process(usage, argv, name: name, message: message)
88
+ [shellopts.idr, shellopts.args]
89
+ end
160
90
 
161
- # Iterate the result as name/value pairs. See {ShellOpts.process} for a
162
- # detailed description
163
- def each(&block)
164
- if block_given?
165
- to_a.each { |*args| yield(*args) }
166
- else
167
- to_a # FIXME: Iterator
168
- end
169
- end
91
+ # Process command line, set current shellopts object, and return a [array, argv]
92
+ # tuple. Returns the representation of the current object if not given any
93
+ # arguments
94
+ def self.as_array(usage, argv, name: self.name, message: nil)
95
+ process(usage, argv, name: name, message: message)
96
+ [shellopts.to_a, shellopts.args]
97
+ end
170
98
 
171
- # Print error message and usage string and exit with status 1. This method
172
- # should be called in response to user-errors (eg. specifying an illegal
173
- # option)
174
- def error(*msgs)
175
- ::ShellOpts.emit_and_exit(program_name, usage, msgs)
176
- end
99
+ # Process command line, set current shellopts object, and return a [hash, argv]
100
+ # tuple. Returns the representation of the current object if not given any
101
+ # arguments
102
+ def self.as_hash(usage, argv, name: self.name, message: nil, use: ShellOpts::DEFAULT_USE, aliases: {})
103
+ process(usage, argv, name: name, message: message)
104
+ [shellopts.to_hash(use: use, aliases: aliases), shellopts.args]
105
+ end
177
106
 
178
- # Print error message and exit with status 1. This method should not be
179
- # called in response to user-errors but system errors (like disk full)
180
- def fail(*msgs)
181
- ::ShellOpts.emit_and_exit(program_name, nil, msgs)
182
- end
107
+ # Process command line, set current shellopts object, and return a [struct, argv]
108
+ # tuple. Returns the representation of the current object if not given any
109
+ # arguments
110
+ def self.as_struct(usage, argv, name: self.name, message: nil, use: ShellOpts::DEFAULT_USE, aliases: {})
111
+ process(usage, argv, name: name, message: message)
112
+ [shellopts.to_struct(use: use, aliases: aliases), shellopts.args]
183
113
  end
184
114
 
185
- # Base class for ShellOpts exceptions
186
- class Error < RuntimeError; end
115
+ # Process command line, set current shellopts object, and then iterate
116
+ # options and commands as an array. Returns an enumerator to the array
117
+ # representation of the current shellopts object if not given a block
118
+ # argument
119
+ def self.each(usage = nil, argv = nil, name: self.name, message: nil, &block)
120
+ process(usage, argv, name: name, message: message)
121
+ shellopts.each(&block)
122
+ end
187
123
 
188
- # Raised when an error is detected in the usage string
189
- class CompilerError < Error
190
- def initialize(start, message)
191
- super(message)
192
- set_backtrace(caller(start))
193
- end
124
+ # Print error message and usage string and exit with status 1. This method
125
+ # should be called in response to user-errors (eg. specifying an illegal
126
+ # option)
127
+ def self.error(*msgs)
128
+ raise "Oops" if shellopts.nil?
129
+ shellopts.error(*msgs)
194
130
  end
195
131
 
196
- # Raised when an internal error is detected
197
- class InternalError < Error; end
132
+ # Print error message and exit with status 1. This method should not be
133
+ # called in response to system errors (eg. disk full)
134
+ def self.fail(*msgs)
135
+ raise "Oops" if shellopts.nil?
136
+ shellopts.fail(*msgs)
137
+ end
198
138
 
199
139
  private
200
- @shellopts = nil
201
-
202
- def self.emit_and_exit(program, usage, *msgs)
203
- $stderr.puts "#{program}: #{msgs.join}"
204
- $stderr.puts "Usage: #{program} #{usage}" if usage
205
- exit 1
140
+ # Reset state variables
141
+ def self.reset()
142
+ @shellopts = nil
206
143
  end
207
- end
208
144
 
209
- PROGRAM = File.basename($PROGRAM_NAME)
145
+ @shellopts = nil
146
+ end