clio 0.0.1 → 0.2.0

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.
Files changed (181) hide show
  1. data/CHANGES +66 -0
  2. data/MANIFEST +48 -169
  3. data/README +13 -17
  4. data/RELEASE +8 -0
  5. data/VERSION +1 -0
  6. data/lib/clio/buffer.rb +93 -0
  7. data/lib/clio/commandable.rb +71 -69
  8. data/lib/clio/commandline.rb +429 -230
  9. data/lib/clio/consoleutils.rb +0 -16
  10. data/lib/clio/facets/kernel.rb +13 -0
  11. data/lib/clio/facets/string.rb +25 -0
  12. data/lib/clio/layout.rb +14 -0
  13. data/lib/clio/layout/flow.rb +1 -0
  14. data/lib/clio/layout/line.rb +23 -0
  15. data/lib/clio/layout/list.rb +33 -0
  16. data/lib/clio/layout/split.rb +122 -0
  17. data/lib/clio/layout/stack.rb +17 -0
  18. data/lib/clio/layout/table.rb +46 -0
  19. data/lib/clio/progressbar.rb +189 -210
  20. data/lib/clio/string.rb +116 -109
  21. data/lib/clio/usage.rb +184 -0
  22. data/lib/clio/usage/argument.rb +84 -0
  23. data/lib/clio/usage/command.rb +440 -0
  24. data/lib/clio/usage/interface.rb +122 -0
  25. data/lib/clio/usage/main.rb +165 -0
  26. data/lib/clio/usage/option.rb +251 -0
  27. data/lib/clio/usage/parser.rb +191 -0
  28. data/lib/clio/usage/signature.rb +55 -0
  29. data/meta/abstract +3 -0
  30. data/meta/authors +1 -0
  31. data/meta/created +1 -0
  32. data/meta/homepage +1 -0
  33. data/meta/license +1 -0
  34. data/meta/repository +1 -0
  35. data/meta/summary +1 -0
  36. data/spec/commandline/autousage.rd +56 -0
  37. data/spec/commandline/bracket.rd +64 -0
  38. data/spec/commandline/completion.rd +38 -0
  39. data/spec/commandline/define.rd +44 -0
  40. data/spec/commandline/method.rd +60 -0
  41. data/spec/commandline/parse.rd +72 -0
  42. data/spec/commandline/scenario.rd +81 -0
  43. data/spec/commandline/subclass.rd +54 -0
  44. data/spec/string/unit.rd +58 -0
  45. data/spec/usage/define.rd +44 -0
  46. data/spec/usage/parse.rd +47 -0
  47. metadata +65 -196
  48. data/HISTORY +0 -11
  49. data/METADATA +0 -18
  50. data/NEWS +0 -10
  51. data/admin/config/reap.yaml +0 -30
  52. data/admin/depot/commandline.rb +0 -219
  53. data/admin/depot/multicommand.rb +0 -403
  54. data/admin/depot/test_multicommand.rb +0 -40
  55. data/admin/log/notes.xml +0 -28
  56. data/admin/log/stats.html +0 -25
  57. data/admin/log/syntax.log +0 -0
  58. data/admin/log/testunit.log +0 -16
  59. data/admin/pack/clio-0.0.1.gem +0 -0
  60. data/admin/share/reap/example.rb +0 -7
  61. data/admin/temps/lib/clio/about.rb.erb +0 -4
  62. data/lib/clio/command.rb +0 -296
  63. data/lib/clio/option.rb +0 -36
  64. data/lib/clio/runmode.rb +0 -126
  65. data/test/test_command.rb +0 -42
  66. data/test/test_commandline.rb +0 -83
  67. data/vendor/Console/Console.cpp +0 -1203
  68. data/vendor/Console/Console.rdoc +0 -690
  69. data/vendor/Console/Console_ANSI.rdoc +0 -302
  70. data/vendor/Console/HISTORY.txt +0 -7
  71. data/vendor/Console/INSTALL.txt +0 -18
  72. data/vendor/Console/Makefile +0 -162
  73. data/vendor/Console/README.txt +0 -26
  74. data/vendor/Console/doc/classes/Win32.html +0 -115
  75. data/vendor/Console/doc/classes/Win32/Console.html +0 -650
  76. data/vendor/Console/doc/classes/Win32/Console.src/M000001.html +0 -31
  77. data/vendor/Console/doc/classes/Win32/Console.src/M000002.html +0 -23
  78. data/vendor/Console/doc/classes/Win32/Console.src/M000003.html +0 -23
  79. data/vendor/Console/doc/classes/Win32/Console.src/M000004.html +0 -27
  80. data/vendor/Console/doc/classes/Win32/Console.src/M000005.html +0 -23
  81. data/vendor/Console/doc/classes/Win32/Console.src/M000006.html +0 -28
  82. data/vendor/Console/doc/classes/Win32/Console.src/M000007.html +0 -23
  83. data/vendor/Console/doc/classes/Win32/Console.src/M000008.html +0 -24
  84. data/vendor/Console/doc/classes/Win32/Console.src/M000009.html +0 -44
  85. data/vendor/Console/doc/classes/Win32/Console.src/M000010.html +0 -23
  86. data/vendor/Console/doc/classes/Win32/Console.src/M000011.html +0 -33
  87. data/vendor/Console/doc/classes/Win32/Console.src/M000012.html +0 -26
  88. data/vendor/Console/doc/classes/Win32/Console.src/M000013.html +0 -27
  89. data/vendor/Console/doc/classes/Win32/Console.src/M000014.html +0 -28
  90. data/vendor/Console/doc/classes/Win32/Console.src/M000015.html +0 -23
  91. data/vendor/Console/doc/classes/Win32/Console.src/M000016.html +0 -23
  92. data/vendor/Console/doc/classes/Win32/Console.src/M000017.html +0 -23
  93. data/vendor/Console/doc/classes/Win32/Console.src/M000018.html +0 -29
  94. data/vendor/Console/doc/classes/Win32/Console.src/M000019.html +0 -23
  95. data/vendor/Console/doc/classes/Win32/Console.src/M000020.html +0 -23
  96. data/vendor/Console/doc/classes/Win32/Console.src/M000021.html +0 -28
  97. data/vendor/Console/doc/classes/Win32/Console.src/M000022.html +0 -23
  98. data/vendor/Console/doc/classes/Win32/Console.src/M000023.html +0 -28
  99. data/vendor/Console/doc/classes/Win32/Console.src/M000024.html +0 -35
  100. data/vendor/Console/doc/classes/Win32/Console.src/M000025.html +0 -28
  101. data/vendor/Console/doc/classes/Win32/Console.src/M000026.html +0 -28
  102. data/vendor/Console/doc/classes/Win32/Console.src/M000027.html +0 -28
  103. data/vendor/Console/doc/classes/Win32/Console.src/M000028.html +0 -31
  104. data/vendor/Console/doc/classes/Win32/Console.src/M000029.html +0 -23
  105. data/vendor/Console/doc/classes/Win32/Console.src/M000030.html +0 -23
  106. data/vendor/Console/doc/classes/Win32/Console.src/M000031.html +0 -23
  107. data/vendor/Console/doc/classes/Win32/Console.src/M000032.html +0 -27
  108. data/vendor/Console/doc/classes/Win32/Console.src/M000033.html +0 -27
  109. data/vendor/Console/doc/classes/Win32/Console.src/M000034.html +0 -25
  110. data/vendor/Console/doc/classes/Win32/Console/ANSI.html +0 -103
  111. data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.html +0 -220
  112. data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000035.html +0 -32
  113. data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000036.html +0 -205
  114. data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000037.html +0 -40
  115. data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000038.html +0 -25
  116. data/vendor/Console/doc/classes/Win32/Console/API.html +0 -758
  117. data/vendor/Console/doc/classes/Win32/Console/API.src/M000039.html +0 -27
  118. data/vendor/Console/doc/classes/Win32/Console/API.src/M000040.html +0 -27
  119. data/vendor/Console/doc/classes/Win32/Console/API.src/M000041.html +0 -27
  120. data/vendor/Console/doc/classes/Win32/Console/API.src/M000042.html +0 -32
  121. data/vendor/Console/doc/classes/Win32/Console/API.src/M000043.html +0 -32
  122. data/vendor/Console/doc/classes/Win32/Console/API.src/M000044.html +0 -28
  123. data/vendor/Console/doc/classes/Win32/Console/API.src/M000045.html +0 -26
  124. data/vendor/Console/doc/classes/Win32/Console/API.src/M000046.html +0 -26
  125. data/vendor/Console/doc/classes/Win32/Console/API.src/M000047.html +0 -27
  126. data/vendor/Console/doc/classes/Win32/Console/API.src/M000048.html +0 -30
  127. data/vendor/Console/doc/classes/Win32/Console/API.src/M000049.html +0 -29
  128. data/vendor/Console/doc/classes/Win32/Console/API.src/M000050.html +0 -27
  129. data/vendor/Console/doc/classes/Win32/Console/API.src/M000051.html +0 -28
  130. data/vendor/Console/doc/classes/Win32/Console/API.src/M000052.html +0 -30
  131. data/vendor/Console/doc/classes/Win32/Console/API.src/M000053.html +0 -27
  132. data/vendor/Console/doc/classes/Win32/Console/API.src/M000054.html +0 -29
  133. data/vendor/Console/doc/classes/Win32/Console/API.src/M000055.html +0 -29
  134. data/vendor/Console/doc/classes/Win32/Console/API.src/M000056.html +0 -28
  135. data/vendor/Console/doc/classes/Win32/Console/API.src/M000057.html +0 -27
  136. data/vendor/Console/doc/classes/Win32/Console/API.src/M000058.html +0 -47
  137. data/vendor/Console/doc/classes/Win32/Console/API.src/M000059.html +0 -32
  138. data/vendor/Console/doc/classes/Win32/Console/API.src/M000060.html +0 -47
  139. data/vendor/Console/doc/classes/Win32/Console/API.src/M000061.html +0 -34
  140. data/vendor/Console/doc/classes/Win32/Console/API.src/M000062.html +0 -32
  141. data/vendor/Console/doc/classes/Win32/Console/API.src/M000063.html +0 -32
  142. data/vendor/Console/doc/classes/Win32/Console/API.src/M000064.html +0 -35
  143. data/vendor/Console/doc/classes/Win32/Console/API.src/M000065.html +0 -26
  144. data/vendor/Console/doc/classes/Win32/Console/API.src/M000066.html +0 -27
  145. data/vendor/Console/doc/classes/Win32/Console/API.src/M000067.html +0 -29
  146. data/vendor/Console/doc/classes/Win32/Console/API.src/M000068.html +0 -27
  147. data/vendor/Console/doc/classes/Win32/Console/API.src/M000069.html +0 -27
  148. data/vendor/Console/doc/classes/Win32/Console/API.src/M000070.html +0 -28
  149. data/vendor/Console/doc/classes/Win32/Console/API.src/M000071.html +0 -27
  150. data/vendor/Console/doc/classes/Win32/Console/API.src/M000072.html +0 -26
  151. data/vendor/Console/doc/classes/Win32/Console/API.src/M000073.html +0 -27
  152. data/vendor/Console/doc/classes/Win32/Console/API.src/M000074.html +0 -31
  153. data/vendor/Console/doc/classes/Win32/Console/API.src/M000075.html +0 -27
  154. data/vendor/Console/doc/classes/Win32/Console/API.src/M000076.html +0 -32
  155. data/vendor/Console/doc/classes/Win32/Console/API.src/M000077.html +0 -27
  156. data/vendor/Console/doc/classes/Win32/Console/API.src/M000078.html +0 -32
  157. data/vendor/Console/doc/classes/Win32/Console/API.src/M000079.html +0 -32
  158. data/vendor/Console/doc/classes/Win32/Console/API.src/M000080.html +0 -32
  159. data/vendor/Console/doc/classes/Win32/Console/Constants.html +0 -360
  160. data/vendor/Console/doc/created.rid +0 -1
  161. data/vendor/Console/doc/files/Console_ANSI_rdoc.html +0 -407
  162. data/vendor/Console/doc/files/Console_cpp.html +0 -104
  163. data/vendor/Console/doc/files/Console_rdoc.html +0 -964
  164. data/vendor/Console/doc/files/lib/Win32/Console/ANSI_rb.html +0 -123
  165. data/vendor/Console/doc/files/lib/Win32/Console_rb.html +0 -297
  166. data/vendor/Console/doc/fr_class_index.html +0 -32
  167. data/vendor/Console/doc/fr_file_index.html +0 -31
  168. data/vendor/Console/doc/fr_method_index.html +0 -106
  169. data/vendor/Console/doc/index.html +0 -24
  170. data/vendor/Console/doc/rdoc-style.css +0 -172
  171. data/vendor/Console/extconf.rb +0 -18
  172. data/vendor/Console/lib/Term/ansicolor.rb +0 -76
  173. data/vendor/Console/lib/Win32/Console.rb +0 -970
  174. data/vendor/Console/lib/Win32/Console/ANSI.rb +0 -305
  175. data/vendor/Console/test/test_cursor.rb +0 -9
  176. data/vendor/Console/test/test_mouse.rb +0 -6
  177. data/vendor/Console/test/test_readinput.rb +0 -62
  178. data/vendor/Console/test/test_readoutput.rb +0 -52
  179. data/vendor/Console/test/test_sendevent.rb +0 -17
  180. data/vendor/Console/test/test_title.rb +0 -14
  181. data/vendor/Console/test/test_write.rb +0 -36
@@ -0,0 +1,165 @@
1
+ require 'clio/usage/command'
2
+
3
+ module Clio
4
+
5
+ module Usage #:nodoc:
6
+
7
+ # = Main
8
+ #
9
+ # Main specifies the toplevel "Command".
10
+ #
11
+ class Main < Command
12
+
13
+ # New Usage.
14
+ #
15
+ def initialize(name=nil, &block)
16
+ name ||= File.basename($0)
17
+ super(name, &block)
18
+ end
19
+
20
+ # Define a command.
21
+ #
22
+ # command('remote')
23
+ # command('remote','add')
24
+ #
25
+ #def command(name, &block)
26
+ # raise "Command cannot have both arguments and subcommands (eg. #{name})." unless arguments.empty?
27
+ # key = name.to_s.strip
28
+ # if cmd = @commands.find{|c| c === key}
29
+ # else
30
+ # cmd = Command.new(key, self)
31
+ # @commands << cmd
32
+ # end
33
+ # cmd.instance_eval(&block) if block
34
+ # cmd
35
+ #end
36
+
37
+ =begin
38
+ #alias_method :[], :command
39
+
40
+
41
+ # ARRAY NOTATION
42
+ #-------------------------------------------------------------
43
+
44
+ #
45
+ def [](*args)
46
+ res = nil
47
+ head, *tail = *args
48
+ case head.to_s
49
+ when /^-/
50
+ x = []
51
+ opts = args.map do |o|
52
+ o = o.to_s
53
+ if i = o.index('=')
54
+ x << o[i+1..-1]
55
+ o[0...i]
56
+ else
57
+ o
58
+ end
59
+ end
60
+ x = x.uniq
61
+
62
+ res = opt(*opts)
63
+ else
64
+ args.each do |name|
65
+ res = command(name)
66
+ end
67
+ end
68
+ return res
69
+ end
70
+ =end
71
+
72
+ =begin
73
+ # Usage text.
74
+ #
75
+ def to_s
76
+ #s = [full_name]
77
+ s = [name]
78
+
79
+ case options.size
80
+ when 0
81
+ when 1, 2, 3
82
+ s.concat(options.collect{ |o| "[#{o.to_s.strip}]" })
83
+ else
84
+ s << "[switches]"
85
+ end
86
+ # switches? vs. options
87
+ s << arguments.join(' ') unless arguments.empty?
88
+
89
+ case commands.size
90
+ when 0
91
+ when 1
92
+ s << commands.join('')
93
+ when 2, 3
94
+ s << '[' + commands.join(' | ') + ']'
95
+ else
96
+ s << 'command'
97
+ end
98
+
99
+ s.flatten.join(' ')
100
+ end
101
+
102
+ # Help text.
103
+ #
104
+ def to_s_help
105
+ s = []
106
+ unless help.empty?
107
+ s << help
108
+ s << ''
109
+ end
110
+ s << "Usage:"
111
+ s << " " + to_s
112
+ unless commands.empty?
113
+ s << ''
114
+ s << 'Commands:'
115
+ s.concat(commands.collect{ |x| " %-20s %s" % [x.key, x.help] }.sort)
116
+ end
117
+ unless arguments.empty?
118
+ s << ''
119
+ s << "Arguments:"
120
+ s.concat(arguments.collect{ |x| " %-20s %s" % [x, x.help] })
121
+ end
122
+ unless options.empty?
123
+ s << ''
124
+ s << 'Switches:'
125
+ s.concat(options.collect{ |x| " %-20s %s" % [x, x.help] })
126
+ end
127
+ s.flatten.join("\n")
128
+ end
129
+ =end
130
+
131
+ def parse(argv)
132
+ Parser.new(self, argv).parse #(argv)
133
+ end
134
+
135
+ # Cache usage into a per-user cache file for reuse.
136
+ # This can be used to greatly speed up tab completion.
137
+ #
138
+ def cache
139
+ File.open(cache_file, 'w'){ |f| f << to_yaml }
140
+ end
141
+
142
+ private
143
+
144
+ # TODO: Use XDG
145
+
146
+ def cache_file
147
+ File.join(File.expand_path('~'), '.cache', 'clio', "#{name}.yaml")
148
+ end
149
+
150
+ def self.cache_file
151
+ File.join(File.expand_path('~'), '.cache', 'clio', "#{name}.yaml")
152
+ end
153
+
154
+ def self.load_cache
155
+ if File.file?(cache_file)
156
+ YAML.load(File.new(cache_file))
157
+ end
158
+ end
159
+
160
+ end#class Main
161
+
162
+ end#module Usage
163
+
164
+ end#module Clio
165
+
@@ -0,0 +1,251 @@
1
+ module Clio
2
+
3
+ module Usage #:nodoc:
4
+
5
+ # = Commandline Option
6
+ #
7
+ class Option
8
+
9
+ # Parent command.
10
+ #attr :parent
11
+
12
+ # Option name.
13
+ attr :name
14
+
15
+ # Alternate names for this option.
16
+ attr :aliases
17
+
18
+ # Option arguments.
19
+ attr :arguments
20
+
21
+ # Option can be used more that once.
22
+ attr :multiple
23
+
24
+ # Option (names) that are mutually exlusive
25
+ # to this option.
26
+ attr :excludes
27
+
28
+ # Is the option greedy (true/false)? A greedy
29
+ # option is one that is parsed from the
30
+ # commandline no matter where it appears.
31
+ #attr_accessor :greedy
32
+
33
+ # Help text for this option.
34
+ attr :help
35
+
36
+ # New Option.
37
+ #def initialize(name, parent=nil, &block)
38
+ def initialize(name, &block)
39
+ @name = clean_name(name)
40
+ #@parent = parent
41
+ @aliases = []
42
+ @arguments = []
43
+ @multiple = false
44
+ #@greedy = false
45
+ @exclude = []
46
+ @help = ''
47
+ instance_eval(&block) if block
48
+ end
49
+
50
+ #
51
+ def initialize_copy(o)
52
+ @name = o.name.dup
53
+ @aliases = o.aliases.dup
54
+ #@multiple = o.multiple
55
+ @exclude = o.exclude.dup
56
+ @help = o.help.dup
57
+ end
58
+
59
+ # Same as +name+ but given as a symbol.
60
+ def key
61
+ name.to_sym
62
+ end
63
+
64
+ # Can this option occur multiple times in the
65
+ # command line?
66
+ def multiple? ; @multiple ; end
67
+
68
+ # Is this option greedy?
69
+ #def greedy? ; @greedy ; end
70
+
71
+ #
72
+ def inspect
73
+ to_s
74
+ #s = "[--#{key}"
75
+ #s << "*" if multiple
76
+ #s << "=" + arguments.join(',') unless arguments.empty?
77
+ #s << " " + aliases.collect{ |a| "-#{a}" } unless aliases.empty?
78
+ ##s << " @excludes=#{@excludes.inspect}" unless @excludes.empty?
79
+ #s << "]"
80
+ #s
81
+ end
82
+
83
+ # Is this option a boolean flag?
84
+ def flag?; @arguments.empty?; end
85
+
86
+ # Assign an argument to the option.
87
+ def argument(name, &block)
88
+ arg = Argument.new(name) #, self)
89
+ arg.instance_eval(&block) if block
90
+ @arguments << arg
91
+ arg
92
+ end
93
+
94
+ # Specify aliases for the option.
95
+ def aliases(*names)
96
+ return @aliases if names.empty?
97
+ names.each do |name|
98
+ @aliases << clean_key(name)
99
+ end
100
+ end
101
+
102
+ # Specify if the option be used multiple times.
103
+ def multiple(bool=nil)
104
+ return @multiple if bool.nil?
105
+ @multiple = bool
106
+ self
107
+ end
108
+
109
+ # Specify mutually exclusive options.
110
+ def xor(*opts)
111
+ @exclusive.concat(opts)
112
+ end
113
+
114
+ #
115
+ #def |(other)
116
+ # xor(other)
117
+ #end
118
+
119
+ #
120
+ def help(string=nil)
121
+ @help.replace(string.to_s) if string
122
+ @help
123
+ end
124
+
125
+ # Tab completion.
126
+ def completion
127
+ arguments.collect{|c| c.key}
128
+ end
129
+
130
+ # SHORTHAND NOTATION
131
+ #-------------------------------------------------------------
132
+
133
+ # Argument shorthand.
134
+ #
135
+ # arg('PIN', 'pin number')
136
+ #
137
+ def arg(slot, help=nil)
138
+ argument(slot).help(help)
139
+ end
140
+
141
+ #
142
+ def to_s
143
+ tiny = aliases.select do |a|
144
+ a.to_s.size == 1
145
+ end
146
+ tiny.unshift(name) if name.size == 1
147
+
148
+ long = aliases.select do |a|
149
+ a.to_s.size > 1
150
+ end
151
+ long.unshift(name) if name.size > 1
152
+
153
+ tiny = tiny.collect{ |l| "-#{l}" }
154
+ long = long.collect{ |w| "--#{w}" }
155
+
156
+ if tiny.empty?
157
+ opts = [ ' ', *long ]
158
+ else
159
+ opts = tiny + long
160
+ end
161
+
162
+ unless arguments.empty?
163
+ args = arguments.collect{ |a| a.to_s.sub(/^[<]/,'').sub(/[>]$/,'') }
164
+ opts.last << "=" + args.join(',')
165
+ end
166
+
167
+ opts.join(' ')
168
+ end
169
+
170
+ #
171
+ def ===(other)
172
+ other = clean_key(other)
173
+ return true if clean_key(key) == other
174
+ return true if aliases.include?(other)
175
+ return false
176
+ end
177
+
178
+ # Breaks down an option at index of argv.
179
+ #def parse(argv, index)
180
+ #end
181
+
182
+ private
183
+
184
+ #
185
+ def clean_key(key)
186
+ clean_name(key).to_sym
187
+ end
188
+
189
+ #
190
+ def clean_name(name)
191
+ name = name.to_s
192
+ name = name.gsub(/^[-]+/, '')
193
+ name.chomp('?')
194
+ end
195
+
196
+ #
197
+ def flag_key?(key)
198
+ name = key.to_s
199
+ return key[-1,1] == '?'
200
+ end
201
+
202
+ #
203
+ def option_key(key)
204
+ k = clean_key(key).to_s
205
+ if k.size == 1
206
+ "-#{k}".to_sym
207
+ else
208
+ "--#{k}".to_sym
209
+ end
210
+ end
211
+
212
+ end
213
+
214
+ end # class Commandline
215
+
216
+ end # module Clio
217
+
218
+ =begin
219
+ # Option class. This is used by some command
220
+ # of the command line parser class to store
221
+ # option information.
222
+ class Option
223
+ attr_reader :name
224
+ attr_accessor :type
225
+ attr_accessor :init
226
+ attr_accessor :desc
227
+
228
+ alias_method :default, :init
229
+ alias_method :description, :desc
230
+
231
+ def initialize(name, desc, opts)
232
+ @name = name
233
+ @desc = desc
234
+ @type = opts[:type] || 'value'
235
+ @init = opts[:default] || opts[:init]
236
+ end
237
+ def usage
238
+ "--#{name}=#{type.to_s.upcase}"
239
+ end
240
+ def assert_valid(value)
241
+ raise "invalid" unless valid?(value)
242
+ end
243
+ def valid?(value)
244
+ validation ? validation.call(value) : true
245
+ end
246
+ def validation(&block)
247
+ @validation = block if block
248
+ @validation
249
+ end
250
+ end
251
+ =end
@@ -0,0 +1,191 @@
1
+ require 'shellwords'
2
+ require 'clio/usage/signature'
3
+ require 'clio/usage/interface'
4
+
5
+ module Clio
6
+
7
+ module Usage #:nodoc:
8
+
9
+ # = Parser
10
+ #
11
+ # Parse commandline arguments according to given Usage.
12
+ #
13
+ class Parser
14
+ attr :usage
15
+ attr :argv
16
+
17
+ attr :signatures
18
+
19
+ #
20
+ def initialize(usage, argv) #, index=0)
21
+ # convert to array if argv string
22
+ if ::String===argv
23
+ argv = Shellwords.shellwords(argv)
24
+ else
25
+ argv = argv.dup
26
+ end
27
+
28
+ @usage = usage
29
+ @argv = argv
30
+
31
+ @parsed = false
32
+ @signatures = []
33
+ @errors = []
34
+ end
35
+
36
+ #
37
+ def name ; usage.name ; end
38
+ def key ; usage.key ; end
39
+
40
+ #
41
+ def inspect
42
+ s = "<" + signatures.inspect + ">"
43
+ s
44
+ #s = "#<#{self.class}"
45
+ #s << " @options=#{@options.inspect}" unless @options.empty?
46
+ #s << " @arguments=#{@arguments.inspect}" unless @arguments.empty?
47
+ #s << " @subcommand=#{@subcommand}>" if @subcommand
48
+ #s << ">"
49
+ #s
50
+ end
51
+
52
+ #
53
+ def parse
54
+ @parsed = false
55
+ @signatures = []
56
+ @errors = []
57
+
58
+ parse_command(usage, argv.dup)
59
+
60
+ @parsed = true
61
+
62
+ return Interface.new(@signatures, @errors)
63
+ end
64
+
65
+ # Has the commandline been parsed?
66
+ def parsed? ; @parsed ; end
67
+
68
+ private
69
+
70
+ # TODO: clean-up parsing
71
+ def parse_command(usage, argv)
72
+ options = {}
73
+ arguments = []
74
+ command = nil
75
+
76
+ #greedy = parse_greedy(usage, argv)
77
+
78
+ #options.update(greedy)
79
+
80
+ until argv.empty?
81
+ use, val = parse_option(usage, argv)
82
+ if use
83
+ #p "use: #{use.key}, #{val}"
84
+ if val == "\t"
85
+ parse_errors << [val, use]
86
+ elsif use.multiple?
87
+ options[use.key] ||= []
88
+ options[use.key] << val
89
+ else
90
+ options[use.key] = val
91
+ end
92
+ elsif !usage.arguments.empty?
93
+ usage.arguments.each do |a|
94
+ if a.splat
95
+ while argv.first && argv.first !~ /^[-]/
96
+ arguments << argv.shift
97
+ end
98
+ break if argv.empty?
99
+ else
100
+ arguments << argv.shift
101
+ end
102
+ end
103
+ else
104
+ break if argv.empty?
105
+ arg = argv.shift
106
+ use = usage.commands.find{|c| c === arg}
107
+ if use
108
+ parse_command(use, argv)
109
+ break
110
+ else
111
+ parse_errors << [arg, usage]
112
+ #raise ParseError, "unknown command or argument #{a} for #{usage.key} command"
113
+ break
114
+ end
115
+ end
116
+ end
117
+ @signatures.unshift(Signature.new(usage.name, arguments, options))
118
+ end
119
+
120
+ =begin
121
+ # Parse greedy options. This function loops thru ARGV and
122
+ # removes any matching greedy options.
123
+ def parse_greedy(usage, argv)
124
+ options = {}
125
+ d, i = [], 0
126
+ while i < argv.size
127
+ case a = argv[i]
128
+ when /^[-].+/
129
+ #res = parse_option(a, i)
130
+ name, val = *a.split('=')
131
+ use = usage.greedy_option?(name)
132
+ if use && use.greedy?
133
+ d << i
134
+ if use.flag?
135
+ val = val || true
136
+ else
137
+ val = argv[i+1] unless val
138
+ i += 1
139
+ d << i
140
+ end
141
+ options[use.key] = val
142
+ end
143
+ res = val
144
+ end
145
+ i += 1
146
+ end
147
+ d.each{ |i| argv[i] = nil }
148
+ argv.compact!
149
+ return options
150
+ end
151
+ =end
152
+
153
+ #
154
+ def parse_option(usage, argv)
155
+ return if argv.first =~ /^[-]+$/
156
+ return if argv.first !~ /(^-.+|=)/
157
+ arg = argv.shift
158
+ name, val = *arg.split('=')
159
+ if use = usage.option?(name)
160
+ if use.flag?
161
+ val = true unless val
162
+ else
163
+ val = argv.shift unless val
164
+ end
165
+ #options[use.name] = val
166
+ else
167
+ parse_errors << [arg, usage.key]
168
+ end
169
+ return use, val
170
+ end
171
+
172
+ public
173
+
174
+ #
175
+ def errors
176
+ @errors
177
+ end
178
+
179
+ alias_method :parse_errors, :errors
180
+
181
+ end #class Parser
182
+
183
+ #
184
+ class ParseError < StandardError
185
+ end
186
+
187
+ end #class Usage
188
+
189
+ end #module Clio
190
+
191
+