shellopts 0.9.5 → 2.0.0.pre.2

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: 12f6d1397c2a4ae0a4e8c168f1d695f25ade753c37f94e8b4373ce57aa222593
4
- data.tar.gz: 9589f39de24f13c5d5bf6ae873b58d425cc393654362e9afa7699c5d7dd81a46
3
+ metadata.gz: 79a36712cf9c41a500726cd042d9932f1c6ed7f7e7a334d5d245e0ad31185c75
4
+ data.tar.gz: ddeec0f65a4d8e4250cbc9d1332626395c135d0c4e34d879fafcfb89b492699a
5
5
  SHA512:
6
- metadata.gz: 577ab3793305b1eeee0b3fca253832603fbeaf4d34a511e11a7625aa356b1031e17116213c055cb5672821e524d8c34409398a1209bc3cdade7a53fded96d87f
7
- data.tar.gz: bcadf1a3c495a6bda0863e42c40ef82744abc2fbe401a57286c335b62cc4e50f51ddf76847d2c360fae08f51120f3fbcd4538076e6527f5d379bd5828978f9b7
6
+ metadata.gz: 2890ba5f277385eb8cc30a9e168d618f3633278cc41066c302ed82d7be46eeefb5a30f41a2471947bc78a0e55e8219cc472887a91b9d753a6687dfda605231e6
7
+ data.tar.gz: a02ecb6e6613163f2915125ea0cd71cab30c7fd3c11f840a99bad0cb27b6a14dad0b3c806d55f8ab752e4f7921731cab0753c562499b7c88eeb8e5e8400efaab
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,34 @@
1
1
 
2
2
  TODO
3
+ o Remove ! from OptionStruct#subcommand return value. We know we're
4
+ processing commands so there is no need to have a distinct name and it
5
+ feels a lot more intuitive without it
6
+ o Add validation block to ShellOpts class methods
7
+ o Get rid of key_name. Define #name on Grammar::Node instead
8
+ o Define #name to the string name of the option/command without prefixed '--'
9
+ for options. This can cause collisions but they can be avoided using aliases
10
+ o Clean-up
11
+ o Grammar::options -> Grammar::option_multihash
12
+ o Clean-up identifiers etc.
13
+ o Un-multi-izing Grammar::option_multihash and turn it into a regular hash from key to option
14
+ o subcommand vs. command consistency
15
+ o Implement ObjectStruct#key! and ObjectStruct#value! (?)
16
+ o Allow command_alias == nil to suppress the method
17
+ o Raise on non-existing names/keys. Only return nil for declared names/keys that are not present
18
+ o Use hash_tree
19
+ o Also allow assignment to usage string for ShellOpts::ShellOpts objects
20
+ o Create a ShellOpts.args method? It would be useful when processing commands:
21
+ case opt
22
+ when "command"
23
+ call_command_method(ShellOpts.args[1], ShellOpts.args[2])
24
+ end
25
+ ShellOpts.args would be a shorthand for ShellOpts.shellopts.args
26
+ Another option would be to create an argument-processing method:
27
+ shellopts.argv(2) -> call error if not exactly two arguments else return elements
28
+ o Add a ShellOpts.option method:
29
+ file = ShellOpts.option("--file")
30
+ This will only work for options on the outermost level... maybe:
31
+ file = ShellOpts.option("load! --file")
3
32
  o Check on return value from #process block to see if all options was handled:
4
33
  case opt
5
34
  when '-v'; verbose = true # Return value 'true' is ok
@@ -11,7 +40,7 @@ TODO
11
40
  o Make an official dump method for debug
12
41
  o Make a note that all options are processed at once and not as-you-go
13
42
  o Test that arguments with spaces work
14
- o Long version usage strings
43
+ o Long version usage strings (major release)
15
44
  o Doc: Example of processing of sub-commands and sub-sub-commands
16
45
 
17
46
  + 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,148 @@ 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
+ # +args+ is a ShellOpts::Argv object containing the the remaning command line
44
+ # arguments. Argv is derived from Array
45
+ #
46
+ # ShellOpts can raise the exception CompilerError is there is an error in the
47
+ # USAGE string. If there is an error in the user supplied command line, #error
48
+ # is called instead and the program terminates with exit code 1. ShellOpts
49
+ # raises ConversionError is there is a name collision when converting to the
50
+ # hash or struct representations. Note that CompilerError and ConversionError
51
+ # are caused by misuse of the library and the problem should be corrected by
52
+ # the developer
53
+ #
54
+ # ShellOpts injects the constant PROGRAM into the global scope. It contains the
12
55
  # name of the program
13
56
  #
14
57
  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
58
+ # Base class for ShellOpts exceptions
59
+ class Error < RuntimeError; end
60
+
61
+ # Raised when a syntax error is detected in the usage string
62
+ class CompilerError < Error
63
+ def initialize(start, message)
64
+ super(message)
65
+ set_backtrace(caller(start))
91
66
  end
92
67
  end
93
68
 
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
69
+ # Raised when an error is detected during conversion from the Idr to array,
70
+ # hash, or struct
71
+ class ConversionError < Error; end
99
72
 
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
73
+ # Raised when an internal error is detected
74
+ class InternalError < Error; end
108
75
 
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
76
+ # The current compilation object. It is set by #process
77
+ def self.shellopts() @shellopts end
116
78
 
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
79
+ # Process command line and set and return the shellopts compile object
80
+ def self.process(usage, argv, name: self.name, message: nil)
81
+ @shellopts.nil? or reset
82
+ messenger = message && Messenger.new(name, message, format: :custom)
83
+ @shellopts = ShellOpts.new(usage, argv, name: name, messenger: messenger)
84
+ end
155
85
 
156
- # Unroll the AST into a nested array
157
- def to_a
158
- @ast.values
159
- end
86
+ # Return the internal data representation of the command line (Idr::Program).
87
+ # Note that #as_program that the remaning arguments are accessible through
88
+ # the returned object
89
+ def self.as_program(usage, argv, name: self.name, message: nil)
90
+ process(usage, argv, name: name, message: message)
91
+ [shellopts.idr, shellopts.args]
92
+ end
160
93
 
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
94
+ # Process command line, set current shellopts object, and return a [array, argv]
95
+ # tuple. Returns the representation of the current object if not given any
96
+ # arguments
97
+ def self.as_array(usage, argv, name: self.name, message: nil)
98
+ process(usage, argv, name: name, message: message)
99
+ [shellopts.to_a, shellopts.args]
100
+ end
170
101
 
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
102
+ # Process command line, set current shellopts object, and return a [hash, argv]
103
+ # tuple. Returns the representation of the current object if not given any
104
+ # arguments
105
+ def self.as_hash(usage, argv, name: self.name, message: nil, use: ShellOpts::DEFAULT_USE, aliases: {})
106
+ process(usage, argv, name: name, message: message)
107
+ [shellopts.to_hash(use: use, aliases: aliases), shellopts.args]
108
+ end
177
109
 
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
110
+ # Process command line, set current shellopts object, and return a [struct, argv]
111
+ # tuple. Returns the representation of the current object if not given any
112
+ # arguments
113
+ def self.as_struct(usage, argv, name: self.name, message: nil, use: ShellOpts::DEFAULT_USE, aliases: {})
114
+ process(usage, argv, name: name, message: message)
115
+ [shellopts.to_struct(use: use, aliases: aliases), shellopts.args]
183
116
  end
184
117
 
185
- # Base class for ShellOpts exceptions
186
- class Error < RuntimeError; end
118
+ # Process command line, set current shellopts object, and then iterate
119
+ # options and commands as an array. Returns an enumerator to the array
120
+ # representation of the current shellopts object if not given a block
121
+ # argument
122
+ def self.each(usage = nil, argv = nil, name: self.name, message: nil, &block)
123
+ process(usage, argv, name: name, message: message)
124
+ shellopts.each(&block)
125
+ end
187
126
 
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
127
+ # Print error message and usage string and exit with status 1. This method
128
+ # should be called in response to user-errors (eg. specifying an illegal
129
+ # option)
130
+ def self.error(*msgs)
131
+ raise "Oops" if shellopts.nil?
132
+ shellopts.error(*msgs)
194
133
  end
195
134
 
196
- # Raised when an internal error is detected
197
- class InternalError < Error; end
135
+ # Print error message and exit with status 1. This method should not be
136
+ # called in response to system errors (eg. disk full)
137
+ def self.fail(*msgs)
138
+ raise "Oops" if shellopts.nil?
139
+ shellopts.fail(*msgs)
140
+ end
198
141
 
199
142
  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
143
+ # Reset state variables
144
+ def self.reset()
145
+ @shellopts = nil
206
146
  end
207
- end
208
147
 
209
- PROGRAM = File.basename($PROGRAM_NAME)
148
+ @shellopts = nil
149
+ end