main 2.8.4 → 2.9.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.
data/README CHANGED
@@ -206,20 +206,6 @@ SAMPLES
206
206
  true
207
207
  42
208
208
 
209
- ~ > ruby samples/a.rb --help
210
-
211
- NAME
212
- a.rb
213
-
214
- SYNOPSIS
215
- a.rb foo [options]+
216
-
217
- PARAMETERS
218
- foo (1 -> int(foo))
219
- the foo param
220
- --help, -h
221
-
222
-
223
209
 
224
210
  <========< samples/b.rb >========>
225
211
 
@@ -248,20 +234,6 @@ SAMPLES
248
234
  true
249
235
  [40, 1, 1]
250
236
 
251
- ~ > ruby samples/b.rb --help
252
-
253
- NAME
254
- b.rb
255
-
256
- SYNOPSIS
257
- b.rb foo foo foo [options]+
258
-
259
- PARAMETERS
260
- foo (3 -> int(foo))
261
- the foo param
262
- --help, -h
263
-
264
-
265
237
 
266
238
  <========< samples/c.rb >========>
267
239
 
@@ -296,20 +268,6 @@ SAMPLES
296
268
  true
297
269
  false
298
270
 
299
- ~ > ruby samples/c.rb --help
300
-
301
- NAME
302
- c.rb
303
-
304
- SYNOPSIS
305
- c.rb foo=foo [bar=bar] [options]+
306
-
307
- PARAMETERS
308
- foo=foo (2 -> float(foo))
309
- bar=bar (1 ~> bool(bar))
310
- --help, -h
311
-
312
-
313
271
 
314
272
  <========< samples/d.rb >========>
315
273
 
@@ -349,19 +307,70 @@ SAMPLES
349
307
  nil
350
308
  false
351
309
 
352
- ~ > ruby samples/d.rb --help
353
310
 
354
- NAME
355
- d.rb
311
+ <========< samples/e.rb >========>
312
+
313
+ ~ > cat samples/e.rb
314
+
315
+ require 'main'
356
316
 
357
- SYNOPSIS
358
- d.rb --foo=foo [options]+
317
+ Main {
318
+ argument 'global-argument'
319
+ option 'global-option'
359
320
 
360
- PARAMETERS
361
- --foo=foo, -f (2 -> float(foo))
362
- --bar=[bar], -b (0 ~> bool(bar=false))
363
- --help, -h
321
+ def run() puts 'global-run' end
322
+
323
+ mode 'a' do
324
+ option 'a-option'
325
+ end
326
+
327
+ mode 'b' do
328
+ option 'b-option'
329
+
330
+ def run() puts 'b-run' end
331
+ end
332
+ }
333
+
334
+ ~ > ruby samples/e.rb
335
+
336
+ argument(global-argument)) 0/1
337
+
338
+
339
+ <========< samples/f.rb >========>
340
+
341
+ ~ > cat samples/f.rb
342
+
343
+ require 'main'
344
+
345
+ Main {
346
+ argument('directory'){ description 'the directory to operate on' }
347
+
348
+ option('force'){ description 'use a bigger hammer' }
349
+
350
+ def run
351
+ puts 'this is how we run when no mode is specified'
352
+ end
353
+
354
+ mode 'compress' do
355
+ option('bzip'){ description 'use bzip compression' }
356
+
357
+ def run
358
+ puts 'this is how we run in compress mode'
359
+ end
360
+ end
361
+
362
+ mode 'uncompress' do
363
+ option('delete-after'){ description 'delete orginal file after uncompressing' }
364
364
 
365
+ def run
366
+ puts 'this is how we run in un-compress mode'
367
+ end
368
+ end
369
+ }
370
+
371
+ ~ > ruby samples/f.rb
372
+
373
+ argument(directory)) 0/1
365
374
 
366
375
 
367
376
  <========< samples/g.rb >========>
@@ -383,20 +392,6 @@ SAMPLES
383
392
 
384
393
  This is what to_options produces: {"help"=>nil, "foo"=>"42", "bar"=>nil}
385
394
 
386
- ~ > ruby samples/g.rb --help
387
-
388
- NAME
389
- g.rb
390
-
391
- SYNOPSIS
392
- g.rb foo [options]+
393
-
394
- PARAMETERS
395
- foo (1 -> foo)
396
- --bar
397
- --help, -h
398
-
399
-
400
395
 
401
396
  <========< samples/h.rb >========>
402
397
 
@@ -443,18 +438,6 @@ SAMPLES
443
438
 
444
439
  "forty-two"
445
440
 
446
- ~ > ruby samples/h.rb --help
447
-
448
- NAME
449
- h.rb
450
-
451
- SYNOPSIS
452
- h.rb (a|b) [options]+
453
-
454
- PARAMETERS
455
- --foobar
456
- --help, -h
457
-
458
441
 
459
442
 
460
443
  DOCS
@@ -0,0 +1,784 @@
1
+ NAME
2
+ main.rb
3
+
4
+ SYNOPSIS
5
+ a class factory and dsl for generating command line programs real quick
6
+
7
+ URI
8
+ http://codeforpeople.com/lib/ruby/
9
+ http://rubyforge.org/projects/codeforpeople/
10
+ http://codeforpeople.rubyforge.org/svn/
11
+
12
+ INSTALL
13
+ gem install main
14
+
15
+ DESCRIPTION
16
+ main.rb features the following:
17
+
18
+ - unification of option, argument, keyword, and environment parameter
19
+ parsing
20
+ - auto generation of usage and help messages
21
+ - support for mode/sub-commands
22
+ - io redirection support
23
+ - logging hooks using ruby's built-in logging mechanism
24
+ - intelligent error handling and exit codes
25
+ - use as dsl or library for building Main objects
26
+ - parsing user defined ARGV and ENV
27
+ - zero requirements for understanding the obtuse apis of *any* command
28
+ line option parsers
29
+ - leather pants
30
+
31
+ in short main.rb aims to drastically lower the barrier to writing uniform
32
+ command line applications.
33
+
34
+ for instance, this program
35
+
36
+ require 'main'
37
+
38
+ Main {
39
+ argument 'foo'
40
+ option 'bar'
41
+
42
+ def run
43
+ p params['foo']
44
+ p params['bar']
45
+ exit_success!
46
+ end
47
+ }
48
+
49
+ sets up a program which requires one argument, 'bar', and which may accept one
50
+ command line switch, '--foo' in addition to the single option/mode which is always
51
+ accepted and handled appropriately: 'help', '--help', '-h'. for the most
52
+ part main.rb stays out of your command line namespace but insists that your
53
+ application has at least a help mode/option.
54
+
55
+ main.rb supports sub-commands in a very simple way
56
+
57
+ require 'main'
58
+
59
+ Main {
60
+ mode 'install' do
61
+ def run() puts 'installing...' end
62
+ end
63
+
64
+ mode 'uninstall' do
65
+ def run() puts 'uninstalling...' end
66
+ end
67
+ }
68
+
69
+ which allows a program, called 'a.rb', to be invoked as
70
+
71
+ ruby a.rb install
72
+
73
+ and
74
+
75
+ ruby a.rb uninstall
76
+
77
+ for simple programs main.rb is a real time saver but it's for more complex
78
+ applications where main.rb's unification of parameter parsing, class
79
+ configuration dsl, and auto-generation of usage messages can really streamline
80
+ command line application development. for example the following 'a.rb'
81
+ program:
82
+
83
+ require 'main'
84
+
85
+ Main {
86
+ argument('foo'){
87
+ cast :int
88
+ }
89
+ keyword('bar'){
90
+ arity 2
91
+ cast :float
92
+ defaults 0.0, 1.0
93
+ }
94
+ option('foobar'){
95
+ argument :optional
96
+ description 'the foobar option is very handy'
97
+ }
98
+ environment('BARFOO'){
99
+ cast :list_of_bool
100
+ synopsis 'export barfoo=value'
101
+ }
102
+
103
+ def run
104
+ p params['foo'].value
105
+ p params['bar'].values
106
+ p params['foobar'].value
107
+ p params['BARFOO'].value
108
+ end
109
+ }
110
+
111
+ when run with a command line of
112
+
113
+ BARFOO=true,false,false ruby a.rb 42 bar=40 bar=2 --foobar=a
114
+
115
+ will produce
116
+
117
+ 42
118
+ [40.0, 2.0]
119
+ "a"
120
+ [true, false, false]
121
+
122
+ while a command line of
123
+
124
+ ruby a.rb --help
125
+
126
+ will produce
127
+
128
+ NAME
129
+ a.rb
130
+
131
+ SYNOPSIS
132
+ a.rb foo [bar=bar] [options]+
133
+
134
+ PARAMETERS
135
+ * foo [ 1 -> int(foo) ]
136
+
137
+ * bar=bar [ 2 ~> float(bar=0.0,1.0) ]
138
+
139
+ * --foobar=[foobar] [ 1 ~> foobar ]
140
+ the foobar option is very handy
141
+
142
+ * --help, -h
143
+
144
+ * export barfoo=value
145
+
146
+ and this shows how all of argument, keyword, option, and environment parsing
147
+ can be declartively dealt with in a unified fashion - the dsl for all
148
+ parameter types is the same - and how auto synopsis and usage generation saves
149
+ keystrokes. the parameter synopsis is compact and can be read as
150
+
151
+ * foo [ 1 -> int(foo) ]
152
+
153
+ 'one argument will get processed via int(argument_name)'
154
+
155
+ 1 : one argument
156
+ -> : will get processed (the argument is required)
157
+ int(foo) : the cast is int, the arg name is foo
158
+
159
+ * bar=bar [ 2 ~> float(bar=0.0,1.0) ]
160
+
161
+ 'two keyword arguments might be processed via float(bar=0.0,1.0)'
162
+
163
+ 2 : two arguments
164
+ ~> : might be processed (the argument is optional)
165
+ float(bar=0.0,1.0) : the cast will be float, the default values are
166
+ 0.0 and 1.0
167
+
168
+ * --foobar=[foobar] [ 1 ~> foobar ]
169
+
170
+ 'one option with optional argument may be given directly'
171
+
172
+ * --help, -h
173
+
174
+ no synopsis, simple switch takes no args and is not required
175
+
176
+ * export barfoo=value
177
+
178
+ a user defined synopsis
179
+
180
+ SAMPLES
181
+ <%= samples %>
182
+
183
+ DOCS
184
+ test/main.rb
185
+
186
+ vim -p lib/main.rb lib/main/*rb
187
+
188
+ API section below
189
+
190
+ HISTORY
191
+ 2.8.3
192
+ - support for block defaults
193
+
194
+
195
+ 2.8.2
196
+ - fixes and tests for negative arity/attr arguments, options, eg
197
+
198
+ argument(:foo){
199
+ arity -1
200
+ }
201
+
202
+ def run # ARGV == %w( a b c )
203
+ p foo #=> %w( a b c )
204
+ end
205
+
206
+ thanks nathan
207
+
208
+ 2.8.1
209
+ - move from attributes.rb to fattr.rb
210
+
211
+ 2.8.0
212
+ - added 'to_options' method for Parameter::Table. this allows you to convert
213
+ all the parameters to a simple hash.
214
+ for example
215
+
216
+ Main {
217
+ option 'foo'
218
+ argument 'baz'
219
+
220
+ run { puts params.to_options.inspect }
221
+
222
+ }
223
+
224
+ 2.7.0
225
+ - removed bundled arrayfields and attributes. these are now dependancies
226
+ mananged by rubygems. a.k.a. you must have rubygems installed for main
227
+ to work.
228
+
229
+ 2.6.0
230
+ - added 'mixin' feaature for storing, and later evaluating a block of
231
+ code. the purpose of this is for use with modes where you want to keep
232
+ your code dry, but may not want to define something in the base class
233
+ for all to inherit. 'mixin' allows you to define the code to inherit
234
+ once and the selectively drop it in child classes (modes) on demand.
235
+ for example
236
+
237
+ Main {
238
+ mixin :foobar do
239
+ option 'foo'
240
+ option 'bar'
241
+ end
242
+
243
+ mode :install do
244
+ mixin :foobar
245
+ end
246
+
247
+ mode :uninstall do
248
+ mixin :foobar
249
+ end
250
+
251
+ mode :clean do
252
+ end
253
+ }
254
+
255
+ - mode definitions are now deferred to the end of the Main block, so you
256
+ can do this
257
+
258
+ Main {
259
+ mode 'a' do
260
+ mixin :foo
261
+ end
262
+
263
+ mode 'b' do
264
+ mixin :foo
265
+ end
266
+
267
+ def inherited_method
268
+ 42
269
+ end
270
+
271
+ mixin 'foo' do
272
+ def another_inherited_method
273
+ 'forty-two'
274
+ end
275
+ end
276
+ }
277
+
278
+ - added sanity check at end of paramter contruction
279
+
280
+ - improved auto usage generation when arity is used with arguments
281
+
282
+ - removed 'p' shortcut in paramerter dsl because it collided with
283
+ Kernel.p. it's now called 'param'. this method is availble *inside* a
284
+ parameter definition
285
+
286
+ option('foo', 'f'){
287
+ synopsis "arity = #{ param.arity }"
288
+ }
289
+
290
+ - fixed bug where '--' did not signal the end of parameter parsing in a
291
+ getoptlong compliant way
292
+
293
+ - added (before/after)_parse_parameters, (before/after)_initialize, and
294
+ (before/after)_run hooks
295
+
296
+ - fixed bug where adding to usage via
297
+
298
+ usage['my_section'] = 'custom message'
299
+
300
+ totally horked the default auto generated usage message
301
+
302
+ - updated dependancies in gemspec.rb for attributes (~> 5.0.0) and
303
+ arrayfields (~> 4.3.0)
304
+
305
+ - check that client code defined run, iff not wrap_run! is called. this is
306
+ so mains with a mode, but no run defined, still function correctly when
307
+ passed a mode
308
+
309
+ - added new shortcut for creating accessors for parameters. for example
310
+
311
+ option('foo'){
312
+ argument :required
313
+ cast :int
314
+ attr
315
+ }
316
+
317
+ def run
318
+ p foo ### this attr will return the parameter's *value*
319
+ end
320
+
321
+ a block can be passed to specify how to extract the value from the
322
+ parameter
323
+
324
+ argument('foo'){
325
+ optional
326
+ default 21
327
+ cast :int
328
+ attr{|param| param.value * 2}
329
+ }
330
+
331
+ def run
332
+ p foo #=> 42
333
+ end
334
+
335
+ - fixed bug where 'abort("message")' would print "message" twice on exit
336
+ if running under a nested mode (yes again - the fix in 2.4.0 wasn't
337
+ complete)
338
+
339
+ - added a time cast, which uses Time.parse
340
+
341
+ argument('login_time'){ cast :time }
342
+
343
+ - added a date cast, which uses Date.parse
344
+
345
+ argument('login_date'){ cast :date }
346
+
347
+
348
+ 2.5.0
349
+ - added 'examples', 'samples', and 'api' kewords to main dsl. each
350
+ keyword takes a list of strings which will be included in the help
351
+ message
352
+
353
+ Main {
354
+ examples "foobar example", "barfoo example"
355
+
356
+ samples <<-txt
357
+ do this
358
+
359
+ don't do that
360
+ txt
361
+
362
+ api %(
363
+ foobar string, hash
364
+
365
+ barfoo hash, string
366
+ )
367
+ }
368
+
369
+ results in a usage message with sections like
370
+
371
+ ...
372
+
373
+ EXAMPLES
374
+ foobar example
375
+ barfoo example
376
+
377
+ SAMPLES
378
+ do this
379
+
380
+ don't do that
381
+
382
+ API
383
+ foobar string, hash
384
+
385
+ barfoo hash, string
386
+
387
+ ...
388
+
389
+ 2.4.0
390
+ - fixed bug where 'abort("message")' would print "message" twice on exit
391
+ if running under a nested mode.
392
+
393
+ - allowed parameters to be overridden completely in subclasses (modes)
394
+
395
+ 2.3.0
396
+ - re-worked Main.new such that client code may define an #initialize
397
+ methods and the class will continue to work. that is to say it's fine
398
+ to do this
399
+
400
+ Main {
401
+ def initialize
402
+ @a = 42
403
+ end
404
+
405
+ def run
406
+ p @a
407
+ end
408
+
409
+ mode 'foo' do
410
+ def run
411
+ p @a
412
+ end
413
+ end
414
+ }
415
+
416
+ the client #initialize will be called *after* main has done it's normal
417
+ initialization so things like @argv, @env, and @stdin will all be there
418
+ in initialize. of course you could have done this before but you'd have
419
+ to both call super and call it with the correct arguments - now you can
420
+ simply ignore it.
421
+
422
+ 2.2.0
423
+ - added ability for parameter dsl error handlers to accept an argument,
424
+ this will be passed the current error. for example
425
+
426
+ argument(:x) do
427
+ arity 42
428
+
429
+ error do |e|
430
+ case e
431
+ when Parameter::Arity
432
+ ...
433
+ end
434
+ end
435
+
436
+ - refined the mode parsing a bit: modes can now be abbreviated to uniqness
437
+ and, when the mode is ambiuous, a nice error message is printed, for
438
+ example:
439
+
440
+ ambiguous mode: in = (inflate or install)?
441
+
442
+ 2.1.0
443
+ - added custom error handling dsl for parameters, this includes the ability
444
+ to prepend, append, or replace the standard error handlers:
445
+
446
+ require 'main'
447
+
448
+ Main {
449
+ argument 'x' do
450
+ error :before do
451
+ puts 'this fires *before* normal error handling using #instance_eval...'
452
+ end
453
+
454
+ error do
455
+ puts 'this fires *instead of* normal error handling using #instance_eval...'
456
+ end
457
+
458
+ error :after do
459
+ puts 'this fires *after* normal error handling using #instance_eval...'
460
+ end
461
+ end
462
+
463
+ run(){ p param['x'].given? }
464
+ }
465
+
466
+ - added ability to exit at any time bypassing *all* error handling using
467
+ 'throw :exit, 42' where 42 is the desired exit status. throw without a
468
+ status simply exits with 0.
469
+
470
+ - added 'help!' method which simply dumps out usage and exits
471
+
472
+ 2.0.0
473
+ - removed need for proxy.rb via Main::Base.wrap_run!
474
+ - added error handling hooks for parameter parsing
475
+ - bundled arrayfields, attributes, and pervasives although gems are tried
476
+ first
477
+ - softened error messages for parameter parsing errors: certain classes of
478
+ errors are now 'softspoken' and print only the message, not the entire
479
+ stacktrace, to stderr. much nicer for users. this is configurable.
480
+ - added subcommand/mode support
481
+ - added support for user defined exception handling on top level
482
+ exceptions/exits
483
+ - added support for negative arity. this users ruby's own arity
484
+ semantics, for example:
485
+
486
+ lambda{|*a|}.arity == -1
487
+ lambda{|a,*b|}.arity == -2
488
+ lambda{|a,b,*c|}.arity == -3
489
+ ...
490
+
491
+ in otherwords parameters now support 'zero or more', 'one or more' ...
492
+ 'n or more' argument semantics
493
+
494
+ 1.0.0
495
+ - some improved usage messages from jeremy hinegardner
496
+
497
+ 0.0.2
498
+ - removed dependancy on attributes/arrayfields. main now has zero gem
499
+ dependancies.
500
+
501
+ - added support for io redirection. redirection of stdin, stdout, and
502
+ stderr can be done to any io like object or object that can be
503
+ inerpreted as a pathname (object.to_s)
504
+
505
+ - main objects can now easily be created and run on demand, which makes
506
+ testing a breeze
507
+
508
+ def test_unit_goodness!
509
+ main =
510
+ Main.new{
511
+ stdout StringIO.new
512
+ stderr '/dev/null'
513
+
514
+ def run
515
+ puts 42
516
+ end
517
+ }
518
+
519
+ main.run
520
+ main.stdout.rewind
521
+
522
+ assert main.stdout.read == "42\n"
523
+ end
524
+
525
+ - added API section to readme and called it 'docs'
526
+
527
+ - wrote a bunch more tests. there are now 42 of them.
528
+
529
+ 0.0.1
530
+
531
+ initial version. this version extracts much of the functionality of alib's
532
+ (gen install alib) Alib.script main program generator and also some of jim's
533
+ freeze's excellent CommandLine::Aplication into what i hope is a simpler and
534
+ more unified interface
535
+
536
+ API
537
+
538
+ Main {
539
+
540
+ ###########################################################################
541
+ # CLASS LEVEL API #
542
+ ###########################################################################
543
+ #
544
+ # the name of the program, auto-set and used in usage
545
+ #
546
+ program 'foo.rb'
547
+ #
548
+ # a short description of program functionality, auto-set and used in usage
549
+ #
550
+ synopsis "foo.rb arg [options]+"
551
+ #
552
+ # long description of program functionality, used in usage iff set
553
+ #
554
+ description <<-hdoc
555
+ this text will automatically be indented to the right level.
556
+
557
+ it should describe how the program works in detail
558
+ hdoc
559
+ #
560
+ # used in usage iff set
561
+ #
562
+ author 'ara.t.howard@gmail.com'
563
+ #
564
+ # used in usage
565
+ #
566
+ version '0.0.42'
567
+ #
568
+ # stdin/out/err can be anthing which responds to read/write or a string
569
+ # which will be opened as in the appropriate mode
570
+ #
571
+ stdin '/dev/null'
572
+ stdout '/dev/null'
573
+ stderr open('/dev/null', 'w')
574
+ #
575
+ # the logger should be a Logger object, something 'write'-able, or a string
576
+ # which will be used to open the logger. the logger_level specifies the
577
+ # initalize verbosity setting, the default is Logger::INFO
578
+ #
579
+ logger(( program + '.log' ))
580
+ logger_level Logger::DEBUG
581
+ #
582
+ # you can configure exit codes. the defaults are shown
583
+ #
584
+ exit_success # 0
585
+ exit_failure # 1
586
+ exit_warn # 42
587
+ #
588
+ # the usage object is rather complex. by default it's an object which can
589
+ # be built up in sections using the
590
+ #
591
+ # usage["BUGS"] = "something about bugs'
592
+ #
593
+ # syntax to append sections onto the already pre-built usage message which
594
+ # contains program, synopsis, parameter descriptions and the like
595
+ #
596
+ # however, you always replace the usage object wholesale with one of your
597
+ # chosing like so
598
+ #
599
+ usage <<-txt
600
+ my own usage message
601
+ txt
602
+
603
+ ###########################################################################
604
+ # MODE API #
605
+ ###########################################################################
606
+ #
607
+ # modes are class factories that inherit from their parent class. they can
608
+ # be nested *arbitrarily* deep. usage messages are tailored for each mode.
609
+ # modes are, for the most part, independant classes but parameters are
610
+ # always a superset of the parent class - a mode accepts all of it's parents
611
+ # paramters *plus* and additional ones
612
+ #
613
+ option 'inherited-option'
614
+ argument 'inherited-argument'
615
+
616
+ mode 'install' do
617
+ option 'force' do
618
+ description 'clobber existing installation'
619
+ end
620
+
621
+ def run
622
+ inherited_method()
623
+ puts 'installing...'
624
+ end
625
+
626
+ mode 'docs' do
627
+ description 'installs the docs'
628
+
629
+ def run
630
+ puts 'installing docs...'
631
+ end
632
+ end
633
+ end
634
+
635
+ mode 'un-install' do
636
+ option 'force' do
637
+ description 'remove even if dependancies exist'
638
+ end
639
+
640
+ def run
641
+ inherited_method()
642
+ puts 'un-installing...'
643
+ end
644
+ end
645
+
646
+ def run
647
+ puts 'no mode yo?'
648
+ end
649
+
650
+ def inherited_method
651
+ puts 'superclass_method...'
652
+ end
653
+
654
+
655
+ ###########################################################################
656
+ # PARAMETER API #
657
+ ###########################################################################
658
+ #
659
+ # all the parameter types of argument|keyword|option|environment share this
660
+ # api. you must specify the type when the parameter method is used.
661
+ # alternatively used one of the shortcut methods
662
+ # argument|keyword|option|environment. in otherwords
663
+ #
664
+ # parameter('foo'){ type :option }
665
+ #
666
+ # is synonymous with
667
+ #
668
+ # option('foo'){ }
669
+ #
670
+ option 'foo' {
671
+ #
672
+ # required - whether this paramter must by supplied on the command line.
673
+ # note that you can create 'required' options with this keyword
674
+ #
675
+ required # or required true
676
+ #
677
+ # argument_required - applies only to options.
678
+ #
679
+ argument_required # argument :required
680
+ #
681
+ # argument_optional - applies only to options.
682
+ #
683
+ argument_optional # argument :optional
684
+ #
685
+ # cast - should be either a lambda taking one argument, or a symbol
686
+ # designation one of the built in casts defined in Main::Cast. supported
687
+ # types are :boolean|:integer|:float|:numeric|:string|:uri. built-in
688
+ # casts can be abbreviated
689
+ #
690
+ cast :int
691
+ #
692
+ # validate - should be a lambda taking one argument and returning
693
+ # true|false
694
+ #
695
+ validate{|int| int == 42}
696
+ #
697
+ # synopsis - should be a concise characterization of the paramter. a
698
+ # default synopsis is built automatically from the parameter. this
699
+ # information is displayed in the usage message
700
+ #
701
+ synopsis '--foo'
702
+ #
703
+ # description - a longer description of the paramter. it appears in the
704
+ # usage also.
705
+ #
706
+ description 'a long description of foo'
707
+ #
708
+ # arity - indicates how many times the parameter should appear on the
709
+ # command line. the default is one. negative arities are supported and
710
+ # follow the same rules as ruby methods/procs.
711
+ #
712
+ arity 2
713
+ #
714
+ # default - you can provide a default value in case none is given. the
715
+ # alias 'defaults' reads a bit nicer when you are giving a list of
716
+ # defaults for paramters of > 1 arity
717
+ #
718
+ defaults 40, 2
719
+ #
720
+ # you can add custom per-parameter error handlers using the following
721
+ #
722
+ error :before do
723
+ puts 'this fires *before* normal error handling using #instance_eval...'
724
+ end
725
+
726
+ error do
727
+ puts 'this fires *instead of* normal error handling using #instance_eval...'
728
+ end
729
+
730
+ error :after do
731
+ puts 'this fires *after* normal error handling using #instance_eval...'
732
+ end
733
+ }
734
+
735
+ ###########################################################################
736
+ # INSTANCE LEVEL API #
737
+ ###########################################################################
738
+ #
739
+ # you must define a run method. it is the only method you must define.
740
+ #
741
+ def run
742
+ #
743
+ # all parameters are available in the 'params' hash and via the alias
744
+ # 'param'. it can be indexed via string or symbol. the values are all
745
+ # Main::Parameter objects
746
+ #
747
+ foo = params['foo']
748
+ #
749
+ # the given? method indicates whether or not the parameter was given on
750
+ # the commandline/environment, etc. in particular this will not be true
751
+ # when a default value was specified but no parameter was given
752
+ #
753
+ foo.given?
754
+ #
755
+ # the list of all values can be retrieved via 'values'. note that this
756
+ # is always an array.
757
+ #
758
+ p foo.values
759
+ #
760
+ # the __first__ value can be retrieved via 'value'. note that this
761
+ # never an array.
762
+ #
763
+ p foo.value
764
+ #
765
+ # the methods debug|info|warn|error|fatal are delegated to the logger
766
+ # object
767
+ #
768
+ info{ "this goes to the log" }
769
+ #
770
+ # you can set the exit_status at anytime. this status is used when
771
+ # exiting the program. exceptions cause this to be ext_failure if, and
772
+ # only if, the current value was exit_success. in otherwords an
773
+ # un-caught exception always results in a failing exit_status
774
+ #
775
+ exit_status exit_failure
776
+ #
777
+ # a few shortcuts both set the exit_status and exit the program.
778
+ #
779
+ exit_success!
780
+ exit_failure!
781
+ exit_warn!
782
+ end
783
+
784
+ }