main 2.8.4 → 2.9.0

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