shellopts 0.9.5 → 2.0.0.pre.2

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: 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