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,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
+