shellopts 2.0.18 → 2.0.19

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: 43a4d96ef2927b72add380e17e0dad25b2004659491a5dc4adb36f3c9965c8c9
4
- data.tar.gz: 507780f5ea40771db0ffbc4d0247b9f8f5d08044953dc0c387e92432c42879df
3
+ metadata.gz: 35b9e7b5699cc1a5637d4c00dd95c74047074f1227b0d05f9a9c8b04e1e2cc8b
4
+ data.tar.gz: c8deed23c8e6f0b26d080e15d2830edb5e65d1b5f2f821ccd83db7db27d7aefd
5
5
  SHA512:
6
- metadata.gz: d57c4a7245f5c22b74c762d986b8a80ca331643a3f32f63421f08f412da01e3f6e21c76e0fe1921fa8337ad2cbc168e00bb9f722f3ebfc1fdb7468619169658d
7
- data.tar.gz: 4ab7b06dd787db06af9ca0d70f6d44a26e251707badef5beecdb3bb719a3fc1bebf5357f00df2702589f4ea6960ebc6af83329adadc3e65bd2746e3dbb536fca
6
+ metadata.gz: 5d3e96ec825ca58c0e653613ab84e2ede3e661737f5699571c81aaf9b2cb1252ea802581e5b981a1757d8a5a750ba998c43730c6d2da7d8228b721b06a45640e
7
+ data.tar.gz: e64eeac4c3bf784f8ef3a5e3a61c596e262bd23c4ee05857f76138f82ff2180afb72ccd5c2b7ffedc4e6aa2887b10c76e3a80c33e24ceadd20e71513549b5bf0
@@ -72,7 +72,7 @@ module ShellOpts
72
72
  # Note that the analyzer fails with an an error if both --with-separator
73
73
  # and --with_separator are used because they would both map to
74
74
  # :with_separator
75
- attr_reader :ident
75
+ attr_accessor :ident
76
76
 
77
77
  # Canonical name (String) of the object
78
78
  #
@@ -23,7 +23,7 @@ module ShellOpts
23
23
  end
24
24
 
25
25
  class Option
26
- SHORT_NAME_RE = /[a-zA-Z0-9]/
26
+ SHORT_NAME_RE = /[a-zA-Z0-9?]/
27
27
  LONG_NAME_RE = /[a-zA-Z0-9][a-zA-Z0-9_-]*/
28
28
  NAME_RE = /(?:#{SHORT_NAME_RE}|#{LONG_NAME_RE})(?:,#{LONG_NAME_RE})*/
29
29
 
@@ -124,23 +124,18 @@ module ShellOpts
124
124
  super(nil, token)
125
125
  end
126
126
 
127
- def add_version_option
128
- option_token = Token.new(:option, 1, 1, "--version")
129
- brief_token = Token.new(:brief, 1, 1, "Write version number and exit")
127
+ def inject_option(decl, brief, paragraph = nil, &block)
128
+ option_token = Token.new(:option, 1, 1, decl)
129
+ brief_token = Token.new(:brief, 1, 1, brief)
130
130
  group = OptionGroup.new(self, option_token)
131
131
  option = Option.parse(group, option_token)
132
132
  brief = Brief.parse(group, brief_token)
133
- end
134
-
135
- def add_help_options
136
- option_token = Token.new(:option, 1, 1, "-h,help")
137
- brief_token = Token.new(:brief, 1, 1, "Write help text and exit")
138
- paragraph_token = Token.new(:text, 1, 1,
139
- "-h prints a brief help text, --help prints a longer man-style description of the command")
140
- group = OptionGroup.new(self, option_token)
141
- option = Option.parse(group, option_token)
142
- brief = Brief.parse(group, brief_token)
143
- paragraph = Paragraph.parse(group, paragraph_token)
133
+ paragraph ||= yield(option) if block_given?
134
+ if paragraph
135
+ paragraph_token = Token.new(:text, 1, 1, paragraph)
136
+ paragraph = Paragraph.parse(group, paragraph_token)
137
+ end
138
+ option
144
139
  end
145
140
  end
146
141
 
@@ -297,6 +297,18 @@ module ShellOpts
297
297
 
298
298
  # The top-level command
299
299
  class Program < Command
300
+ # Accessors for standard options values that are not affected if the option
301
+ # is renamed
302
+ attr_accessor :__quiet__
303
+ attr_accessor :__verbose__
304
+ attr_accessor :__debug__
305
+
306
+ def initialize
307
+ super
308
+ @__quiet__ = false
309
+ @__verbose__ = 0
310
+ @__debug__ = false
311
+ end
300
312
  end
301
313
 
302
314
  # Option models an option as given by the user on the subcommand line.
@@ -1,3 +1,3 @@
1
1
  module ShellOpts
2
- VERSION = "2.0.18"
2
+ VERSION = "2.0.19"
3
3
  end
data/lib/shellopts.rb CHANGED
@@ -96,17 +96,20 @@ module ShellOpts
96
96
  # Automatically add a -h and a --help option if true
97
97
  attr_reader :help
98
98
 
99
- # Version of client program. If not nil a --version option is added to the program
100
- def version
101
- return @version if @version
102
- exe = caller.find { |line| line =~ /`<top \(required\)>'$/ }&.sub(/:.*/, "")
103
- file = Dir.glob(File.dirname(exe) + "/../lib/*/version.rb").first
104
- @version = IO.read(file).sub(/^.*VERSION\s*=\s*"(.*?)".*$/m, '\1') or
105
- raise ArgumentError, "ShellOpts needs an explicit version"
106
- end
99
+ # Version of client program. If not nil, a --version option is added to the program
100
+ attr_reader :version
101
+
102
+ # Automatically add a -q and a --quiet option if true
103
+ attr_reader :quiet
107
104
 
108
- # Add message options (TODO)
109
- attr_accessor :msgopts
105
+ # Automatically add a -v and a --verbose option if true
106
+ attr_reader :verbose
107
+
108
+ # Automatically add a --debug option if true
109
+ attr_reader :debug
110
+
111
+ # Version number (this is usually detected dynamically)
112
+ attr_reader :version_number
110
113
 
111
114
  # Floating options
112
115
  attr_accessor :float
@@ -122,12 +125,33 @@ module ShellOpts
122
125
  attr_reader :tokens
123
126
  alias_method :ast, :grammar
124
127
 
125
- def initialize(name: nil, help: true, version: true, msgopts: false, float: true, exception: false)
128
+ def initialize(name: nil,
129
+ # Options
130
+ help: true,
131
+ version: true,
132
+ quiet: nil,
133
+ verbose: nil,
134
+ debug: nil,
135
+
136
+ # Version number (usually detected)
137
+ version_number: nil,
138
+
139
+ # Floating options
140
+ float: true,
141
+
142
+ # Let exceptions through
143
+ exceptions: false
144
+ )
145
+
126
146
  @name = name || File.basename($PROGRAM_NAME)
127
147
  @help = help
128
- @use_version = version ? true : false
129
- @version = @use_version && @version != true ? @version : nil
130
- @msgopts, @float, @exception = msgopts, float, exception
148
+ @version = version || (version.nil? && !version_number.nil?)
149
+ @quiet = quiet
150
+ @verbose = verbose
151
+ @debug = debug
152
+ @version_number = version_number || find_version_number
153
+ @float = float
154
+ @exception = exception
131
155
  end
132
156
 
133
157
  # Compile source and return grammar object. Also sets #spec and #grammar.
@@ -139,8 +163,31 @@ module ShellOpts
139
163
  @file = find_caller_file
140
164
  @tokens = Lexer.lex(name, @spec, @oneline)
141
165
  ast = Parser.parse(tokens)
142
- ast.add_version_option if @use_version
143
- ast.add_help_options if @help
166
+
167
+ help_spec = (@help == true ? "-h,help" : @help)
168
+ version_spec = (@version == true ? "--version" : @version)
169
+ quiet_spec = (@quiet == true ? "-q,quiet" : @quiet)
170
+ verbose_spec = (@verbose == true ? "+v,verbose" : @verbose)
171
+ debug_spec = (@debug == true ? "--debug" : @debug)
172
+
173
+ @quiet_option =
174
+ ast.inject_option(quiet_spec, "Quiet", "Do not write anything to standard output") if @quiet
175
+ @verbose_option =
176
+ ast.inject_option(verbose_spec, "Increase verbosity", "Write verbose output") if @verbose
177
+ @debug_option =
178
+ ast.inject_option(debug_spec, "Write debug information") if @debug
179
+ @help_option =
180
+ ast.inject_option(help_spec, "Write short or long help") { |option|
181
+ short_option = option.short_names.first
182
+ long_option = option.long_names.first
183
+ [
184
+ short_option && "#{short_option} prints a brief help text",
185
+ long_option && "#{long_option} prints a longer man-style description of the command"
186
+ ].compact.join(", ")
187
+ } if @help
188
+ @version_option =
189
+ ast.inject_option(version_spec, "Write version number and exit") if @version
190
+
144
191
  @grammar = Analyzer.analyze(ast)
145
192
  }
146
193
  self
@@ -153,16 +200,22 @@ module ShellOpts
153
200
  handle_exceptions {
154
201
  @argv = argv.dup
155
202
  @program, @args = Interpreter.interpret(grammar, argv, float: float, exception: exception)
156
- if @program.version?
157
- puts version
158
- exit
159
- elsif @program.help?
160
- if @program[:help].name == "-h"
161
- ShellOpts.brief
162
- else
203
+
204
+ # Process standard options (that may have been renamed)
205
+ if @program.__send__(:"#{@help_option.ident}?")
206
+ if @program[:help].name =~ /^--/
163
207
  ShellOpts.help
208
+ else
209
+ ShellOpts.brief
164
210
  end
165
211
  exit
212
+ elsif @program.__send__(:"#{@version_option.ident}?")
213
+ puts version_number
214
+ exit
215
+ else
216
+ @program.__quiet__ = @program.__send__(:"#{@quiet_option.ident}?") if @quiet
217
+ @program.__verbose__ = @program.__send__(:"#{@verbose_option.ident}") if @verbose
218
+ @program.__debug__ = @program.__send__(:"#{@debug_option.ident}?") if @debug
166
219
  end
167
220
  }
168
221
  self
@@ -235,6 +288,13 @@ module ShellOpts
235
288
  def self.help(subject = nil) ::ShellOpts.instance.help(subject) end
236
289
 
237
290
  private
291
+ def find_version_number
292
+ exe = caller.find { |line| line =~ /`<top \(required\)>'$/ }&.sub(/:.*/, "") or return nil
293
+ file = Dir.glob(File.dirname(exe) + "/../lib/*/version.rb").first or return nil
294
+ IO.read(file).sub(/^.*VERSION\s*=\s*"(.*?)".*$/m, '\1') or
295
+ raise ArgumentError, "ShellOpts needs an explicit version"
296
+ end
297
+
238
298
  def handle_exceptions(&block)
239
299
  return yield if exception
240
300
  begin
@@ -322,9 +382,13 @@ module ShellOpts
322
382
  end
323
383
  end
324
384
 
325
- def self.process(spec, argv, msgopts: false, **opts)
326
- msgopts ||= Messages.is_included?
327
- ShellOpts.process(spec, argv, msgopts: msgopts, **opts)
385
+
386
+ def self.process(spec, argv, quiet: nil, verbose: nil, debug: nil, **opts)
387
+ constrain quiet, String, true, false, nil
388
+ quiet = quiet.nil? ? Message.is_included? || Verbose.is_included? : quiet
389
+ verbose = verbose.nil? ? ::ShellOpts::Verbose.is_included? : verbose
390
+ debug = debug.nil? ? Debug.is_included? : debug
391
+ ShellOpts.process(spec, argv, quiet: quiet, verbose: verbose, debug: debug, **opts)
328
392
  end
329
393
 
330
394
  @instance = nil
@@ -345,31 +409,57 @@ module ShellOpts
345
409
  exit 1
346
410
  end
347
411
 
348
- # The Include module brings the reporting methods into the namespace when
349
- # included
350
- module Messages
412
+ def self.notice(message)
413
+ $stderr.puts "#{instance.program.__grammar__.name}: #{message}" \
414
+ if !instance.quiet || !instance.program.quiet?
415
+ end
416
+
417
+ def self.mesg(message)
418
+ $stdout.puts message if !instance.quiet || !instance.program.__quiet__
419
+ end
420
+
421
+ def self.verb(level = 1, message)
422
+ $stdout.puts message if instance.verbose && level <= instance.program.__verbose__
423
+ end
424
+
425
+ def self.debug(message)
426
+ $stdout.puts message if instance.debug && instance.program.__debug__
427
+ end
428
+
429
+ def self.quiet_flag
430
+ end
431
+
432
+ def self.verbose_flag
433
+ end
434
+
435
+ def self.debug_flag
436
+ end
437
+
438
+ module Message
351
439
  @is_included = false
352
440
  def self.is_included?() @is_included end
353
- def self.include(...)
354
- @is_included = true
355
- super
356
- end
441
+ def self.included(...) @is_included = true; super end
357
442
 
358
- def notice(message)
359
- $stderr.puts "#{name}: #{message}" if !quiet?
360
- end
443
+ def notice(message) ::ShellOpts.notice(message) end
444
+ def mesg(message) ::ShellOpts.mesg(message) end
445
+ end
361
446
 
362
- def mesg(message)
363
- $stdout.puts message if !quiet?
364
- end
447
+ module Verbose
448
+ @is_included = false
449
+ def self.is_included?() @is_included end
450
+ def self.included(...) @is_included = true; super end
365
451
 
366
- def verb(level = 1, message)
367
- $stdout.puts message if level <= @verbose
368
- end
452
+ def notice(message) ::ShellOpts.notice(message) end
453
+ def mesg(message) ::ShellOpts.mesg(message) end
454
+ def verb(level = 1, message) ::ShellOpts.verb(level, message) end
455
+ end
369
456
 
370
- def debug(message)
371
- $stdout.puts message if debug?
372
- end
457
+ module Debug
458
+ @is_included = false
459
+ def self.is_included?() @is_included end
460
+ def self.included(...) @is_included = true; super end
461
+
462
+ def debug(message) ::ShellOpts.debug(message) end
373
463
  end
374
464
 
375
465
  module ErrorHandling