main 2.9.3 → 3.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|