trollop 1.0 → 1.1

Sign up to get free protection for your applications and to get access to all the features.
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