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.
@@ -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
  }