bel 0.3.0-x86-mingw32 → 0.3.1-x86-mingw32

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