main 2.9.3 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,253 @@
1
+ module Main
2
+ class Program
3
+ module InstanceMethods
4
+ # instance methods
5
+ #
6
+ fattr('main'){ self.class }
7
+ fattr('argv'){ main.argv }
8
+ fattr('env'){ main.env }
9
+ fattr('opts'){ main.opts }
10
+ fattr('stdin'){ main.stdin }
11
+ fattr('stdout'){ main.stdout }
12
+ fattr('stderr'){ main.stderr }
13
+ fattr('logger'){ main.logger }
14
+ fattr('params')
15
+
16
+ %w(
17
+ program name synopsis description author version
18
+ exit_status exit_success exit_failure exit_warn
19
+ logger_level
20
+ usage
21
+ ).each{|a| fattr(a){ self.class.send a}}
22
+
23
+ alias_method 'status', 'exit_status'
24
+ alias_method 'status=', 'exit_status='
25
+
26
+ %w( parameters param ).each do |dst|
27
+ alias_method "#{ dst }", "params"
28
+ alias_method "#{ dst }=", "params="
29
+ alias_method "#{ dst }?", "params?"
30
+ end
31
+
32
+ %w( debug info warn fatal error ).each do |m|
33
+ module_eval <<-code
34
+ def #{ m } *a, &b
35
+ logger.#{ m } *a, &b
36
+ end
37
+ code
38
+ end
39
+
40
+ def pre_initialize() :hook end
41
+ def before_initialize() :hook end
42
+ def main_initialize()
43
+ setup_finalizers
44
+ setup_io_restoration
45
+ setup_io_redirection
46
+ setup_logging
47
+ end
48
+ def initialize() :hook end
49
+ def after_initialize() :hook end
50
+ def post_initialize() :hook end
51
+
52
+ def setup_finalizers
53
+ @finalizers = finalizers = []
54
+ ObjectSpace.define_finalizer(self) do
55
+ while((f = finalizers.pop)); f.call; end
56
+ end
57
+ end
58
+
59
+ def finalize
60
+ while((f = @finalizers.pop)); f.call; end
61
+ end
62
+
63
+ def setup_io_redirection
64
+ self.stdin = opts['stdin'] || opts[:stdin] || stdin
65
+ self.stdout = opts['stdout'] || opts[:stdout] || stdout
66
+ self.stderr = opts['stderr'] || opts[:stderr] || stderr
67
+ end
68
+
69
+ def setup_logging
70
+ log = self.class.logger || stderr
71
+ self.logger = log
72
+ end
73
+ undef_method 'logger='
74
+ def logger= log
75
+ unless(defined?(@logger) and @logger == log)
76
+ case log
77
+ when ::Logger, Logger
78
+ @logger = log
79
+ when IO, StringIO
80
+ @logger = Logger.new log
81
+ @logger.level = logger_level
82
+ else
83
+ @logger = Logger.new(*log)
84
+ @logger.level = logger_level
85
+ end
86
+ end
87
+ @logger
88
+ end
89
+
90
+ def setup_io_restoration
91
+ [STDIN, STDOUT, STDERR].each do |io|
92
+ dup = io.dup and @finalizers.push lambda{ io.reopen dup rescue nil }
93
+ end
94
+ end
95
+
96
+ undef_method 'stdin='
97
+ def stdin= io
98
+ unless(defined?(@stdin) and (@stdin == io))
99
+ @stdin =
100
+ if io.respond_to? 'read'
101
+ io
102
+ else
103
+ fd = open io.to_s, 'r+'
104
+ @finalizers.push lambda{ fd.close }
105
+ fd
106
+ end
107
+ begin
108
+ STDIN.reopen @stdin
109
+ rescue
110
+ $stdin = @stdin
111
+ ::Object.const_set 'STDIN', @stdin
112
+ end
113
+ end
114
+ end
115
+
116
+ undef_method 'stdout='
117
+ def stdout= io
118
+ unless(defined?(@stdout) and (@stdout == io))
119
+ @stdout =
120
+ if io.respond_to? 'write'
121
+ io
122
+ else
123
+ fd = open io.to_s, 'w+'
124
+ @finalizers.push lambda{ fd.close }
125
+ fd
126
+ end
127
+ STDOUT.reopen @stdout rescue($stdout = @stdout)
128
+ end
129
+ end
130
+
131
+ undef_method 'stderr='
132
+ def stderr= io
133
+ unless(defined?(@stderr) and (@stderr == io))
134
+ @stderr =
135
+ if io.respond_to? 'write'
136
+ io
137
+ else
138
+ fd = open io.to_s, 'w+'
139
+ @finalizers.push lambda{ fd.close }
140
+ fd
141
+ end
142
+ STDERR.reopen @stderr rescue($stderr = @stderr)
143
+ end
144
+ end
145
+
146
+ def pre_parse_parameters() :hook end
147
+ def before_parse_parameters() :hook end
148
+ def parse_parameters
149
+ pre_parse_parameters
150
+ before_parse_parameters
151
+
152
+ self.class.parameters.parse(self)
153
+ @params = Parameter::Table.new
154
+ self.class.parameters.each{|p| @params[p.name.to_s] = p}
155
+
156
+ after_parse_parameters
157
+ post_parse_parameters
158
+ end
159
+ def after_parse_parameters() :hook end
160
+ def post_parse_parameters() :hook end
161
+
162
+ def pre_run() :hook end
163
+ def before_run() :hook end
164
+ def run
165
+ raise NotImplementedError, 'run not defined'
166
+ end
167
+ def after_run() :hook end
168
+ def post_run() :hook end
169
+
170
+ fattr 'mode'
171
+ def modes
172
+ self.class.modes
173
+ end
174
+
175
+ def help!(status = 0)
176
+ print usage.to_s
177
+ exit(status)
178
+ end
179
+
180
+ def help?
181
+ (params['help'] and params['help'].given?) or argv.first == 'help'
182
+ end
183
+
184
+ def abort(message = 'exit')
185
+ raise SystemExit.new(message)
186
+ end
187
+
188
+ def handle_exception(e)
189
+ if e.respond_to?(:error_handler_before)
190
+ fcall(e, :error_handler_before, self)
191
+ end
192
+
193
+ if e.respond_to?(:error_handler_instead)
194
+ fcall(e, :error_handler_instead, self)
195
+ else
196
+ if e.respond_to?(:status)
197
+ exit_status(( e.status ))
198
+ end
199
+
200
+ if Softspoken === e or SystemExit === e
201
+ quiet = ((SystemExit === e and e.message.respond_to?('abort')) or # see main/stdext.rb
202
+ (SystemExit === e and e.message == 'exit'))
203
+ stderr.puts e.message unless quiet
204
+ else
205
+ fatal{ e }
206
+ end
207
+ end
208
+
209
+ if e.respond_to?(:error_handler_after)
210
+ fcall(e, :error_handler_after, self)
211
+ end
212
+
213
+ exit_status(( exit_failure )) if exit_status == exit_success
214
+ exit_status(( Integer(exit_status) rescue(exit_status ? 0 : 1) ))
215
+ end
216
+
217
+ def handle_exit(status)
218
+ exit(( Integer(status) rescue 1 ))
219
+ end
220
+
221
+ def fcall(object, method, *argv, &block)
222
+ method = object.method(method)
223
+ arity = m.arity
224
+ if arity >= 0
225
+ argv = argv[0, arity]
226
+ else
227
+ arity = arity.abs - 1
228
+ argv = argv[0, arity] + argv[arity .. -1]
229
+ end
230
+ method.call(*argv, &block)
231
+ end
232
+
233
+ %w[ before instead after ].each do |which|
234
+ module_eval <<-code
235
+ def error_handler_#{ which } *argv, &block
236
+ block.call *argv
237
+ end
238
+ code
239
+ end
240
+
241
+ def instance_eval_block(*argv, &block)
242
+ singleton_class =
243
+ class << self
244
+ self
245
+ end
246
+ singleton_class.module_eval{ define_method('__instance_eval_block', &block) }
247
+ fcall(self, '__instance_eval_block', *argv, &block)
248
+ end
249
+ end
250
+
251
+ include InstanceMethods
252
+ end
253
+ end
@@ -1,16 +1,17 @@
1
1
  class Object
2
- def singleton_class object = self, &block
3
- sc =
2
+ def singleton_class(object = self, &block)
3
+ singleton_class =
4
4
  class << object
5
5
  self
6
6
  end
7
- block ? sc.module_eval(&block) : sc
7
+ block ? singleton_class.module_eval(&block) : singleton_class
8
8
  end
9
-
10
9
  end
11
10
 
12
- module SaneAbort
13
- def abort message = nil
11
+ module Kernel
12
+ private
13
+ undef_method 'abort'
14
+ def abort(message = nil)
14
15
  if message
15
16
  message = message.to_s
16
17
  message.singleton_class{ fattr 'abort' => true }
@@ -20,19 +21,16 @@ module SaneAbort
20
21
  end
21
22
  end
22
23
 
23
- def abort message = nil
24
- if message
25
- message = message.to_s
26
- message.singleton_class{ fattr 'abort' => true }
27
- STDERR.puts message
28
- end
29
- exit 1
30
- end
31
- def Process.abort message = nil
32
- if message
33
- message = message.to_s
34
- message.singleton_class{ fattr 'abort' => true }
35
- STDERR.puts message
24
+ module Process
25
+ class << Process
26
+ undef_method 'abort'
27
+ def abort(message = nil)
28
+ if message
29
+ message = message.to_s
30
+ message.singleton_class{ fattr 'abort' => true }
31
+ STDERR.puts message
32
+ end
33
+ exit 1
36
34
  end
37
- exit 1
38
35
  end
36
+ end
@@ -3,11 +3,12 @@
3
3
 
4
4
  Gem::Specification::new do |spec|
5
5
  spec.name = "main"
6
- spec.version = "2.9.3"
6
+ spec.description = 'a class factory and dsl for generating command line programs real quick'
7
+ spec.version = "3.0.1"
7
8
  spec.platform = Gem::Platform::RUBY
8
9
  spec.summary = "main"
9
10
 
10
- spec.files = ["lib", "lib/main", "lib/main/base.rb", "lib/main/cast.rb", "lib/main/factories.rb", "lib/main/getoptlong.rb", "lib/main/logger.rb", "lib/main/mode.rb", "lib/main/parameter.rb", "lib/main/softspoken.rb", "lib/main/stdext.rb", "lib/main/usage.rb", "lib/main/util.rb", "lib/main.rb", "main.gemspec", "Rakefile", "README", "README.erb", "samples", "samples/a.rb", "samples/b.rb", "samples/c.rb", "samples/d.rb", "samples/e.rb", "samples/f.rb", "samples/g.rb", "samples/h.rb", "test", "test/main.rb", "TODO"]
11
+ spec.files = ["a.rb", "lib", "lib/main", "lib/main/cast.rb", "lib/main/dsl.rb", "lib/main/factories.rb", "lib/main/getoptlong.rb", "lib/main/logger.rb", "lib/main/mode.rb", "lib/main/parameter.rb", "lib/main/program", "lib/main/program/class_methods.rb", "lib/main/program/instance_methods.rb", "lib/main/program.rb", "lib/main/softspoken.rb", "lib/main/stdext.rb", "lib/main/usage.rb", "lib/main/util.rb", "lib/main.rb", "main.gemspec", "Rakefile", "README", "README.erb", "samples", "samples/a.rb", "samples/b.rb", "samples/c.rb", "samples/d.rb", "samples/e.rb", "samples/f.rb", "samples/g.rb", "samples/h.rb", "test", "test/main.rb", "TODO"]
11
12
  spec.executables = []
12
13
 
13
14
 
@@ -16,8 +17,8 @@ Gem::Specification::new do |spec|
16
17
 
17
18
  spec.has_rdoc = true
18
19
  spec.test_files = "test/main.rb"
19
- #spec.add_dependency 'lib', '>= version'
20
- #spec.add_dependency 'fattr'
20
+ spec.add_dependency 'fattr', '>= 1.0.3'
21
+ spec.add_dependency 'arrayfields', '>= 4.5.0'
21
22
 
22
23
  spec.extensions.push(*[])
23
24
 
@@ -1,18 +1,27 @@
1
1
  require 'main'
2
2
 
3
+ ARGV.replace %w( x y argument )
4
+
3
5
  Main {
4
- argument 'global-argument'
5
- option 'global-option'
6
+ argument 'argument'
7
+ option 'option'
6
8
 
7
- def run() puts 'global-run' end
9
+ def run() puts 'run' end
8
10
 
9
11
  mode 'a' do
10
12
  option 'a-option'
13
+ def run() puts 'a-run' end
11
14
  end
12
15
 
13
- mode 'b' do
14
- option 'b-option'
16
+ mode 'x' do
17
+ option 'x-option'
18
+
19
+ def run() puts 'x-run' end
20
+
21
+ mode 'y' do
22
+ option 'y-option'
15
23
 
16
- def run() puts 'b-run' end
24
+ def run() puts 'y-run' end
25
+ end
17
26
  end
18
27
  }
@@ -1,5 +1,7 @@
1
1
  require 'main'
2
2
 
3
+ ARGV.replace %W( compress /data )
4
+
3
5
  Main {
4
6
  argument('directory'){ description 'the directory to operate on' }
5
7
 
@@ -1,11 +1,11 @@
1
- $:.unshift '.'
2
- $:.unshift './lib'
3
- $:.unshift '..'
4
- $:.unshift '../lib'
1
+ $:.unshift('.')
2
+ $:.unshift('./lib')
3
+ $:.unshift('..')
4
+ $:.unshift('../lib')
5
5
 
6
- require 'stringio'
7
- require 'test/unit'
8
- require 'main'
6
+ require('stringio')
7
+ require('test/unit')
8
+ require('main')
9
9
 
10
10
 
11
11
  class T < Test::Unit::TestCase
@@ -22,7 +22,7 @@ class T < Test::Unit::TestCase
22
22
  def teardown
23
23
  end
24
24
 
25
- def main argv=[], env={}, &b
25
+ def main(argv=[], env={}, &block)
26
26
  at_exit{ exit! }
27
27
 
28
28
  $VERBOSE=nil
@@ -30,32 +30,33 @@ class T < Test::Unit::TestCase
30
30
  ENV.clear
31
31
  env.each{|k,v| ENV[k.to_s]=v.to_s}
32
32
 
33
- this = self
33
+ test = self
34
34
 
35
- klass = ::Main.create do
36
- module_eval &b if b
35
+ factory = Main.factory(&block)
37
36
 
38
- define_method :handle_exception do |e|
39
- if e.respond_to? :status
40
- this.status = e.status
37
+ program = factory.build(argv, env)
38
+
39
+ main = program.new
40
+
41
+ program.evaluate do
42
+ define_method :handle_exception do |exception|
43
+ if exception.respond_to?(:status)
44
+ test.status = main.status = exception.status
41
45
  else
42
- raise
46
+ test.status = main.status
47
+ raise(exception)
43
48
  end
44
49
  end
45
-
46
- define_method :handle_throw do |*a|
50
+ define_method :handle_exit do |status|
51
+ test.status = main.status = status
47
52
  end
48
53
  end
49
54
 
50
- main = klass.new argv, env
55
+ main.logger = logger
51
56
 
52
- main.logger = @logger
57
+ main.run
53
58
 
54
- begin
55
- main.run
56
- ensure
57
- this.status ||= main.exit_status
58
- end
59
+ test.status ||= main.exit_status
59
60
 
60
61
  main
61
62
  end
@@ -77,7 +78,7 @@ class T < Test::Unit::TestCase
77
78
  define_method(:run){ x = 42 }
78
79
  }
79
80
  }
80
- assert x == 42
81
+ assert_equal 42, x
81
82
  end
82
83
 
83
84
  # exit status
@@ -88,7 +89,7 @@ class T < Test::Unit::TestCase
88
89
  def run() end
89
90
  }
90
91
  }
91
- assert status == 0
92
+ assert_equal 0, status
92
93
  end
93
94
  def test_0030
94
95
  assert_nothing_raised{
@@ -96,7 +97,7 @@ class T < Test::Unit::TestCase
96
97
  def run() exit 42 end
97
98
  }
98
99
  }
99
- assert status == 42
100
+ assert_equal 42, status
100
101
  end
101
102
  def test_0040
102
103
  assert_nothing_raised{
@@ -106,7 +107,7 @@ class T < Test::Unit::TestCase
106
107
  }
107
108
  }
108
109
  Process.wait
109
- assert $?.exitstatus == 42
110
+ assert_equal 42, $?.exitstatus
110
111
  }
111
112
  end
112
113
  def test_0050
@@ -115,15 +116,7 @@ class T < Test::Unit::TestCase
115
116
  def run() exit 42 end
116
117
  }
117
118
  }
118
- assert status == 42
119
- end
120
- def test_0060
121
- assert_nothing_raised{
122
- main{
123
- def run() raise ArgumentError end
124
- }
125
- }
126
- assert status == 1
119
+ assert_equal 42, status
127
120
  end
128
121
  def test_0060
129
122
  assert_raises(RuntimeError){
@@ -131,7 +124,7 @@ class T < Test::Unit::TestCase
131
124
  def run() exit_status 42; raise end
132
125
  }
133
126
  }
134
- assert status == 42
127
+ assert_equal 42, status
135
128
  end
136
129
  def test_0070
137
130
  assert_raises(ArgumentError){
@@ -139,7 +132,7 @@ class T < Test::Unit::TestCase
139
132
  def run() exit_status 42; raise ArgumentError end
140
133
  }
141
134
  }
142
- assert status == 42
135
+ assert_equal 42, status
143
136
  end
144
137
 
145
138
  # parameter parsing
@@ -439,9 +432,9 @@ class T < Test::Unit::TestCase
439
432
  foobar = nil
440
433
  assert_nothing_raised{
441
434
  main(%w[foo=40 --bar=2 foobar foo=42]){
442
- kw('foo'){ cast :int; arity 2 }
443
- opt('bar='){ cast :int }
444
- arg 'foobar'
435
+ keyword('foo'){ cast :int; arity 2 }
436
+ option('bar='){ cast :int }
437
+ argument 'foobar'
445
438
 
446
439
  define_method('run'){
447
440
  foo = param['foo']
@@ -459,7 +452,7 @@ class T < Test::Unit::TestCase
459
452
  foo = nil
460
453
  assert_nothing_raised{
461
454
  main([], 'foo' => '42'){
462
- env('foo'){ cast :int }
455
+ environment('foo'){ cast :int }
463
456
  define_method('run'){
464
457
  foo = param['foo']
465
458
  }
@@ -488,7 +481,7 @@ class T < Test::Unit::TestCase
488
481
  end
489
482
  def test_0290
490
483
  assert_nothing_raised{
491
- u = Main::Usage.default Main.create
484
+ u = Main::Usage.default(Main.factory)
492
485
  }
493
486
  end
494
487
  def test_0300
@@ -662,7 +655,7 @@ class T < Test::Unit::TestCase
662
655
  argv = %w( a b c )
663
656
  assert_nothing_raised{
664
657
  main(argv.dup) {
665
- argument('zero_or_more'){ arity -1 }
658
+ argument('zero_or_more'){ arity(-1) }
666
659
  run{ m = self }
667
660
  }
668
661
  }
@@ -673,7 +666,7 @@ class T < Test::Unit::TestCase
673
666
  argv = %w( a b c )
674
667
  assert_nothing_raised{
675
668
  main(argv.dup) {
676
- argument('zero_or_more'){ arity -1 }
669
+ argument('zero_or_more'){ arity(-1) }
677
670
  run{ m = self }
678
671
  }
679
672
  }
@@ -684,7 +677,7 @@ class T < Test::Unit::TestCase
684
677
  argv = %w( a b c )
685
678
  assert_nothing_raised{
686
679
  main(argv.dup) {
687
- argument('zero_or_more'){ arity '*' }
680
+ argument('zero_or_more'){ arity('*') }
688
681
  run{ m = self }
689
682
  }
690
683
  }
@@ -695,7 +688,7 @@ class T < Test::Unit::TestCase
695
688
  argv = %w( a b c )
696
689
  assert_nothing_raised{
697
690
  main(argv.dup) {
698
- argument('one_or_more'){ arity -2 }
691
+ argument('one_or_more'){ arity(-2) }
699
692
  run{ m = self }
700
693
  }
701
694
  }
@@ -706,7 +699,7 @@ class T < Test::Unit::TestCase
706
699
  argv = %w( a b c )
707
700
  assert_nothing_raised{
708
701
  main(argv.dup) {
709
- argument('two_or_more'){ arity -3 }
702
+ argument('two_or_more'){ arity(-3) }
710
703
  run{ m = self }
711
704
  }
712
705
  }
@@ -717,7 +710,7 @@ class T < Test::Unit::TestCase
717
710
  argv = %w()
718
711
  assert_nothing_raised{
719
712
  main(argv.dup) {
720
- argument('zero_or_more'){ arity -1 }
713
+ argument('zero_or_more'){ arity(-1) }
721
714
  run{ m = self }
722
715
  }
723
716
  }
@@ -728,7 +721,7 @@ class T < Test::Unit::TestCase
728
721
  argv = %w()
729
722
  assert_raises(Main::Parameter::NotGiven){
730
723
  main(argv.dup) {
731
- argument('one_or_more'){ arity -2 }
724
+ argument('one_or_more'){ arity(-2) }
732
725
  run{ m = self }
733
726
  }
734
727
  }
@@ -738,7 +731,7 @@ class T < Test::Unit::TestCase
738
731
  argv = %w( a )
739
732
  assert_raises(Main::Parameter::Arity){
740
733
  main(argv.dup) {
741
- argument('two_or_more'){ arity -3 }
734
+ argument('two_or_more'){ arity(-3) }
742
735
  run{ m = self }
743
736
  }
744
737
  }
@@ -748,7 +741,7 @@ class T < Test::Unit::TestCase
748
741
  argv = %w( a )
749
742
  assert_raises(Main::Parameter::Arity){
750
743
  main(argv.dup) {
751
- argument('two_or_more'){ arity -4 }
744
+ argument('two_or_more'){ arity(-4) }
752
745
  run{ m = self }
753
746
  }
754
747
  }
@@ -767,6 +760,7 @@ class T < Test::Unit::TestCase
767
760
  end
768
761
  }
769
762
  }
763
+ assert m, 'm.nil!'
770
764
  assert m.param['b'].value == 'b'
771
765
  end
772
766
  def test_0490
@@ -782,8 +776,38 @@ class T < Test::Unit::TestCase
782
776
  end
783
777
  }
784
778
  }
779
+ assert m, 'm.nil!'
785
780
  assert m.param['c'].value == 'c'
786
781
  end
782
+ def test_0491
783
+ m = nil
784
+ argv = %w(a b c)
785
+ count = Hash.new{|h,k| h[k] = 0}
786
+ assert_nothing_raised{
787
+ main(argv.dup) {
788
+ %w(
789
+ initialize
790
+ pre_initialize
791
+ before_initialize
792
+ post_initialize
793
+ after_initialize
794
+ ).each do |method|
795
+ define_method(method){ count[method] += 1 }
796
+ end
797
+ mode 'a' do
798
+ mode 'b' do
799
+ mode 'c' do
800
+ run{ m = self }
801
+ end
802
+ end
803
+ end
804
+ }
805
+ }
806
+ assert m, 'm.nil!'
807
+ count.each do |key, val|
808
+ assert val==1, key
809
+ end
810
+ end
787
811
 
788
812
 
789
813
  # parameter attr/fattr/attribute
@@ -832,7 +856,7 @@ class T < Test::Unit::TestCase
832
856
  argvs.each do |argv|
833
857
  assert_nothing_raised{
834
858
  main(argv.dup) {
835
- argument(name){ arity -1; attr }
859
+ argument(name){ arity(-1); attr }
836
860
  run{ m = send(name) }
837
861
  }
838
862
  }