robolson-simplesem 0.1.3 → 0.1.4

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.
@@ -0,0 +1,695 @@
1
+ ## lib/trollop.rb -- trollop command-line processing library
2
+ ## Author:: William Morgan (mailto: wmorgan-trollop@masanjin.net)
3
+ ## Copyright:: Copyright 2007 William Morgan
4
+ ## License:: GNU GPL version 2
5
+
6
+ module Trollop
7
+
8
+ VERSION = "1.10.2"
9
+
10
+ ## Thrown by Parser in the event of a commandline error. Not needed if
11
+ ## you're using the Trollop::options entry.
12
+ class CommandlineError < StandardError; end
13
+
14
+ ## Thrown by Parser if the user passes in '-h' or '--help'. Handled
15
+ ## automatically by Trollop#options.
16
+ class HelpNeeded < StandardError; end
17
+
18
+ ## Thrown by Parser if the user passes in '-h' or '--version'. Handled
19
+ ## automatically by Trollop#options.
20
+ class VersionNeeded < StandardError; end
21
+
22
+ ## Regex for floating point numbers
23
+ FLOAT_RE = /^-?((\d+(\.\d+)?)|(\.\d+))$/
24
+
25
+ ## Regex for parameters
26
+ PARAM_RE = /^-(-|\.$|[^\d\.])/
27
+
28
+ ## The commandline parser. In typical usage, the methods in this class
29
+ ## will be handled internally by Trollop::options. In this case, only the
30
+ ## #opt, #banner and #version, #depends, and #conflicts methods will
31
+ ## typically be called.
32
+ ##
33
+ ## If it's necessary to instantiate this class (for more complicated
34
+ ## argument-parsing situations), be sure to call #parse to actually
35
+ ## produce the output hash.
36
+ class Parser
37
+
38
+ ## The set of values that indicate a flag option when passed as the
39
+ ## +:type+ parameter of #opt.
40
+ FLAG_TYPES = [:flag, :bool, :boolean]
41
+
42
+ ## The set of values that indicate a single-parameter option when
43
+ ## passed as the +:type+ parameter of #opt.
44
+ ##
45
+ ## A value of +io+ corresponds to a readable IO resource, including
46
+ ## a filename, URI, or the strings 'stdin' or '-'.
47
+ SINGLE_ARG_TYPES = [:int, :integer, :string, :double, :float, :io]
48
+
49
+ ## The set of values that indicate a multiple-parameter option when
50
+ ## passed as the +:type+ parameter of #opt.
51
+ MULTI_ARG_TYPES = [:ints, :integers, :strings, :doubles, :floats, :ios]
52
+
53
+ ## The complete set of legal values for the +:type+ parameter of #opt.
54
+ TYPES = FLAG_TYPES + SINGLE_ARG_TYPES + MULTI_ARG_TYPES
55
+
56
+ INVALID_SHORT_ARG_REGEX = /[\d-]/ #:nodoc:
57
+
58
+ ## The values from the commandline that were not interpreted by #parse.
59
+ attr_reader :leftovers
60
+
61
+ ## The complete configuration hashes for each option. (Mainly useful
62
+ ## for testing.)
63
+ attr_reader :specs
64
+
65
+ ## Initializes the parser, and instance-evaluates any block given.
66
+ def initialize *a, &b
67
+ @version = nil
68
+ @leftovers = []
69
+ @specs = {}
70
+ @long = {}
71
+ @short = {}
72
+ @order = []
73
+ @constraints = []
74
+ @stop_words = []
75
+ @stop_on_unknown = false
76
+
77
+ #instance_eval(&b) if b # can't take arguments
78
+ cloaker(&b).bind(self).call(*a) if b
79
+ end
80
+
81
+ ## Define an option. +name+ is the option name, a unique identifier
82
+ ## for the option that you will use internally, which should be a
83
+ ## symbol or a string. +desc+ is a string description which will be
84
+ ## displayed in help messages.
85
+ ##
86
+ ## Takes the following optional arguments:
87
+ ##
88
+ ## [+: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.
89
+ ## [+:short+] Specify the short form of the argument, i.e. the form with one dash. If unspecified, will be automatically derived from +name+.
90
+ ## [+: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.
91
+ ## [+: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+.
92
+ ## [+:required+] If set to +true+, the argument must be provided on the commandline.
93
+ ## [+: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.)
94
+ ##
95
+ ## Note that there are two types of argument multiplicity: an argument
96
+ ## can take multiple values, e.g. "--arg 1 2 3". An argument can also
97
+ ## be allowed to occur multiple times, e.g. "--arg 1 --arg 2".
98
+ ##
99
+ ## Arguments that take multiple values should have a +:type+ parameter
100
+ ## drawn from +MULTI_ARG_TYPES+ (e.g. +:strings+), or a +:default:+
101
+ ## value of an array of the correct type (e.g. [String]). The
102
+ ## value of this argument will be an array of the parameters on the
103
+ ## commandline.
104
+ ##
105
+ ## Arguments that can occur multiple times should be marked with
106
+ ## +:multi+ => +true+. The value of this argument will also be an array.
107
+ ##
108
+ ## These two attributes can be combined (e.g. +:type+ => +:strings+,
109
+ ## +:multi+ => +true+), in which case the value of the argument will be
110
+ ## an array of arrays.
111
+ ##
112
+ ## There's one ambiguous case to be aware of: when +:multi+: is true and a
113
+ ## +:default+ is set to an array (of something), it's ambiguous whether this
114
+ ## is a multi-value argument as well as a multi-occurrence argument.
115
+ ## In thise case, Trollop assumes that it's not a multi-value argument.
116
+ ## If you want a multi-value, multi-occurrence argument with a default
117
+ ## value, you must specify +:type+ as well.
118
+
119
+ def opt name, desc="", opts={}
120
+ raise ArgumentError, "you already have an argument named '#{name}'" if @specs.member? name
121
+
122
+ ## fill in :type
123
+ opts[:type] = # normalize
124
+ case opts[:type]
125
+ when :boolean, :bool; :flag
126
+ when :integer; :int
127
+ when :integers; :ints
128
+ when :double; :float
129
+ when :doubles; :floats
130
+ when Class
131
+ case opts[:type].to_s # sigh... there must be a better way to do this
132
+ when 'TrueClass', 'FalseClass'; :flag
133
+ when 'String'; :string
134
+ when 'Integer'; :int
135
+ when 'Float'; :float
136
+ when 'IO'; :io
137
+ else
138
+ raise ArgumentError, "unsupported argument type '#{opts[:type].class.name}'"
139
+ end
140
+ when nil; nil
141
+ else
142
+ raise ArgumentError, "unsupported argument type '#{opts[:type]}'" unless TYPES.include?(opts[:type])
143
+ opts[:type]
144
+ end
145
+
146
+ ## for options with :multi => true, an array default doesn't imply
147
+ ## a multi-valued argument. for that you have to specify a :type
148
+ ## as well. (this is how we disambiguate an ambiguous situation;
149
+ ## see the docs for Parser#opt for details.)
150
+ disambiguated_default =
151
+ if opts[:multi] && opts[:default].is_a?(Array) && !opts[:type]
152
+ opts[:default].first
153
+ else
154
+ opts[:default]
155
+ end
156
+
157
+ type_from_default =
158
+ case disambiguated_default
159
+ when Integer; :int
160
+ when Numeric; :float
161
+ when TrueClass, FalseClass; :flag
162
+ when String; :string
163
+ when IO; :io
164
+ when Array
165
+ if opts[:default].empty?
166
+ raise ArgumentError, "multiple argument type cannot be deduced from an empty array for '#{opts[:default][0].class.name}'"
167
+ end
168
+ case opts[:default][0] # the first element determines the types
169
+ when Integer; :ints
170
+ when Numeric; :floats
171
+ when String; :strings
172
+ when IO; :ios
173
+ else
174
+ raise ArgumentError, "unsupported multiple argument type '#{opts[:default][0].class.name}'"
175
+ end
176
+ when nil; nil
177
+ else
178
+ raise ArgumentError, "unsupported argument type '#{opts[:default].class.name}'"
179
+ end
180
+
181
+ raise ArgumentError, ":type specification and default type don't match" if opts[:type] && type_from_default && opts[:type] != type_from_default
182
+
183
+ opts[:type] = opts[:type] || type_from_default || :flag
184
+
185
+ ## fill in :long
186
+ opts[:long] = opts[:long] ? opts[:long].to_s : name.to_s.gsub("_", "-")
187
+ opts[:long] =
188
+ case opts[:long]
189
+ when /^--([^-].*)$/
190
+ $1
191
+ when /^[^-]/
192
+ opts[:long]
193
+ else
194
+ raise ArgumentError, "invalid long option name #{opts[:long].inspect}"
195
+ end
196
+ raise ArgumentError, "long option name #{opts[:long].inspect} is already taken; please specify a (different) :long" if @long[opts[:long]]
197
+
198
+ ## fill in :short
199
+ opts[:short] = opts[:short].to_s if opts[:short] unless opts[:short] == :none
200
+ opts[:short] =
201
+ case opts[:short]
202
+ when nil
203
+ c = opts[:long].split(//).find { |c| c !~ INVALID_SHORT_ARG_REGEX && !@short.member?(c) }
204
+ raise ArgumentError, "can't generate a short option name for #{opts[:long].inspect}: out of unique characters" unless c
205
+ c
206
+ when /^-(.)$/
207
+ $1
208
+ when /^.$/
209
+ opts[:short]
210
+ when :none
211
+ nil
212
+ else
213
+ raise ArgumentError, "invalid short option name '#{opts[:short].inspect}'"
214
+ end
215
+ if opts[:short]
216
+ raise ArgumentError, "short option name #{opts[:short].inspect} is already taken; please specify a (different) :short" if @short[opts[:short]]
217
+ raise ArgumentError, "a short option name can't be a number or a dash" if opts[:short] =~ INVALID_SHORT_ARG_REGEX
218
+ end
219
+
220
+ ## fill in :default for flags
221
+ opts[:default] = false if opts[:type] == :flag && opts[:default].nil?
222
+
223
+ ## autobox :default for :multi (multi-occurrence) arguments
224
+ opts[:default] = [opts[:default]] if opts[:default] && opts[:multi] && !opts[:default].is_a?(Array)
225
+
226
+ ## fill in :multi
227
+ opts[:multi] ||= false
228
+
229
+ opts[:desc] ||= desc
230
+ @long[opts[:long]] = name
231
+ @short[opts[:short]] = name if opts[:short]
232
+ @specs[name] = opts
233
+ @order << [:opt, name]
234
+ end
235
+
236
+ ## Sets the version string. If set, the user can request the version
237
+ ## on the commandline. Should probably be of the form "<program name>
238
+ ## <version number>".
239
+ def version s=nil; @version = s if s; @version end
240
+
241
+ ## Adds text to the help display. Can be interspersed with calls to
242
+ ## #opt to build a multi-section help page.
243
+ def banner s; @order << [:text, s] end
244
+ alias :text :banner
245
+
246
+ ## Marks two (or more!) options as requiring each other. Only handles
247
+ ## undirected (i.e., mutual) dependencies. Directed dependencies are
248
+ ## better modeled with Trollop::die.
249
+ def depends *syms
250
+ syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
251
+ @constraints << [:depends, syms]
252
+ end
253
+
254
+ ## Marks two (or more!) options as conflicting.
255
+ def conflicts *syms
256
+ syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
257
+ @constraints << [:conflicts, syms]
258
+ end
259
+
260
+ ## Defines a set of words which cause parsing to terminate when
261
+ ## encountered, such that any options to the left of the word are
262
+ ## parsed as usual, and options to the right of the word are left
263
+ ## intact.
264
+ ##
265
+ ## A typical use case would be for subcommand support, where these
266
+ ## would be set to the list of subcommands. A subsequent Trollop
267
+ ## invocation would then be used to parse subcommand options, after
268
+ ## shifting the subcommand off of ARGV.
269
+ def stop_on *words
270
+ @stop_words = [*words].flatten
271
+ end
272
+
273
+ ## Similar to #stop_on, but stops on any unknown word when encountered
274
+ ## (unless it is a parameter for an argument). This is useful for
275
+ ## cases where you don't know the set of subcommands ahead of time,
276
+ ## i.e., without first parsing the global options.
277
+ def stop_on_unknown
278
+ @stop_on_unknown = true
279
+ end
280
+
281
+ ## yield successive arg, parameter pairs
282
+ def each_arg args # :nodoc:
283
+ remains = []
284
+ i = 0
285
+
286
+ until i >= args.length
287
+ if @stop_words.member? args[i]
288
+ remains += args[i .. -1]
289
+ return remains
290
+ end
291
+ case args[i]
292
+ when /^--$/ # arg terminator
293
+ remains += args[(i + 1) .. -1]
294
+ return remains
295
+ when /^--(\S+?)=(\S+)$/ # long argument with equals
296
+ yield "--#{$1}", [$2]
297
+ i += 1
298
+ when /^--(\S+)$/ # long argument
299
+ params = collect_argument_parameters(args, i + 1)
300
+ unless params.empty?
301
+ num_params_taken = yield args[i], params
302
+ unless num_params_taken
303
+ if @stop_on_unknown
304
+ remains += args[i + 1 .. -1]
305
+ return remains
306
+ else
307
+ remains += params
308
+ end
309
+ end
310
+ i += 1 + num_params_taken
311
+ else # long argument no parameter
312
+ yield args[i], nil
313
+ i += 1
314
+ end
315
+ when /^-(\S+)$/ # one or more short arguments
316
+ shortargs = $1.split(//)
317
+ shortargs.each_with_index do |a, j|
318
+ if j == (shortargs.length - 1)
319
+ params = collect_argument_parameters(args, i + 1)
320
+ unless params.empty?
321
+ num_params_taken = yield "-#{a}", params
322
+ unless num_params_taken
323
+ if @stop_on_unknown
324
+ remains += args[i + 1 .. -1]
325
+ return remains
326
+ else
327
+ remains += params
328
+ end
329
+ end
330
+ i += 1 + num_params_taken
331
+ else # argument no parameter
332
+ yield "-#{a}", nil
333
+ i += 1
334
+ end
335
+ else
336
+ yield "-#{a}", nil
337
+ end
338
+ end
339
+ else
340
+ if @stop_on_unknown
341
+ remains += args[i .. -1]
342
+ return remains
343
+ else
344
+ remains << args[i]
345
+ i += 1
346
+ end
347
+ end
348
+ end
349
+
350
+ remains
351
+ end
352
+
353
+ ## Parses the commandline. Typically called by Trollop::options.
354
+ def parse cmdline=ARGV
355
+ vals = {}
356
+ required = {}
357
+
358
+ opt :version, "Print version and exit" if @version unless @specs[:version] || @long["version"]
359
+ opt :help, "Show this message" unless @specs[:help] || @long["help"]
360
+
361
+ @specs.each do |sym, opts|
362
+ required[sym] = true if opts[:required]
363
+ vals[sym] = opts[:default]
364
+ end
365
+
366
+ ## resolve symbols
367
+ given_args = {}
368
+ @leftovers = each_arg cmdline do |arg, params|
369
+ sym =
370
+ case arg
371
+ when /^-([^-])$/
372
+ @short[$1]
373
+ when /^--([^-]\S*)$/
374
+ @long[$1]
375
+ else
376
+ raise CommandlineError, "invalid argument syntax: '#{arg}'"
377
+ end
378
+ raise CommandlineError, "unknown argument '#{arg}'" unless sym
379
+
380
+ if given_args.include?(sym) && !@specs[sym][:multi]
381
+ raise CommandlineError, "option '#{arg}' specified multiple times"
382
+ end
383
+
384
+ given_args[sym] ||= {}
385
+
386
+ given_args[sym][:arg] = arg
387
+ given_args[sym][:params] ||= []
388
+
389
+ # The block returns the number of parameters taken.
390
+ num_params_taken = 0
391
+
392
+ unless params.nil?
393
+ if SINGLE_ARG_TYPES.include?(@specs[sym][:type])
394
+ given_args[sym][:params] << params[0, 1] # take the first parameter
395
+ num_params_taken = 1
396
+ elsif MULTI_ARG_TYPES.include?(@specs[sym][:type])
397
+ given_args[sym][:params] << params # take all the parameters
398
+ num_params_taken = params.size
399
+ end
400
+ end
401
+
402
+ num_params_taken
403
+ end
404
+
405
+ ## check for version and help args
406
+ raise VersionNeeded if given_args.include? :version
407
+ raise HelpNeeded if given_args.include? :help
408
+
409
+ ## check constraint satisfaction
410
+ @constraints.each do |type, syms|
411
+ constraint_sym = syms.find { |sym| given_args[sym] }
412
+ next unless constraint_sym
413
+
414
+ case type
415
+ when :depends
416
+ syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym][:long]} requires --#{@specs[sym][:long]}" unless given_args.include? sym }
417
+ when :conflicts
418
+ syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym][:long]} conflicts with --#{@specs[sym][:long]}" if given_args.include?(sym) && (sym != constraint_sym) }
419
+ end
420
+ end
421
+
422
+ required.each do |sym, val|
423
+ raise CommandlineError, "option '#{sym}' must be specified" unless given_args.include? sym
424
+ end
425
+
426
+ ## parse parameters
427
+ given_args.each do |sym, given_data|
428
+ arg = given_data[:arg]
429
+ params = given_data[:params]
430
+
431
+ opts = @specs[sym]
432
+ raise CommandlineError, "option '#{arg}' needs a parameter" if params.empty? && opts[:type] != :flag
433
+
434
+ case opts[:type]
435
+ when :flag
436
+ vals[sym] = !opts[:default]
437
+ when :int, :ints
438
+ vals[sym] = params.map { |pg| pg.map { |p| parse_integer_parameter p, arg } }
439
+ when :float, :floats
440
+ vals[sym] = params.map { |pg| pg.map { |p| parse_float_parameter p, arg } }
441
+ when :string, :strings
442
+ vals[sym] = params.map { |pg| pg.map { |p| p.to_s } }
443
+ when :io, :ios
444
+ vals[sym] = params.map { |pg| pg.map { |p| parse_io_parameter p, arg } }
445
+ end
446
+
447
+ if SINGLE_ARG_TYPES.include?(opts[:type])
448
+ unless opts[:multi] # single parameter
449
+ vals[sym] = vals[sym][0][0]
450
+ else # multiple options, each with a single parameter
451
+ vals[sym] = vals[sym].map { |p| p[0] }
452
+ end
453
+ elsif MULTI_ARG_TYPES.include?(opts[:type]) && !opts[:multi]
454
+ vals[sym] = vals[sym][0] # single option, with multiple parameters
455
+ end
456
+ # else: multiple options, with multiple parameters
457
+ end
458
+
459
+ ## allow openstruct-style accessors
460
+ class << vals
461
+ def method_missing(m, *args)
462
+ self[m] || self[m.to_s]
463
+ end
464
+ end
465
+ vals
466
+ end
467
+
468
+ def parse_integer_parameter param, arg #:nodoc:
469
+ raise CommandlineError, "option '#{arg}' needs an integer" unless param =~ /^\d+$/
470
+ param.to_i
471
+ end
472
+
473
+ def parse_float_parameter param, arg #:nodoc:
474
+ raise CommandlineError, "option '#{arg}' needs a floating-point number" unless param =~ FLOAT_RE
475
+ param.to_f
476
+ end
477
+
478
+ def parse_io_parameter param, arg #:nodoc:
479
+ case param
480
+ when /^(stdin|-)$/i; $stdin
481
+ else
482
+ require 'open-uri'
483
+ begin
484
+ open param
485
+ rescue SystemCallError => e
486
+ raise CommandlineError, "file or url for option '#{arg}' cannot be opened: #{e.message}"
487
+ end
488
+ end
489
+ end
490
+
491
+ def collect_argument_parameters args, start_at #:nodoc:
492
+ params = []
493
+ pos = start_at
494
+ while args[pos] && args[pos] !~ PARAM_RE && !@stop_words.member?(args[pos]) do
495
+ params << args[pos]
496
+ pos += 1
497
+ end
498
+ params
499
+ end
500
+
501
+ def width #:nodoc:
502
+ @width ||=
503
+ if $stdout.tty?
504
+ begin
505
+ require 'curses'
506
+ Curses::init_screen
507
+ x = Curses::cols
508
+ Curses::close_screen
509
+ x
510
+ rescue Exception
511
+ 80
512
+ end
513
+ else
514
+ 80
515
+ end
516
+ end
517
+
518
+ ## Print the help message to +stream+.
519
+ def educate stream=$stdout
520
+ width # just calculate it now; otherwise we have to be careful not to
521
+ # call this unless the cursor's at the beginning of a line.
522
+
523
+ left = {}
524
+ @specs.each do |name, spec|
525
+ left[name] = "--#{spec[:long]}" +
526
+ (spec[:short] ? ", -#{spec[:short]}" : "") +
527
+ case spec[:type]
528
+ when :flag; ""
529
+ when :int; " <i>"
530
+ when :ints; " <i+>"
531
+ when :string; " <s>"
532
+ when :strings; " <s+>"
533
+ when :float; " <f>"
534
+ when :floats; " <f+>"
535
+ when :io; " <filename/uri>"
536
+ when :ios; " <filename/uri+>"
537
+ end
538
+ end
539
+
540
+ leftcol_width = left.values.map { |s| s.length }.max || 0
541
+ rightcol_start = leftcol_width + 6 # spaces
542
+
543
+ unless @order.size > 0 && @order.first.first == :text
544
+ stream.puts "#@version\n" if @version
545
+ stream.puts "Options:"
546
+ end
547
+
548
+ @order.each do |what, opt|
549
+ if what == :text
550
+ stream.puts wrap(opt)
551
+ next
552
+ end
553
+
554
+ spec = @specs[opt]
555
+ stream.printf " %#{leftcol_width}s: ", left[opt]
556
+ desc = spec[:desc] + begin
557
+ default_s = case spec[:default]
558
+ when $stdout; "<stdout>"
559
+ when $stdin; "<stdin>"
560
+ when $stderr; "<stderr>"
561
+ when Array
562
+ spec[:default].join(", ")
563
+ else
564
+ spec[:default].to_s
565
+ end
566
+
567
+ if spec[:default]
568
+ if spec[:desc] =~ /\.$/
569
+ " (Default: #{default_s})"
570
+ else
571
+ " (default: #{default_s})"
572
+ end
573
+ else
574
+ ""
575
+ end
576
+ end
577
+ stream.puts wrap(desc, :width => width - rightcol_start - 1, :prefix => rightcol_start)
578
+ end
579
+ end
580
+
581
+ def wrap_line str, opts={} # :nodoc:
582
+ prefix = opts[:prefix] || 0
583
+ width = opts[:width] || (self.width - 1)
584
+ start = 0
585
+ ret = []
586
+ until start > str.length
587
+ nextt =
588
+ if start + width >= str.length
589
+ str.length
590
+ else
591
+ x = str.rindex(/\s/, start + width)
592
+ x = str.index(/\s/, start) if x && x < start
593
+ x || str.length
594
+ end
595
+ ret << (ret.empty? ? "" : " " * prefix) + str[start ... nextt]
596
+ start = nextt + 1
597
+ end
598
+ ret
599
+ end
600
+
601
+ def wrap str, opts={} # :nodoc:
602
+ if str == ""
603
+ [""]
604
+ else
605
+ str.split("\n").map { |s| wrap_line s, opts }.flatten
606
+ end
607
+ end
608
+
609
+ ## instance_eval but with ability to handle block arguments
610
+ ## thanks to why: http://redhanded.hobix.com/inspect/aBlockCostume.html
611
+ def cloaker &b #:nodoc:
612
+ (class << self; self; end).class_eval do
613
+ define_method :cloaker_, &b
614
+ meth = instance_method :cloaker_
615
+ remove_method :cloaker_
616
+ meth
617
+ end
618
+ end
619
+ end
620
+
621
+ ## The top-level entry method into Trollop. Creates a Parser object,
622
+ ## passes the block to it, then parses +args+ with it, handling any
623
+ ## errors or requests for help or version information appropriately (and
624
+ ## then exiting). Modifies +args+ in place. Returns a hash of option
625
+ ## values.
626
+ ##
627
+ ## The block passed in should contain zero or more calls to +opt+
628
+ ## (Parser#opt), zero or more calls to +text+ (Parser#text), and
629
+ ## probably a call to +version+ (Parser#version).
630
+ ##
631
+ ## Example:
632
+ ##
633
+ ## require 'trollop'
634
+ ## opts = Trollop::options do
635
+ ## opt :monkey, "Use monkey mode" # a flag --monkey, defaulting to false
636
+ ## opt :goat, "Use goat mode", :default => true # a flag --goat, defaulting to true
637
+ ## opt :num_limbs, "Number of limbs", :default => 4 # an integer --num-limbs <i>, defaulting to 4
638
+ ## opt :num_thumbs, "Number of thumbs", :type => :int # an integer --num-thumbs <i>, defaulting to nil
639
+ ## end
640
+ ##
641
+ ## p opts # returns a hash: { :monkey => false, :goat => true, :num_limbs => 4, :num_thumbs => nil }
642
+ ##
643
+ ## See more examples at http://trollop.rubyforge.org.
644
+ def options args = ARGV, *a, &b
645
+ @p = Parser.new(*a, &b)
646
+ begin
647
+ vals = @p.parse args
648
+ args.clear
649
+ @p.leftovers.each { |l| args << l }
650
+ vals
651
+ rescue CommandlineError => e
652
+ $stderr.puts "Error: #{e.message}."
653
+ $stderr.puts "Try --help for help."
654
+ exit(-1)
655
+ rescue HelpNeeded
656
+ @p.educate
657
+ exit
658
+ rescue VersionNeeded
659
+ puts @p.version
660
+ exit
661
+ end
662
+ end
663
+
664
+ ## Informs the user that their usage of 'arg' was wrong, as detailed by
665
+ ## 'msg', and dies. Example:
666
+ ##
667
+ ## options do
668
+ ## opt :volume, :default => 0.0
669
+ ## end
670
+ ##
671
+ ## die :volume, "too loud" if opts[:volume] > 10.0
672
+ ## die :volume, "too soft" if opts[:volume] < 0.1
673
+ ##
674
+ ## In the one-argument case, simply print that message, a notice
675
+ ## about -h, and die. Example:
676
+ ##
677
+ ## options do
678
+ ## opt :whatever # ...
679
+ ## end
680
+ ##
681
+ ## Trollop::die "need at least one filename" if ARGV.empty?
682
+ def die arg, msg=nil
683
+ if msg
684
+ $stderr.puts "Error: argument --#{@p.specs[arg][:long]} #{msg}."
685
+ else
686
+ $stderr.puts "Error: #{arg}."
687
+ end
688
+ $stderr.puts "Try --help for help."
689
+ exit(-1)
690
+ end
691
+
692
+ module_function :options, :die
693
+
694
+ end # module
695
+
@@ -9,4 +9,4 @@ jumpt 10, D[1] < D[0] // if(m < n)
9
9
  set 1, D[1]-D[0]
10
10
  jump 11
11
11
  set 0, D[0]-D[1]
12
- jump 6
12
+ jump 6
@@ -2,4 +2,4 @@ set 0, 0
2
2
  set write, "hello world!"
3
3
  set 0, D[0]+1
4
4
  jumpt ip-3, D[0] < 5
5
- halt
5
+ halt