trollop 1.0 → 1.1

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.
Files changed (5) hide show
  1. data/History.txt +13 -0
  2. data/Rakefile +1 -1
  3. data/lib/trollop.rb +69 -33
  4. data/test/test_trollop.rb +48 -1
  5. metadata +2 -2
@@ -1,2 +1,15 @@
1
+ == 1.1 / 2007-01-30
2
+ * Trollop::options now passes any arguments as block arguments. Since
3
+ instance variables are not properly captured by the block, this
4
+ makes it slightly less noisy to pass them in as local variables.
5
+ (A real-life use for _why's cloaker!)
6
+ * Help display now preserves original argument order.
7
+ * Trollop::die now also has a single string form in case death is not
8
+ due to a single argument.
9
+ * Parser#text now an alias for Parser#banner, and can be called
10
+ multiple times, with the output being placed in the right position
11
+ in the help text.
12
+ * Slightly more indicative formatting for parameterized arguments.
13
+
1
14
  == 1.0 / 2007-01-29
2
15
  * Initial release.
data/Rakefile CHANGED
@@ -16,7 +16,7 @@ Hoe.new('trollop', Trollop::VERSION) do |p|
16
16
  end
17
17
 
18
18
  ## is there really no way to make a rule for this?
19
- WWW_FILES = %w(www/index.html README.txt FAQ.txt)
19
+ WWW_FILES = %w(index.html README.txt FAQ.txt)
20
20
 
21
21
  task :upload_webpage => WWW_FILES do |t|
22
22
  sh "scp -C #{t.prerequisites * ' '} wmorgan@rubyforge.org:/var/www/gforge-projects/trollop/"
@@ -5,7 +5,7 @@
5
5
 
6
6
  module Trollop
7
7
 
8
- VERSION = "1.0"
8
+ VERSION = "1.1"
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.
@@ -40,16 +40,16 @@ class Parser
40
40
  attr_reader :specs
41
41
 
42
42
  ## Initializes the parser, and instance-evaluates any block given.
43
- def initialize &b
43
+ def initialize *a, &b
44
44
  @version = nil
45
- @banner = nil
46
45
  @leftovers = []
47
46
  @specs = {}
48
47
  @long = {}
49
48
  @short = {}
49
+ @order = []
50
50
 
51
- opt :help, "Show this message"
52
- instance_eval(&b) if b
51
+ #instance_eval(&b) if b # can't take arguments
52
+ cloaker(&b).bind(self).call(*a) if b
53
53
  end
54
54
 
55
55
  ## Add an option. 'name' is the argument name, a unique identifier
@@ -152,22 +152,17 @@ class Parser
152
152
  opts[:desc] ||= desc
153
153
  @short[opts[:short]] = @long[opts[:long]] = name
154
154
  @specs[name] = opts
155
+ @order << [:opt, name]
155
156
  end
156
157
 
157
158
  ## Sets the version string. If set, the user can request the version
158
159
  ## on the commandline. Should be of the form "<program name>
159
160
  ## <version number>".
160
- def version s=nil;
161
- if s
162
- @version = s
163
- opt :version, "Print version and exit"
164
- end
165
- @version
166
- end
161
+ def version s=nil; @version = s if s; @version end
167
162
 
168
- ## Sets the banner. If set, this will be printed at the top of the
169
- ## help display.
170
- def banner s=nil; @banner = s if s; @banner end
163
+ ## Adds text to the help display.
164
+ def banner s; @order << [:text, s] end
165
+ alias :text :banner
171
166
 
172
167
  ## yield successive arg, parameter pairs
173
168
  def each_arg args # :nodoc:
@@ -214,6 +209,9 @@ class Parser
214
209
  required = {}
215
210
  found = {}
216
211
 
212
+ opt :version, "Print version and exit" if @version unless @specs[:version]
213
+ opt :help, "Show this message" unless @specs[:help]
214
+
217
215
  @specs.each do |name, opts|
218
216
  required[name] = true if opts[:required]
219
217
  vals[name] = opts[:default]
@@ -280,23 +278,38 @@ class Parser
280
278
  def educate stream=$stdout
281
279
  width # just calculate it now; otherwise we have to be careful not to
282
280
  # call this unless the cursor's at the beginning of a line.
283
- if @banner
284
- stream.puts wrap(@banner)
285
- elsif @version
286
- stream.puts
287
- stream.puts @version
288
- end
289
281
 
290
- unless @banner
291
- stream.puts "Options: "
282
+ left = {}
283
+ @specs.each do |name, spec|
284
+ left[name] = "--#{spec[:long]}, -#{spec[:short]}" +
285
+ case spec[:type]
286
+ when :flag
287
+ ""
288
+ when :int
289
+ " <i>"
290
+ when :string
291
+ " <s>"
292
+ when :float
293
+ " <f>"
294
+ end
292
295
  end
293
296
 
294
- specs = @long.keys.sort.map { |longname| @specs[@long[longname]] }
295
- leftcols = specs.map { |spec| "--#{spec[:long]}, -#{spec[:short]}" }
296
- leftcol_width = leftcols.map { |s| s.length }.max
297
+ leftcol_width = left.values.map { |s| s.length }.max || 0
297
298
  rightcol_start = leftcol_width + 6 # spaces
298
- specs.each_with_index do |spec, i|
299
- stream.printf(" %#{leftcol_width}s: ", leftcols[i]);
299
+
300
+ unless @order.size > 0 && @order.first.first == :text
301
+ stream.puts "#@version\n" if @version
302
+ stream.puts "Options:"
303
+ end
304
+
305
+ @order.each do |what, opt|
306
+ if what == :text
307
+ stream.puts wrap(opt)
308
+ next
309
+ end
310
+
311
+ spec = @specs[opt]
312
+ stream.printf " %#{leftcol_width}s: ", left[opt]
300
313
  desc = spec[:desc] +
301
314
  if spec[:default]
302
315
  if spec[:desc] =~ /\.$/
@@ -338,6 +351,17 @@ class Parser
338
351
  str.split("\n").map { |s| wrap_line s, opts }.flatten
339
352
  end
340
353
  end
354
+
355
+ ## instance_eval but with ability to handle block arguments
356
+ ## thanks to why: http://redhanded.hobix.com/inspect/aBlockCostume.html
357
+ def cloaker &b #:nodoc:
358
+ (class << self; self; end).class_eval do
359
+ define_method :cloaker_, &b
360
+ meth = instance_method :cloaker_
361
+ remove_method :cloaker_
362
+ meth
363
+ end
364
+ end
341
365
  end
342
366
 
343
367
  ## The top-level entry method into Trollop. Creates a Parser object,
@@ -351,8 +375,8 @@ end
351
375
  ## and a call to version (Parser#version).
352
376
  ##
353
377
  ## See the synopsis in README.txt for examples.
354
- def options &b
355
- @p = Parser.new(&b)
378
+ def options *a, &b
379
+ @p = Parser.new(*a, &b)
356
380
  begin
357
381
  vals = @p.parse ARGV
358
382
  ARGV.clear
@@ -380,9 +404,21 @@ end
380
404
  ##
381
405
  ## die :volume, "too loud" if opts[:volume] > 10.0
382
406
  ## die :volume, "too soft" if opts[:volume] < 0.1
383
-
384
- def die arg, msg
385
- $stderr.puts "Error: parameter for option '--#{@p.specs[arg][:long]}' or '-#{@p.specs[arg][:short]}' #{msg}."
407
+ ##
408
+ ## In the one-argument case, simply print that message, a notice
409
+ ## about -h, and die. Example:
410
+ ##
411
+ ## options do
412
+ ## opt :whatever # ...
413
+ ## end
414
+ ##
415
+ ## Trollop::die "need at least one filename" if ARGV.empty?
416
+ def die arg, msg=nil
417
+ if msg
418
+ $stderr.puts "Error: parameter for option '--#{@p.specs[arg][:long]}' or '-#{@p.specs[arg][:short]}' #{msg}."
419
+ else
420
+ $stderr.puts "Error: #{arg}."
421
+ end
386
422
  $stderr.puts "Try --help for help."
387
423
  exit(-1)
388
424
  end
@@ -4,7 +4,7 @@
4
4
  ## License:: GNU GPL version 2
5
5
 
6
6
  require 'test/unit'
7
- require 'yaml'
7
+ require 'stringio'
8
8
  require 'trollop'
9
9
 
10
10
  module Trollop
@@ -294,6 +294,53 @@ EOM
294
294
  assert_equal "hello-there", @p.specs[:hello_there][:long]
295
295
  end
296
296
 
297
+ def test_arguments_passed_through_block
298
+ @goat = 3
299
+ boat = 4
300
+ Parser.new(@goat) do |goat|
301
+ boat = goat
302
+ end
303
+ assert_equal @goat, boat
304
+ end
305
+
306
+ def test_help_has_default_banner
307
+ @p = Parser.new
308
+ sio = StringIO.new "w"
309
+ @p.parse []
310
+ @p.educate sio
311
+ help = sio.string.split "\n"
312
+ assert help[0] =~ /options/i
313
+ assert_equal 2, help.length # options, then -h
314
+
315
+ @p = Parser.new
316
+ @p.version "my version"
317
+ sio = StringIO.new "w"
318
+ @p.parse []
319
+ @p.educate sio
320
+ help = sio.string.split "\n"
321
+ assert help[0] =~ /my version/i
322
+ assert_equal 4, help.length # version, options, -h, -v
323
+
324
+ @p = Parser.new
325
+ @p.banner "my own banner"
326
+ sio = StringIO.new "w"
327
+ @p.parse []
328
+ @p.educate sio
329
+ help = sio.string.split "\n"
330
+ assert help[0] =~ /my own banner/i
331
+ assert_equal 2, help.length # banner, -h
332
+ end
333
+
334
+ def test_help_preserves_positions
335
+ @p.opt :zzz, "zzz"
336
+ @p.opt :aaa, "aaa"
337
+ sio = StringIO.new "w"
338
+ @p.educate sio
339
+
340
+ help = sio.string.split "\n"
341
+ assert help[1] =~ /zzz/
342
+ assert help[2] =~ /aaa/
343
+ end
297
344
  end
298
345
 
299
346
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: trollop
5
5
  version: !ruby/object:Gem::Version
6
- version: "1.0"
7
- date: 2007-01-29 00:00:00 -08:00
6
+ version: "1.1"
7
+ date: 2007-01-30 00:00:00 -08:00
8
8
  summary: Trollop is YAFCLAP --- yet another fine commandline argument processing library 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).
9
9
  require_paths:
10
10
  - lib