trollop 1.7.2 → 1.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/README.txt +11 -52
  2. data/lib/trollop.rb +19 -3
  3. data/test/test_trollop.rb +75 -0
  4. metadata +3 -3
data/README.txt CHANGED
@@ -24,6 +24,7 @@ Trollop: getting you 90% of the way there with only 10% of the effort.
24
24
  - Sensible defaults. No tweaking necessary, much tweaking possible.
25
25
  - Support for long options, short options, short option bundling,
26
26
  and automatic type validation and conversion.
27
+ - Support for subcommands.
27
28
  - Automatic help message generation, wrapped to current screen width.
28
29
  - Lots of unit tests.
29
30
 
@@ -61,63 +62,21 @@ Trollop: getting you 90% of the way there with only 10% of the effort.
61
62
  Trollop::die :volume, "must be non-negative" if opts[:volume] < 0
62
63
  Trollop::die :file, "must exist" unless File.exist?(opts[:file]) if opts[:file]
63
64
 
64
- ###### real-life ######
65
+ ##### sub-command support ######
65
66
 
66
67
  require 'trollop'
67
- opts = Trollop::options do
68
- version "sup-sync (sup #{Redwood::VERSION})"
69
- banner <<EOS
70
- Synchronizes the Sup index with one or more message sources by adding
71
- messages, deleting messages, or changing message state in the index as
72
- appropriate.
73
-
74
- [...]
75
-
76
- Usage:
77
- sup-sync [options] <source>*
78
-
79
- where <source>* is zero or more source URIs. If no sources are given,
80
- sync from all usual sources. Supported source URI schemes can be seen
81
- by running "sup-add --help".
82
-
83
- Options controlling WHICH messages sup-sync operates on:
84
- EOS
85
- opt :new, "Operate on new messages only. Don't scan over the entire source. (Default.)", :short => :none
86
- opt :changed, "Scan over the entire source for messages that have been deleted, altered, or moved from another source. (In the case of mbox sources, this includes all messages AFTER an altered message.)"
87
- opt :restored, "Operate only on those messages included in a dump file as specified by --restore which have changed state."
88
- opt :all, "Operate on all messages in the source, regardless of newness or changedness."
89
- opt :start_at, "For --changed and --all, start at a particular offset.", :type => :int
90
-
91
- text <<EOS
92
-
93
- Options controlling HOW message state is altered:
94
- EOS
95
- opt :asis, "If the message is already in the index, preserve its state. Otherwise, use default source state. (Default.)", :short => :none
96
- opt :restore, "Restore message state from a dump file created with sup-dump. If a message is not in this dumpfile, act as --asis.", :type => String, :short => :none
97
- opt :discard, "Discard any message state in the index and use the default source state. Dangerous!", :short => :none
98
- opt :archive, "When using the default source state, mark messages as archived.", :short => "-x"
99
- opt :read, "When using the default source state, mark messages as read."
100
- opt :extra_labels, "When using the default source state, also apply these user-defined labels. Should be a comma-separated list.", :type => String, :short => :none
101
-
102
- text <<EOS
103
-
104
- Other options:
105
- EOS
106
- opt :verbose, "Print message ids as they're processed."
107
- opt :optimize, "As the final operation, optimize the index."
108
- opt :all_sources, "Scan over all sources.", :short => :none
109
- opt :dry_run, "Don't actually modify the index. Probably only useful with --verbose.", :short => "-n"
110
- opt :version, "Show version information", :short => :none
111
-
112
- conflicts :changed, :all, :new, :restored
113
- conflicts :asis, :restore, :discard
68
+ global_opts = Trollop::options do
69
+ opt :global_option, "This is a global option"
70
+ stop_on %w(sub-command-1 sub-command-2)
114
71
  end
115
- Trollop::die :restored, "requires --restore" if opts[:restored] unless opts[:restore]
116
- if opts[:start_at]
117
- Trollop::die :start_at, "must be non-negative" if opts[:start_at] < 0
118
- Trollop::die :start_at, "requires either --changed or --all" unless opts[:changed] || opts[:all]
72
+
73
+ cmd = ARGV.shift
74
+ cmd_opts = Trollop::options do
75
+ opt :cmd_option, "This is an option only for the subcommand"
119
76
  end
120
77
 
78
+ puts "global: #{global_opts.inspect}, cmd: #{cmd.inspect}, cmd options: #{cmd_opts.inspect}"
79
+
121
80
  == REQUIREMENTS
122
81
 
123
82
  * none!
@@ -5,7 +5,7 @@
5
5
 
6
6
  module Trollop
7
7
 
8
- VERSION = "1.7.2"
8
+ VERSION = "1.8"
9
9
 
10
10
  ## Thrown by Parser in the event of a commandline error. Not needed if
11
11
  ## you're using the Trollop::options entry.
@@ -49,6 +49,7 @@ class Parser
49
49
  @short = {}
50
50
  @order = []
51
51
  @constraints = []
52
+ @stop_words = []
52
53
 
53
54
  #instance_eval(&b) if b # can't take arguments
54
55
  cloaker(&b).bind(self).call(*a) if b
@@ -186,12 +187,27 @@ class Parser
186
187
  @constraints << [:conflicts, syms]
187
188
  end
188
189
 
190
+ ## Defines a set of words which cause parsing to terminate when encountered,
191
+ ## such that any options to the left of the word are parsed as usual, and
192
+ ## options to the right of the word are left intact.
193
+ ##
194
+ ## A typical use case would be for subcommand support, where these would be
195
+ ## set to the list of subcommands. A subsequent Trollop invocation would
196
+ ## then be used to parse subcommand options.
197
+ def stop_on *words
198
+ @stop_words = [*words].flatten
199
+ end
200
+
189
201
  ## yield successive arg, parameter pairs
190
202
  def each_arg args # :nodoc:
191
203
  remains = []
192
204
  i = 0
193
205
 
194
206
  until i >= args.length
207
+ if @stop_words.member? args[i]
208
+ remains += args[i .. -1]
209
+ break
210
+ end
195
211
  case args[i]
196
212
  when /^--$/ # arg terminator
197
213
  remains += args[(i + 1) .. -1]
@@ -200,7 +216,7 @@ class Parser
200
216
  yield "--#{$1}", $2
201
217
  i += 1
202
218
  when /^--(\S+)$/ # long argument
203
- if args[i + 1] && args[i + 1] !~ PARAM_RE
219
+ if args[i + 1] && args[i + 1] !~ PARAM_RE && !@stop_words.member?(args[i + 1])
204
220
  remains << args[i + 1] unless yield args[i], args[i + 1]
205
221
  i += 2
206
222
  else # long argument no parameter
@@ -210,7 +226,7 @@ class Parser
210
226
  when /^-(\S+)$/ # one or more short arguments
211
227
  shortargs = $1.split(//)
212
228
  shortargs.each_with_index do |a, j|
213
- if j == (shortargs.length - 1) && args[i + 1] && args[i + 1] !~ PARAM_RE
229
+ if j == (shortargs.length - 1) && args[i + 1] && args[i + 1] !~ PARAM_RE && !@stop_words.member?(args[i + 1])
214
230
  remains << args[i + 1] unless yield "-#{a}", args[i + 1]
215
231
  i += 1 # once more below
216
232
  else
@@ -463,6 +463,81 @@ EOM
463
463
 
464
464
  assert_nothing_raised { @p.parse(%w(--arg1 --arg2)) }
465
465
  end
466
+
467
+ def test_stopwords_mixed
468
+ @p.opt "arg1", :default => false
469
+ @p.opt "arg2", :default => false
470
+ @p.stop_on %w(happy sad)
471
+
472
+ opts = @p.parse %w(--arg1 happy --arg2)
473
+ assert_equal true, opts["arg1"]
474
+ assert_equal false, opts["arg2"]
475
+
476
+ ## restart parsing
477
+ @p.leftovers.shift
478
+ opts = @p.parse @p.leftovers
479
+ assert_equal false, opts["arg1"]
480
+ assert_equal true, opts["arg2"]
481
+ end
482
+
483
+ def test_stopwords_no_stopwords
484
+ @p.opt "arg1", :default => false
485
+ @p.opt "arg2", :default => false
486
+ @p.stop_on %w(happy sad)
487
+
488
+ opts = @p.parse %w(--arg1 --arg2)
489
+ assert_equal true, opts["arg1"]
490
+ assert_equal true, opts["arg2"]
491
+
492
+ ## restart parsing
493
+ @p.leftovers.shift
494
+ opts = @p.parse @p.leftovers
495
+ assert_equal false, opts["arg1"]
496
+ assert_equal false, opts["arg2"]
497
+ end
498
+
499
+ def test_stopwords_multiple_stopwords
500
+ @p.opt "arg1", :default => false
501
+ @p.opt "arg2", :default => false
502
+ @p.stop_on %w(happy sad)
503
+
504
+ opts = @p.parse %w(happy sad --arg1 --arg2)
505
+ assert_equal false, opts["arg1"]
506
+ assert_equal false, opts["arg2"]
507
+
508
+ ## restart parsing
509
+ @p.leftovers.shift
510
+ opts = @p.parse @p.leftovers
511
+ assert_equal false, opts["arg1"]
512
+ assert_equal false, opts["arg2"]
513
+
514
+ ## restart parsing again
515
+ @p.leftovers.shift
516
+ opts = @p.parse @p.leftovers
517
+ assert_equal true, opts["arg1"]
518
+ assert_equal true, opts["arg2"]
519
+ end
520
+
521
+ def test_stopwords_with_short_args
522
+ @p.opt :global_option, "This is a global option", :short => "-g"
523
+ @p.stop_on %w(sub-command-1 sub-command-2)
524
+
525
+ global_opts = @p.parse %w(-g sub-command-1 -c)
526
+ cmd = @p.leftovers.shift
527
+
528
+ @q = Parser.new
529
+ @q.opt :cmd_option, "This is an option only for the subcommand", :short => "-c"
530
+ cmd_opts = @q.parse @p.leftovers
531
+
532
+ assert_equal true, global_opts[:global_option]
533
+ assert_nil global_opts[:cmd_option]
534
+
535
+ assert_equal true, cmd_opts[:cmd_option]
536
+ assert_nil cmd_opts[:global_option]
537
+
538
+ assert_equal cmd, "sub-command-1"
539
+ assert_equal @q.leftovers, []
540
+ end
466
541
  end
467
542
 
468
543
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trollop
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.2
4
+ version: "1.8"
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Morgan
@@ -9,11 +9,11 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-01-16 00:00:00 -08:00
12
+ date: 2008-06-16 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
16
- description: "== DESCRIPTION Trollop is YAFCLAP --- yet another fine commandline argument processor for Ruby. Trollop is designed to provide the maximal amount of GNU-style argument processing in the minimum number of lines of code (for you, the programmer). - Simple usage. - Sensible defaults. No tweaking necessary, much tweaking possible. - Support for long options, short options, short option bundling, and automatic type validation and conversion. - Automatic help message generation, wrapped to current screen width. - Lots of unit tests. Synopsis ###### simple ###### require 'trollop' opts = Trollop::options do opt :monkey, \"Use monkey mode\" opt :goat, \"Use goat mode\", :default => true opt :num_limbs, \"Set number of limbs\", :default => 4 end p opts ###### medium ###### require 'trollop' opts = Trollop::options do version \"test 1.2.3 (c) 2007 William Morgan\" banner <<-EOS Test is an awesome program that does something very, very important. Usage: test [options] <filenames>+ where [options] are: EOS opt :ignore, \"Ignore incorrect values\" opt :file, \"Extra data filename to read in, with a very long option description like this one\", :type => String opt :volume, \"Volume level\", :default => 3.0 opt :iters, \"Number of iterations\", :default => 5 end Trollop::die :volume, \"must be non-negative\" if opts[:volume] < 0 Trollop::die :file, \"must exist\" unless File.exist?(opts[:file]) if opts[:file] ###### real-life ######"
16
+ description: "== DESCRIPTION Trollop is YAFCLAP --- yet another fine commandline argument processor for Ruby. Trollop is designed to provide the maximal amount of GNU-style argument processing in the minimum number of lines of code (for you, the programmer). - Simple usage. - Sensible defaults. No tweaking necessary, much tweaking possible. - Support for long options, short options, short option bundling, and automatic type validation and conversion. - Support for subcommands. - Automatic help message generation, wrapped to current screen width. - Lots of unit tests. Synopsis ###### simple ###### require 'trollop' opts = Trollop::options do opt :monkey, \"Use monkey mode\" opt :goat, \"Use goat mode\", :default => true opt :num_limbs, \"Set number of limbs\", :default => 4 end p opts ###### medium ###### require 'trollop' opts = Trollop::options do version \"test 1.2.3 (c) 2007 William Morgan\" banner <<-EOS Test is an awesome program that does something very, very important. Usage: test [options] <filenames>+ where [options] are: EOS opt :ignore, \"Ignore incorrect values\" opt :file, \"Extra data filename to read in, with a very long option description like this one\", :type => String opt :volume, \"Volume level\", :default => 3.0 opt :iters, \"Number of iterations\", :default => 5 end Trollop::die :volume, \"must be non-negative\" if opts[:volume] < 0 Trollop::die :file, \"must exist\" unless File.exist?(opts[:file]) if opts[:file] ##### sub-command support ######"
17
17
  email: wmorgan-trollop@masanjin.net
18
18
  executables: []
19
19