clio 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. data/COPYING +170 -0
  2. data/HISTORY +11 -0
  3. data/MANIFEST +181 -0
  4. data/METADATA +18 -0
  5. data/NEWS +10 -0
  6. data/README +52 -0
  7. data/admin/config/reap.yaml +30 -0
  8. data/admin/depot/commandline.rb +219 -0
  9. data/admin/depot/multicommand.rb +403 -0
  10. data/admin/depot/test_multicommand.rb +40 -0
  11. data/admin/log/notes.xml +28 -0
  12. data/admin/log/stats.html +25 -0
  13. data/admin/log/syntax.log +0 -0
  14. data/admin/log/testunit.log +16 -0
  15. data/admin/pack/clio-0.0.1.gem +0 -0
  16. data/admin/share/reap/example.rb +7 -0
  17. data/admin/temps/lib/clio/about.rb.erb +4 -0
  18. data/lib/clio/ansicode.rb +319 -0
  19. data/lib/clio/command.rb +296 -0
  20. data/lib/clio/commandable.rb +195 -0
  21. data/lib/clio/commandline.rb +275 -0
  22. data/lib/clio/consoleutils.rb +117 -0
  23. data/lib/clio/errors.rb +16 -0
  24. data/lib/clio/option.rb +36 -0
  25. data/lib/clio/progressbar.rb +253 -0
  26. data/lib/clio/runmode.rb +126 -0
  27. data/lib/clio/string.rb +147 -0
  28. data/test/test_command.rb +42 -0
  29. data/test/test_commandline.rb +83 -0
  30. data/vendor/Console/Console.cpp +1203 -0
  31. data/vendor/Console/Console.rdoc +690 -0
  32. data/vendor/Console/Console_ANSI.rdoc +302 -0
  33. data/vendor/Console/HISTORY.txt +7 -0
  34. data/vendor/Console/INSTALL.txt +18 -0
  35. data/vendor/Console/Makefile +162 -0
  36. data/vendor/Console/README.txt +26 -0
  37. data/vendor/Console/doc/classes/Win32.html +115 -0
  38. data/vendor/Console/doc/classes/Win32/Console.html +650 -0
  39. data/vendor/Console/doc/classes/Win32/Console.src/M000001.html +31 -0
  40. data/vendor/Console/doc/classes/Win32/Console.src/M000002.html +23 -0
  41. data/vendor/Console/doc/classes/Win32/Console.src/M000003.html +23 -0
  42. data/vendor/Console/doc/classes/Win32/Console.src/M000004.html +27 -0
  43. data/vendor/Console/doc/classes/Win32/Console.src/M000005.html +23 -0
  44. data/vendor/Console/doc/classes/Win32/Console.src/M000006.html +28 -0
  45. data/vendor/Console/doc/classes/Win32/Console.src/M000007.html +23 -0
  46. data/vendor/Console/doc/classes/Win32/Console.src/M000008.html +24 -0
  47. data/vendor/Console/doc/classes/Win32/Console.src/M000009.html +44 -0
  48. data/vendor/Console/doc/classes/Win32/Console.src/M000010.html +23 -0
  49. data/vendor/Console/doc/classes/Win32/Console.src/M000011.html +33 -0
  50. data/vendor/Console/doc/classes/Win32/Console.src/M000012.html +26 -0
  51. data/vendor/Console/doc/classes/Win32/Console.src/M000013.html +27 -0
  52. data/vendor/Console/doc/classes/Win32/Console.src/M000014.html +28 -0
  53. data/vendor/Console/doc/classes/Win32/Console.src/M000015.html +23 -0
  54. data/vendor/Console/doc/classes/Win32/Console.src/M000016.html +23 -0
  55. data/vendor/Console/doc/classes/Win32/Console.src/M000017.html +23 -0
  56. data/vendor/Console/doc/classes/Win32/Console.src/M000018.html +29 -0
  57. data/vendor/Console/doc/classes/Win32/Console.src/M000019.html +23 -0
  58. data/vendor/Console/doc/classes/Win32/Console.src/M000020.html +23 -0
  59. data/vendor/Console/doc/classes/Win32/Console.src/M000021.html +28 -0
  60. data/vendor/Console/doc/classes/Win32/Console.src/M000022.html +23 -0
  61. data/vendor/Console/doc/classes/Win32/Console.src/M000023.html +28 -0
  62. data/vendor/Console/doc/classes/Win32/Console.src/M000024.html +35 -0
  63. data/vendor/Console/doc/classes/Win32/Console.src/M000025.html +28 -0
  64. data/vendor/Console/doc/classes/Win32/Console.src/M000026.html +28 -0
  65. data/vendor/Console/doc/classes/Win32/Console.src/M000027.html +28 -0
  66. data/vendor/Console/doc/classes/Win32/Console.src/M000028.html +31 -0
  67. data/vendor/Console/doc/classes/Win32/Console.src/M000029.html +23 -0
  68. data/vendor/Console/doc/classes/Win32/Console.src/M000030.html +23 -0
  69. data/vendor/Console/doc/classes/Win32/Console.src/M000031.html +23 -0
  70. data/vendor/Console/doc/classes/Win32/Console.src/M000032.html +27 -0
  71. data/vendor/Console/doc/classes/Win32/Console.src/M000033.html +27 -0
  72. data/vendor/Console/doc/classes/Win32/Console.src/M000034.html +25 -0
  73. data/vendor/Console/doc/classes/Win32/Console/ANSI.html +103 -0
  74. data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.html +220 -0
  75. data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000035.html +32 -0
  76. data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000036.html +205 -0
  77. data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000037.html +40 -0
  78. data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000038.html +25 -0
  79. data/vendor/Console/doc/classes/Win32/Console/API.html +758 -0
  80. data/vendor/Console/doc/classes/Win32/Console/API.src/M000039.html +27 -0
  81. data/vendor/Console/doc/classes/Win32/Console/API.src/M000040.html +27 -0
  82. data/vendor/Console/doc/classes/Win32/Console/API.src/M000041.html +27 -0
  83. data/vendor/Console/doc/classes/Win32/Console/API.src/M000042.html +32 -0
  84. data/vendor/Console/doc/classes/Win32/Console/API.src/M000043.html +32 -0
  85. data/vendor/Console/doc/classes/Win32/Console/API.src/M000044.html +28 -0
  86. data/vendor/Console/doc/classes/Win32/Console/API.src/M000045.html +26 -0
  87. data/vendor/Console/doc/classes/Win32/Console/API.src/M000046.html +26 -0
  88. data/vendor/Console/doc/classes/Win32/Console/API.src/M000047.html +27 -0
  89. data/vendor/Console/doc/classes/Win32/Console/API.src/M000048.html +30 -0
  90. data/vendor/Console/doc/classes/Win32/Console/API.src/M000049.html +29 -0
  91. data/vendor/Console/doc/classes/Win32/Console/API.src/M000050.html +27 -0
  92. data/vendor/Console/doc/classes/Win32/Console/API.src/M000051.html +28 -0
  93. data/vendor/Console/doc/classes/Win32/Console/API.src/M000052.html +30 -0
  94. data/vendor/Console/doc/classes/Win32/Console/API.src/M000053.html +27 -0
  95. data/vendor/Console/doc/classes/Win32/Console/API.src/M000054.html +29 -0
  96. data/vendor/Console/doc/classes/Win32/Console/API.src/M000055.html +29 -0
  97. data/vendor/Console/doc/classes/Win32/Console/API.src/M000056.html +28 -0
  98. data/vendor/Console/doc/classes/Win32/Console/API.src/M000057.html +27 -0
  99. data/vendor/Console/doc/classes/Win32/Console/API.src/M000058.html +47 -0
  100. data/vendor/Console/doc/classes/Win32/Console/API.src/M000059.html +32 -0
  101. data/vendor/Console/doc/classes/Win32/Console/API.src/M000060.html +47 -0
  102. data/vendor/Console/doc/classes/Win32/Console/API.src/M000061.html +34 -0
  103. data/vendor/Console/doc/classes/Win32/Console/API.src/M000062.html +32 -0
  104. data/vendor/Console/doc/classes/Win32/Console/API.src/M000063.html +32 -0
  105. data/vendor/Console/doc/classes/Win32/Console/API.src/M000064.html +35 -0
  106. data/vendor/Console/doc/classes/Win32/Console/API.src/M000065.html +26 -0
  107. data/vendor/Console/doc/classes/Win32/Console/API.src/M000066.html +27 -0
  108. data/vendor/Console/doc/classes/Win32/Console/API.src/M000067.html +29 -0
  109. data/vendor/Console/doc/classes/Win32/Console/API.src/M000068.html +27 -0
  110. data/vendor/Console/doc/classes/Win32/Console/API.src/M000069.html +27 -0
  111. data/vendor/Console/doc/classes/Win32/Console/API.src/M000070.html +28 -0
  112. data/vendor/Console/doc/classes/Win32/Console/API.src/M000071.html +27 -0
  113. data/vendor/Console/doc/classes/Win32/Console/API.src/M000072.html +26 -0
  114. data/vendor/Console/doc/classes/Win32/Console/API.src/M000073.html +27 -0
  115. data/vendor/Console/doc/classes/Win32/Console/API.src/M000074.html +31 -0
  116. data/vendor/Console/doc/classes/Win32/Console/API.src/M000075.html +27 -0
  117. data/vendor/Console/doc/classes/Win32/Console/API.src/M000076.html +32 -0
  118. data/vendor/Console/doc/classes/Win32/Console/API.src/M000077.html +27 -0
  119. data/vendor/Console/doc/classes/Win32/Console/API.src/M000078.html +32 -0
  120. data/vendor/Console/doc/classes/Win32/Console/API.src/M000079.html +32 -0
  121. data/vendor/Console/doc/classes/Win32/Console/API.src/M000080.html +32 -0
  122. data/vendor/Console/doc/classes/Win32/Console/Constants.html +360 -0
  123. data/vendor/Console/doc/created.rid +1 -0
  124. data/vendor/Console/doc/files/Console_ANSI_rdoc.html +407 -0
  125. data/vendor/Console/doc/files/Console_cpp.html +104 -0
  126. data/vendor/Console/doc/files/Console_rdoc.html +964 -0
  127. data/vendor/Console/doc/files/lib/Win32/Console/ANSI_rb.html +123 -0
  128. data/vendor/Console/doc/files/lib/Win32/Console_rb.html +297 -0
  129. data/vendor/Console/doc/fr_class_index.html +32 -0
  130. data/vendor/Console/doc/fr_file_index.html +31 -0
  131. data/vendor/Console/doc/fr_method_index.html +106 -0
  132. data/vendor/Console/doc/index.html +24 -0
  133. data/vendor/Console/doc/rdoc-style.css +172 -0
  134. data/vendor/Console/extconf.rb +18 -0
  135. data/vendor/Console/lib/Term/ansicolor.rb +76 -0
  136. data/vendor/Console/lib/Win32/Console.rb +970 -0
  137. data/vendor/Console/lib/Win32/Console/ANSI.rb +305 -0
  138. data/vendor/Console/test/test_cursor.rb +9 -0
  139. data/vendor/Console/test/test_mouse.rb +6 -0
  140. data/vendor/Console/test/test_readinput.rb +62 -0
  141. data/vendor/Console/test/test_readoutput.rb +52 -0
  142. data/vendor/Console/test/test_sendevent.rb +17 -0
  143. data/vendor/Console/test/test_title.rb +14 -0
  144. data/vendor/Console/test/test_write.rb +36 -0
  145. metadata +253 -0
@@ -0,0 +1,30 @@
1
+ ---
2
+
3
+ syntax: {}
4
+
5
+ autotools: ~
6
+
7
+ testunit: {}
8
+
9
+ basicstats: {}
10
+
11
+ notes: {}
12
+
13
+ rdoc:
14
+ template: jamis
15
+ inline: true
16
+
17
+ ridoc: {}
18
+
19
+ gem:
20
+ exclude:
21
+ - doc/rdoc
22
+ - doc/ri
23
+
24
+ rubyforge:
25
+ unixname: clio
26
+ groupid: 6913
27
+ # publishmap:
28
+ # admin/web: .
29
+ # doc/rdoc: rdoc
30
+
@@ -0,0 +1,219 @@
1
+ require 'shellwords'
2
+ require 'facets/kernel/object_class'
3
+
4
+ module Clio
5
+ ### = Commandline
6
+ ###
7
+ ### What a strange thing is the Clio Commandline.
8
+ ### An entity unknown until put upon.
9
+ class Commandline
10
+ instance_methods.each{ |m| private m if m !~ /^(__|instance_|object_|send$|inspect$)/ }
11
+
12
+ ### Splits a raw command line into two smaller
13
+ ### ones. The first including only options
14
+ ### upto the first non-option argument. This
15
+ ### makes quick work of separating subcommands
16
+ ### from a main command.
17
+ # TODO: Rename this method.
18
+ def self.gerrymander(argv=ARGV)
19
+ if String===argv
20
+ argv = Shellwords.shellwords(argv)
21
+ end
22
+ sub = argv.find{ |x| x !~ /^[-]/ }
23
+ idx = argv.index(sub)
24
+ opts = argv[0...idx]
25
+ scmd = argv[idx..-1]
26
+ return new(opts), new(scmd)
27
+ end
28
+
29
+ ### Define an option attibute.
30
+ ### While commandline can be used without
31
+ ### pre-declartion of support options
32
+ ### doding so allows for creating option
33
+ ### aliases. Eg. --quiet and -q.
34
+ def self.attr(name, *aliases)
35
+ name = name.to_s
36
+ if name =~ /\?$/
37
+ name = name.chomp('?')
38
+ #attr_writer name
39
+ module_eval "def #{name}?; self[:#{name}] ; end"
40
+ aliases.each do |alt|
41
+ alt = alt.to_s.chomp('?')
42
+ alias_method("#{alt}?", "#{name}?")
43
+ #alias_method("#{alt}=", "#{name}=")
44
+ end
45
+ else
46
+ attr_reader(name)
47
+ aliases.each do |alt|
48
+ #alt = alt.to_s.chomp('?') # TODO: raise error ?
49
+ alias_method("#{alt}" , "#{name}")
50
+ #alias_method("#{alt}=", "#{name}=")
51
+ end
52
+ end
53
+ end
54
+
55
+ ### Returns a list of all pre-defined options.
56
+ ### It does this by seaching class ancestry
57
+ ### for instance_methods until it reaches the
58
+ ### Commandline base class.
59
+ ### TODO: Rename #runmodes method.
60
+ ### TODO: Robust enough? Use an Inheritor instead?
61
+ def self.runmodes
62
+ index = ancestors.index(::Clio::Commandline)
63
+ options = ancestors[0...index].inject([]) do |opts, ancestor|
64
+ opts | ancestor.instance_methods(false)
65
+ end
66
+ options.reject{ |o| o =~ /\=$/ }
67
+ options.collect{ |o| o.to_sym }
68
+ end
69
+
70
+ public
71
+
72
+ ### This method provides the centralized means of accessing
73
+ ### the options and arguments of the commandline.
74
+ def [](index)
75
+ case index
76
+ when Integer
77
+ @arguments[index] ||= (
78
+ args = @argv.select{ |e| e !~ /^-/ }
79
+ val = args[index]
80
+ @argv.delete(args[index])
81
+ val
82
+ )
83
+ else
84
+ index = index.to_s
85
+ name = index.chomp('?')
86
+ key = name.to_sym
87
+ return @options[key] if @options.key?(key)
88
+
89
+ @options[key] = if index =~ /\?$/
90
+ name.size == 1 ? option_letter_flag(name) : option_flag(name)
91
+ else
92
+ name.size == 1 ? option_letter_value(name) : option_value(name)
93
+ end
94
+ end
95
+ end
96
+
97
+ ### Access to the underlying commandline "ARGV".
98
+ ### This will show what is yet to be processed.
99
+ def instance_delegate ; @argv ; end
100
+
101
+ private
102
+
103
+ ### New Commandline. Takse a single argument
104
+ ### which can be a "shell" string, or an array
105
+ ### of shell arguments, like ARGV. If none
106
+ ### is given it defaults to ARGV.
107
+ def initialize(argv=ARGV)
108
+ case argv
109
+ when String
110
+ @argv = Shellwords.shellwords(argv)
111
+ else
112
+ @argv = argv.dup
113
+ end
114
+ @arguments = []
115
+ @options = {}
116
+
117
+ object_class.runmodes.each do |name|
118
+ self[name]
119
+ end
120
+ end
121
+
122
+ ###
123
+ #def initialize(argv=ARGV)
124
+ # if Hash===argv
125
+ # argv.each{ |k,v| send("#{k}=", v) }
126
+ # else
127
+ # self.class.runmodes.each do |name|
128
+ # option(name)
129
+ # end
130
+ # end
131
+ #end
132
+
133
+ ### Routes to #[].
134
+ def method_missing(name, *args)
135
+ super unless args.empty?
136
+ case name.to_s
137
+ when /\=$/
138
+ super
139
+ else
140
+ self[name]
141
+ end
142
+ end
143
+
144
+ ### Helper method. This can be replaceb by
145
+ ### String#index when it supports blocks.
146
+ ### Err.. when will that be Matz?
147
+ def index(array, &block)
148
+ find = array.find(&block)
149
+ array.index(find)
150
+ end
151
+
152
+ ### Parse a flag option.
153
+ def option_flag(name)
154
+ p name
155
+ o = "--#{name}"
156
+ i = index(@argv){ |e| e =~ /^#{o}[=]?/ }
157
+ return false unless i
158
+ raise ArgumentError if @argv[i] =~ /=/
159
+ @argv[i] = nil
160
+ return true
161
+ end
162
+
163
+ ### Parse a value option.
164
+ def option_value(name)
165
+ o = "--#{name}"
166
+ i = index(@argv){ |e| e =~ /^#{o}[=]?/ }
167
+ return false unless i
168
+
169
+ if @argv[i] =~ /=/
170
+ key, val = *@argv[i].split('=')
171
+ argv[i] = nil
172
+ else
173
+ case @argv[i+1]
174
+ when nil, /^-/
175
+ raise ArgumentError
176
+ else
177
+ key = @argv[i]
178
+ val = @argv[i+1]
179
+ @argv[i,2] = nil
180
+ end
181
+ end
182
+ return val
183
+ end
184
+
185
+ ### Parse a single letter flag option.
186
+ def option_letter_flag(letter)
187
+ o = letter
188
+ i = index(@argv){ |e| e =~ /[-]\w+(#{o})\w*$/ }
189
+ if i
190
+ @argv[i] = @argv[i].gsub(o,'')
191
+ true
192
+ end
193
+ false
194
+ end
195
+
196
+ ### Parse a single letter value option.
197
+ def option_letter_value(letter)
198
+ o = letter
199
+ i = index(@argv){ |e| e =~ /#{o}(\=|$)/ }
200
+ return nil unless i
201
+ if @argv[i] =~ /=/
202
+ rest, val = argv[i].split('=')
203
+ @argv[i] = rest
204
+ else
205
+ case @argv[i+1]
206
+ when nil, /^-/
207
+ raise ArgumentError
208
+ else
209
+ val = argv[i+1]
210
+ @argv[i] = argv[i].gsub(o,'')
211
+ @argv[i+1] = nil
212
+ end
213
+ end
214
+ return val
215
+ end
216
+
217
+ end
218
+ end
219
+
@@ -0,0 +1,403 @@
1
+ warn "MultiCommand is under construction!"
2
+ exit 0
3
+
4
+ # = Clio::MultiCommand
5
+ #
6
+ # Base class with metaclass DSL for creating
7
+ # well defined, static command line interfaces.
8
+ #
9
+ # == Authors
10
+ #
11
+ # * Trans
12
+ #
13
+ # == Copying
14
+ #
15
+ # Copyright (c) 2005,2008 Thomas Sawyer
16
+ # Lesser GNU Public License
17
+ #
18
+ # This module is free software. You may use, modify, and/or
19
+ # redistribute this software under the same terms as Ruby.
20
+ #
21
+ # This program is distributed in the hope that it will be
22
+ # useful, but WITHOUT ANY WARRANTY; without even the implied
23
+ # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
24
+ # PURPOSE.
25
+
26
+ begin
27
+ require 'annotatable'
28
+ rescue LoadError => e
29
+ $stderr << "ERROR: Clio Multicommand depends on 'annotatable'."
30
+ exit 0
31
+ end
32
+
33
+ #require 'facets/argvector'
34
+ require 'clio/errors'
35
+
36
+ module Clio
37
+
38
+ # Here is an example of usage:
39
+ #
40
+ # # General Options
41
+ #
42
+ # # Build Subcommand
43
+ #
44
+ # class MyMultiCommand < Clio::MultiCommand
45
+ #
46
+ # cmd "save to file"
47
+ #
48
+ # opt :file do
49
+ # desc "very useful option"
50
+ # type :path,
51
+ # flag :f,
52
+ # end
53
+ #
54
+ # def save(args, opts)
55
+ #
56
+ # end
57
+ #
58
+ # def fallback(opts)
59
+ # # if no subcommand
60
+ # end
61
+ # end
62
+ #
63
+ # MyMultiCommand.start
64
+ #
65
+ class MultiCommand
66
+
67
+ include Annotatable
68
+
69
+ annotation :cmd
70
+
71
+ annotation :opt
72
+
73
+ def self.method_added(name)
74
+ anns = self.class.annotations(name)
75
+ desc = anns[:cmd]
76
+ @options << Option.new(name, @_desc, @_opts)
77
+ @_opt = nil
78
+ end
79
+ end
80
+
81
+
82
+
83
+
84
+
85
+ # Include this in your dispatch command if you want
86
+ # all options to be traeted the same.
87
+
88
+ module UniversalOptions
89
+ end
90
+
91
+ #
92
+
93
+ def self.option_arity(arity_hash=nil)
94
+ if arity_hash
95
+ (@option_arity ||= {}).merge!(arity_hash)
96
+ end
97
+ @option_arity
98
+ end
99
+
100
+ #
101
+
102
+ def self.start(line=nil)
103
+ cargs = Argvector.new(line || ARGV, option_arity)
104
+ pre = cargs.preoptions
105
+
106
+ if instance_method(:call).arity == 0 #is_a?(SingleCommand)
107
+ args, opts = *cargs.parameters
108
+ new(args, opts).call
109
+ else
110
+ subc, args, opts = *cargs.subcommand
111
+ if self < UniversalOptions
112
+ new(pre, opts).call(subc, args, opts)
113
+ else
114
+ new(pre).call(subc, args, opts)
115
+ end
116
+ end
117
+ end
118
+
119
+ # Command Arguments (for single commands).
120
+
121
+ attr :arguments
122
+
123
+ # Command options. For dispatch commands these are the pre-options.
124
+
125
+ attr :options
126
+
127
+ # For dispatchers, this is a convenience method for creating subcommands.
128
+
129
+ def self.subcommand(name, command_class, options=nil)
130
+ options ||= {}
131
+ if options[:no_merge]
132
+ file, line = __FILE__, __LINE__+1
133
+ code = %{
134
+ def #{name}(args, opts)
135
+ #{command_class}.new(args, opts).call
136
+ end
137
+ }
138
+ else
139
+ file, line = __FILE__, __LINE__+1
140
+ code = %{
141
+ def #{name}(args, opts)
142
+ opts.merge(options)
143
+ #{command_class}.new(args, opts).call
144
+ end
145
+ }
146
+ end
147
+ class_eval(code, file, line)
148
+ end
149
+
150
+ private
151
+
152
+ #
153
+
154
+ def initialize(*args)
155
+ @arguments = []
156
+ @options = {}
157
+
158
+ opts, args = *args.partition{ |e| Hash===e }
159
+ #TEST("options should all be hashes"){ ! opts.all?{ |e| Hash===e }
160
+ initialize_arguments(*args)
161
+ initialize_options(*opts)
162
+ end
163
+
164
+ #
165
+
166
+ def initialize_arguments(*arguments)
167
+ @arguments.concat(arguments)
168
+ end
169
+
170
+ #
171
+
172
+ def initialize_options(*options)
173
+ options = options.inject{ |h,o| h.merge(o) }
174
+ begin
175
+ opt, val = nil, nil
176
+ options.each do |opt, val|
177
+ opt = opt.gsub('-','_')
178
+ send("#{opt}=", val)
179
+ end
180
+ rescue NoMethodError
181
+ option_missing(opt, val)
182
+ end
183
+ @options.update(options)
184
+ end
185
+
186
+ public
187
+
188
+ # For a single command (ie. a subcommand) override #call with arity=0.
189
+
190
+ def call(cmd=nil, *args)
191
+ opts = Hash==args.last ? args.pop : {}
192
+ #TEST("options should all be hashes"){ ! opts.all?{ |e| Hash===e }
193
+ #cmd = :default if cmd.nil?
194
+ if cmd.nil?
195
+ default
196
+ else
197
+ begin
198
+ # FIXME: rename call to [] ?
199
+ raise NameError if cmd == 'call'
200
+ raise NameError unless commands.include?(cmd.to_sym)
201
+ subcommand = method(cmd)
202
+ parameters = [args, opts]
203
+ rescue NameError
204
+ subcommand = method(:command_missing)
205
+ parameters = [cmd, args, opts]
206
+ end
207
+ if subcommand.arity < 0
208
+ subcommand.call(*parameters[0..subcommand.arity])
209
+ else
210
+ subcommand.call(*parameters[0,subcommand.arity])
211
+ end
212
+ end
213
+ end
214
+
215
+ # Display help message.
216
+ # The one provided is just a very limited dummy routine.
217
+
218
+ # def help
219
+ # puts "USAGE #{File.basename($0)} [options]"
220
+ # puts "\nOptions:"
221
+ # options = self.class.instance_methods(false)
222
+ # options = options - Command.instance_methods(true)
223
+ # options = options.select{ |m| m.to_s =~ /=$/ }
224
+ # options.each do |opt|
225
+ # puts " --#{opt.to_s.chomp('=')}"
226
+ # end
227
+ # end
228
+
229
+ private
230
+
231
+ # Override default to provide non-subcommand functionality.
232
+
233
+ def default; end
234
+
235
+ # TODO: Add "if no setter method".
236
+ def commands
237
+ @_commands ||= (
238
+ cmds = self.class.instance_methods(true) - Command.instance_methods(true)
239
+ cmds.select{ |c| c !~ /\W/ }
240
+ cmds.collect{ |c| c.to_sym }
241
+ )
242
+ end
243
+
244
+ #
245
+
246
+ def command_missing(cmd, args, opt)
247
+ raise NoCommandError.new(cmd, args << opt)
248
+ end
249
+
250
+ #
251
+
252
+ def option_missing(opt, arg=nil)
253
+ raise NoOptionError.new(opt)
254
+ end
255
+
256
+ end
257
+
258
+ # Temporary backward compatability.
259
+ MasterCommand = Command
260
+
261
+ end
262
+
263
+
264
+ module Console #:nodoc:
265
+ # For backward compatibility.
266
+ Command = CLI::Command
267
+ end
268
+
269
+
270
+ # SCRAP CODE FOR REFERENCE TO POSSIBLE ADD FUTURE FEATURES
271
+
272
+ =begin
273
+
274
+ # We include a module here so you can define your own help
275
+ # command and call #super to utilize this one.
276
+
277
+ module Help
278
+
279
+ def help
280
+ opts = help_options
281
+ s = ""
282
+ s << "#{File.basename($0)}\n\n"
283
+ unless opts.empty?
284
+ s << "OPTIONS\n"
285
+ s << help_options
286
+ s << "\n"
287
+ end
288
+ s << "COMMANDS\n"
289
+ s << help_commands
290
+ puts s
291
+ end
292
+
293
+ private
294
+
295
+ def help_commands
296
+ help = self.class.help
297
+ bufs = help.keys.collect{ |a| a.to_s.size }.max + 3
298
+ lines = []
299
+ help.each { |cmd, str|
300
+ cmd = cmd.to_s
301
+ if cmd !~ /^_/
302
+ lines << " " + cmd + (" " * (bufs - cmd.size)) + str
303
+ end
304
+ }
305
+ lines.join("\n")
306
+ end
307
+
308
+ def help_options
309
+ help = self.class.help
310
+ bufs = help.keys.collect{ |a| a.to_s.size }.max + 3
311
+ lines = []
312
+ help.each { |cmd, str|
313
+ cmd = cmd.to_s
314
+ if cmd =~ /^_/
315
+ lines << " " + cmd.gsub(/_/,'-') + (" " * (bufs - cmd.size)) + str
316
+ end
317
+ }
318
+ lines.join("\n")
319
+ end
320
+
321
+ module ClassMethods
322
+
323
+ def help( str=nil )
324
+ return (@help ||= {}) unless str
325
+ @current_help = str
326
+ end
327
+
328
+ def method_added( meth )
329
+ if @current_help
330
+ @help ||= {}
331
+ @help[meth] = @current_help
332
+ @current_help = nil
333
+ end
334
+ end
335
+
336
+ end
337
+
338
+ end
339
+
340
+ include Help
341
+ extend Help::ClassMethods
342
+
343
+ =end
344
+
345
+ =begin
346
+
347
+ # Provides a very basic usage help string.
348
+ #
349
+ # TODO Add support for __options.
350
+ def usage
351
+ str = []
352
+ public_methods(false).sort.each do |meth|
353
+ meth = meth.to_s
354
+ case meth
355
+ when /^_/
356
+ opt = meth.sub(/^_+/, '')
357
+ meth = method(meth)
358
+ if meth.arity == 0
359
+ str << (opt.size > 1 ? "[--#{opt}]" : "[-#{opt}]")
360
+ elsif meth.arity == 1
361
+ str << (opt.size > 1 ? "[--#{opt} value]" : "[-#{opt} value]")
362
+ elsif meth.arity > 0
363
+ v = []; meth.arity.times{ |i| v << 'value' + (i + 1).to_s }
364
+ str << (opt.size > 1 ? "[--#{opt} #{v.join(' ')}]" : "[-#{opt} #{v.join(' ')}]")
365
+ else
366
+ str << (opt.size > 1 ? "[--#{opt} *values]" : "[-#{opt} *values]")
367
+ end
368
+ when /=$/
369
+ opt = meth.chomp('=')
370
+ str << (opt.size > 1 ? "[--#{opt} value]" : "[-#{opt} value]")
371
+ when /!$/
372
+ opt = meth.chomp('!')
373
+ str << (opt.size > 1 ? "[--#{opt}]" : "[-#{opt}]")
374
+ end
375
+ end
376
+ return str.join(" ")
377
+ end
378
+
379
+ #
380
+
381
+ def self.usage_class(usage)
382
+ c = Class.new(self)
383
+ argv = Shellwords.shellwords(usage)
384
+ argv.each_with_index do |name, i|
385
+ if name =~ /^-/
386
+ if argv[i+1] =~ /^[(.*?)]/
387
+ c.class_eval %{
388
+ attr_accessor :#{name}
389
+ }
390
+ else
391
+ c.class_eval %{
392
+ attr_reader :#{name}
393
+ def #{name}! ; @#{name} = true ; end
394
+ }
395
+ end
396
+ end
397
+ end
398
+ return c
399
+ end
400
+
401
+ end
402
+
403
+ =end