shellopts 0.9.4 → 2.0.0.pre.1

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