kajiki 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -22,13 +22,13 @@ module Kajiki
22
22
  def self.preset_options(preset, options = {})
23
23
  case preset
24
24
  when :minimal
25
- Trollop.options do
25
+ Optimist.options do
26
26
  banner OPT_DESCS[:banner]
27
27
  opt :daemonize, OPT_DESCS[:daemonize]
28
28
  opt :pid, OPT_DESCS[:pid], type: :string
29
29
  end
30
30
  when :simple
31
- Trollop.options do
31
+ Optimist.options do
32
32
  banner OPT_DESCS[:banner]
33
33
  opt :config, OPT_DESCS[:config], type: :string if options[:config]
34
34
  opt :daemonize, OPT_DESCS[:daemonize]
@@ -40,7 +40,7 @@ module Kajiki
40
40
  depends(:user, :group) unless options[:user] == false
41
41
  end
42
42
  when :server
43
- Trollop.options do
43
+ Optimist.options do
44
44
  banner OPT_DESCS[:banner]
45
45
  opt :address, OPT_DESCS[:address], default: '0.0.0.0'
46
46
  opt :config, OPT_DESCS[:config], type: :string if options[:config]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kajiki
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ken J.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-17 00:00:00.000000000 Z
11
+ date: 2020-01-13 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A simple gem to build daemons
14
14
  email:
@@ -22,9 +22,9 @@ files:
22
22
  - kajiki.gemspec
23
23
  - lib/kajiki.rb
24
24
  - lib/kajiki/handler.rb
25
+ - lib/kajiki/optimist.rb
25
26
  - lib/kajiki/presets.rb
26
27
  - lib/kajiki/runner.rb
27
- - lib/kajiki/trollop.rb
28
28
  homepage: https://github.com/kenjij/kajiki
29
29
  licenses:
30
30
  - MIT
@@ -35,19 +35,17 @@ require_paths:
35
35
  - lib
36
36
  required_ruby_version: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  required_rubygems_version: !ruby/object:Gem::Requirement
42
42
  requirements:
43
- - - '>='
43
+ - - ">="
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
46
  requirements: []
47
- rubyforge_project:
48
- rubygems_version: 2.4.6
47
+ rubygems_version: 3.0.6
49
48
  signing_key:
50
49
  specification_version: 4
51
50
  summary: A simple Ruby gem to ease building daemons.
52
51
  test_files: []
53
- has_rdoc:
@@ -1,846 +0,0 @@
1
- # lib/trollop.rb -- trollop command-line processing library
2
- # Copyright (c) 2008-2014 William Morgan.
3
- # Copyright (c) 2014 Red Hat, Inc.
4
- # trollop is licensed under the same terms as Ruby.
5
-
6
- require 'date'
7
-
8
- module Trollop
9
- VERSION = "2.1.1"
10
-
11
- ## Thrown by Parser in the event of a commandline error. Not needed if
12
- ## you're using the Trollop::options entry.
13
- class CommandlineError < StandardError; end
14
-
15
- ## Thrown by Parser if the user passes in '-h' or '--help'. Handled
16
- ## automatically by Trollop#options.
17
- class HelpNeeded < StandardError; end
18
-
19
- ## Thrown by Parser if the user passes in '-v' or '--version'. Handled
20
- ## automatically by Trollop#options.
21
- class VersionNeeded < StandardError; end
22
-
23
- ## Regex for floating point numbers
24
- FLOAT_RE = /^-?((\d+(\.\d+)?)|(\.\d+))([eE][-+]?[\d]+)?$/
25
-
26
- ## Regex for parameters
27
- PARAM_RE = /^-(-|\.$|[^\d\.])/
28
-
29
- ## The commandline parser. In typical usage, the methods in this class
30
- ## will be handled internally by Trollop::options. In this case, only the
31
- ## #opt, #banner and #version, #depends, and #conflicts methods will
32
- ## typically be called.
33
- ##
34
- ## If you want to instantiate this class yourself (for more complicated
35
- ## argument-parsing logic), call #parse to actually produce the output hash,
36
- ## and consider calling it from within
37
- ## Trollop::with_standard_exception_handling.
38
- class Parser
39
-
40
- ## The set of values that indicate a flag option when passed as the
41
- ## +:type+ parameter of #opt.
42
- FLAG_TYPES = [:flag, :bool, :boolean]
43
-
44
- ## The set of values that indicate a single-parameter (normal) option when
45
- ## passed as the +:type+ parameter of #opt.
46
- ##
47
- ## A value of +io+ corresponds to a readable IO resource, including
48
- ## a filename, URI, or the strings 'stdin' or '-'.
49
- SINGLE_ARG_TYPES = [:int, :integer, :string, :double, :float, :io, :date]
50
-
51
- ## The set of values that indicate a multiple-parameter option (i.e., that
52
- ## takes multiple space-separated values on the commandline) when passed as
53
- ## the +:type+ parameter of #opt.
54
- MULTI_ARG_TYPES = [:ints, :integers, :strings, :doubles, :floats, :ios, :dates]
55
-
56
- ## The complete set of legal values for the +:type+ parameter of #opt.
57
- TYPES = FLAG_TYPES + SINGLE_ARG_TYPES + MULTI_ARG_TYPES
58
-
59
- INVALID_SHORT_ARG_REGEX = /[\d-]/ #:nodoc:
60
-
61
- ## The values from the commandline that were not interpreted by #parse.
62
- attr_reader :leftovers
63
-
64
- ## The complete configuration hashes for each option. (Mainly useful
65
- ## for testing.)
66
- attr_reader :specs
67
-
68
- ## A flag that determines whether or not to raise an error if the parser is passed one or more
69
- ## options that were not registered ahead of time. If 'true', then the parser will simply
70
- ## ignore options that it does not recognize.
71
- attr_accessor :ignore_invalid_options
72
-
73
- ## Initializes the parser, and instance-evaluates any block given.
74
- def initialize *a, &b
75
- @version = nil
76
- @leftovers = []
77
- @specs = {}
78
- @long = {}
79
- @short = {}
80
- @order = []
81
- @constraints = []
82
- @stop_words = []
83
- @stop_on_unknown = false
84
-
85
- #instance_eval(&b) if b # can't take arguments
86
- cloaker(&b).bind(self).call(*a) if b
87
- end
88
-
89
- ## Define an option. +name+ is the option name, a unique identifier
90
- ## for the option that you will use internally, which should be a
91
- ## symbol or a string. +desc+ is a string description which will be
92
- ## displayed in help messages.
93
- ##
94
- ## Takes the following optional arguments:
95
- ##
96
- ## [+:long+] Specify the long form of the argument, i.e. the form with two dashes. If unspecified, will be automatically derived based on the argument name by turning the +name+ option into a string, and replacing any _'s by -'s.
97
- ## [+:short+] Specify the short form of the argument, i.e. the form with one dash. If unspecified, will be automatically derived from +name+.
98
- ## [+:type+] Require that the argument take a parameter or parameters of type +type+. For a single parameter, the value can be a member of +SINGLE_ARG_TYPES+, or a corresponding Ruby class (e.g. +Integer+ for +:int+). For multiple-argument parameters, the value can be any member of +MULTI_ARG_TYPES+ constant. If unset, the default argument type is +:flag+, meaning that the argument does not take a parameter. The specification of +:type+ is not necessary if a +:default+ is given.
99
- ## [+:default+] Set the default value for an argument. Without a default value, the hash returned by #parse (and thus Trollop::options) will have a +nil+ value for this key unless the argument is given on the commandline. The argument type is derived automatically from the class of the default value given, so specifying a +:type+ is not necessary if a +:default+ is given. (But see below for an important caveat when +:multi+: is specified too.) If the argument is a flag, and the default is set to +true+, then if it is specified on the the commandline the value will be +false+.
100
- ## [+:required+] If set to +true+, the argument must be provided on the commandline.
101
- ## [+:multi+] If set to +true+, allows multiple occurrences of the option on the commandline. Otherwise, only a single instance of the option is allowed. (Note that this is different from taking multiple parameters. See below.)
102
- ##
103
- ## Note that there are two types of argument multiplicity: an argument
104
- ## can take multiple values, e.g. "--arg 1 2 3". An argument can also
105
- ## be allowed to occur multiple times, e.g. "--arg 1 --arg 2".
106
- ##
107
- ## Arguments that take multiple values should have a +:type+ parameter
108
- ## drawn from +MULTI_ARG_TYPES+ (e.g. +:strings+), or a +:default:+
109
- ## value of an array of the correct type (e.g. [String]). The
110
- ## value of this argument will be an array of the parameters on the
111
- ## commandline.
112
- ##
113
- ## Arguments that can occur multiple times should be marked with
114
- ## +:multi+ => +true+. The value of this argument will also be an array.
115
- ## In contrast with regular non-multi options, if not specified on
116
- ## the commandline, the default value will be [], not nil.
117
- ##
118
- ## These two attributes can be combined (e.g. +:type+ => +:strings+,
119
- ## +:multi+ => +true+), in which case the value of the argument will be
120
- ## an array of arrays.
121
- ##
122
- ## There's one ambiguous case to be aware of: when +:multi+: is true and a
123
- ## +:default+ is set to an array (of something), it's ambiguous whether this
124
- ## is a multi-value argument as well as a multi-occurrence argument.
125
- ## In thise case, Trollop assumes that it's not a multi-value argument.
126
- ## If you want a multi-value, multi-occurrence argument with a default
127
- ## value, you must specify +:type+ as well.
128
-
129
- def opt name, desc="", opts={}, &b
130
- raise ArgumentError, "you already have an argument named '#{name}'" if @specs.member? name
131
-
132
- ## fill in :type
133
- opts[:type] = # normalize
134
- case opts[:type]
135
- when :boolean, :bool; :flag
136
- when :integer; :int
137
- when :integers; :ints
138
- when :double; :float
139
- when :doubles; :floats
140
- when Class
141
- case opts[:type].name
142
- when 'TrueClass', 'FalseClass'; :flag
143
- when 'String'; :string
144
- when 'Integer'; :int
145
- when 'Float'; :float
146
- when 'IO'; :io
147
- when 'Date'; :date
148
- else
149
- raise ArgumentError, "unsupported argument type '#{opts[:type].class.name}'"
150
- end
151
- when nil; nil
152
- else
153
- raise ArgumentError, "unsupported argument type '#{opts[:type]}'" unless TYPES.include?(opts[:type])
154
- opts[:type]
155
- end
156
-
157
- ## for options with :multi => true, an array default doesn't imply
158
- ## a multi-valued argument. for that you have to specify a :type
159
- ## as well. (this is how we disambiguate an ambiguous situation;
160
- ## see the docs for Parser#opt for details.)
161
- disambiguated_default = if opts[:multi] && opts[:default].is_a?(Array) && !opts[:type]
162
- opts[:default].first
163
- else
164
- opts[:default]
165
- end
166
-
167
- type_from_default =
168
- case disambiguated_default
169
- when Integer; :int
170
- when Numeric; :float
171
- when TrueClass, FalseClass; :flag
172
- when String; :string
173
- when IO; :io
174
- when Date; :date
175
- when Array
176
- if opts[:default].empty?
177
- if opts[:type]
178
- raise ArgumentError, "multiple argument type must be plural" unless MULTI_ARG_TYPES.include?(opts[:type])
179
- nil
180
- else
181
- raise ArgumentError, "multiple argument type cannot be deduced from an empty array for '#{opts[:default][0].class.name}'"
182
- end
183
- else
184
- case opts[:default][0] # the first element determines the types
185
- when Integer; :ints
186
- when Numeric; :floats
187
- when String; :strings
188
- when IO; :ios
189
- when Date; :dates
190
- else
191
- raise ArgumentError, "unsupported multiple argument type '#{opts[:default][0].class.name}'"
192
- end
193
- end
194
- when nil; nil
195
- else
196
- raise ArgumentError, "unsupported argument type '#{opts[:default].class.name}'"
197
- end
198
-
199
- raise ArgumentError, ":type specification and default type don't match (default type is #{type_from_default})" if opts[:type] && type_from_default && opts[:type] != type_from_default
200
-
201
- opts[:type] = opts[:type] || type_from_default || :flag
202
-
203
- ## fill in :long
204
- opts[:long] = opts[:long] ? opts[:long].to_s : name.to_s.gsub("_", "-")
205
- opts[:long] = case opts[:long]
206
- when /^--([^-].*)$/; $1
207
- when /^[^-]/; opts[:long]
208
- else; raise ArgumentError, "invalid long option name #{opts[:long].inspect}"
209
- end
210
- raise ArgumentError, "long option name #{opts[:long].inspect} is already taken; please specify a (different) :long" if @long[opts[:long]]
211
-
212
- ## fill in :short
213
- opts[:short] = opts[:short].to_s if opts[:short] unless opts[:short] == :none
214
- opts[:short] = case opts[:short]
215
- when /^-(.)$/; $1
216
- when nil, :none, /^.$/; opts[:short]
217
- else raise ArgumentError, "invalid short option name '#{opts[:short].inspect}'"
218
- end
219
-
220
- if opts[:short]
221
- raise ArgumentError, "short option name #{opts[:short].inspect} is already taken; please specify a (different) :short" if @short[opts[:short]]
222
- raise ArgumentError, "a short option name can't be a number or a dash" if opts[:short] =~ INVALID_SHORT_ARG_REGEX
223
- end
224
-
225
- ## fill in :default for flags
226
- opts[:default] = false if opts[:type] == :flag && opts[:default].nil?
227
-
228
- ## autobox :default for :multi (multi-occurrence) arguments
229
- opts[:default] = [opts[:default]] if opts[:default] && opts[:multi] && !opts[:default].is_a?(Array)
230
-
231
- ## fill in :multi
232
- opts[:multi] ||= false
233
- opts[:callback] ||= b if block_given?
234
- opts[:desc] ||= desc
235
- @long[opts[:long]] = name
236
- @short[opts[:short]] = name if opts[:short] && opts[:short] != :none
237
- @specs[name] = opts
238
- @order << [:opt, name]
239
- end
240
-
241
- ## Sets the version string. If set, the user can request the version
242
- ## on the commandline. Should probably be of the form "<program name>
243
- ## <version number>".
244
- def version(s = nil); @version = s if s; @version end
245
-
246
- ## Sets the usage string. If set the message will be printed as the
247
- ## first line in the help (educate) output and ending in two new
248
- ## lines.
249
- def usage(s = nil) ; @usage = s if s; @usage end
250
-
251
- ## Adds a synopsis (command summary description) right below the
252
- ## usage line, or as the first line if usage isn't specified.
253
- def synopsis(s = nil) ; @synopsis = s if s; @synopsis end
254
-
255
- ## Adds text to the help display. Can be interspersed with calls to
256
- ## #opt to build a multi-section help page.
257
- def banner s; @order << [:text, s] end
258
- alias :text :banner
259
-
260
- ## Marks two (or more!) options as requiring each other. Only handles
261
- ## undirected (i.e., mutual) dependencies. Directed dependencies are
262
- ## better modeled with Trollop::die.
263
- def depends *syms
264
- syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
265
- @constraints << [:depends, syms]
266
- end
267
-
268
- ## Marks two (or more!) options as conflicting.
269
- def conflicts *syms
270
- syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
271
- @constraints << [:conflicts, syms]
272
- end
273
-
274
- ## Defines a set of words which cause parsing to terminate when
275
- ## encountered, such that any options to the left of the word are
276
- ## parsed as usual, and options to the right of the word are left
277
- ## intact.
278
- ##
279
- ## A typical use case would be for subcommand support, where these
280
- ## would be set to the list of subcommands. A subsequent Trollop
281
- ## invocation would then be used to parse subcommand options, after
282
- ## shifting the subcommand off of ARGV.
283
- def stop_on *words
284
- @stop_words = [*words].flatten
285
- end
286
-
287
- ## Similar to #stop_on, but stops on any unknown word when encountered
288
- ## (unless it is a parameter for an argument). This is useful for
289
- ## cases where you don't know the set of subcommands ahead of time,
290
- ## i.e., without first parsing the global options.
291
- def stop_on_unknown
292
- @stop_on_unknown = true
293
- end
294
-
295
- ## Parses the commandline. Typically called by Trollop::options,
296
- ## but you can call it directly if you need more control.
297
- ##
298
- ## throws CommandlineError, HelpNeeded, and VersionNeeded exceptions.
299
- def parse cmdline=ARGV
300
- vals = {}
301
- required = {}
302
-
303
- opt :version, "Print version and exit" if @version unless @specs[:version] || @long["version"]
304
- opt :help, "Show this message" unless @specs[:help] || @long["help"]
305
-
306
- @specs.each do |sym, opts|
307
- required[sym] = true if opts[:required]
308
- vals[sym] = opts[:default]
309
- vals[sym] = [] if opts[:multi] && !opts[:default] # multi arguments default to [], not nil
310
- end
311
-
312
- resolve_default_short_options!
313
-
314
- ## resolve symbols
315
- given_args = {}
316
- @leftovers = each_arg cmdline do |arg, params|
317
- ## handle --no- forms
318
- arg, negative_given = if arg =~ /^--no-([^-]\S*)$/
319
- ["--#{$1}", true]
320
- else
321
- [arg, false]
322
- end
323
-
324
- sym = case arg
325
- when /^-([^-])$/; @short[$1]
326
- when /^--([^-]\S*)$/; @long[$1] || @long["no-#{$1}"]
327
- else; raise CommandlineError, "invalid argument syntax: '#{arg}'"
328
- end
329
-
330
- sym = nil if arg =~ /--no-/ # explicitly invalidate --no-no- arguments
331
-
332
- unless sym
333
- next 0 if ignore_invalid_options
334
- raise CommandlineError, "unknown argument '#{arg}'" unless sym
335
- end
336
-
337
- if given_args.include?(sym) && !@specs[sym][:multi]
338
- raise CommandlineError, "option '#{arg}' specified multiple times"
339
- end
340
-
341
- given_args[sym] ||= {}
342
- given_args[sym][:arg] = arg
343
- given_args[sym][:negative_given] = negative_given
344
- given_args[sym][:params] ||= []
345
-
346
- # The block returns the number of parameters taken.
347
- num_params_taken = 0
348
-
349
- unless params.nil?
350
- if SINGLE_ARG_TYPES.include?(@specs[sym][:type])
351
- given_args[sym][:params] << params[0, 1] # take the first parameter
352
- num_params_taken = 1
353
- elsif MULTI_ARG_TYPES.include?(@specs[sym][:type])
354
- given_args[sym][:params] << params # take all the parameters
355
- num_params_taken = params.size
356
- end
357
- end
358
-
359
- num_params_taken
360
- end
361
-
362
- ## check for version and help args
363
- raise VersionNeeded if given_args.include? :version
364
- raise HelpNeeded if given_args.include? :help
365
-
366
- ## check constraint satisfaction
367
- @constraints.each do |type, syms|
368
- constraint_sym = syms.find { |sym| given_args[sym] }
369
- next unless constraint_sym
370
-
371
- case type
372
- when :depends
373
- syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym][:long]} requires --#{@specs[sym][:long]}" unless given_args.include? sym }
374
- when :conflicts
375
- syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym][:long]} conflicts with --#{@specs[sym][:long]}" if given_args.include?(sym) && (sym != constraint_sym) }
376
- end
377
- end
378
-
379
- required.each do |sym, val|
380
- raise CommandlineError, "option --#{@specs[sym][:long]} must be specified" unless given_args.include? sym
381
- end
382
-
383
- ## parse parameters
384
- given_args.each do |sym, given_data|
385
- arg, params, negative_given = given_data.values_at :arg, :params, :negative_given
386
-
387
- opts = @specs[sym]
388
- if params.empty? && opts[:type] != :flag
389
- raise CommandlineError, "option '#{arg}' needs a parameter" unless opts[:default]
390
- params << [opts[:default]]
391
- end
392
-
393
- vals["#{sym}_given".intern] = true # mark argument as specified on the commandline
394
-
395
- case opts[:type]
396
- when :flag
397
- vals[sym] = (sym.to_s =~ /^no_/ ? negative_given : !negative_given)
398
- when :int, :ints
399
- vals[sym] = params.map { |pg| pg.map { |p| parse_integer_parameter p, arg } }
400
- when :float, :floats
401
- vals[sym] = params.map { |pg| pg.map { |p| parse_float_parameter p, arg } }
402
- when :string, :strings
403
- vals[sym] = params.map { |pg| pg.map { |p| p.to_s } }
404
- when :io, :ios
405
- vals[sym] = params.map { |pg| pg.map { |p| parse_io_parameter p, arg } }
406
- when :date, :dates
407
- vals[sym] = params.map { |pg| pg.map { |p| parse_date_parameter p, arg } }
408
- end
409
-
410
- if SINGLE_ARG_TYPES.include?(opts[:type])
411
- unless opts[:multi] # single parameter
412
- vals[sym] = vals[sym][0][0]
413
- else # multiple options, each with a single parameter
414
- vals[sym] = vals[sym].map { |p| p[0] }
415
- end
416
- elsif MULTI_ARG_TYPES.include?(opts[:type]) && !opts[:multi]
417
- vals[sym] = vals[sym][0] # single option, with multiple parameters
418
- end
419
- # else: multiple options, with multiple parameters
420
-
421
- opts[:callback].call(vals[sym]) if opts.has_key?(:callback)
422
- end
423
-
424
- ## modify input in place with only those
425
- ## arguments we didn't process
426
- cmdline.clear
427
- @leftovers.each { |l| cmdline << l }
428
-
429
- ## allow openstruct-style accessors
430
- class << vals
431
- def method_missing(m, *args)
432
- self[m] || self[m.to_s]
433
- end
434
- end
435
- vals
436
- end
437
-
438
- def parse_date_parameter param, arg #:nodoc:
439
- begin
440
- begin
441
- require 'chronic'
442
- time = Chronic.parse(param)
443
- rescue NameError
444
- # chronic is not available
445
- end
446
- time ? Date.new(time.year, time.month, time.day) : Date.parse(param)
447
- rescue ArgumentError
448
- raise CommandlineError, "option '#{arg}' needs a date"
449
- end
450
- end
451
-
452
- ## Print the help message to +stream+.
453
- def educate stream=$stdout
454
- width # hack: calculate it now; otherwise we have to be careful not to
455
- # call this unless the cursor's at the beginning of a line.
456
- left = {}
457
- @specs.each do |name, spec|
458
- left[name] =
459
- (spec[:short] && spec[:short] != :none ? "-#{spec[:short]}" : "") +
460
- (spec[:short] && spec[:short] != :none ? ", " : "") + "--#{spec[:long]}" +
461
- case spec[:type]
462
- when :flag; ""
463
- when :int; "=<i>"
464
- when :ints; "=<i+>"
465
- when :string; "=<s>"
466
- when :strings; "=<s+>"
467
- when :float; "=<f>"
468
- when :floats; "=<f+>"
469
- when :io; "=<filename/uri>"
470
- when :ios; "=<filename/uri+>"
471
- when :date; "=<date>"
472
- when :dates; "=<date+>"
473
- end +
474
- (spec[:type] == :flag && spec[:default] ? ", --no-#{spec[:long]}" : "")
475
- end
476
-
477
- leftcol_width = left.values.map { |s| s.length }.max || 0
478
- rightcol_start = leftcol_width + 6 # spaces
479
-
480
- unless @order.size > 0 && @order.first.first == :text
481
- command_name = File.basename($0).gsub(/\.[^.]+$/, '')
482
- stream.puts "Usage: #{command_name} #@usage\n" if @usage
483
- stream.puts "#@synopsis\n" if @synopsis
484
- stream.puts if @usage or @synopsis
485
- stream.puts "#@version\n" if @version
486
- stream.puts "Options:"
487
- end
488
-
489
- @order.each do |what, opt|
490
- if what == :text
491
- stream.puts wrap(opt)
492
- next
493
- end
494
-
495
- spec = @specs[opt]
496
- stream.printf " %-#{leftcol_width}s ", left[opt]
497
- desc = spec[:desc] + begin
498
- default_s = case spec[:default]
499
- when $stdout; "<stdout>"
500
- when $stdin; "<stdin>"
501
- when $stderr; "<stderr>"
502
- when Array
503
- spec[:default].join(", ")
504
- else
505
- spec[:default].to_s
506
- end
507
-
508
- if spec[:default]
509
- if spec[:desc] =~ /\.$/
510
- " (Default: #{default_s})"
511
- else
512
- " (default: #{default_s})"
513
- end
514
- else
515
- ""
516
- end
517
- end
518
- stream.puts wrap(desc, :width => width - rightcol_start - 1, :prefix => rightcol_start)
519
- end
520
- end
521
-
522
- def width #:nodoc:
523
- @width ||= if $stdout.tty?
524
- begin
525
- require 'io/console'
526
- IO.console.winsize.last
527
- rescue LoadError
528
- legacy_width
529
- end
530
- else
531
- 80
532
- end
533
- end
534
-
535
- def legacy_width
536
- # Support for older Rubies where io/console is not available
537
- `tput cols`.to_i
538
- rescue Errno::ENOENT
539
- 80
540
- end
541
- private :legacy_width
542
-
543
- def wrap str, opts={} # :nodoc:
544
- if str == ""
545
- [""]
546
- else
547
- inner = false
548
- str.split("\n").map do |s|
549
- line = wrap_line s, opts.merge(:inner => inner)
550
- inner = true
551
- line
552
- end.flatten
553
- end
554
- end
555
-
556
- ## The per-parser version of Trollop::die (see that for documentation).
557
- def die arg, msg
558
- if msg
559
- $stderr.puts "Error: argument --#{@specs[arg][:long]} #{msg}."
560
- else
561
- $stderr.puts "Error: #{arg}."
562
- end
563
- $stderr.puts "Try --help for help."
564
- exit(-1)
565
- end
566
-
567
- private
568
-
569
- ## yield successive arg, parameter pairs
570
- def each_arg args
571
- remains = []
572
- i = 0
573
-
574
- until i >= args.length
575
- if @stop_words.member? args[i]
576
- remains += args[i .. -1]
577
- return remains
578
- end
579
- case args[i]
580
- when /^--$/ # arg terminator
581
- remains += args[(i + 1) .. -1]
582
- return remains
583
- when /^--(\S+?)=(.*)$/ # long argument with equals
584
- yield "--#{$1}", [$2]
585
- i += 1
586
- when /^--(\S+)$/ # long argument
587
- params = collect_argument_parameters(args, i + 1)
588
- unless params.empty?
589
- num_params_taken = yield args[i], params
590
- unless num_params_taken
591
- if @stop_on_unknown
592
- remains += args[i + 1 .. -1]
593
- return remains
594
- else
595
- remains += params
596
- end
597
- end
598
- i += 1 + num_params_taken
599
- else # long argument no parameter
600
- yield args[i], nil
601
- i += 1
602
- end
603
- when /^-(\S+)$/ # one or more short arguments
604
- shortargs = $1.split(//)
605
- shortargs.each_with_index do |a, j|
606
- if j == (shortargs.length - 1)
607
- params = collect_argument_parameters(args, i + 1)
608
- unless params.empty?
609
- num_params_taken = yield "-#{a}", params
610
- unless num_params_taken
611
- if @stop_on_unknown
612
- remains += args[i + 1 .. -1]
613
- return remains
614
- else
615
- remains += params
616
- end
617
- end
618
- i += 1 + num_params_taken
619
- else # argument no parameter
620
- yield "-#{a}", nil
621
- i += 1
622
- end
623
- else
624
- yield "-#{a}", nil
625
- end
626
- end
627
- else
628
- if @stop_on_unknown
629
- remains += args[i .. -1]
630
- return remains
631
- else
632
- remains << args[i]
633
- i += 1
634
- end
635
- end
636
- end
637
-
638
- remains
639
- end
640
-
641
- def parse_integer_parameter param, arg
642
- raise CommandlineError, "option '#{arg}' needs an integer" unless param =~ /^-?[\d_]+$/
643
- param.to_i
644
- end
645
-
646
- def parse_float_parameter param, arg
647
- raise CommandlineError, "option '#{arg}' needs a floating-point number" unless param =~ FLOAT_RE
648
- param.to_f
649
- end
650
-
651
- def parse_io_parameter param, arg
652
- case param
653
- when /^(stdin|-)$/i; $stdin
654
- else
655
- require 'open-uri'
656
- begin
657
- open param
658
- rescue SystemCallError => e
659
- raise CommandlineError, "file or url for option '#{arg}' cannot be opened: #{e.message}"
660
- end
661
- end
662
- end
663
-
664
- def collect_argument_parameters args, start_at
665
- params = []
666
- pos = start_at
667
- while args[pos] && args[pos] !~ PARAM_RE && !@stop_words.member?(args[pos]) do
668
- params << args[pos]
669
- pos += 1
670
- end
671
- params
672
- end
673
-
674
- def resolve_default_short_options!
675
- @order.each do |type, name|
676
- next unless type == :opt
677
- opts = @specs[name]
678
- next if opts[:short]
679
-
680
- c = opts[:long].split(//).find { |d| d !~ INVALID_SHORT_ARG_REGEX && !@short.member?(d) }
681
- if c # found a character to use
682
- opts[:short] = c
683
- @short[c] = name
684
- end
685
- end
686
- end
687
-
688
- def wrap_line str, opts={}
689
- prefix = opts[:prefix] || 0
690
- width = opts[:width] || (self.width - 1)
691
- start = 0
692
- ret = []
693
- until start > str.length
694
- nextt =
695
- if start + width >= str.length
696
- str.length
697
- else
698
- x = str.rindex(/\s/, start + width)
699
- x = str.index(/\s/, start) if x && x < start
700
- x || str.length
701
- end
702
- ret << ((ret.empty? && !opts[:inner]) ? "" : " " * prefix) + str[start ... nextt]
703
- start = nextt + 1
704
- end
705
- ret
706
- end
707
-
708
- ## instance_eval but with ability to handle block arguments
709
- ## thanks to _why: http://redhanded.hobix.com/inspect/aBlockCostume.html
710
- def cloaker &b
711
- (class << self; self; end).class_eval do
712
- define_method :cloaker_, &b
713
- meth = instance_method :cloaker_
714
- remove_method :cloaker_
715
- meth
716
- end
717
- end
718
- end
719
-
720
- ## The easy, syntactic-sugary entry method into Trollop. Creates a Parser,
721
- ## passes the block to it, then parses +args+ with it, handling any errors or
722
- ## requests for help or version information appropriately (and then exiting).
723
- ## Modifies +args+ in place. Returns a hash of option values.
724
- ##
725
- ## The block passed in should contain zero or more calls to +opt+
726
- ## (Parser#opt), zero or more calls to +text+ (Parser#text), and
727
- ## probably a call to +version+ (Parser#version).
728
- ##
729
- ## The returned block contains a value for every option specified with
730
- ## +opt+. The value will be the value given on the commandline, or the
731
- ## default value if the option was not specified on the commandline. For
732
- ## every option specified on the commandline, a key "<option
733
- ## name>_given" will also be set in the hash.
734
- ##
735
- ## Example:
736
- ##
737
- ## require 'trollop'
738
- ## opts = Trollop::options do
739
- ## opt :monkey, "Use monkey mode" # a flag --monkey, defaulting to false
740
- ## opt :name, "Monkey name", :type => :string # a string --name <s>, defaulting to nil
741
- ## opt :num_limbs, "Number of limbs", :default => 4 # an integer --num-limbs <i>, defaulting to 4
742
- ## end
743
- ##
744
- ## ## if called with no arguments
745
- ## p opts # => {:monkey=>false, :name=>nil, :num_limbs=>4, :help=>false}
746
- ##
747
- ## ## if called with --monkey
748
- ## p opts # => {:monkey=>true, :name=>nil, :num_limbs=>4, :help=>false, :monkey_given=>true}
749
- ##
750
- ## See more examples at http://trollop.rubyforge.org.
751
- def options args=ARGV, *a, &b
752
- @last_parser = Parser.new(*a, &b)
753
- with_standard_exception_handling(@last_parser) { @last_parser.parse args }
754
- end
755
-
756
- ## If Trollop::options doesn't do quite what you want, you can create a Parser
757
- ## object and call Parser#parse on it. That method will throw CommandlineError,
758
- ## HelpNeeded and VersionNeeded exceptions when necessary; if you want to
759
- ## have these handled for you in the standard manner (e.g. show the help
760
- ## and then exit upon an HelpNeeded exception), call your code from within
761
- ## a block passed to this method.
762
- ##
763
- ## Note that this method will call System#exit after handling an exception!
764
- ##
765
- ## Usage example:
766
- ##
767
- ## require 'trollop'
768
- ## p = Trollop::Parser.new do
769
- ## opt :monkey, "Use monkey mode" # a flag --monkey, defaulting to false
770
- ## opt :goat, "Use goat mode", :default => true # a flag --goat, defaulting to true
771
- ## end
772
- ##
773
- ## opts = Trollop::with_standard_exception_handling p do
774
- ## o = p.parse ARGV
775
- ## raise Trollop::HelpNeeded if ARGV.empty? # show help screen
776
- ## o
777
- ## end
778
- ##
779
- ## Requires passing in the parser object.
780
-
781
- def with_standard_exception_handling parser
782
- begin
783
- yield
784
- rescue CommandlineError => e
785
- $stderr.puts "Error: #{e.message}."
786
- $stderr.puts "Try --help for help."
787
- exit(-1)
788
- rescue HelpNeeded
789
- parser.educate
790
- exit
791
- rescue VersionNeeded
792
- puts parser.version
793
- exit
794
- end
795
- end
796
-
797
- ## Informs the user that their usage of 'arg' was wrong, as detailed by
798
- ## 'msg', and dies. Example:
799
- ##
800
- ## options do
801
- ## opt :volume, :default => 0.0
802
- ## end
803
- ##
804
- ## die :volume, "too loud" if opts[:volume] > 10.0
805
- ## die :volume, "too soft" if opts[:volume] < 0.1
806
- ##
807
- ## In the one-argument case, simply print that message, a notice
808
- ## about -h, and die. Example:
809
- ##
810
- ## options do
811
- ## opt :whatever # ...
812
- ## end
813
- ##
814
- ## Trollop::die "need at least one filename" if ARGV.empty?
815
- def die arg, msg=nil
816
- if @last_parser
817
- @last_parser.die arg, msg
818
- else
819
- raise ArgumentError, "Trollop::die can only be called after Trollop::options"
820
- end
821
- end
822
-
823
- ## Displays the help message and dies. Example:
824
- ##
825
- ## options do
826
- ## opt :volume, :default => 0.0
827
- ## banner <<-EOS
828
- ## Usage:
829
- ## #$0 [options] <name>
830
- ## where [options] are:
831
- ## EOS
832
- ## end
833
- ##
834
- ## Trollop::educate if ARGV.empty?
835
- def educate
836
- if @last_parser
837
- @last_parser.educate
838
- exit
839
- else
840
- raise ArgumentError, "Trollop::educate can only be called after Trollop::options"
841
- end
842
- end
843
-
844
- module_function :options, :die, :educate, :with_standard_exception_handling
845
-
846
- end # module