clio 0.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.
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,296 @@
1
+ require 'clio/errors'
2
+ require 'clio/option'
3
+
4
+ module Clio
5
+
6
+ # = Command
7
+ #
8
+ # Command is Clio's low-level command option parser solution.
9
+ # Despite being low-level, it is actually quite easy to used
10
+ # and integrates will with Ruby.
11
+ #
12
+ # The Command class does not to try overly determine your needs via a
13
+ # declarative options DSL, rather it just makes it easy for you to
14
+ # process options into a command class. It does this primarily by
15
+ # using a simple method naming trick. Methods with names starting
16
+ # with underscores (eg. _n or __name) are treated as options.
17
+ #
18
+ # Clio::Command encourages the command pattern (hence the name). So one
19
+ # class does one thing and one thing only. This helps ensure a robust
20
+ # design, albeit at the expense of churning a quick all-in-one solution.
21
+ #
22
+ # For a quicker solution to command line parsing have a look at
23
+ # Clio::Commandable or Clio::Commandline.
24
+ #
25
+ # Although it is low-level it does provide a single high-level "DSL"
26
+ # command for describing usage. This is purely a descriptive measure,
27
+ # and has no barring on the functionality. It is provided to ease
28
+ # the creation of help and command completion output.
29
+ #
30
+ # Simply specify:
31
+ #
32
+ # usage :optname, "options description", :type=>"TYPE", :default=>"DEFAULT"
33
+ #
34
+ # Here is an example of usage.
35
+ #
36
+ # MainCommand < Clio::Command
37
+ #
38
+ # usage :quiet, "keep it quiet?", :type=>:BOOLEAN, :default=>:FALSE
39
+ # usage :file, "what file to use", :type=>:FILE, :alias => :f
40
+ #
41
+ # # boolean flag
42
+ # def __quiet
43
+ # @quiet = true
44
+ # end
45
+ #
46
+ # # required option
47
+ # def __file(fname)
48
+ # @file = fname
49
+ # end
50
+ #
51
+ # # one letter shortcut
52
+ # alias _f __flag
53
+ #
54
+ # # run command
55
+ # def call(*args)
56
+ # subcommand = args.shift
57
+ # case subcommand
58
+ # when 'show'
59
+ # puts File.read(@file)
60
+ # when 'rshow'
61
+ # puts File.read(@file).reverse
62
+ # else
63
+ # puts "Unknown subcommand"
64
+ # end
65
+ # end
66
+ #
67
+ # end
68
+ #
69
+ # MainCommand.run
70
+ #
71
+ # You can chain subcommands together via a case statement like
72
+ # that given above. Eg.
73
+ #
74
+ # case subcommand
75
+ # when 'build'
76
+ # BuildCommand.run(args)
77
+ # ...
78
+ #
79
+ # TODO: Support passing a string or *args, opts in place of ARGV.
80
+ #
81
+ class Command
82
+
83
+ # Used to invoke this command.
84
+ def run(argv=ARGV)
85
+ args = self.class.parse(self, argv)
86
+ call(*args)
87
+ end
88
+
89
+ # This is command function. Override this
90
+ # to do what the command does.
91
+ def call(*args)
92
+ end
93
+
94
+ # Override option_missing if needed.
95
+ # This receives the name of the option and
96
+ # the remaining arguments list. It must consume
97
+ # any argument it uses from the (begining of)
98
+ # the list.
99
+ def option_missing(opt, *argv)
100
+ raise NoOptionError, opt
101
+ end
102
+
103
+ class << self
104
+
105
+ #
106
+ def parse(obj, argv=ARGV)
107
+ argv = argv.dup
108
+ args, opts, i = [], {}, 0
109
+ while argv.size > 0
110
+ case opt = argv.shift
111
+ when /=/
112
+ parse_equal(obj, opt, argv)
113
+ when /^--/
114
+ parse_option(obj, opt, argv)
115
+ when /^-/
116
+ parse_flags(obj, opt, argv)
117
+ else
118
+ args << opt
119
+ end
120
+ end
121
+ return args
122
+ end
123
+
124
+ #
125
+ def parse_equal(obj, opt, argv)
126
+ if md = /^[-]*(.*?)=(.*?)$/.match(opt)
127
+ x, v = md[1], md[2]
128
+ else
129
+ raise ArgumentError, "#{x}"
130
+ end
131
+ if obj.respond_to?("__#{x}")
132
+ obj.send("__#{x}",v)
133
+ else
134
+ obj.option_missing(x, v) # argv?
135
+ end
136
+ end
137
+
138
+ #
139
+ def parse_option(obj, opt, argv)
140
+ x = opt[2..-1]
141
+ if obj.respond_to?("__#{x}")
142
+ m = obj.method("__#{x}")
143
+ if m.arity >= 0
144
+ a = []
145
+ m.arity.times{ a << argv.shift }
146
+ m.call(*a)
147
+ else
148
+ m.call
149
+ end
150
+ else
151
+ obj.option_missing(x, argv)
152
+ end
153
+ end
154
+
155
+ #
156
+ def parse_flags(obj, opt, args)
157
+ x = opt[1..-1]
158
+ c = 0
159
+ x.split(//).each do |k|
160
+ if m = obj.method("_#{k}")
161
+ a = []
162
+ m.arity.times{ a << argv.shift }
163
+ m.call(*a)
164
+ else
165
+ obj.option_missing(x, argv)
166
+ end
167
+ end
168
+ end
169
+
170
+ # Shortcut for
171
+ #
172
+ # Command.new.run()
173
+ #
174
+ def run(argv=ARGV)
175
+ new.run(argv)
176
+ end
177
+
178
+ def uses
179
+ @usage ||= []
180
+ @usage.collect do |u|
181
+ u.usage
182
+ end.join(' ')
183
+ end
184
+
185
+ def usage(name, desc, opts)
186
+ @usage ||= []
187
+ @usage << Option.new(name, desc, opts)
188
+ end
189
+
190
+ #def help
191
+ # #command_attrs.each do |k, o|
192
+ # # puts "%-20s %s" % [o.usage, o.description]
193
+ # #end
194
+ #end
195
+
196
+ end #class << self
197
+
198
+ end
199
+
200
+ =begin
201
+ # TODO: use clio/option
202
+ class UseOption
203
+ attr_reader :name
204
+ attr_accessor :type
205
+ attr_accessor :init
206
+ attr_accessor :desc
207
+
208
+ alias_method :default, :init
209
+ alias_method :description, :desc
210
+
211
+ def initialize(name, desc, opts)
212
+ @name = name
213
+ @desc = desc
214
+ @type = opts[:type] || 'value'
215
+ @init = opts[:default] || opts[:init]
216
+ end
217
+ def usage
218
+ "--#{name}=#{type.to_s.upcase}"
219
+ end
220
+ def assert_valid(value)
221
+ raise "invalid" unless valid?(value)
222
+ end
223
+ def valid?(value)
224
+ validation ? validation.call(value) : true
225
+ end
226
+ def validation(&block)
227
+ @validation = block if block
228
+ @validation
229
+ end
230
+ end
231
+ =end
232
+
233
+ end
234
+
235
+
236
+ =begin :spec:
237
+
238
+ require 'quarry/spec'
239
+
240
+ class MyCommand < Clio::Command
241
+ attr_reader :size, :quiet, :file
242
+
243
+ def initialize
244
+ @file = 'hey.txt' # default
245
+ end
246
+
247
+ use :quiet, "supress standard output", :type => :boolean
248
+
249
+ def __quiet(bool=true)
250
+ @quiet = bool ? true : bool
251
+ end
252
+
253
+ use :size, "what size will it be?", :type => :integer, :default => '0'
254
+
255
+ def __size(integer)
256
+ @size = integer.to_i
257
+ end
258
+
259
+ use :file, "where to store the stuff", :init => 'hey.txt'
260
+
261
+ def __file(fname)
262
+ @file = fname
263
+ end
264
+
265
+ def call(*args)
266
+ @args = args
267
+ end
268
+ end
269
+
270
+ Quarry.spec "Command" do
271
+ before do
272
+ @mc = MyCommand.new
273
+ end
274
+
275
+ demonstrate 'boolean option' do
276
+ @mc.run(['--quiet'])
277
+ @mc.quiet.assert == true
278
+ end
279
+
280
+ demonstrate 'integer option' do
281
+ @mc.run(['--size=4'])
282
+ @mc.size.assert == 4
283
+ end
284
+
285
+ demonstrate 'default value' do
286
+ @mc.run([''])
287
+ @mc.file.assert == 'hey.txt'
288
+ end
289
+
290
+ demonstrate 'usage output' do
291
+ MyCommand.usage.assert == "--quiet=BOOLEAN --size=INTEGER --file=VALUE"
292
+ end
293
+ end
294
+
295
+ =end
296
+
@@ -0,0 +1,195 @@
1
+ require 'clio/errors'
2
+
3
+ module Clio
4
+
5
+ # = Commandable mixin
6
+ #
7
+ # The Commandable mixin is a very quick and and easy
8
+ # way to make almost any class usable via a command
9
+ # line interface. It simply uses writer methods as
10
+ # option setters, and the first command line argument
11
+ # as the method to call, with the subsequent arguments
12
+ # passed to the method.
13
+ #
14
+ # The only limitation of this approach (besides the weak
15
+ # control of the process) is that required options must
16
+ # be specified with the key=value notation.
17
+ #
18
+ # class X
19
+ # include Clio::Commandable
20
+ #
21
+ # attr_accessor :quiet
22
+ #
23
+ # def bread(*args)
24
+ # ["BREAD", quiet, *args]
25
+ # end
26
+ #
27
+ # def butter(*args)
28
+ # ["BUTTER", quiet, *args]
29
+ # end
30
+ # end
31
+ #
32
+ # x = X.new
33
+ #
34
+ # x.execute_command("butter yum")
35
+ # => ["BUTTER", nil, "yum"]
36
+ #
37
+ # x.execute_command("bread --quiet")
38
+ # => ["BUTTER", true]
39
+ #
40
+ # Commandable also defines #command_missing and #option_missing,
41
+ # which you can override to provide suitable results.
42
+ #
43
+ module Commandable
44
+
45
+ # Used to invoke the command.
46
+ def execute_command(argv=ARGV)
47
+ Commandable.run(self, argv)
48
+ end
49
+
50
+ # This is the fallback subcommand. Override this to provide
51
+ # a fallback when no command is given on the commandline.
52
+ def command_missing
53
+ raise NoMethodError
54
+ end
55
+
56
+ # Override option_missing if needed.
57
+ # This receives the name of the option and
58
+ # the remaining arguments list. It must consume
59
+ # any argument it uses from the (begining of)
60
+ # the list.
61
+ def option_missing(opt, *argv)
62
+ raise NoOptionError, opt
63
+ end
64
+
65
+ class << self
66
+
67
+ def run(obj, argv=ARGV)
68
+ args = parse(obj, argv)
69
+ subcmd = args.shift
70
+ if subcmd && !obj.respond_to?("#{subcmd}=")
71
+ obj.send(subcmd, *args)
72
+ else
73
+ obj.command_missing
74
+ end
75
+ end
76
+
77
+ #def run(obj)
78
+ # methname, args = *parse(obj)
79
+ # meth = obj.method(methname)
80
+ # meth.call(*args)
81
+ #end
82
+
83
+ #
84
+ def parse(obj, argv)
85
+ case argv
86
+ when String
87
+ require 'shellwords'
88
+ argv = Shellwords.shellwords(argv)
89
+ else
90
+ argv = argv.dup
91
+ end
92
+
93
+ argv = argv.dup
94
+ args, opts, i = [], {}, 0
95
+ while argv.size > 0
96
+ case opt = argv.shift
97
+ when /=/
98
+ parse_equal(obj, opt, argv)
99
+ when /^--/
100
+ parse_option(obj, opt, argv)
101
+ when /^-/
102
+ parse_flags(obj, opt, argv)
103
+ else
104
+ args << opt
105
+ end
106
+ end
107
+ return args
108
+ end
109
+
110
+ #
111
+ def parse_equal(obj, opt, argv)
112
+ if md = /^[-]*(.*?)=(.*?)$/.match(opt)
113
+ x, v = md[1], md[2]
114
+ else
115
+ raise ArgumentError, "#{x}"
116
+ end
117
+ if obj.respond_to?("#{x}=")
118
+ # TODO: to_b if 'true' or 'false' ?
119
+ obj.send("#{x}=",v)
120
+ else
121
+ obj.option_missing(x, v) # argv?
122
+ end
123
+ end
124
+
125
+ #
126
+ def parse_option(obj, opt, argv)
127
+ x = opt[2..-1]
128
+ if obj.respond_to?("#{x}=")
129
+ obj.send("#{x}=",true)
130
+ else
131
+ obj.option_missing(x, argv)
132
+ end
133
+ end
134
+
135
+ #
136
+ def parse_flags(obj, opt, args)
137
+ x = opt[1..-1]
138
+ c = 0
139
+ x.split(//).each do |k|
140
+ if obj.respond_to?("#{k}=")
141
+ obj.send("#{k}=",true)
142
+ else
143
+ obj.option_missing(x, argv)
144
+ end
145
+ end
146
+ end
147
+
148
+ end #class << self
149
+
150
+ end
151
+
152
+ end
153
+
154
+
155
+
156
+ =begin SPEC
157
+
158
+ require 'quarry/spec'
159
+
160
+ class X
161
+ include Clio::Commandable
162
+
163
+ attr_accessor :file
164
+ attr_accessor :quiet
165
+
166
+ attr :cmd
167
+
168
+ #
169
+ def bread(*args)
170
+ @cmd = "BREAD"
171
+ end
172
+
173
+ #
174
+ def butter(*args)
175
+ @cmd = "BUTTER"
176
+ end
177
+ end
178
+
179
+ Quarry.spec "Commandable" do
180
+
181
+ verify "first command runs" do
182
+ x = X.new
183
+ x.execute_command("bread")
184
+ x.cmd.assert == "BREAD"
185
+ end
186
+
187
+ verify "second command runs" do
188
+ x = X.new
189
+ x.execute_command("butter")
190
+ x.cmd.assert == "BUTTER"
191
+ end
192
+ end
193
+
194
+ =end
195
+