trollop 2.0 → 2.1.0

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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: be70256e210067fa6547103ba32b51a4242a6382
4
+ data.tar.gz: 958ed3d139b74b319cf793208d7482c634663fbc
5
+ SHA512:
6
+ metadata.gz: 36ba799aa516cf9160cfce8809c45939bdfef580dac0f30f8c8bac85f6e1e1a13bd0f786eb7b8da79006a4f4677bd2e8bb036262a917db9ab5714c2910f5789c
7
+ data.tar.gz: 6ffcdcf7434e5182eb8aca04cf1fbcdfd63d65e5af5a9b360e80a72c7a18ff39f45a7afe4fa429796ba6d1f297d28b1abbc32caf360f8a7a73643c06b7d84fb5
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.swp
13
+ *.o
14
+ *.a
15
+ mkmf.log
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.9.3"
4
+ - "2.0"
5
+ - "2.1"
data/FAQ.txt CHANGED
@@ -93,6 +93,3 @@ A: The big change was boolean parameter (aka flag) handling. In pre-2.0,
93
93
 
94
94
  Using --magic will result in :no_magic => false, and --no-magic will result in
95
95
  :no_magic => true, and neither will result in :no_magic => true.
96
-
97
-
98
-
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in trollop.gemspec
4
+ gemspec
@@ -1,3 +1,18 @@
1
+ == 2.1.0 / 2014-12-23
2
+ * Integer parser now supports underscore separator.
3
+ * Add Parser#usage and Parser#synopsis commands for creating a standard banner
4
+ message. Using Parser#banner directly will override both of those.
5
+ * Add Parser#ignore_invalid_options to prevent erroring on unknown options.
6
+ * Allow flags to act as switches if they have defaults set and no value is
7
+ passed on the commandline
8
+ * Parser#opt learned to accept a block or a :callback option which it will call
9
+ after parsing the option.
10
+ * Add Trollop::educate which displays the help message and dies.
11
+ * Reformat help message to be more GNUish.
12
+ * Fix command name in help message when script has no extension.
13
+ * Fix handling of newlines inside descriptions
14
+ * Documentation and other fixes.
15
+
1
16
  == 2.0 / 2012-08-11
2
17
  * Change flag logic: --no-X will always be false, and --X will always be true,
3
18
  regardless of default.
@@ -0,0 +1,57 @@
1
+ # trollop
2
+
3
+ http://manageiq.github.io/trollop/
4
+
5
+ [![Gem Version](https://badge.fury.io/rb/trollop.svg)](http://badge.fury.io/rb/trollop)
6
+ [![Build Status](https://travis-ci.org/ManageIQ/trollop.svg)](https://travis-ci.org/ManageIQ/trollop)
7
+ [![Code Climate](https://codeclimate.com/github/ManageIQ/trollop/badges/gpa.svg)](https://codeclimate.com/github/ManageIQ/trollop)
8
+ [![Coverage Status](http://img.shields.io/coveralls/ManageIQ/trollop.svg)](https://coveralls.io/r/ManageIQ/trollop)
9
+ [![Dependency Status](https://gemnasium.com/ManageIQ/trollop.svg)](https://gemnasium.com/ManageIQ/trollop)
10
+
11
+ Documentation quickstart: See Trollop.options and then Trollop::Parser#opt.
12
+ Also see the examples at http://manageiq.github.io/trollop/.
13
+
14
+ ## Description
15
+
16
+ Trollop is a commandline option parser for Ruby that just gets out of your way.
17
+ One line of code per option is all you need to write. For that, you get a nice
18
+ automatically-generated help page, robust option parsing, and sensible defaults
19
+ for everything you don't specify.
20
+
21
+ ## Features
22
+
23
+ - Dirt-simple usage.
24
+ - Single file. Throw it in lib/ if you don't want to make it a Rubygem dependency.
25
+ - Sensible defaults. No tweaking necessary, much tweaking possible.
26
+ - Support for long options, short options, subcommands, and automatic type validation and
27
+ conversion.
28
+ - Automatic help message generation, wrapped to current screen width.
29
+
30
+ ## Requirements
31
+
32
+ * A burning desire to write less code.
33
+
34
+ ## Install
35
+
36
+ * gem install trollop
37
+
38
+ ## Synopsis
39
+
40
+ ```ruby
41
+ require 'trollop'
42
+ opts = Trollop::options do
43
+ opt :monkey, "Use monkey mode" # flag --monkey, default false
44
+ opt :name, "Monkey name", :type => :string # string --name <s>, default nil
45
+ opt :num_limbs, "Number of limbs", :default => 4 # integer --num-limbs <i>, default to 4
46
+ end
47
+
48
+ p opts # a hash: { :monkey=>false, :name=>nil, :num_limbs=>4, :help=>false }
49
+ ```
50
+
51
+ ## License
52
+
53
+ Copyright &copy; 2008-2014 [William Morgan](http://masanjin.net/).
54
+
55
+ Copyright &copy; 2014 Red Hat, Inc.
56
+
57
+ Trollop is licensed under the same terms as Ruby.
@@ -0,0 +1,12 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+ require 'coveralls/rake/task'
4
+
5
+ task :default => :test
6
+
7
+ Rake::TestTask.new do |t|
8
+ t.libs << 'test'
9
+ t.pattern = "test/test_*.rb"
10
+ end
11
+
12
+ Coveralls::RakeTask.new
@@ -1,13 +1,12 @@
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:: the same terms as ruby itself
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
5
 
6
6
  require 'date'
7
7
 
8
8
  module Trollop
9
-
10
- VERSION = "2.0"
9
+ VERSION = "2.1.0"
11
10
 
12
11
  ## Thrown by Parser in the event of a commandline error. Not needed if
13
12
  ## you're using the Trollop::options entry.
@@ -17,7 +16,7 @@ class CommandlineError < StandardError; end
17
16
  ## automatically by Trollop#options.
18
17
  class HelpNeeded < StandardError; end
19
18
 
20
- ## Thrown by Parser if the user passes in '-h' or '--version'. Handled
19
+ ## Thrown by Parser if the user passes in '-v' or '--version'. Handled
21
20
  ## automatically by Trollop#options.
22
21
  class VersionNeeded < StandardError; end
23
22
 
@@ -66,6 +65,11 @@ class Parser
66
65
  ## for testing.)
67
66
  attr_reader :specs
68
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
+
69
73
  ## Initializes the parser, and instance-evaluates any block given.
70
74
  def initialize *a, &b
71
75
  @version = nil
@@ -122,7 +126,7 @@ class Parser
122
126
  ## If you want a multi-value, multi-occurrence argument with a default
123
127
  ## value, you must specify +:type+ as well.
124
128
 
125
- def opt name, desc="", opts={}
129
+ def opt name, desc="", opts={}, &b
126
130
  raise ArgumentError, "you already have an argument named '#{name}'" if @specs.member? name
127
131
 
128
132
  ## fill in :type
@@ -220,7 +224,7 @@ class Parser
220
224
 
221
225
  ## fill in :multi
222
226
  opts[:multi] ||= false
223
-
227
+ opts[:callback] ||= b if block_given?
224
228
  opts[:desc] ||= desc
225
229
  @long[opts[:long]] = name
226
230
  @short[opts[:short]] = name if opts[:short] && opts[:short] != :none
@@ -233,6 +237,20 @@ class Parser
233
237
  ## <version number>".
234
238
  def version s=nil; @version = s if s; @version end
235
239
 
240
+ ## Sets the usage string. If set the message will be printed as the
241
+ ## first line in the help (educate) output and ending in two new
242
+ ## lines.
243
+ def usage s=nil; @usage = s if s; @usage end
244
+
245
+ ## Sets the usage string. If set the message will be printed as the
246
+ ## first line in the help (educate) output and ending in two new
247
+ ## lines.
248
+ def usage s=nil; @usage = s if s; @usage end
249
+
250
+ ## Adds a synopsis (command summary description) right below the
251
+ ## usage line, or as the first line if usage isn't specified.
252
+ def synopsis s=nil; @synopsis = s if s; @synopsis end
253
+
236
254
  ## Adds text to the help display. Can be interspersed with calls to
237
255
  ## #opt to build a multi-section help page.
238
256
  def banner s; @order << [:text, s] end
@@ -245,7 +263,7 @@ class Parser
245
263
  syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
246
264
  @constraints << [:depends, syms]
247
265
  end
248
-
266
+
249
267
  ## Marks two (or more!) options as conflicting.
250
268
  def conflicts *syms
251
269
  syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
@@ -310,7 +328,10 @@ class Parser
310
328
 
311
329
  sym = nil if arg =~ /--no-/ # explicitly invalidate --no-no- arguments
312
330
 
313
- raise CommandlineError, "unknown argument '#{arg}'" unless sym
331
+ unless sym
332
+ next 0 if ignore_invalid_options
333
+ raise CommandlineError, "unknown argument '#{arg}'" unless sym
334
+ end
314
335
 
315
336
  if given_args.include?(sym) && !@specs[sym][:multi]
316
337
  raise CommandlineError, "option '#{arg}' specified multiple times"
@@ -363,7 +384,10 @@ class Parser
363
384
  arg, params, negative_given = given_data.values_at :arg, :params, :negative_given
364
385
 
365
386
  opts = @specs[sym]
366
- raise CommandlineError, "option '#{arg}' needs a parameter" if params.empty? && opts[:type] != :flag
387
+ if params.empty? && opts[:type] != :flag
388
+ raise CommandlineError, "option '#{arg}' needs a parameter" unless opts[:default]
389
+ params << [opts[:default]]
390
+ end
367
391
 
368
392
  vals["#{sym}_given".intern] = true # mark argument as specified on the commandline
369
393
 
@@ -392,6 +416,8 @@ class Parser
392
416
  vals[sym] = vals[sym][0] # single option, with multiple parameters
393
417
  end
394
418
  # else: multiple options, with multiple parameters
419
+
420
+ opts[:callback].call(vals[sym]) if opts.has_key?(:callback)
395
421
  end
396
422
 
397
423
  ## modify input in place with only those
@@ -411,6 +437,7 @@ class Parser
411
437
  def parse_date_parameter param, arg #:nodoc:
412
438
  begin
413
439
  begin
440
+ require 'chronic'
414
441
  time = Chronic.parse(param)
415
442
  rescue NameError
416
443
  # chronic is not available
@@ -427,28 +454,33 @@ class Parser
427
454
  # call this unless the cursor's at the beginning of a line.
428
455
  left = {}
429
456
  @specs.each do |name, spec|
430
- left[name] = "--#{spec[:long]}" +
431
- (spec[:type] == :flag && spec[:default] ? ", --no-#{spec[:long]}" : "") +
432
- (spec[:short] && spec[:short] != :none ? ", -#{spec[:short]}" : "") +
457
+ left[name] =
458
+ (spec[:short] && spec[:short] != :none ? "-#{spec[:short]}" : "") +
459
+ (spec[:short] && spec[:short] != :none ? ", " : "") + "--#{spec[:long]}" +
433
460
  case spec[:type]
434
461
  when :flag; ""
435
- when :int; " <i>"
436
- when :ints; " <i+>"
437
- when :string; " <s>"
438
- when :strings; " <s+>"
439
- when :float; " <f>"
440
- when :floats; " <f+>"
441
- when :io; " <filename/uri>"
442
- when :ios; " <filename/uri+>"
443
- when :date; " <date>"
444
- when :dates; " <date+>"
445
- end
462
+ when :int; "=<i>"
463
+ when :ints; "=<i+>"
464
+ when :string; "=<s>"
465
+ when :strings; "=<s+>"
466
+ when :float; "=<f>"
467
+ when :floats; "=<f+>"
468
+ when :io; "=<filename/uri>"
469
+ when :ios; "=<filename/uri+>"
470
+ when :date; "=<date>"
471
+ when :dates; "=<date+>"
472
+ end +
473
+ (spec[:type] == :flag && spec[:default] ? ", --no-#{spec[:long]}" : "")
446
474
  end
447
475
 
448
476
  leftcol_width = left.values.map { |s| s.length }.max || 0
449
477
  rightcol_start = leftcol_width + 6 # spaces
450
478
 
451
479
  unless @order.size > 0 && @order.first.first == :text
480
+ command_name = File.basename($0).gsub /\.[^.]+$/, ''
481
+ stream.puts "Usage: #{command_name} #@usage\n" if @usage
482
+ stream.puts "#@synopsis\n" if @synopsis
483
+ stream.puts if @usage or @synopsis
452
484
  stream.puts "#@version\n" if @version
453
485
  stream.puts "Options:"
454
486
  end
@@ -460,7 +492,7 @@ class Parser
460
492
  end
461
493
 
462
494
  spec = @specs[opt]
463
- stream.printf " %#{leftcol_width}s: ", left[opt]
495
+ stream.printf " %-#{leftcol_width}s ", left[opt]
464
496
  desc = spec[:desc] + begin
465
497
  default_s = case spec[:default]
466
498
  when $stdout; "<stdout>"
@@ -506,7 +538,12 @@ class Parser
506
538
  if str == ""
507
539
  [""]
508
540
  else
509
- str.split("\n").map { |s| wrap_line s, opts }.flatten
541
+ inner = false
542
+ str.split("\n").map do |s|
543
+ line = wrap_line s, opts.merge(:inner => inner)
544
+ inner = true
545
+ line
546
+ end.flatten
510
547
  end
511
548
  end
512
549
 
@@ -596,7 +633,7 @@ private
596
633
  end
597
634
 
598
635
  def parse_integer_parameter param, arg
599
- raise CommandlineError, "option '#{arg}' needs an integer" unless param =~ /^\d+$/
636
+ raise CommandlineError, "option '#{arg}' needs an integer" unless param =~ /^-?[\d_]+$/
600
637
  param.to_i
601
638
  end
602
639
 
@@ -648,7 +685,7 @@ private
648
685
  start = 0
649
686
  ret = []
650
687
  until start > str.length
651
- nextt =
688
+ nextt =
652
689
  if start + width >= str.length
653
690
  str.length
654
691
  else
@@ -656,7 +693,7 @@ private
656
693
  x = str.index(/\s/, start) if x && x < start
657
694
  x || str.length
658
695
  end
659
- ret << (ret.empty? ? "" : " " * prefix) + str[start ... nextt]
696
+ ret << ((ret.empty? && !opts[:inner]) ? "" : " " * prefix) + str[start ... nextt]
660
697
  start = nextt + 1
661
698
  end
662
699
  ret
@@ -777,6 +814,27 @@ def die arg, msg=nil
777
814
  end
778
815
  end
779
816
 
780
- module_function :options, :die, :with_standard_exception_handling
817
+ ## Displays the help message and dies. Example:
818
+ ##
819
+ ## options do
820
+ ## opt :volume, :default => 0.0
821
+ ## banner <<-EOS
822
+ ## Usage:
823
+ ## #$0 [options] <name>
824
+ ## where [options] are:
825
+ ## EOS
826
+ ## end
827
+ ##
828
+ ## Trollop::educate if ARGV.empty?
829
+ def educate
830
+ if @last_parser
831
+ @last_parser.educate
832
+ exit
833
+ else
834
+ raise ArgumentError, "Trollop::educate can only be called after Trollop::options"
835
+ end
836
+ end
837
+
838
+ module_function :options, :die, :educate, :with_standard_exception_handling
781
839
 
782
840
  end # module
@@ -0,0 +1,23 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+
3
+ unless ENV['MUTANT']
4
+ require "coveralls"
5
+ require "simplecov"
6
+
7
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
8
+ Coveralls::SimpleCov::Formatter,
9
+ SimpleCov::Formatter::HTMLFormatter,
10
+ ]
11
+
12
+ end
13
+
14
+ begin
15
+ require "pry"
16
+ rescue LoadError
17
+ end
18
+
19
+ require 'test/unit'
20
+
21
+ SimpleCov.start unless ENV['MUTANT']
22
+
23
+ require 'trollop'
@@ -1,12 +1,5 @@
1
- ## test/test_trollop.rb -- unit tests for trollop
2
- ## Author:: William Morgan (mailto: wmorgan-trollop@masanjin.net)
3
- ## Copyright:: Copyright 2007 William Morgan
4
- ## License:: GNU GPL version 2
5
-
6
- require 'rubygems'
7
- require 'test/unit'
8
1
  require 'stringio'
9
- require 'trollop'
2
+ require_relative 'test_helper'
10
3
 
11
4
  module Trollop
12
5
  module Test
@@ -16,6 +9,11 @@ class Trollop < ::Test::Unit::TestCase
16
9
  @p = Parser.new
17
10
  end
18
11
 
12
+ def test_die_without_options_ever_run
13
+ ::Trollop.send(:instance_variable_set, "@last_parser", nil)
14
+ assert_raise(ArgumentError) { ::Trollop.die 'hello' }
15
+ end
16
+
19
17
  def test_unknown_arguments
20
18
  assert_raise(CommandlineError) { @p.parse(%w(--arg)) }
21
19
  @p.opt "arg"
@@ -78,6 +76,8 @@ class Trollop < ::Test::Unit::TestCase
78
76
  ## type is correctly derived from :default
79
77
  def test_type_correctly_derived_from_default
80
78
  assert_raise(ArgumentError) { @p.opt "badarg", "desc", :default => [] }
79
+ assert_raise(ArgumentError) { @p.opt "badarg3", "desc", :default => [{1 => 2}] }
80
+ assert_raise(ArgumentError) { @p.opt "badarg4", "desc", :default => Hash.new }
81
81
 
82
82
  opts = nil
83
83
 
@@ -87,6 +87,11 @@ class Trollop < ::Test::Unit::TestCase
87
87
  assert_equal 0, opts["argsi"]
88
88
  assert_nothing_raised { opts = @p.parse(%w(--argsi 4)) }
89
89
  assert_equal 4, opts["argsi"]
90
+ assert_nothing_raised { opts = @p.parse(%w(--argsi=4)) }
91
+ assert_equal 4, opts["argsi"]
92
+ assert_nothing_raised { opts = @p.parse(%w(--argsi=-4)) }
93
+ assert_equal -4, opts["argsi"]
94
+
90
95
  assert_raise(CommandlineError) { @p.parse(%w(--argsi 4.2)) }
91
96
  assert_raise(CommandlineError) { @p.parse(%w(--argsi hello)) }
92
97
 
@@ -156,7 +161,7 @@ class Trollop < ::Test::Unit::TestCase
156
161
  assert_equal ["3.4"], opts["argmst"]
157
162
  assert_nothing_raised { opts = @p.parse(%w(--argmst goodbye)) }
158
163
  assert_equal ["goodbye"], opts["argmst"]
159
- end
164
+ end
160
165
 
161
166
  ## :type and :default must match if both are specified
162
167
  def test_type_and_default_must_match
@@ -175,6 +180,26 @@ class Trollop < ::Test::Unit::TestCase
175
180
  assert_nothing_raised { @p.opt "argmst", "desc", :type => :strings, :default => ["yo"] }
176
181
  end
177
182
 
183
+ ##
184
+ def test_flags_with_defaults_and_no_args_act_as_switches
185
+ opts = nil
186
+
187
+ @p.opt :argd, "desc", :default => "default_string"
188
+
189
+ opts = @p.parse(%w(--))
190
+ assert !opts[:argd_given]
191
+ assert_equal "default_string", opts[:argd]
192
+
193
+ opts = @p.parse(%w( --argd ))
194
+ assert opts[:argd_given]
195
+ assert_equal "default_string", opts[:argd]
196
+
197
+ opts = @p.parse(%w(--argd different_string))
198
+ assert opts[:argd_given]
199
+ assert_equal "different_string", opts[:argd]
200
+
201
+ end
202
+
178
203
  def test_long_detects_bad_names
179
204
  assert_nothing_raised { @p.opt "goodarg", "desc", :long => "none" }
180
205
  assert_nothing_raised { @p.opt "goodarg2", "desc", :long => "--two" }
@@ -233,7 +258,7 @@ class Trollop < ::Test::Unit::TestCase
233
258
 
234
259
  sio = StringIO.new "w"
235
260
  @p.educate sio
236
- assert sio.string =~ /--arg:\s+desc/
261
+ assert sio.string =~ /--arg\s+desc/
237
262
 
238
263
  assert_raise(CommandlineError) { @p.parse %w(-a) }
239
264
  end
@@ -387,6 +412,20 @@ where [options] are:
387
412
  EOM
388
413
  end
389
414
 
415
+ def test_multi_line_description
416
+ out = StringIO.new
417
+ @p.opt :arg, <<-EOM, :type => :int
418
+ This is an arg
419
+ with a multi-line description
420
+ EOM
421
+ @p.educate(out)
422
+ assert_equal <<-EOM, out.string
423
+ Options:
424
+ --arg=<i> This is an arg
425
+ with a multi-line description
426
+ EOM
427
+ end
428
+
390
429
  def test_floating_point_formatting
391
430
  @p.opt :arg, "desc", :type => :float, :short => "f"
392
431
  opts = nil
@@ -422,13 +461,8 @@ EOM
422
461
  opts = nil
423
462
  assert_nothing_raised { opts = @p.parse(['-d', 'Jan 4, 2007']) }
424
463
  assert_equal Date.civil(2007, 1, 4), opts[:arg]
425
- begin
426
- require 'chronic'
427
- assert_nothing_raised { opts = @p.parse(['-d', 'today']) }
428
- assert_equal Date.today, opts[:arg]
429
- rescue LoadError
430
- # chronic is not available
431
- end
464
+ assert_nothing_raised { opts = @p.parse(['-d', 'today']) }
465
+ assert_equal Date.today, opts[:arg]
432
466
  end
433
467
 
434
468
  def test_short_options_cant_be_numeric
@@ -471,7 +505,7 @@ EOM
471
505
  assert_equal [], @p.leftovers
472
506
  end
473
507
 
474
- def short_options_with_multiple_options_does_not_affect_flags_type
508
+ def test_short_options_with_multiple_options_does_not_affect_flags_type
475
509
  opts = nil
476
510
 
477
511
  assert_nothing_raised do
@@ -674,6 +708,41 @@ EOM
674
708
  assert_equal 2, help.length # banner, -h
675
709
  end
676
710
 
711
+ def test_help_has_optional_usage
712
+ @p = Parser.new
713
+ @p.usage "OPTIONS FILES"
714
+ sio = StringIO.new "w"
715
+ @p.parse []
716
+ @p.educate sio
717
+ help = sio.string.split "\n"
718
+ assert help[0] =~ /OPTIONS FILES/i
719
+ assert_equal 4, help.length # line break, options, then -h
720
+ end
721
+
722
+ def test_help_has_optional_synopsis
723
+ @p = Parser.new
724
+ @p.synopsis "About this program"
725
+ sio = StringIO.new "w"
726
+ @p.parse []
727
+ @p.educate sio
728
+ help = sio.string.split "\n"
729
+ assert help[0] =~ /About this program/i
730
+ assert_equal 4, help.length # line break, options, then -h
731
+ end
732
+
733
+ def test_help_has_specific_order_for_usage_and_synopsis
734
+ @p = Parser.new
735
+ @p.usage "OPTIONS FILES"
736
+ @p.synopsis "About this program"
737
+ sio = StringIO.new "w"
738
+ @p.parse []
739
+ @p.educate sio
740
+ help = sio.string.split "\n"
741
+ assert help[0] =~ /OPTIONS FILES/i
742
+ assert help[1] =~ /About this program/i
743
+ assert_equal 5, help.length # line break, options, then -h
744
+ end
745
+
677
746
  def test_help_preserves_positions
678
747
  @p.opt :zzz, "zzz"
679
748
  @p.opt :aaa, "aaa"
@@ -685,6 +754,44 @@ EOM
685
754
  assert help[2] =~ /aaa/
686
755
  end
687
756
 
757
+ def test_help_includes_option_types
758
+ @p.opt :arg1, 'arg', :type => :int
759
+ @p.opt :arg2, 'arg', :type => :ints
760
+ @p.opt :arg3, 'arg', :type => :string
761
+ @p.opt :arg4, 'arg', :type => :strings
762
+ @p.opt :arg5, 'arg', :type => :float
763
+ @p.opt :arg6, 'arg', :type => :floats
764
+ @p.opt :arg7, 'arg', :type => :io
765
+ @p.opt :arg8, 'arg', :type => :ios
766
+ @p.opt :arg9, 'arg', :type => :date
767
+ @p.opt :arg10, 'arg', :type => :dates
768
+ sio = StringIO.new "w"
769
+ @p.educate sio
770
+
771
+ help = sio.string.split "\n"
772
+ assert help[1] =~ /<i>/
773
+ assert help[2] =~ /<i\+>/
774
+ assert help[3] =~ /<s>/
775
+ assert help[4] =~ /<s\+>/
776
+ assert help[5] =~ /<f>/
777
+ assert help[6] =~ /<f\+>/
778
+ assert help[7] =~ /<filename\/uri>/
779
+ assert help[8] =~ /<filename\/uri\+>/
780
+ assert help[9] =~ /<date>/
781
+ assert help[10] =~ /<date\+>/
782
+ end
783
+
784
+ def test_help_has_grammatical_default_text
785
+ @p.opt :arg1, 'description with period.', :default => 'hello'
786
+ @p.opt :arg2, 'description without period', :default => 'world'
787
+ sio = StringIO.new 'w'
788
+ @p.educate sio
789
+
790
+ help = sio.string.split "\n"
791
+ assert help[1] =~ /Default/
792
+ assert help[2] =~ /default/
793
+ end
794
+
688
795
  def test_version_and_help_short_args_can_be_overridden
689
796
  @p.opt :verbose, "desc", :short => "-v"
690
797
  @p.opt :hello, "desc", :short => "-h"
@@ -951,6 +1058,31 @@ EOM
951
1058
  end
952
1059
  end
953
1060
 
1061
+ def test_date_arg_type
1062
+ temp = Date.new
1063
+ @p.opt :arg, 'desc', :type => :date
1064
+ @p.opt :arg2, 'desc', :type => Date
1065
+ @p.opt :arg3, 'desc', :default => temp
1066
+
1067
+ opts = nil
1068
+ assert_nothing_raised { opts = @p.parse }
1069
+ assert_equal temp, opts[:arg3]
1070
+
1071
+ assert_nothing_raised { opts = @p.parse %w(--arg 5/1/2010) }
1072
+ assert_kind_of Date, opts[:arg]
1073
+ assert_equal Date.new(2010, 5, 1), opts[:arg]
1074
+
1075
+ assert_nothing_raised { opts = @p.parse %w(--arg2 5/1/2010) }
1076
+ assert_kind_of Date, opts[:arg2]
1077
+ assert_equal Date.new(2010, 5, 1), opts[:arg2]
1078
+ end
1079
+
1080
+ def test_unknown_arg_class_type
1081
+ assert_raise ArgumentError do
1082
+ @p.opt :arg, 'desc', :type => Hash
1083
+ end
1084
+ end
1085
+
954
1086
  def test_io_arg_type
955
1087
  @p.opt :arg, "desc", :type => :io
956
1088
  @p.opt :arg2, "desc", :type => IO
@@ -1124,12 +1256,52 @@ EOM
1124
1256
  end
1125
1257
 
1126
1258
  def test_simple_interface_handles_die
1259
+ old_stderr, $stderr = $stderr, StringIO.new('w')
1127
1260
  ARGV.clear
1128
1261
  ARGV.unshift "--potato"
1129
1262
  ::Trollop::options do
1130
1263
  opt :potato
1131
1264
  end
1132
1265
  assert_raises(SystemExit) { ::Trollop::die :potato, "is invalid" }
1266
+ ensure
1267
+ $stderr = old_stderr
1268
+ end
1269
+
1270
+ def test_simple_interface_handles_die_without_message
1271
+ old_stderr, $stderr = $stderr, StringIO.new('w')
1272
+ ARGV.clear
1273
+ ARGV.unshift "--potato"
1274
+ opts = ::Trollop::options do
1275
+ opt :potato
1276
+ end
1277
+ assert_raises(SystemExit) { ::Trollop::die :potato }
1278
+ assert $stderr.string =~ /Error:/
1279
+ ensure
1280
+ $stderr = old_stderr
1281
+ end
1282
+
1283
+ def test_with_standard_exception_handling
1284
+ assert_raise(SystemExit) do
1285
+ ::Trollop.with_standard_exception_handling(@p) do
1286
+ raise ::Trollop::CommandlineError.new('cl error')
1287
+ end
1288
+ end
1289
+ end
1290
+
1291
+ def test_supports_callback_inline
1292
+ assert_raises(RuntimeError, "good") do
1293
+ @p.opt :cb1 do |vals|
1294
+ raise "good"
1295
+ end
1296
+ @p.parse(%w(--cb1))
1297
+ end
1298
+ end
1299
+
1300
+ def test_supports_callback_param
1301
+ assert_raises(RuntimeError, "good") do
1302
+ @p.opt :cb1, "with callback", :callback => lambda { |vals| raise "good" }
1303
+ @p.parse(%w(--cb1))
1304
+ end
1133
1305
  end
1134
1306
  end
1135
1307
 
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'trollop'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "trollop"
8
+ spec.version = Trollop::VERSION
9
+ spec.authors = ["William Morgan", "Keenan Brock"]
10
+ spec.email = "keenan@thebrocks.net"
11
+ spec.summary = "Trollop is a commandline option parser for Ruby that just gets out of your way."
12
+ spec.description = "Trollop is a commandline option parser for Ruby that just
13
+ gets out of your way. One line of code per option is all you need to write.
14
+ For that, you get a nice automatically-generated help page, robust option
15
+ parsing, command subcompletion, and sensible defaults for everything you don't
16
+ specify."
17
+ spec.homepage = "http://manageiq.github.io/trollop/"
18
+ spec.license = "MIT"
19
+
20
+ spec.files = `git ls-files -z`.split("\x0")
21
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
22
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
23
+
24
+ spec.add_runtime_dependency 'curses'
25
+ spec.require_paths = ["lib"]
26
+
27
+ spec.add_development_dependency "minitest", "~> 4.7.3"
28
+ spec.add_development_dependency "bundler", "~> 1.6"
29
+ spec.add_development_dependency "rake", "~> 10.0"
30
+ spec.add_development_dependency "chronic"
31
+ spec.add_development_dependency "simplecov"
32
+ spec.add_development_dependency "coveralls"
33
+ end
metadata CHANGED
@@ -1,59 +1,162 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trollop
3
3
  version: !ruby/object:Gem::Version
4
- version: '2.0'
5
- prerelease:
4
+ version: 2.1.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - William Morgan
8
+ - Keenan Brock
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-14 00:00:00.000000000 Z
13
- dependencies: []
14
- description: ! 'Trollop is a commandline option parser for Ruby that just
15
-
12
+ date: 2015-01-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: curses
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: minitest
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: 4.7.3
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: 4.7.3
42
+ - !ruby/object:Gem::Dependency
43
+ name: bundler
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '1.6'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '1.6'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rake
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '10.0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '10.0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: chronic
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: simplecov
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: coveralls
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ description: |-
113
+ Trollop is a commandline option parser for Ruby that just
16
114
  gets out of your way. One line of code per option is all you need to write.
17
-
18
115
  For that, you get a nice automatically-generated help page, robust option
19
-
20
- parsing, command subcompletion, and sensible defaults for everything you don''t
21
-
22
- specify.'
23
- email: wmorgan-trollop@masanjin.net
116
+ parsing, command subcompletion, and sensible defaults for everything you don't
117
+ specify.
118
+ email: keenan@thebrocks.net
24
119
  executables: []
25
120
  extensions: []
26
121
  extra_rdoc_files: []
27
122
  files:
28
- - lib/trollop.rb
29
- - test/test_trollop.rb
123
+ - ".gitignore"
124
+ - ".travis.yml"
30
125
  - FAQ.txt
126
+ - Gemfile
31
127
  - History.txt
128
+ - README.md
129
+ - Rakefile
130
+ - lib/trollop.rb
32
131
  - release-script.txt
33
- - README.txt
34
- homepage: http://trollop.rubyforge.org
35
- licenses: []
132
+ - test/test_helper.rb
133
+ - test/test_trollop.rb
134
+ - trollop.gemspec
135
+ homepage: http://manageiq.github.io/trollop/
136
+ licenses:
137
+ - MIT
138
+ metadata: {}
36
139
  post_install_message:
37
140
  rdoc_options: []
38
141
  require_paths:
39
142
  - lib
40
143
  required_ruby_version: !ruby/object:Gem::Requirement
41
- none: false
42
144
  requirements:
43
- - - ! '>='
145
+ - - ">="
44
146
  - !ruby/object:Gem::Version
45
147
  version: '0'
46
148
  required_rubygems_version: !ruby/object:Gem::Requirement
47
- none: false
48
149
  requirements:
49
- - - ! '>='
150
+ - - ">="
50
151
  - !ruby/object:Gem::Version
51
152
  version: '0'
52
153
  requirements: []
53
- rubyforge_project: trollop
54
- rubygems_version: 1.8.23
154
+ rubyforge_project:
155
+ rubygems_version: 2.2.2
55
156
  signing_key:
56
- specification_version: 3
157
+ specification_version: 4
57
158
  summary: Trollop is a commandline option parser for Ruby that just gets out of your
58
159
  way.
59
- test_files: []
160
+ test_files:
161
+ - test/test_helper.rb
162
+ - test/test_trollop.rb
data/README.txt DELETED
@@ -1,50 +0,0 @@
1
- == trollop
2
-
3
- by William Morgan (http://masanjin.net/)
4
-
5
- Main page: http://trollop.rubyforge.org
6
-
7
- Release announcements and comments: http://masanjin.net/blog/label/trollop/.
8
-
9
- Documentation quickstart: See Trollop.options and then Trollop::Parser#opt.
10
- Also see the examples at http://trollop.rubyforge.org/.
11
-
12
- == DESCRIPTION
13
-
14
- Trollop is a commandline option parser for Ruby that just gets out of your way.
15
- One line of code per option is all you need to write. For that, you get a nice
16
- automatically-generated help page, robust option parsing, and sensible defaults
17
- for everything you don't specify.
18
-
19
- == FEATURES
20
-
21
- - Dirt-simple usage.
22
- - Single file. Throw it in lib/ if you don't want to make it a Rubygem dependency.
23
- - Sensible defaults. No tweaking necessary, much tweaking possible.
24
- - Support for long options, short options, subcommands, and automatic type validation and
25
- conversion.
26
- - Automatic help message generation, wrapped to current screen width.
27
-
28
- == REQUIREMENTS
29
-
30
- * A burning desire to write less code.
31
-
32
- == INSTALL
33
-
34
- * gem install trollop
35
-
36
- == SYNOPSIS
37
-
38
- require 'trollop'
39
- opts = Trollop::options do
40
- opt :monkey, "Use monkey mode" # flag --monkey, default false
41
- opt :name, "Monkey name", :type => :string # string --name <s>, default nil
42
- opt :num_limbs, "Number of limbs", :default => 4 # integer --num-limbs <i>, default to 4
43
- end
44
-
45
- p opts # a hash: { :monkey=>false, :name=>nil, :num_limbs=>4, :help=>false }
46
-
47
- == LICENSE
48
-
49
- Copyright (c) 2008--2012 William Morgan. Trollop is distributed under the same
50
- terms as Ruby.