main 2.2.0 → 2.3.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
@@ -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