main 2.9.3 → 3.0.1
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 +27 -11
- data/README.erb +5 -3
- data/Rakefile +3 -2
- data/TODO +1 -1
- data/a.rb +5 -0
- data/lib/main.rb +2 -15
- data/lib/main/dsl.rb +77 -0
- data/lib/main/factories.rb +17 -11
- data/lib/main/mode.rb +4 -2
- data/lib/main/parameter.rb +16 -13
- data/lib/main/program.rb +6 -0
- data/lib/main/program/class_methods.rb +260 -0
- data/lib/main/program/instance_methods.rb +253 -0
- data/lib/main/stdext.rb +18 -20
- data/main.gemspec +5 -4
- data/samples/e.rb +15 -6
- data/samples/f.rb +2 -0
- data/test/main.rb +78 -54
- metadata +29 -6
- data/lib/main/base.rb +0 -517
data/README
CHANGED
@@ -7,7 +7,7 @@ SYNOPSIS
|
|
7
7
|
URI
|
8
8
|
http://codeforpeople.com/lib/ruby/
|
9
9
|
http://rubyforge.org/projects/codeforpeople/
|
10
|
-
http://
|
10
|
+
http://github.com/ahoward/main
|
11
11
|
|
12
12
|
INSTALL
|
13
13
|
gem install main
|
@@ -314,26 +314,35 @@ SAMPLES
|
|
314
314
|
|
315
315
|
require 'main'
|
316
316
|
|
317
|
+
ARGV.replace %w( x y argument )
|
318
|
+
|
317
319
|
Main {
|
318
|
-
argument '
|
319
|
-
option '
|
320
|
+
argument 'argument'
|
321
|
+
option 'option'
|
320
322
|
|
321
|
-
def run() puts '
|
323
|
+
def run() puts 'run' end
|
322
324
|
|
323
325
|
mode 'a' do
|
324
326
|
option 'a-option'
|
327
|
+
def run() puts 'a-run' end
|
325
328
|
end
|
326
329
|
|
327
|
-
mode '
|
328
|
-
option '
|
330
|
+
mode 'x' do
|
331
|
+
option 'x-option'
|
332
|
+
|
333
|
+
def run() puts 'x-run' end
|
334
|
+
|
335
|
+
mode 'y' do
|
336
|
+
option 'y-option'
|
329
337
|
|
330
|
-
|
338
|
+
def run() puts 'y-run' end
|
339
|
+
end
|
331
340
|
end
|
332
341
|
}
|
333
342
|
|
334
343
|
~ > ruby samples/e.rb
|
335
344
|
|
336
|
-
|
345
|
+
y-run
|
337
346
|
|
338
347
|
|
339
348
|
<========< samples/f.rb >========>
|
@@ -342,6 +351,8 @@ SAMPLES
|
|
342
351
|
|
343
352
|
require 'main'
|
344
353
|
|
354
|
+
ARGV.replace %W( compress /data )
|
355
|
+
|
345
356
|
Main {
|
346
357
|
argument('directory'){ description 'the directory to operate on' }
|
347
358
|
|
@@ -370,7 +381,7 @@ SAMPLES
|
|
370
381
|
|
371
382
|
~ > ruby samples/f.rb
|
372
383
|
|
373
|
-
|
384
|
+
this is how we run in compress mode
|
374
385
|
|
375
386
|
|
376
387
|
<========< samples/g.rb >========>
|
@@ -442,12 +453,17 @@ SAMPLES
|
|
442
453
|
|
443
454
|
DOCS
|
444
455
|
test/main.rb
|
445
|
-
|
446
456
|
vim -p lib/main.rb lib/main/*rb
|
447
|
-
|
448
457
|
API section below
|
449
458
|
|
450
459
|
HISTORY
|
460
|
+
3.0.0
|
461
|
+
- major refactor to support modes via module/extend vs. subclassing.
|
462
|
+
MIGHT NOT be backward compatible, though no known issues thus far.
|
463
|
+
|
464
|
+
2.9.0
|
465
|
+
- support ruby 1.9
|
466
|
+
|
451
467
|
2.8.3
|
452
468
|
- support for block defaults
|
453
469
|
|
data/README.erb
CHANGED
@@ -7,7 +7,7 @@ SYNOPSIS
|
|
7
7
|
URI
|
8
8
|
http://codeforpeople.com/lib/ruby/
|
9
9
|
http://rubyforge.org/projects/codeforpeople/
|
10
|
-
http://
|
10
|
+
http://github.com/ahoward/main
|
11
11
|
|
12
12
|
INSTALL
|
13
13
|
gem install main
|
@@ -182,12 +182,14 @@ SAMPLES
|
|
182
182
|
|
183
183
|
DOCS
|
184
184
|
test/main.rb
|
185
|
-
|
186
185
|
vim -p lib/main.rb lib/main/*rb
|
187
|
-
|
188
186
|
API section below
|
189
187
|
|
190
188
|
HISTORY
|
189
|
+
3.0.0
|
190
|
+
- major refactor to support modes via module/extend vs. subclassing.
|
191
|
+
MIGHT NOT be backward compatible, though no known issues thus far.
|
192
|
+
|
191
193
|
2.9.0
|
192
194
|
- support ruby 1.9
|
193
195
|
|
data/Rakefile
CHANGED
@@ -64,6 +64,7 @@ task :gemspec do
|
|
64
64
|
|
65
65
|
Gem::Specification::new do |spec|
|
66
66
|
spec.name = #{ lib.inspect }
|
67
|
+
spec.description = 'a class factory and dsl for generating command line programs real quick'
|
67
68
|
spec.version = #{ version.inspect }
|
68
69
|
spec.platform = Gem::Platform::RUBY
|
69
70
|
spec.summary = #{ lib.inspect }
|
@@ -77,8 +78,8 @@ task :gemspec do
|
|
77
78
|
|
78
79
|
spec.has_rdoc = #{ has_rdoc.inspect }
|
79
80
|
spec.test_files = #{ test_files.inspect }
|
80
|
-
|
81
|
-
|
81
|
+
spec.add_dependency 'fattr', '>= 1.0.3'
|
82
|
+
spec.add_dependency 'arrayfields', '>= 4.5.0'
|
82
83
|
|
83
84
|
spec.extensions.push(*#{ extensions.inspect })
|
84
85
|
|
data/TODO
CHANGED
data/lib/main.rb
CHANGED
@@ -2,7 +2,7 @@ module Main
|
|
2
2
|
#
|
3
3
|
# top level constants
|
4
4
|
#
|
5
|
-
Main::VERSION = '
|
5
|
+
Main::VERSION = '3.0.1' unless
|
6
6
|
defined? Main::VERSION
|
7
7
|
def self.version() Main::VERSION end
|
8
8
|
|
@@ -29,20 +29,7 @@ module Main
|
|
29
29
|
end
|
30
30
|
|
31
31
|
require 'fattr'
|
32
|
-
begin
|
33
|
-
version = Fattr.version
|
34
|
-
raise unless version[%r/^1\./]
|
35
|
-
rescue
|
36
|
-
abort "main requires fattrs >= 1.0.3 - gem install fattr"
|
37
|
-
end
|
38
|
-
|
39
32
|
require 'arrayfields'
|
40
|
-
begin
|
41
|
-
version = Arrayfields.version
|
42
|
-
raise unless version[%r/^4\./]
|
43
|
-
rescue
|
44
|
-
abort "main requires arrayfields >= 4.5.0 - gem install arrayfields"
|
45
|
-
end
|
46
33
|
#
|
47
34
|
# main's own libs
|
48
35
|
#
|
@@ -55,6 +42,6 @@ module Main
|
|
55
42
|
require libdir + 'parameter'
|
56
43
|
require libdir + 'getoptlong'
|
57
44
|
require libdir + 'mode'
|
58
|
-
require libdir + '
|
45
|
+
require libdir + 'program'
|
59
46
|
require libdir + 'factories'
|
60
47
|
end
|
data/lib/main/dsl.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
def parameter(*a, &b)
|
2
|
+
(parameters << Parameter.create(:parameter, self, *a, &b)).last
|
3
|
+
end
|
4
|
+
|
5
|
+
def argument(*a, &b)
|
6
|
+
(parameters << Parameter.create(:argument, self, *a, &b)).last
|
7
|
+
end
|
8
|
+
alias_method 'arg', 'argument'
|
9
|
+
|
10
|
+
def option(*a, &b)
|
11
|
+
(parameters << Parameter.create(:option, self, *a, &b)).last
|
12
|
+
end
|
13
|
+
alias_method 'opt', 'option'
|
14
|
+
alias_method 'switch', 'option'
|
15
|
+
|
16
|
+
def keyword(*a, &b)
|
17
|
+
(parameters << Parameter.create(:keyword, self, *a, &b)).last
|
18
|
+
end
|
19
|
+
alias_method 'kw', 'keyword'
|
20
|
+
|
21
|
+
def environment(*a, &b)
|
22
|
+
(parameters << Parameter.create(:environment, self, *a, &b)).last
|
23
|
+
end
|
24
|
+
alias_method 'env', 'environment'
|
25
|
+
|
26
|
+
def default_options!
|
27
|
+
option 'help', 'h' unless parameters.has_option?('help', 'h')
|
28
|
+
end
|
29
|
+
|
30
|
+
def mode(name, &block)
|
31
|
+
name = name.to_s
|
32
|
+
modes[name] = block
|
33
|
+
block.fattr(:name => name)
|
34
|
+
block
|
35
|
+
end
|
36
|
+
|
37
|
+
def can_has(ptype, *a, &b)
|
38
|
+
key = a.map{|s| s.to_s}.sort_by{|s| -s.size }.first
|
39
|
+
can_has_hash.update key => [ptype, a, b]
|
40
|
+
key
|
41
|
+
end
|
42
|
+
|
43
|
+
def has(key, *keys)
|
44
|
+
keys = [key, *keys].flatten.compact.map{|k| k.to_s}
|
45
|
+
keys.map do |key|
|
46
|
+
ptype, a, b = can_has_hash[key]
|
47
|
+
abort "yo - can *not* has #{ key.inspect }!?" unless(ptype and a and b)
|
48
|
+
send ptype, *a, &b
|
49
|
+
key
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def mixin(name, *names, &block)
|
54
|
+
names = [name, *names].flatten.compact.map{|name| name.to_s}
|
55
|
+
if block
|
56
|
+
names.each do |name|
|
57
|
+
mixin_table[name] = block
|
58
|
+
end
|
59
|
+
else
|
60
|
+
names.each do |name|
|
61
|
+
module_eval(&mixin_table[name])
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
## TODO - for some reason these hork the usage!
|
67
|
+
|
68
|
+
%w[ examples samples api ].each do |chunkname|
|
69
|
+
module_eval <<-code
|
70
|
+
def #{ chunkname } *a, &b
|
71
|
+
txt = b ? b.call : a.join("\\n")
|
72
|
+
usage['#{ chunkname }'] = txt
|
73
|
+
end
|
74
|
+
code
|
75
|
+
end
|
76
|
+
alias_method 'example', 'examples'
|
77
|
+
alias_method 'sample', 'samples'
|
data/lib/main/factories.rb
CHANGED
@@ -1,20 +1,26 @@
|
|
1
1
|
module Main
|
2
|
-
def Main.
|
3
|
-
|
2
|
+
def Main.factory(&block)
|
3
|
+
Program.factory(&block)
|
4
4
|
end
|
5
5
|
|
6
|
-
def Main.
|
7
|
-
|
6
|
+
def Main.create(&block)
|
7
|
+
factory(&block)
|
8
8
|
end
|
9
9
|
|
10
|
-
def Main.
|
11
|
-
|
10
|
+
def Main.new(*args, &block)
|
11
|
+
factory(&block).build(*args).new()
|
12
12
|
end
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
::Main.run argv, env, opts, &block
|
17
|
-
end
|
18
|
-
alias_method 'main', 'Main'
|
14
|
+
def Main.run(*args, &block)
|
15
|
+
new(*args, &block).run()
|
19
16
|
end
|
20
17
|
end
|
18
|
+
|
19
|
+
module Kernel
|
20
|
+
private
|
21
|
+
def Main(*args, &block)
|
22
|
+
Main.run(*args, &block)
|
23
|
+
end
|
24
|
+
|
25
|
+
alias_method 'main', 'Main'
|
26
|
+
end
|
data/lib/main/mode.rb
CHANGED
@@ -12,11 +12,13 @@ module Main
|
|
12
12
|
ensure
|
13
13
|
self.fields = []
|
14
14
|
end
|
15
|
+
|
15
16
|
def add klass
|
16
17
|
mode_name = Mode.new klass.mode_name
|
17
18
|
raise Duplicate, mode_name if has_key? mode_name
|
18
19
|
self[mode_name] = klass
|
19
20
|
end
|
21
|
+
|
20
22
|
def find_by_mode m, options = {}
|
21
23
|
quiet = options['quiet'] || options[:quiet]
|
22
24
|
each_pair do |mode, klass|
|
@@ -37,8 +39,8 @@ module Main
|
|
37
39
|
end
|
38
40
|
end
|
39
41
|
|
40
|
-
def self.list
|
41
|
-
List.new
|
42
|
+
def self.list(*a, &b)
|
43
|
+
List.new(*a, &b)
|
42
44
|
end
|
43
45
|
end
|
44
46
|
end
|
data/lib/main/parameter.rb
CHANGED
@@ -38,22 +38,24 @@ module Main
|
|
38
38
|
@sym ||= name.split(%r/::/).last.downcase.to_sym
|
39
39
|
end
|
40
40
|
|
41
|
-
def class_for
|
41
|
+
def class_for(type)
|
42
42
|
sym = type.to_s.downcase.to_sym
|
43
43
|
c = Types.detect{|t| t.sym == sym}
|
44
44
|
raise ArgumentError, type.inspect unless c
|
45
45
|
c
|
46
46
|
end
|
47
47
|
|
48
|
-
def create
|
49
|
-
c = class_for
|
48
|
+
def create(type, main, *a, &b)
|
49
|
+
c = class_for(type)
|
50
50
|
obj = c.allocate
|
51
51
|
obj.type = c.sym
|
52
|
-
obj.
|
52
|
+
obj.main = main
|
53
|
+
obj.instance_eval{ initialize(*a, &b) }
|
53
54
|
obj
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
58
|
+
fattr 'main'
|
57
59
|
fattr 'type'
|
58
60
|
fattr 'names'
|
59
61
|
fattr 'abbreviations'
|
@@ -74,8 +76,9 @@ module Main
|
|
74
76
|
fattr 'error_handler_instead'
|
75
77
|
fattr 'error_handler_after'
|
76
78
|
|
77
|
-
def initialize
|
78
|
-
@names = Cast.list_of_string
|
79
|
+
def initialize(name, *names, &block)
|
80
|
+
@names = Cast.list_of_string(name, *names)
|
81
|
+
|
79
82
|
@names.map! do |name|
|
80
83
|
if name =~ %r/^-+/
|
81
84
|
name.gsub! %r/^-+/, ''
|
@@ -330,7 +333,7 @@ puts
|
|
330
333
|
defaults!
|
331
334
|
validate!
|
332
335
|
|
333
|
-
argv.push
|
336
|
+
argv.push(*ignore[1..-1]) unless ignore.empty?
|
334
337
|
|
335
338
|
return self
|
336
339
|
ensure
|
@@ -520,8 +523,8 @@ puts
|
|
520
523
|
replace keep
|
521
524
|
end
|
522
525
|
|
523
|
-
def <<
|
524
|
-
delete
|
526
|
+
def <<(*a)
|
527
|
+
delete(*a)
|
525
528
|
super
|
526
529
|
end
|
527
530
|
end
|
@@ -541,7 +544,7 @@ puts
|
|
541
544
|
name = param.name
|
542
545
|
a ||= name
|
543
546
|
b = fattr_block_for name, &block
|
544
|
-
|
547
|
+
@param.main.module_eval{ fattr(*a, &b) }
|
545
548
|
end
|
546
549
|
alias_method 'attribute', 'fattr'
|
547
550
|
|
@@ -550,8 +553,8 @@ puts
|
|
550
553
|
lambda{ block.call self.param[name] }
|
551
554
|
end
|
552
555
|
|
553
|
-
def attr
|
554
|
-
fattr
|
556
|
+
def attr(*a, &b)
|
557
|
+
fattr(*a, &b)
|
555
558
|
end
|
556
559
|
|
557
560
|
def example *list
|
@@ -643,7 +646,7 @@ puts
|
|
643
646
|
raise ArgumentError, 'no default'
|
644
647
|
end
|
645
648
|
unless values.empty?
|
646
|
-
param.defaults.push
|
649
|
+
param.defaults.push(*values)
|
647
650
|
end
|
648
651
|
unless block.nil?
|
649
652
|
param.defaults.push block
|
data/lib/main/program.rb
ADDED
@@ -0,0 +1,260 @@
|
|
1
|
+
module Main
|
2
|
+
class Program
|
3
|
+
module ClassMethods
|
4
|
+
fattr('name'){ File.basename($0) }
|
5
|
+
fattr('program'){ File.basename($0) }
|
6
|
+
fattr('synopsis'){ Main::Usage.default_synopsis(self) }
|
7
|
+
fattr('description')
|
8
|
+
fattr('usage'){ Main::Usage.default_usage(self) }
|
9
|
+
fattr('modes'){ Main::Mode.list }
|
10
|
+
|
11
|
+
fattr('author')
|
12
|
+
fattr('version')
|
13
|
+
fattr('stdin'){ $stdin }
|
14
|
+
fattr('stdout'){ $stdout }
|
15
|
+
fattr('stderr'){ $stderr }
|
16
|
+
fattr('logger'){ Logger.new(stderr) }
|
17
|
+
fattr('logger_level'){ Logger::INFO }
|
18
|
+
fattr('exit_status'){ nil }
|
19
|
+
fattr('exit_success'){ Main::EXIT_SUCCESS }
|
20
|
+
fattr('exit_failure'){ Main::EXIT_FAILURE }
|
21
|
+
fattr('exit_warn'){ Main::EXIT_WARN }
|
22
|
+
fattr('parameters'){ Main::Parameter::List[] }
|
23
|
+
fattr('can_has_hash'){ Hash.new }
|
24
|
+
fattr('mixin_table'){ Hash.new }
|
25
|
+
|
26
|
+
fattr('factory')
|
27
|
+
fattr('argv')
|
28
|
+
fattr('env')
|
29
|
+
fattr('opts')
|
30
|
+
|
31
|
+
def factory(&block)
|
32
|
+
Factory.new(&block)
|
33
|
+
end
|
34
|
+
alias_method 'create', 'factory'
|
35
|
+
|
36
|
+
class Factory
|
37
|
+
def initialize(&block)
|
38
|
+
@block = block || lambda{}
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_proc
|
42
|
+
@block
|
43
|
+
end
|
44
|
+
|
45
|
+
def build(*args, &block)
|
46
|
+
argv = (args.shift || ARGV).map{|arg| arg.dup}
|
47
|
+
env = (args.shift || ENV).to_hash.dup
|
48
|
+
opts = (args.shift || {}).to_hash.dup
|
49
|
+
|
50
|
+
factory = self
|
51
|
+
program = Class.new(Program)
|
52
|
+
program.evaluate(&factory)
|
53
|
+
|
54
|
+
program.module_eval do
|
55
|
+
program.factory = factory
|
56
|
+
program.argv = argv
|
57
|
+
program.env = env
|
58
|
+
program.opts = opts
|
59
|
+
|
60
|
+
dynamically_extend_via_commandline_modes!
|
61
|
+
program.set_default_options!
|
62
|
+
|
63
|
+
define_method(:run, &block) if block
|
64
|
+
|
65
|
+
wrap_run!
|
66
|
+
end
|
67
|
+
program
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def new()
|
72
|
+
instance = allocate
|
73
|
+
instance.instance_eval do
|
74
|
+
pre_initialize()
|
75
|
+
before_initialize()
|
76
|
+
main_initialize()
|
77
|
+
initialize()
|
78
|
+
after_initialize()
|
79
|
+
post_initialize()
|
80
|
+
end
|
81
|
+
instance
|
82
|
+
end
|
83
|
+
|
84
|
+
def evaluate(&block)
|
85
|
+
module_eval(&block)
|
86
|
+
end
|
87
|
+
|
88
|
+
def set_default_options!
|
89
|
+
option('help', 'h') unless parameters.has_option?('help', 'h')
|
90
|
+
end
|
91
|
+
|
92
|
+
# TODO - ambiguous modes
|
93
|
+
|
94
|
+
# extend the class based on modules given in argv
|
95
|
+
#
|
96
|
+
def dynamically_extend_via_commandline_modes!
|
97
|
+
size = modes.size
|
98
|
+
depth_first_modes = Array.fields
|
99
|
+
|
100
|
+
loop do
|
101
|
+
modes.each do |mode|
|
102
|
+
arg = argv.first && %r/^#{ argv.first }/
|
103
|
+
if arg and mode.name =~ arg
|
104
|
+
argv.shift
|
105
|
+
modes.clear
|
106
|
+
evaluate(&mode)
|
107
|
+
depth_first_modes[mode.name] = mode
|
108
|
+
break
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
arg = argv.first && %r/^#{ argv.first }/
|
113
|
+
more_modes = (
|
114
|
+
!modes.empty? and modes.any?{|mode| arg && mode.name =~ arg}
|
115
|
+
)
|
116
|
+
|
117
|
+
break unless more_modes
|
118
|
+
end
|
119
|
+
|
120
|
+
self.modes = depth_first_modes
|
121
|
+
end
|
122
|
+
|
123
|
+
# wrap up users run method to handle errors, etc
|
124
|
+
#
|
125
|
+
def wrap_run!
|
126
|
+
evaluate do
|
127
|
+
alias_method 'run!', 'run'
|
128
|
+
|
129
|
+
def run()
|
130
|
+
exit_status =
|
131
|
+
catch :exit do
|
132
|
+
begin
|
133
|
+
parse_parameters
|
134
|
+
|
135
|
+
if help?
|
136
|
+
puts(usage)
|
137
|
+
exit
|
138
|
+
end
|
139
|
+
|
140
|
+
pre_run
|
141
|
+
before_run
|
142
|
+
run!
|
143
|
+
after_run
|
144
|
+
post_run
|
145
|
+
|
146
|
+
finalize
|
147
|
+
rescue Object => exception
|
148
|
+
self.exit_status ||= exception.status if exception.respond_to?(:status)
|
149
|
+
handle_exception(exception)
|
150
|
+
end
|
151
|
+
nil
|
152
|
+
end
|
153
|
+
|
154
|
+
self.exit_status ||= (exit_status || exit_success)
|
155
|
+
handle_exit(self.exit_status)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# TODO
|
161
|
+
def fully_qualified_mode
|
162
|
+
modes.map{|mode| mode.name}.join(' ')
|
163
|
+
end
|
164
|
+
|
165
|
+
def mode_name
|
166
|
+
return 'main' if modes.empty?
|
167
|
+
fully_qualified_mode
|
168
|
+
end
|
169
|
+
|
170
|
+
undef_method 'usage'
|
171
|
+
def usage(*args, &block)
|
172
|
+
usage! unless defined? @usage
|
173
|
+
return @usage if args.empty? and block.nil?
|
174
|
+
key, value, *ignored = args
|
175
|
+
value = block.call if block
|
176
|
+
@usage[key.to_s] = value.to_s
|
177
|
+
end
|
178
|
+
|
179
|
+
def parameter(*a, &b)
|
180
|
+
(parameters << Parameter.create(:parameter, self, *a, &b)).last
|
181
|
+
end
|
182
|
+
|
183
|
+
def argument(*a, &b)
|
184
|
+
(parameters << Parameter.create(:argument, self, *a, &b)).last
|
185
|
+
end
|
186
|
+
|
187
|
+
def option(*a, &b)
|
188
|
+
(parameters << Parameter.create(:option, self, *a, &b)).last
|
189
|
+
end
|
190
|
+
|
191
|
+
def keyword(*a, &b)
|
192
|
+
(parameters << Parameter.create(:keyword, self, *a, &b)).last
|
193
|
+
end
|
194
|
+
|
195
|
+
def environment(*a, &b)
|
196
|
+
(parameters << Parameter.create(:environment, self, *a, &b)).last
|
197
|
+
end
|
198
|
+
|
199
|
+
def default_options!
|
200
|
+
option 'help', 'h' unless parameters.has_option?('help', 'h')
|
201
|
+
end
|
202
|
+
|
203
|
+
def mode(name, &block)
|
204
|
+
name = name.to_s
|
205
|
+
modes[name] = block
|
206
|
+
block.fattr(:name => name)
|
207
|
+
block
|
208
|
+
end
|
209
|
+
|
210
|
+
def can_has(ptype, *a, &b)
|
211
|
+
key = a.map{|s| s.to_s}.sort_by{|s| -s.size }.first
|
212
|
+
can_has_hash.update key => [ptype, a, b]
|
213
|
+
key
|
214
|
+
end
|
215
|
+
|
216
|
+
def has(key, *keys)
|
217
|
+
keys = [key, *keys].flatten.compact.map{|k| k.to_s}
|
218
|
+
keys.map do |key|
|
219
|
+
ptype, a, b = can_has_hash[key]
|
220
|
+
abort "yo - can *not* has #{ key.inspect }!?" unless(ptype and a and b)
|
221
|
+
send ptype, *a, &b
|
222
|
+
key
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def mixin(name, *names, &block)
|
227
|
+
names = [name, *names].flatten.compact.map{|name| name.to_s}
|
228
|
+
if block
|
229
|
+
names.each do |name|
|
230
|
+
mixin_table[name] = block
|
231
|
+
end
|
232
|
+
else
|
233
|
+
names.each do |name|
|
234
|
+
module_eval(&mixin_table[name])
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
## TODO - for some reason these hork the usage!
|
240
|
+
|
241
|
+
%w[ examples samples api ].each do |chunkname|
|
242
|
+
module_eval <<-code
|
243
|
+
def #{ chunkname } *a, &b
|
244
|
+
txt = b ? b.call : a.join("\\n")
|
245
|
+
usage['#{ chunkname }'] = txt
|
246
|
+
end
|
247
|
+
code
|
248
|
+
end
|
249
|
+
alias_method 'example', 'examples'
|
250
|
+
alias_method 'sample', 'samples'
|
251
|
+
|
252
|
+
def run(&block)
|
253
|
+
block ||= lambda{}
|
254
|
+
define_method(:run, &block) if block
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
extend ClassMethods
|
259
|
+
end
|
260
|
+
end
|