main 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -370,6 +370,33 @@ DOCS
370
370
  API section below
371
371
 
372
372
  HISTORY
373
+ 2.3.0
374
+ - re-worked Main.new such that client code may define an #initialize
375
+ methods and the class will continue to work. that is to say it's fine
376
+ to do this
377
+
378
+ Main {
379
+ def initialize
380
+ @a = 42
381
+ end
382
+
383
+ def run
384
+ p @a
385
+ end
386
+
387
+ mode 'foo' do
388
+ def run
389
+ p @a
390
+ end
391
+ end
392
+ }
393
+
394
+ the client #initialize will be called *after* main has done it's normal
395
+ initialization so things like @argv, @env, and @stdin will all be there
396
+ in initialize. of course you could have done this before but you'd have
397
+ to both call super and call it with the correct arguments - now you can
398
+ simply ignore it.
399
+
373
400
  2.2.0
374
401
  - added ability for parameter dsl error handlers to accept an argument,
375
402
  this will be passed the current error. for example
data/a.rb CHANGED
@@ -1,19 +1,17 @@
1
1
  require 'main'
2
2
 
3
3
  Main {
4
- argument 'x' do
5
- arity 2
6
4
 
7
- error :before do |e|
8
- p e
9
- puts 'this fires *before* normal error handling using #instance_eval...'
5
+ mode 'foo' do
6
+ def run
7
+ p mode
8
+ p @a
10
9
  end
10
+ end
11
11
 
12
- error do |e|
13
- p e
14
- puts 'this fires *instead of* normal error handling using #instance_eval...'
15
- end
12
+ def initialize
13
+ @a = 42
16
14
  end
17
15
 
18
- run(){ p param['x'].given? }
16
+ run(){ p @a; p @argv; p @env; }
19
17
  }
data/gemspec.rb CHANGED
@@ -1,26 +1,31 @@
1
-
2
1
  lib, version = File::basename(File::dirname(File::expand_path(__FILE__))).split %r/-/, 2
3
2
 
4
3
  require 'rubygems'
5
4
 
6
5
  Gem::Specification::new do |spec|
7
6
  $VERBOSE = nil
7
+
8
+ shiteless = lambda do |list|
9
+ list.delete_if do |file|
10
+ file =~ %r/\.svn/ or
11
+ file =~ %r/\.tmp/
12
+ end
13
+ end
14
+
8
15
  spec.name = lib
9
16
  spec.version = version
10
17
  spec.platform = Gem::Platform::RUBY
11
18
  spec.summary = lib
12
19
 
13
- spec.files = Dir::glob "**/**"
14
- spec.executables = Dir::glob("bin/*").map{|exe| File::basename exe}
20
+ spec.files = shiteless[Dir::glob("**/**")]
21
+ spec.executables = shiteless[Dir::glob("bin/*")].map{|exe| File::basename exe}
15
22
 
16
23
  spec.require_path = "lib"
17
24
  spec.autorequire = lib
18
25
 
19
26
  spec.has_rdoc = File::exist? "doc"
20
27
  spec.test_suite_file = "test/#{ lib }.rb" if File::directory? "test"
21
-
22
- spec.add_dependency 'attributes', '>= 4.1.0'
23
- spec.add_dependency 'arrayfields', '>= 4.3.0'
28
+ #spec.add_dependency 'lib', '>= version'
24
29
 
25
30
  spec.extensions << "extconf.rb" if File::exists? "extconf.rb"
26
31
 
data/install.rb CHANGED
@@ -37,6 +37,8 @@ def install_rb(srcdir=nil, destdir=nil, mode=nil, bin=nil)
37
37
  next if (f = f[srcdir.length+1..-1]) == nil
38
38
  next if (/CVS$/ =~ File.dirname(f))
39
39
  next if f =~ %r/\.lnk/
40
+ next if f =~ %r/\.svn/
41
+ next if f =~ %r/\.swp/
40
42
  path.push f
41
43
  dir |= [File.dirname(f)]
42
44
  end
@@ -2,7 +2,7 @@ module Main
2
2
  #
3
3
  # top level constants
4
4
  #
5
- Main::VERSION = '2.2.0' unless
5
+ Main::VERSION = '2.3.0' unless
6
6
  defined? Main::VERSION
7
7
  def self.version() Main::VERSION end
8
8
 
@@ -21,9 +21,7 @@ module Main
21
21
  end
22
22
 
23
23
  pre_run
24
-
25
24
  self.class.const_get(:RUN).bind(self).call(*a, &b)
26
-
27
25
  post_run
28
26
 
29
27
  finalize
@@ -127,6 +125,16 @@ module Main
127
125
  end
128
126
 
129
127
  def run(&b) define_method(:run, &b) end
128
+
129
+ def new(*a, &b)
130
+ allocate.instance_eval do
131
+ pre_initialize
132
+ main_initialize *a, &b
133
+ initialize
134
+ post_initialize
135
+ self
136
+ end
137
+ end
130
138
  end
131
139
 
132
140
  module DSL
@@ -199,14 +207,17 @@ module Main
199
207
  code
200
208
  end
201
209
 
210
+ =begin
211
+ =end
202
212
  def pre_initialize() :hook end
203
- def initialize argv = ARGV, env = ENV, opts = {}
213
+ def main_initialize argv = ARGV, env = ENV, opts = {}
204
214
  @argv, @env, @opts = argv, env, opts
205
215
  setup_finalizers
206
216
  setup_io_restoration
207
217
  setup_io_redirection
208
218
  setup_logging
209
219
  end
220
+ def initialize() :hook end
210
221
  def post_initialize() :hook end
211
222
 
212
223
  def setup_finalizers
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: main
5
5
  version: !ruby/object:Gem::Version
6
- version: 2.2.0
7
- date: 2007-10-24 00:00:00 -06:00
6
+ version: 2.3.0
7
+ date: 2007-10-27 00:00:00 -06:00
8
8
  summary: main
9
9
  require_paths:
10
10
  - lib
@@ -49,9 +49,7 @@ files:
49
49
  - lib/main/usage.rb
50
50
  - lib/main/util.rb
51
51
  - lib/main.rb
52
- - main-2.2.0.gem
53
52
  - README
54
- - README.tmpl
55
53
  - samples
56
54
  - samples/a.rb
57
55
  - samples/b.rb
@@ -73,22 +71,5 @@ extensions: []
73
71
 
74
72
  requirements: []
75
73
 
76
- dependencies:
77
- - !ruby/object:Gem::Dependency
78
- name: attributes
79
- version_requirement:
80
- version_requirements: !ruby/object:Gem::Version::Requirement
81
- requirements:
82
- - - ">="
83
- - !ruby/object:Gem::Version
84
- version: 4.1.0
85
- version:
86
- - !ruby/object:Gem::Dependency
87
- name: arrayfields
88
- version_requirement:
89
- version_requirements: !ruby/object:Gem::Version::Requirement
90
- requirements:
91
- - - ">="
92
- - !ruby/object:Gem::Version
93
- version: 4.3.0
94
- version:
74
+ dependencies: []
75
+
@@ -1,551 +0,0 @@
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://rubyforge.org/projects/codeforpeople/
9
- http://codeforpeople.com/lib/ruby/
10
-
11
- INSTALL
12
- gem install main
13
-
14
- DESCRIPTION
15
- main.rb features the following:
16
-
17
- - unification of option, argument, keyword, and environment parameter
18
- parsing
19
- - auto generation of usage and help messages
20
- - support for mode/sub-commands
21
- - io redirection support
22
- - logging hooks using ruby's built-in logging mechanism
23
- - intelligent error handling and exit codes
24
- - use as dsl or library for building Main objects
25
- - parsing user defined ARGV and ENV
26
- - zero requirements for understanding the obtuse apis of *any* command
27
- line option parsers
28
-
29
- in short main.rb aims to drastically lower the barrier to writing uniform
30
- command line applications.
31
-
32
- for instance, this program
33
-
34
- require 'main'
35
-
36
- Main {
37
- argument 'foo'
38
- option 'bar'
39
-
40
- def run
41
- p params['foo']
42
- p params['bar']
43
- exit_success!
44
- end
45
- }
46
-
47
- sets up a program which requires one argument, 'bar', and which may accept one
48
- command line switch, '--foo' in addition to the single option/mode which is always
49
- accepted and handled appropriately: 'help', '--help', '-h'. for the most
50
- part main.rb stays out of your command line namespace but insists that your
51
- application has at least a help mode/option.
52
-
53
- main.rb supports sub-commands in a very simple way
54
-
55
- require 'main'
56
-
57
- Main {
58
- mode 'install' do
59
- def run() puts 'installing...' end
60
- end
61
-
62
- mode 'uninstall' do
63
- def run() puts 'uninstalling...' end
64
- end
65
- }
66
-
67
- which allows you a program called 'a.rb' to be invoked as
68
-
69
- ruby a.rb install
70
-
71
- and
72
-
73
- ruby a.rb uninstall
74
-
75
- for simple programs main.rb is a real time saver but it's for more complex
76
- applications where main.rb's unification of parameter parsing, class
77
- configuration dsl, and auto-generation of usage messages can really streamline
78
- command line application development. for example the following 'a.rb'
79
- program:
80
-
81
- require 'main'
82
-
83
- Main {
84
- argument('foo'){
85
- cast :int
86
- }
87
- keyword('bar'){
88
- arity 2
89
- cast :float
90
- defaults 0.0, 1.0
91
- }
92
- option('foobar'){
93
- argument :optional
94
- description 'the foobar option is very handy'
95
- }
96
- environment('BARFOO'){
97
- cast :list_of_bool
98
- synopsis 'export barfoo=value'
99
- }
100
-
101
- def run
102
- p params['foo'].value
103
- p params['bar'].values
104
- p params['foobar'].value
105
- p params['BARFOO'].value
106
- end
107
- }
108
-
109
- when run with a command line of
110
-
111
- BARFOO=true,false,false ruby a.rb 42 bar=40 bar=2 --foobar=a
112
-
113
- will produce
114
-
115
- 42
116
- [40.0, 2.0]
117
- "a"
118
- [true, false, false]
119
-
120
- while a command line of
121
-
122
- ruby a.rb --help
123
-
124
- will produce
125
-
126
- NAME
127
- a.rb
128
-
129
- SYNOPSIS
130
- a.rb foo [bar=bar] [options]+
131
-
132
- PARAMETERS
133
- * foo [ 1 -> int(foo) ]
134
-
135
- * bar=bar [ 2 ~> float(bar=0.0,1.0) ]
136
-
137
- * --foobar=[foobar] [ 1 ~> foobar ]
138
- the foobar option is very handy
139
-
140
- * --help, -h
141
-
142
- * export barfoo=value
143
-
144
- and this shows how all of argument, keyword, option, and environment parsing
145
- can be declartively dealt with in a unified fashion - the dsl for all
146
- parameter types is the same - and how auto synopsis and usage generation saves
147
- keystrokes. the parameter synopsis is compact and can be read as
148
-
149
- * foo [ 1 -> int(foo) ]
150
-
151
- 'one argument will get processed via int(argument_name)'
152
-
153
- 1 : one argument
154
- -> : will get processed (the argument is required)
155
- int(foo) : the cast is int, the arg name is foo
156
-
157
- * bar=bar [ 2 ~> float(bar=0.0,1.0) ]
158
-
159
- 'two keyword arguments might be processed via float(bar=0.0,1.0)'
160
-
161
- 2 : two arguments
162
- ~> : might be processed (the argument is optional)
163
- float(bar=0.0,1.0) : the cast will be float, the default values are
164
- 0.0 and 1.0
165
-
166
- * --foobar=[foobar] [ 1 ~> foobar ]
167
-
168
- 'one option with optional argument may be given directly'
169
-
170
- * --help, -h
171
-
172
- no synopsis, simple switch takes no args and is not required
173
-
174
- * export barfoo=value
175
-
176
- a user defined synopsis
177
-
178
- SAMPLES
179
- @samples
180
-
181
- DOCS
182
- test/main.rb
183
-
184
- vim -o lib/main.rb lib/main/*
185
-
186
- API section below
187
-
188
- HISTORY
189
- 2.2.0
190
- - added ability for parameter dsl error handlers to accept an argument,
191
- this will be passed the current error. for example
192
-
193
- argument(:x) do
194
- arity 42
195
-
196
- error do |e|
197
- case e
198
- when Parameter::Arity
199
- ...
200
- end
201
- end
202
-
203
- - refined the mode parsing a bit: modes can now be abbreviated to uniqness
204
- and, when the mode is ambiuous, a nice error message is printed, for
205
- example:
206
-
207
- ambiguous mode: in = (inflate or install)?
208
-
209
- 2.1.0
210
- - added custom error handling dsl for parameters, this includes the ability
211
- to prepend, append, or replace the standard error handlers:
212
-
213
- require 'main'
214
-
215
- Main {
216
- argument 'x' do
217
- error :before do
218
- puts 'this fires *before* normal error handling using #instance_eval...'
219
- end
220
-
221
- error do
222
- puts 'this fires *instead of* normal error handling using #instance_eval...'
223
- end
224
-
225
- error :after do
226
- puts 'this fires *after* normal error handling using #instance_eval...'
227
- end
228
- end
229
-
230
- run(){ p param['x'].given? }
231
- }
232
-
233
- - added ability to exit at any time bypassing *all* error handling using
234
- 'throw :exit, 42' where 42 is the desired exit status. throw without a
235
- status simply exits with 0.
236
-
237
- - added 'help!' method which simply dumps out usage and exits
238
-
239
- 2.0.0
240
- - removed need for proxy.rb via Main::Base.wrap_run!
241
- - added error handling hooks for parameter parsing
242
- - bundled arrayfields, attributes, and pervasives although gems are tried
243
- first
244
- - softened error messages for parameter parsing errors: certain classes of
245
- errors are now 'softspoken' and print only the message, not the entire
246
- stacktrace, to stderr. much nicer for users. this is configurable.
247
- - added subcommand/mode support
248
- - added support for user defined exception handling on top level
249
- exceptions/exits
250
- - added support for negative arity. this users ruby's own arity
251
- semantics, for example:
252
-
253
- lambda{|*a|}.arity == -1
254
- lambda{|a,*b|}.arity == -2
255
- lambda{|a,b,*c|}.arity == -3
256
- ...
257
-
258
- in otherwords parameters now support 'zero or more', 'one or more' ...
259
- 'n or more' argument semantics
260
-
261
- 1.0.0
262
- - some improved usage messages from jeremy hinegardner
263
-
264
- 0.0.2
265
- - removed dependancy on attributes/arrayfields. main now has zero gem
266
- dependancies.
267
-
268
- - added support for io redirection. redirection of stdin, stdout, and
269
- stderr can be done to any io like object or object that can be
270
- inerpreted as a pathname (object.to_s)
271
-
272
- - main objects can now easily be created and run on demand, which makes
273
- testing a breeze
274
-
275
- def test_unit_goodness!
276
- main =
277
- Main.new{
278
- stdout StringIO.new
279
- stderr '/dev/null'
280
-
281
- def run
282
- puts 42
283
- end
284
- }
285
-
286
- main.run
287
- main.stdout.rewind
288
-
289
- assert main.stdout.read == "42\n"
290
- end
291
-
292
- - added API section to readme and called it 'docs'
293
-
294
- - wrote a bunch more tests. there are now 42 of them.
295
-
296
- 0.0.1
297
-
298
- initial version. this version extracts much of the functionality of alib's
299
- (gen install alib) Alib.script main program generator and also some of jim's
300
- freeze's excellent CommandLine::Aplication into what i hope is a simpler and
301
- more unified interface
302
-
303
- API
304
-
305
- Main {
306
-
307
- ###########################################################################
308
- # CLASS LEVEL API #
309
- ###########################################################################
310
- #
311
- # the name of the program, auto-set and used in usage
312
- #
313
- program 'foo.rb'
314
- #
315
- # a short description of program functionality, auto-set and used in usage
316
- #
317
- synopsis "foo.rb arg [options]+"
318
- #
319
- # long description of program functionality, used in usage iff set
320
- #
321
- description <<-hdoc
322
- this text will automatically be indented to the right level.
323
-
324
- it should describe how the program works in detail
325
- hdoc
326
- #
327
- # used in usage iff set
328
- #
329
- author 'ara.t.howard@gmail.com'
330
- #
331
- # used in usage
332
- #
333
- version '0.0.42'
334
- #
335
- # stdin/out/err can be anthing which responds to read/write or a string
336
- # which will be opened as in the appropriate mode
337
- #
338
- stdin '/dev/null'
339
- stdout '/dev/null'
340
- stderr open('/dev/null', 'w')
341
- #
342
- # the logger should be a Logger object, something 'write'-able, or a string
343
- # which will be used to open the logger. the logger_level specifies the
344
- # initalize verbosity setting, the default is Logger::INFO
345
- #
346
- logger(( program + '.log' ))
347
- logger_level Logger::DEBUG
348
- #
349
- # you can configure exit codes. the defaults are shown
350
- #
351
- exit_success # 0
352
- exit_failure # 1
353
- exit_warn # 42
354
- #
355
- # the usage object is rather complex. by default it's an object which can
356
- # be built up in sections using the
357
- #
358
- # usage["BUGS"] = "something about bugs'
359
- #
360
- # syntax to append sections onto the already pre-built usage message which
361
- # contains program, synopsis, parameter descriptions and the like
362
- #
363
- # however, you always replace the usage object wholesale with one of your
364
- # chosing like so
365
- #
366
- usage <<-txt
367
- my own usage message
368
- txt
369
-
370
- ###########################################################################
371
- # MODE API #
372
- ###########################################################################
373
- #
374
- # modes are class factories that inherit from their parent class. they can
375
- # be nested *arbitrarily* deep. usage messages are tailored for each mode.
376
- # modes are, for the most part, independant classes but parameters are
377
- # always a superset of the parent class - a mode accepts all of it's parents
378
- # paramters *plus* and additional ones
379
- #
380
- option 'inherited-option'
381
- argument 'inherited-argument'
382
-
383
- mode 'install' do
384
- option 'force' do
385
- description 'clobber existing installation'
386
- end
387
-
388
- def run
389
- inherited_method()
390
- puts 'installing...'
391
- end
392
-
393
- mode 'docs' do
394
- description 'installs the docs'
395
-
396
- def run
397
- puts 'installing docs...'
398
- end
399
- end
400
- end
401
-
402
- mode 'un-install' do
403
- option 'force' do
404
- description 'remove even if dependancies exist'
405
- end
406
-
407
- def run
408
- inherited_method()
409
- puts 'un-installing...'
410
- end
411
- end
412
-
413
- def run
414
- puts 'no mode yo?'
415
- end
416
-
417
- def inherited_method
418
- puts 'superclass_method...'
419
- end
420
-
421
-
422
- ###########################################################################
423
- # PARAMETER API #
424
- ###########################################################################
425
- #
426
- # all the parameter types of argument|keyword|option|environment share this
427
- # api. you must specify the type when the parameter method is used.
428
- # alternatively used one of the shortcut methods
429
- # argument|keyword|option|environment. in otherwords
430
- #
431
- # parameter('foo'){ type :option }
432
- #
433
- # is synonymous with
434
- #
435
- # option('foo'){ }
436
- #
437
- option 'foo' {
438
- #
439
- # required - whether this paramter must by supplied on the command line.
440
- # note that you can create 'required' options with this keyword
441
- #
442
- required # or required true
443
- #
444
- # argument_required - applies only to options.
445
- #
446
- argument_required # argument :required
447
- #
448
- # argument_optional - applies only to options.
449
- #
450
- argument_optional # argument :optional
451
- #
452
- # cast - should be either a lambda taking one argument, or a symbol
453
- # designation one of the built in casts defined in Main::Cast. supported
454
- # types are :boolean|:integer|:float|:numeric|:string|:uri. built-in
455
- # casts can be abbreviated
456
- #
457
- cast :int
458
- #
459
- # validate - should be a lambda taking one argument and returning
460
- # true|false
461
- #
462
- validate{|int| int == 42}
463
- #
464
- # synopsis - should be a concise characterization of the paramter. a
465
- # default synopsis is built automatically from the parameter. this
466
- # information is displayed in the usage message
467
- #
468
- synopsis '--foo'
469
- #
470
- # description - a longer description of the paramter. it appears in the
471
- # usage also.
472
- #
473
- description 'a long description of foo'
474
- #
475
- # arity - indicates how many times the parameter should appear on the
476
- # command line. the default is one. negative arities are supported and
477
- # follow the same rules as ruby methods/procs.
478
- #
479
- arity 2
480
- #
481
- # default - you can provide a default value in case none is given. the
482
- # alias 'defaults' reads a bit nicer when you are giving a list of
483
- # defaults for paramters of > 1 arity
484
- #
485
- defaults 40, 2
486
- #
487
- # you can add custom per-parameter error handlers using the following
488
- #
489
- error :before do
490
- puts 'this fires *before* normal error handling using #instance_eval...'
491
- end
492
-
493
- error do
494
- puts 'this fires *instead of* normal error handling using #instance_eval...'
495
- end
496
-
497
- error :after do
498
- puts 'this fires *after* normal error handling using #instance_eval...'
499
- end
500
- }
501
-
502
- ###########################################################################
503
- # INSTANCE LEVEL API #
504
- ###########################################################################
505
- #
506
- # you must define a run method. it is the only method you must define.
507
- #
508
- def run
509
- #
510
- # all parameters are available in the 'params' hash and via the alias
511
- # 'param'. it can be indexed via string or symbol. the values are all
512
- # Main::Parameter objects
513
- #
514
- foo = params['foo']
515
- #
516
- # the given? method indicates whether or not the parameter was given on
517
- # the commandline/environment, etc. in particular this will not be true
518
- # when a default value was specified but no parameter was given
519
- #
520
- foo.given?
521
- #
522
- # the list of all values can be retrieved via 'values'. note that this
523
- # is always an array.
524
- #
525
- p foo.values
526
- #
527
- # the __first__ value can be retrieved via 'value'. note that this
528
- # never an array.
529
- #
530
- p foo.value
531
- #
532
- # the methods debug|info|warn|error|fatal are delegated to the logger
533
- # object
534
- #
535
- info{ "this goes to the log" }
536
- #
537
- # you can set the exit_status at anytime. this status is used when
538
- # exiting the program. exceptions cause this to be ext_failure if, and
539
- # only if, the current value was exit_success. in otherwords an
540
- # un-caught exception always results in a failing exit_status
541
- #
542
- exit_status exit_failure
543
- #
544
- # a few shortcuts both set the exit_status and exit the program.
545
- #
546
- exit_success!
547
- exit_failure!
548
- exit_warn!
549
- end
550
-
551
- }
File without changes