clio 0.0.1 → 0.2.0

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