optparse-lite 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ require 'json'
2
+ require 'strscan'
3
+ require 'nandoc/filters'
4
+ me = File.dirname(__FILE__)+'/nandoc-custom-tags'
5
+ require me + '/app.rb'
6
+ require me + '/playback.rb'
@@ -0,0 +1,102 @@
1
+ require 'syntax/convertors/html'
2
+ module OptparseLite
3
+ class AppTag < ::NanDoc::Filters::CustomTag
4
+ ::NanDoc::Filters::CustomTags.register_class(self)
5
+ include NanDoc::SpecDoc::Playback::Terminal::ColorToHtml
6
+ include NanDoc::StringMethods # module_basename
7
+ ColorizeRuby = ::Syntax::Convertors::HTML.for_syntax('ruby')
8
+
9
+ class << self
10
+ def =~ whole_file
11
+ /\(see: test[^ ]*\.rb - app - ["']/ =~ whole_file
12
+ end
13
+ end
14
+ def name
15
+ 'optparse lite custom tag - app'
16
+ end
17
+ def run content
18
+ numetal = content.gsub(
19
+ /\(see: (test[^ ]*\.rb) - app - ["']([^"']+)["'](.*)\)/
20
+ ) do
21
+ show_app_code($1, $2, $3)
22
+ end
23
+ end
24
+ def tag_parser
25
+ TagParser.new
26
+ end
27
+ def show_app_code testfile, label, rest
28
+ opts = parse_rest_assert(rest)
29
+ NanDoc::Project.instance.require_test_file testfile
30
+ recs = NanDoc::SpecDoc::Recordings.get_for_key(:generic)
31
+ scn = NanDoc::SpecDoc::Playback::SexpScanner.new(recs)
32
+ scn.skip_to_after_assert :story, label
33
+ aa = scn.offset
34
+ scn.skip_to_after_assert :story_stop
35
+ bb = scn.offset - 2
36
+ these = scn.sexp[aa..bb]
37
+ meth = NanDoc::SpecDoc::Playback::Method.new
38
+ doc = NanDoc::Html::Tags.new
39
+ html_opts = opts[:epilogue] ? {} : opts # hack
40
+ doc.push_smart 'pre', 'ruby', '', html_opts
41
+ # the below is written inline in the tests, because we can
42
+ # if opts[:prologue]
43
+ # code = "#!/usr/bin/env ruby\n\n"
44
+ # doc.push_smart('pre','ruby', code) # no colorize!
45
+ # end
46
+ meth.run_sexp doc, these
47
+ if opts[:epilogue]
48
+ # scan back
49
+ j = scn.offset - 1
50
+ j -=1 while scn.sexp[j] && scn.sexp[j][0] != :optparse_app_module
51
+ if ! scn.sexp[j]
52
+ fail("primus sucks")
53
+ end
54
+ mod = scn.sexp[j][1]
55
+ use_mod = module_basename(mod)
56
+ ruby = "\n#{use_mod}.run"
57
+ doc.content.push "<br />"<<ColorizeRuby.convert(ruby, false)
58
+ end
59
+ html = doc.to_html
60
+ html
61
+ end
62
+ private
63
+ def parse_rest_assert str
64
+ return {} if str == ""
65
+ /\A - (.+)\Z/ =~ str or fail("can't parse rest: #{str.inspect}")
66
+ things = {}
67
+ case $1
68
+ when 'full'; things[:prologue] = true; things[:epilogue] = true;
69
+ else
70
+ things = JSON.parse($1) or fail("wanted json had: #{$1.inspect}")
71
+ end
72
+ things
73
+ end
74
+ end
75
+ class AppTag
76
+ class TagParser < ::NanDoc::Filters::CustomTag::TagParser
77
+ Symbols = {
78
+ :start => :path,
79
+ :path => {
80
+ :re => /[-\/_a-z0-9]*(?:test|spec)[-_a-z0-9]*\.rb/,
81
+ :desc => "test file path",
82
+ :next => [:sep, :app_keyword]
83
+ },
84
+ :sep => {
85
+ :re => / *(?:-|\/) */,
86
+ :desc => "separator {-|\\/}",
87
+ :no_sexp => true
88
+ },
89
+ :app_keyword => {
90
+ :re => /app\b/,
91
+ :desc => "'app' keyword",
92
+ :next => [:sep, :more_token]
93
+ },
94
+ :more_token => {
95
+ :desc => "open token (\"foo\" or \"'foo'\" or '\"foo\"')",
96
+ :re => /'[^']*'|"[^"]"|[^[:space:]]+/,# yeah we're not etc..
97
+ :next => Or[ :end, [:sep, :more_token] ]
98
+ }
99
+ }
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,63 @@
1
+ require 'shellwords'
2
+
3
+ module OptparseLite
4
+ class PlaybackTag < ::NanDoc::Filters::CustomTag
5
+ ::NanDoc::Filters::CustomTags.register_class(self)
6
+ include NanDoc::SpecDoc::Playback::Terminal::ColorToHtml
7
+ include NanDoc::StringMethods
8
+ include Nanoc3::Helpers::HTMLEscape
9
+ class << self
10
+ def =~ whole_file
11
+ /\(see: test[^ ]*\.rb - playback - ["']/ =~ whole_file
12
+ end
13
+ end
14
+ def name
15
+ 'optparse lite custom tag - playback'
16
+ end
17
+ def run content
18
+ numetal = content.gsub(
19
+ /\(see: (test[^ ]*\.rb) - playback - ["']([^"']+)["'](?: - (.+))?\)/
20
+ ) do
21
+ html = show_playback($1, $2, $3)
22
+ html
23
+ end
24
+ numetal
25
+ end
26
+ def show_playback testfile, testname, xtra
27
+ opts =
28
+ if xtra
29
+ JSON.parse(xtra) or fail("failed to parse json: #{xtra}")
30
+ else
31
+ {}
32
+ end
33
+ proj = NanDoc::Project.instance
34
+ proxy = proj.test_framework_proxy_for_file(testfile)
35
+ sexp = proxy.sexp_get testfile, testname
36
+ scn = NanDoc::SpecDoc::Playback::SexpScanner.new(sexp)
37
+ scn.scan_assert(:method)
38
+ doc = NanDoc::Html::Tags.new
39
+ while true do
40
+ app = scn.scan_assert(:app)[1]
41
+ name = app.spec.invocation_name
42
+ argv = scn.scan_assert(:argv)[1]
43
+ # command = "./#{name} #{argv.shelljoin}"
44
+ # shelljoin is ugly and dumb
45
+ command = "./#{name} #{myshelljoin(argv)}"
46
+ out = scn.scan_assert(:out)[1]
47
+ cmd_html = prompt_highlight2('~ > ', command)
48
+ doc.push_smart("pre", 'terminal', cmd_html, opts)
49
+ opts.clear
50
+ colored = terminal_color_to_html(out) || html_escape(out)
51
+ doc.content.push colored
52
+ if scn.current && scn.current.first == :app
53
+ doc.content.push "\n\n"
54
+ # stay -- rare tests that do multiple commands
55
+ else
56
+ break
57
+ end
58
+ end
59
+ html = doc.to_html
60
+ html
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,131 @@
1
+ require 'minitest/autorun'
2
+ require 'optparse-lite'
3
+ require 'nandoc/spec-doc'
4
+
5
+ NanDoc::SpecDoc::Playback::Method.handlers[:optparse_app_module] = [:skip]
6
+ NanDoc::SpecDoc::GenericAgent.custom_spec_hook(:grab_optparse_app) do
7
+ recordings.add(:optparse_app_module, :placeholder)
8
+ record = recordings[recordings.length - 1]
9
+ ::OptparseLite.after_included_once do |mod|
10
+ record[1] = mod
11
+ end
12
+ end
13
+
14
+ # extend minitest with optparse-lite-specific stuff!
15
+ module OptparseLite
16
+ module Test
17
+ class << self
18
+ attr_accessor :verbose # set below
19
+ end
20
+ module Capture
21
+ class Capturer
22
+ def initialize mod
23
+ # make a regexp that can deduce the local module name from the
24
+ # name of the class that minitest generates, e.g.:
25
+ # OptparseLite::Test => /^OptparseliteTest(.+)Spec/
26
+ @mod = mod
27
+ @regexp = Regexp.new('^'+
28
+ mod.to_s.split('::').map{|x| x.downcase.capitalize}.join +
29
+ '(.+)Spec'
30
+ )
31
+ end
32
+ def capture app=nil, &b
33
+ app ||= @application_module
34
+ do_record = @spec && @spec.respond_to?(:nandoc)
35
+ ui = app.send(:ui)
36
+ ui.push
37
+ if do_record
38
+ app.set_argv_hook do |argv|
39
+ @spec.nandoc.recordings.add(:app, app)
40
+ @spec.nandoc.recordings.add(:argv, argv)
41
+ end
42
+ end
43
+ @last_return_value = app.instance_eval(&b)
44
+ str = ui.pop.to_str # tacitly assumes stderr is empty, breaks else
45
+ if do_record
46
+ @spec.nandoc.recordings.add(:out, str)
47
+ end
48
+ $stdout.puts "\n\n#{str}\n" if Test.verbose
49
+ str
50
+ end
51
+ def capture2 app=nil, &b
52
+ do_record = @spec && @spec.respond_to?(:nandoc)
53
+ app ||= @application_module
54
+ ui = app.send(:ui)
55
+ ui.push
56
+ @last_return_value = app.instance_eval(&b)
57
+ out, err = ui.pop(true)
58
+ out, err = out.to_s, err.to_s
59
+ if Test.verbose
60
+ $stdout.puts "\n\nout:\n#{out}\n."
61
+ $stdout.puts "\n\nerr:\n#{out}\n."
62
+ end
63
+ if do_record
64
+ if ""!=out && ""!=err
65
+ fail("don't be a dick")
66
+ end
67
+ @spec.nandoc.recordings.add(:out, out + err)
68
+ end
69
+ [out, err]
70
+ end
71
+ def get_app_from_spec spec
72
+ name = @regexp.match(spec.class.to_s)[1].downcase
73
+ @cache ||= Hash[
74
+ @mod.constants.map{|x|[x.downcase, @mod.const_get(x)]}
75
+ ]
76
+ @cache[name]
77
+ end
78
+ def init_fork spec
79
+ @application_module = get_app_from_spec(spec)
80
+ @spec = spec # this has nandoc
81
+ end
82
+ def fork thing
83
+ ret = dup
84
+ ret.init_fork(thing)
85
+ ret
86
+ end
87
+ attr_accessor :last_return_value
88
+ attr_accessor :regexp
89
+ end
90
+ class << self
91
+ def included mod
92
+ base = MiniTest::Spec
93
+ capturer_prototype = Capturer.new(mod)
94
+ base.send(:define_method, :capturer) do ||
95
+ @capturer ||= capturer_prototype.fork(self)
96
+ end
97
+ base.send(:define_method, :capture) do |*a, &b|
98
+ capturer.capture(*a, &b)
99
+ end
100
+ base.send(:define_method, :capture2) do |*a, &b|
101
+ capturer.capture2(*a, &b)
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ # core extensions just for tests!
110
+ class String
111
+ def noindent n=nil
112
+ n ||= /\A *(?! )/.match(self)[0].length
113
+ s = gsub(/^ {#{n}}/, '')
114
+ s
115
+ end
116
+ end
117
+
118
+ if ARGV.include? '-v'
119
+ OptparseLite::Test.verbose = true
120
+ end
121
+
122
+ # hack to turn off randomness, for running the simplest
123
+ # test cases first
124
+ #
125
+ if (idx = ARGV.index('--seed')) && '0'==ARGV[idx+1]
126
+ class MiniTest::TestCase
127
+ def test_order
128
+ :alpha
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,5 @@
1
+ require 'treebis'
2
+
3
+ class Treebis::Task::RunContext
4
+ attr_reader :on_path
5
+ end
@@ -0,0 +1,963 @@
1
+ require 'optparse-lite/test/setup'
2
+
3
+ # wierd bug!!! ruby test/test.rb --seed 3611
4
+
5
+ module OptparseLite::Test
6
+
7
+ include OptparseLite::Test::Capture
8
+ NanDoc::SpecDoc.include_to(class << self; self end)
9
+
10
+ nandoc.story 'empty app'
11
+ nandoc.grab_optparse_app
12
+ nandoc.record_ruby
13
+ #!/usr/bin/env ruby
14
+
15
+ require 'optparse-lite'
16
+ class Empty
17
+ include OptparseLite
18
+ end
19
+ nandoc.record_ruby_stop
20
+
21
+ nandoc.story_stop
22
+
23
+ Empty.spec.invocation_name = "empty-app.rb"
24
+
25
+ describe Empty do
26
+ include NanDoc::SpecDoc
27
+
28
+ it 'empty-app.rb must work' do
29
+ nandoc.record
30
+ exp = <<-HERE.noindent
31
+ \e[32;mUsage:\e[0m empty-app.rb (this screen. no commands defined.)
32
+ HERE
33
+ act = capture{ run [] }
34
+ assert_no_diff(exp, act)
35
+ end
36
+
37
+ it 'no run' do
38
+ OptparseLite.suppress_run!
39
+ out, err = capture2{ run [] }
40
+ OptparseLite.enable_run!
41
+ assert_equal "run disabled. (probably for gentesting)\n", err
42
+ assert_equal "", out
43
+ end
44
+ end
45
+
46
+
47
+ nandoc.story 'one meth'
48
+ nandoc.grab_optparse_app
49
+ nandoc.record_ruby
50
+ class OneMeth
51
+ include OptparseLite
52
+ def bar
53
+ ui.puts 'done!'
54
+ end
55
+ end
56
+ nandoc.record_ruby_stop
57
+ nandoc.story_stop
58
+ OneMeth.spec.invocation_name = "one-meth-app.rb"
59
+
60
+ describe OneMeth do
61
+ include NanDoc::SpecDoc
62
+
63
+ it 'one-meth-app.rb runs' do
64
+ nandoc.record
65
+ out = capture{ run ['bar'] }
66
+ assert_equal "done!\n", out
67
+ end
68
+
69
+
70
+ it "one-meth-app.rb works like help when the command is not found" do
71
+ nandoc.record
72
+ exp = <<-HERE.noindent
73
+ i don't know how to \e[32;mbazzle\e[0m.
74
+ try \e[32;mone-meth-app.rb\e[0m \e[32;m-h\e[0m for help.
75
+ HERE
76
+ act = capture{ run ["bazzle"] }
77
+ assert_no_diff(exp, act)
78
+ end
79
+
80
+
81
+ it 'one-meth-app.rb ask for help must work' do
82
+ nandoc.record
83
+ exp = <<-HERE.noindent
84
+ \e[32;mUsage:\e[0m one-meth-app.rb (bar) [<opts>] [<args>]
85
+
86
+ \e[32;mCommands:\e[0m
87
+ bar usage: bar
88
+ type -h after a command or subcommand name for more help
89
+ HERE
90
+ act = capture{ run ["-h"] }
91
+ assert_no_diff(exp, act)
92
+ end
93
+
94
+
95
+ it 'one-meth-app.rb no args must work' do
96
+ exp = <<-HERE.noindent
97
+ \e[32;mUsage:\e[0m one-meth-app.rb (bar) [<opts>] [<args>]
98
+
99
+ \e[32;mCommands:\e[0m
100
+ bar usage: bar
101
+ type -h after a command or subcommand name for more help
102
+ HERE
103
+ act = capture{ run [] }
104
+ assert_no_diff(exp, act)
105
+ end
106
+
107
+
108
+ it 'one-meth-app.rb ask for help bad command must work' do
109
+ exp = <<-HERE.noindent
110
+ i don't know how to \e[32;mska\e[0m.
111
+ try \e[32;mone-meth-app.rb\e[0m \e[32;m-h\e[0m for help.
112
+ HERE
113
+ act = capture{ run ["-h", "ska"] }
114
+ assert_no_diff(exp, act)
115
+ end
116
+
117
+
118
+ it 'one-meth-app.rb ask for help partial match must work' do
119
+ exp = <<-HERE.noindent
120
+ \e[32;mUsage:\e[0m one-meth-app.rb bar
121
+ HERE
122
+ act = capture{ run ["-h", "b"] }
123
+ assert_no_diff(exp, act)
124
+ end
125
+
126
+
127
+ it 'one-meth-app.rb ask for help full match must work' do
128
+ nandoc.record
129
+ exp = <<-HERE.noindent
130
+ \e[32;mUsage:\e[0m one-meth-app.rb bar
131
+ HERE
132
+ act = capture{ run ["-h", "bar"] }
133
+ assert_no_diff(exp, act)
134
+ end
135
+ end
136
+
137
+
138
+ nandoc.story 'persistent'
139
+ nandoc.grab_optparse_app
140
+ nandoc.record_ruby
141
+ class PersistentService
142
+ include OptparseLite
143
+ def initialize
144
+ @num = 0
145
+ end
146
+ def ping
147
+ @num += 1
148
+ ui.puts "i have pinged #{@num} times"
149
+ end
150
+ end
151
+ nandoc.record_ruby_stop
152
+ nandoc.story_stop
153
+ PersistentService.spec.invocation_name = "persistent-service-app.rb"
154
+
155
+ describe PersistentService do
156
+ include NanDoc::SpecDoc
157
+
158
+ it 'persistent-service-app.rb multiple requests' do
159
+ nandoc.record
160
+ exp = <<-HERE.noindent
161
+ i have pinged 1 times
162
+ HERE
163
+ act = capture{ run ["ping"] }
164
+ assert_no_diff(exp, act)
165
+ exp = <<-HERE.noindent
166
+ i have pinged 2 times
167
+ HERE
168
+ act = capture{ run ["ping"] }
169
+ assert_no_diff(exp, act)
170
+ end
171
+ end
172
+
173
+ nandoc.story 'neg arity'
174
+ nandoc.grab_optparse_app
175
+ nandoc.record_ruby
176
+ class OneMethWithNegArity
177
+ include OptparseLite
178
+ def bar(*a); end
179
+ end
180
+ nandoc.record_ruby_stop
181
+ nandoc.story_stop
182
+ OneMethWithNegArity.spec.invocation_name = "one-meth-with-neg-arity-app.rb"
183
+
184
+ describe OneMethWithNegArity do
185
+ include NanDoc::SpecDoc
186
+
187
+ it 'one-meth-with-neg-arity-app.rb must work' do
188
+ nandoc.record
189
+ exp = <<-HERE.noindent
190
+ \e[32;mUsage:\e[0m one-meth-with-neg-arity-app.rb (bar) [<opts>] [<args>]
191
+
192
+ \e[32;mCommands:\e[0m
193
+ bar usage: bar [<arg1>]
194
+ type -h after a command or subcommand name for more help
195
+ HERE
196
+ act = capture{ run [] }
197
+ assert_no_diff(exp, act)
198
+ end
199
+ end
200
+
201
+
202
+ class OneMethWithPosArity
203
+ include OptparseLite
204
+ def bar(a); end
205
+ end
206
+ OneMethWithPosArity.spec.invocation_name = "one-meth-with-pos-arity-app.rb"
207
+
208
+ describe OneMethWithPosArity do
209
+ include NanDoc::SpecDoc
210
+
211
+ it 'one-meth-with-pos-arity-app.rb must work' do
212
+ exp = <<-HERE.noindent
213
+ \e[32;mUsage:\e[0m one-meth-with-pos-arity-app.rb (bar) [<opts>] [<args>]
214
+
215
+ \e[32;mCommands:\e[0m
216
+ bar usage: bar <arg1>
217
+ type -h after a command or subcommand name for more help
218
+ HERE
219
+ act = capture{ run [] }
220
+ assert_no_diff(exp, act)
221
+ end
222
+ end
223
+
224
+ nandoc.story 'one meth desc'
225
+ nandoc.grab_optparse_app
226
+ nandoc.record_ruby
227
+ class OneMethDesc
228
+ include OptparseLite
229
+
230
+ app.desc "when u wanna have a good time"
231
+
232
+ desc "this is for barring"
233
+ def bar; end
234
+ end
235
+ nandoc.record_ruby_stop
236
+ nandoc.story_stop
237
+ OneMethDesc.spec.invocation_name = "one-meth-desc-app.rb"
238
+
239
+ describe OneMethDesc do
240
+ include NanDoc::SpecDoc
241
+
242
+ it 'one-meth-desc-app.rb must work' do
243
+ nandoc.record
244
+ exp = <<-HERE.noindent
245
+ \e[32;mUsage:\e[0m one-meth-desc-app.rb (bar) [<opts>] [<args>]
246
+ when u wanna have a good time
247
+
248
+ \e[32;mCommands:\e[0m
249
+ bar this is for barring
250
+ type -h after a command or subcommand name for more help
251
+ HERE
252
+ act = capture{ run [] }
253
+ assert_no_diff(exp, act)
254
+ end
255
+ it 'one-meth-desc-app.rb ask for help must work' do
256
+ nandoc.record
257
+ exp = <<-HERE.noindent
258
+ \e[32;mUsage:\e[0m one-meth-desc-app.rb bar
259
+ \e[32;mDescription:\e[0m this is for barring
260
+ HERE
261
+ act = capture{ run ["-h", "bar"] }
262
+ assert_no_diff(exp, act)
263
+ end
264
+ end
265
+
266
+
267
+ nandoc.story 'one meth usage'
268
+ nandoc.grab_optparse_app
269
+ nandoc.record_ruby
270
+ class OneMethUsage
271
+ include OptparseLite
272
+ usage "<paint> <ball>"
273
+ def bar a, b; end
274
+ end
275
+ nandoc.record_ruby_stop
276
+ nandoc.story_stop
277
+
278
+ OneMethUsage.spec.invocation_name = "one-meth-usage-app.rb"
279
+
280
+ describe OneMethUsage do
281
+ include NanDoc::SpecDoc
282
+
283
+ it 'one-meth-usage-app.rb must work' do
284
+ nandoc.record
285
+ exp = <<-HERE.noindent
286
+ \e[32;mUsage:\e[0m one-meth-usage-app.rb (bar) [<opts>] [<args>]
287
+
288
+ \e[32;mCommands:\e[0m
289
+ bar usage: bar <paint> <ball>
290
+ type -h after a command or subcommand name for more help
291
+ HERE
292
+ act = capture{ run [] }
293
+ assert_no_diff(exp, act)
294
+ end
295
+ end
296
+
297
+
298
+ nandoc.story 'three meth'
299
+ nandoc.grab_optparse_app
300
+ nandoc.record_ruby
301
+ class ThreeMeth
302
+ include OptparseLite
303
+ def foo; end
304
+ def bar(arg1, arg2); end
305
+ desc "faz line one"
306
+ desc "faz line two"
307
+ def faz; end
308
+ end
309
+ nandoc.record_ruby_stop
310
+ nandoc.story_stop
311
+ ThreeMeth.spec.invocation_name = "three-meth-app.rb"
312
+
313
+ describe ThreeMeth do
314
+ include NanDoc::SpecDoc
315
+
316
+ it 'three-meth-app.rb no args must work' do
317
+ nandoc.record
318
+ exp = <<-HERE.noindent
319
+ \e[32;mUsage:\e[0m three-meth-app.rb (foo|bar|faz) [<opts>] [<args>]
320
+
321
+ \e[32;mCommands:\e[0m
322
+ foo usage: foo
323
+ bar usage: bar <arg1> <arg2>
324
+ faz faz line one
325
+ type -h after a command or subcommand name for more help
326
+ HERE
327
+ act = capture{ run [] }
328
+ assert_no_diff(exp, act)
329
+ end
330
+
331
+ it 'three-meth-app.rb help requested command not found must work' do
332
+ nandoc.record
333
+ exp = <<-HERE.noindent
334
+ i don't know how to \e[32;mska\e[0m.
335
+ try \e[32;mthree-meth-app.rb\e[0m \e[32;m-h\e[0m for help.
336
+ HERE
337
+ act = capture{ run ["-h", "ska"] }
338
+ assert_no_diff(exp, act)
339
+ end
340
+
341
+ it 'three-meth-app.rb help requested partial match must work 1' do
342
+ nandoc.record
343
+ exp = <<-HERE.noindent
344
+ did you mean \e[32;mfoo\e[0m or \e[32;mfaz\e[0m?
345
+ try \e[32;mthree-meth-app.rb\e[0m \e[32;m-h\e[0m for help.
346
+ HERE
347
+ act = capture{ run ["-h", "f"] }
348
+ assert_no_diff(exp, act)
349
+ end
350
+
351
+ it 'three-meth-app.rb help requested partial match must work 2' do
352
+ nandoc.record
353
+ exp = <<-HERE.noindent
354
+ \e[32;mUsage:\e[0m three-meth-app.rb faz
355
+ \e[32;mDescription:\e[0m
356
+ faz line one
357
+ faz line two
358
+ HERE
359
+ act = capture{ run ["-h", "fa"] }
360
+ assert_no_diff(exp, act)
361
+ end
362
+ end
363
+
364
+ describe OptparseLite::OptsLike do
365
+ include NanDoc::SpecDoc
366
+
367
+ it "ops must be OptsLike" do
368
+ e = assert_raises(RuntimeError) do
369
+ class BadOpts
370
+ include OptparseLite
371
+ opts nil
372
+ def foo; end
373
+ end
374
+ end
375
+ assert_equal(e.message, 'opts must be OptsLike')
376
+ end
377
+ end
378
+
379
+
380
+ module OptsStub
381
+ include OptparseLite::OptsLike
382
+ extend self
383
+ def syntax_tokens
384
+ ['--fake', '-b=<foo>']
385
+ end
386
+ def doc_sexp
387
+ [[:hdr, 'Awesome Opts:'],
388
+ [:opt, '-h,--hey','awesome desc'],
389
+ [:opt, '-H,--HO=<ho>', 'awesome desc2']]
390
+ end
391
+ end
392
+
393
+ class CmdWithOpts
394
+ include OptparseLite
395
+ opts OptsStub
396
+ def foo; end
397
+ end
398
+ CmdWithOpts.spec.invocation_name = "cmd-with-opts-app.rb"
399
+
400
+ describe CmdWithOpts do
401
+ include NanDoc::SpecDoc
402
+
403
+ it 'cmd-with-opts-app.rb must work with stub' do
404
+ exp = <<-HERE.noindent
405
+ \e[32;mUsage:\e[0m cmd-with-opts-app.rb (foo) [<opts>] [<args>]
406
+
407
+ \e[32;mCommands:\e[0m
408
+ foo usage: foo [--fake] [-b=<foo>]
409
+ type -h after a command or subcommand name for more help
410
+ HERE
411
+ act = capture{ run [] }
412
+ assert_no_diff(exp, act)
413
+ end
414
+ it 'cmd-with-opts-app.rb multiline description stub' do
415
+ exp = <<-HERE.noindent
416
+ \e[32;mUsage:\e[0m cmd-with-opts-app.rb foo [--fake] [-b=<foo>]
417
+ \e[32;mAwesome Opts:\e[0m
418
+ -h,--hey awesome desc
419
+ -H,--HO=<ho> awesome desc2
420
+ HERE
421
+ act = capture{ run ["-h", "foo"] }
422
+ assert_no_diff(exp, act)
423
+ end
424
+ end
425
+
426
+ nandoc.story 'more usage'
427
+ nandoc.grab_optparse_app
428
+ nandoc.record_ruby
429
+ class CovPatch
430
+ include OptparseLite
431
+
432
+ usage '[-blah -blah] <blah1> <blah2>'
433
+ def wierd_usage
434
+ end
435
+
436
+ usage '-one -opt -another [<args>]'
437
+ def useless_interpolate a1, a2
438
+ end
439
+ end
440
+ nandoc.record_ruby_stop
441
+ nandoc.story_stop
442
+
443
+ CovPatch.spec.invocation_name = "cov-patch-app.rb"
444
+
445
+ describe CovPatch do
446
+ include NanDoc::SpecDoc
447
+
448
+ it 'cov-patch-app.rb displays wierd usage (no validation!?)' do # @todo
449
+ nandoc.record
450
+ exp = <<-HERE.noindent
451
+ \e[32;mUsage:\e[0m cov-patch-app.rb wierd-usage [-blah -blah] <blah1> <blah2>
452
+ HERE
453
+ act = capture{ run ["-h", "wierd-"] }
454
+ assert_no_diff(exp, act)
455
+ end
456
+
457
+
458
+ it 'cov-patch-app.rb interpolates args for no reason' do
459
+ nandoc.record
460
+ exp = <<-HERE.noindent
461
+ \e[32;mUsage:\e[0m cov-patch-app.rb useless-interpolate -one -opt -another <arg1> <arg2>
462
+ HERE
463
+ act = capture{ run ["-h", "use"] }
464
+ assert_no_diff(exp, act)
465
+ end
466
+ end
467
+
468
+
469
+
470
+ class OptsMock
471
+ include OptparseLite::OptsLike
472
+ def initialize(sexp); @sexp = sexp end
473
+ def doc_sexp; @sexp; end
474
+ def syntax_tokens
475
+ @sexp.select{|x| x.first==:opt}.map{|x| x[1]}
476
+ end
477
+ end
478
+
479
+ class BannerTime
480
+ include OptparseLite
481
+
482
+ opts OptsMock.new([
483
+ [:hdr, 'Eric Banner:'],
484
+ [:opt, '--foo, -Bar', 'some opt desc'],
485
+ [:opt, '-foobric', 'another'],
486
+ [:txt, 'multiline description that is'],
487
+ [:txt, 'not a banner:'],
488
+ [:opt, '--stanley','foobric'],
489
+ [:txt,'this is desc'],
490
+ [:hdr,'This is banner:'],
491
+ [:opt, '-a,-b','bloofis goofis']
492
+ ])
493
+ def fix_desc opts, a, b=nil
494
+ end
495
+ end
496
+ BannerTime.spec.invocation_name = "banner-time-app.rb"
497
+
498
+ describe BannerTime do
499
+ include NanDoc::SpecDoc
500
+
501
+ it 'banner-time-app.rb must work' do
502
+ exp = <<-HERE.noindent
503
+ \e[32;mUsage:\e[0m banner-time-app.rb fix-desc [--foo, -Bar] [-foobric] [--stanley] [-a,-b] <arg1> [<arg2>]
504
+ \e[32;mEric Banner:\e[0m
505
+ --foo, -Bar some opt desc
506
+ -foobric another
507
+ multiline description that is
508
+ not a banner:
509
+ --stanley foobric
510
+ this is desc
511
+ \e[32;mThis is banner:\e[0m
512
+ -a,-b bloofis goofis
513
+ HERE
514
+ act = capture{ run ["-h", "fix"] }
515
+ assert_no_diff(exp, act)
516
+ end
517
+ end
518
+
519
+
520
+ describe OptparseLite::OptParser do
521
+ include NanDoc::SpecDoc
522
+
523
+ it "must fail on no mames param" do
524
+ e = assert_raises(RuntimeError) do
525
+ OptparseLite::OptParser.new{
526
+ opt '--[no-]mames[=<joai>]'
527
+ }.compile!
528
+ end
529
+ assert_match(/let's not take arguments with no- style opts/,e.message)
530
+ end
531
+ end
532
+
533
+
534
+ nandoc.story 'finally'
535
+ nandoc.grab_optparse_app
536
+ nandoc.record_ruby
537
+ class Finally
538
+ include OptparseLite
539
+
540
+ opts {
541
+ banner 'Fun Options:'
542
+ opt '-a, --alpha', 'desco', :foo
543
+ opt '-b, --beta=<foo>', 'desc for beta', :fooey, 'more desc for beta'
544
+ banner 'Eric Banner:'
545
+ banner 'not eric banner, just some desco'
546
+ banner 'another not banner, just some chit chat:'
547
+ opt '--gamma[=<baz>]','gamma is where it\'s at'
548
+ opt '--[no-]mames', :juae
549
+ }
550
+ def do_it opts, a, b=nil
551
+
552
+ end
553
+ end
554
+ nandoc.record_ruby_stop
555
+ nandoc.story_stop
556
+ Finally.spec.invocation_name = "finally-app.rb"
557
+
558
+ describe Finally do
559
+
560
+ include NanDoc::SpecDoc
561
+
562
+ it 'finally-app.rb general help' do
563
+ nandoc.record
564
+ exp = <<-HERE.noindent
565
+ \e[32;mUsage:\e[0m finally-app.rb (do-it) [<opts>] [<args>]
566
+
567
+ \e[32;mCommands:\e[0m
568
+ do-it usage: do-it [--alpha,-a] [--beta,-b=<foo>] [--gamma[=<baz>]] [--[no-]mames] <arg1> [<arg2>]
569
+ type -h after a command or subcommand name for more help
570
+ HERE
571
+ act = capture{ run [] }
572
+ assert_no_diff(exp, act)
573
+ end
574
+
575
+ it 'finally-app.rb command help' do
576
+ nandoc.record
577
+ exp = <<-HERE.noindent
578
+ \e[32;mUsage:\e[0m finally-app.rb do-it [--alpha,-a] [--beta,-b=<foo>] [--gamma[=<baz>]] [--[no-]mames] <arg1> [<arg2>]
579
+ \e[32;mFun Options:\e[0m
580
+ --alpha, -a desco
581
+ --beta, -b=<foo> desc for beta
582
+ more desc for beta
583
+ \e[32;mEric Banner:\e[0m
584
+ not eric banner, just some desco
585
+ another not banner, just some chit chat:
586
+ --gamma[=<baz>] gamma is where it's at
587
+ --[no-]mames
588
+ HERE
589
+ act = capture{ run ["-h", "do"] }
590
+ assert_no_diff(exp, act)
591
+ end
592
+
593
+ it 'finally-app.rb complains on optparse errors' do
594
+ nandoc.record
595
+ exp_out = <<-HERE.noindent
596
+ HERE
597
+ exp_err = <<-HERE.noindent
598
+ finally-app.rb: couldn't do-it because of the following errors:
599
+ \e[32;m--beta\e[0m requires a parameter (-b=<foo>)
600
+ i don't recognize the parameter: \e[32;m--not\e[0m
601
+ \e[32;m--alpha\e[0m does not take an arguement (\"yo\")
602
+ \e[32;mUsage:\e[0m finally-app.rb do-it [--alpha,-a] [--beta,-b=<foo>] [--gamma[=<baz>]] [--[no-]mames] <arg1> [<arg2>]
603
+ try \e[32;mfinally-app.rb\e[0m \e[32;mhelp\e[0m \e[32;mdo-it\e[0m for full syntax and usage.
604
+ HERE
605
+ act_out, act_err = capture2{ run ["do", "--not=an", "option", "--beta", "--alpha=yo", "--no-mames"] }
606
+ assert_no_diff(exp_out, act_out)
607
+ assert_no_diff(exp_err, act_err)
608
+ end
609
+ end
610
+
611
+ class Raiser
612
+ include OptparseLite
613
+
614
+ def arg_error
615
+ raise ArgumentError.new("this is an application-level arg error")
616
+ end
617
+
618
+ def rt_error
619
+ raise RuntimeError.new("this is an application-level runtime error")
620
+ end
621
+
622
+ def ui_level_error arg1, arg2
623
+ end
624
+ end
625
+ Raiser.spec.invocation_name = "raiser-app.rb"
626
+
627
+ describe Raiser do
628
+ include NanDoc::SpecDoc
629
+
630
+
631
+ it 'lets application level argument errors thru' do
632
+ e = assert_raises(ArgumentError) do
633
+ Raiser.run(%w(arg_error))
634
+ end
635
+ assert_match %r!arg error!, e.message
636
+ end
637
+
638
+ it 'lets application level runtime errors thru' do
639
+ e = assert_raises(RuntimeError) do
640
+ Raiser.run(%w(rt_error))
641
+ end
642
+ assert_match %!runtime error!, e.message
643
+ end
644
+
645
+ it 'rescues argument errors to the controller methods' do
646
+ exp_out = <<-HERE.noindent
647
+ HERE
648
+ exp_err = <<-HERE.noindent
649
+ raiser-app.rb: couldn't ui-level-error because of an error:
650
+ wrong number of arguments (0 for 2)
651
+ \e[32;mUsage:\e[0m raiser-app.rb ui-level-error <arg1> <arg2>
652
+ try \e[32;mraiser-app.rb\e[0m \e[32;mhelp\e[0m \e[32;mui-level-error\e[0m for full syntax and usage.
653
+ HERE
654
+ act_out, act_err = capture2{ run ["ui-"] }
655
+ assert_no_diff(exp_out, act_out)
656
+ assert_no_diff(exp_err, act_err)
657
+ end
658
+ end
659
+
660
+ describe OptparseLite::Np do
661
+ include NanDoc::SpecDoc
662
+
663
+ it "fails on this" do
664
+ e = assert_raises(RuntimeError) do
665
+ OptparseLite::Np.new(:the,'thing'){}
666
+ end
667
+ assert_match %r!blah blah!, e.message
668
+ e = assert_raises(RuntimeError) do
669
+ OptparseLite::Np.new(:the,'thing',10){||}
670
+ end
671
+ assert_match %r!count and block mutually exclusive!, e.message
672
+ end
673
+ end
674
+
675
+
676
+ nandoc.story 'agg opts'
677
+ nandoc.grab_optparse_app
678
+ nandoc.record_ruby
679
+ class AggOpts
680
+ include OptparseLite
681
+ opts {
682
+ banner 'Alpha Options:'
683
+ opt '-a, --alpha', 'this is alpha'
684
+ opt '-b', 'this is beta', :default=>'heh but it\'s argless'
685
+ }
686
+ desc "you will see this at the top above the opts? or not"
687
+ opts {
688
+ banner 'Gamma Options:'
689
+ opt '-g, --gamma=<foo>', 'this is gamma',
690
+ 'multiline gamma', :default=>'great gams'
691
+ opt '-d, --delta'
692
+ }
693
+ def go_with_it opts, a, b=nil
694
+ opts = opts.merge(:first_arg=>a, :second_arg=>b)
695
+ resp = opts.keys.map(&:to_s).sort.map{|k| [k.to_sym, opts[k.to_sym]]}
696
+ ui.puts resp.inspect
697
+ end
698
+ end
699
+ nandoc.record_ruby_stop
700
+ nandoc.story_stop
701
+ AggOpts.spec.invocation_name = "agg-opts-app.rb"
702
+
703
+ describe AggOpts do
704
+ include NanDoc::SpecDoc
705
+
706
+ it 'agg-opts-app.rb help display' do
707
+ nandoc.record
708
+ exp = <<-HERE.noindent
709
+ \e[32;mUsage:\e[0m agg-opts-app.rb go-with-it [--alpha,-a] [-b] [--gamma,-g=<foo>] [--delta,-d] <arg1> [<arg2>]
710
+ \e[32;mAlpha Options:\e[0m
711
+ --alpha, -a this is alpha
712
+ -b this is beta
713
+ you will see this at the top above the opts? or not
714
+ \e[32;mGamma Options:\e[0m
715
+ --gamma, -g=<foo> this is gamma
716
+ multiline gamma
717
+ --delta, -d
718
+ HERE
719
+ act = capture{ run ["-h", "go"] }
720
+ assert_no_diff(exp, act)
721
+ end
722
+
723
+ it 'agg-opts-app.rb opt validation' do
724
+ nandoc.record
725
+ exp_out = <<-HERE.noindent
726
+ HERE
727
+ exp_err = <<-HERE.noindent
728
+ agg-opts-app.rb: couldn't go-with-it because of the following errors:
729
+ \e[32;m--alpha\e[0m does not take an arguement (\"foo\")
730
+ i don't recognize these parameters: \e[32;m--gamma,\e[0m and \e[32;m--digle\e[0m
731
+ \e[32;mUsage:\e[0m agg-opts-app.rb go-with-it [--alpha,-a] [-b] [--gamma,-g=<foo>] [--delta,-d] <arg1> [<arg2>]
732
+ try \e[32;magg-opts-app.rb\e[0m \e[32;mhelp\e[0m \e[32;mgo-with-it\e[0m for full syntax and usage.
733
+ HERE
734
+ act_out, act_err = capture2{ run ["go", "--digle=fingle,", "--gamma,", "--alpha=foo"] }
735
+ assert_no_diff(exp_out, act_out)
736
+ assert_no_diff(exp_err, act_err)
737
+ end
738
+
739
+ it 'agg-opts-app.rb must work' do
740
+ nandoc.record
741
+ exp = <<-HERE.noindent
742
+ [[:b, \"heh but it's argless\"], [:first_arg, \"foo\"], [:gamma, \"great gams\"], [:second_arg, nil]]
743
+ HERE
744
+ act = capture{ run ["go", "foo"] }
745
+ assert_no_diff(exp, act)
746
+ end
747
+ end
748
+
749
+ nandoc.story 'sub'
750
+ nandoc.grab_optparse_app
751
+ nandoc.record_ruby
752
+ class Sub
753
+ include OptparseLite
754
+
755
+ subcommands :fric, 'bric-dic', :frac
756
+ def foo(*a)
757
+ subcommand_dispatch(*a)
758
+ end
759
+
760
+ private
761
+
762
+ usage '[<opts>] <crank-harder>'
763
+ desc 'crank harder'
764
+ opts {
765
+ opt '-f', "this does blah", :accessor=>:f
766
+ }
767
+ def foo_fric opts, arg
768
+ opts.merge!({:arg=>arg, :method=>:foo_fric})
769
+ thing = opts.keys.map(&:to_s).sort.map{|x| [x, opts[x.to_sym]]}
770
+ ui.puts thing.inspect
771
+ opts
772
+ end
773
+
774
+ usage '[<opts>] <somefile>'
775
+ desc 'some awesome times'
776
+ opts {
777
+ opt '-b,--blah', "this does blah"
778
+ }
779
+ def foo_bric_dic opts, arg
780
+ opts.merge!({:arg=>arg, :method=>:foo_bric_dic})
781
+ thing = opts.keys.map(&:to_s).sort.map{|x| [x, opts[x.to_sym]]}
782
+ ui.puts thing.inspect
783
+ opts
784
+ end
785
+
786
+ def foo_frac
787
+ end
788
+ end
789
+ nandoc.record_ruby_stop
790
+ nandoc.story_stop
791
+ Sub.spec.invocation_name = "sub-app.rb"
792
+
793
+ describe Sub do
794
+ include NanDoc::SpecDoc
795
+
796
+ it 'sub-app.rb with command with no arg shows subcommand list' do
797
+ nandoc.record
798
+ exp = <<-HERE.noindent
799
+ \e[32;mUsage:\e[0m sub-app.rb foo (fric|bric-dic|frac) [<opts>] [<args>]
800
+
801
+ \e[32;mSub Commands:\e[0m
802
+ fric crank harder
803
+ bric-dic some awesome times
804
+ frac usage: foo frac
805
+ type -h after a command or subcommand name for more help
806
+ HERE
807
+ act = capture{ run ["foo"] }
808
+ assert_no_diff(exp, act)
809
+ act = capture{ run ["foo", "-h"] }
810
+ assert_no_diff(exp, act)
811
+ end
812
+ it 'sub-app.rb shows help on sub-command' do
813
+ nandoc.record
814
+ exp = <<-HERE.noindent
815
+ \e[32;mUsage:\e[0m sub-app.rb foo fric [-f] <crank-harder>
816
+ \e[32;mDescription:\e[0m crank harder
817
+ -f this does blah
818
+ HERE
819
+ act = capture{ run ["foo", "-h", "fric"] }
820
+ assert_no_diff(exp, act)
821
+ end
822
+ it 'sub-app.rb must work' do
823
+ nandoc.record
824
+ exp = <<-HERE.noindent
825
+ [[\"arg\", \"frak\"], [\"method\", :foo_fric]]
826
+ HERE
827
+ act = capture{ run ["foo", "fric", "frak"] }
828
+ assert_no_diff(exp, act)
829
+ exp = <<-HERE.noindent
830
+ [[\"arg\", \"frak\"], [\"method\", :foo_fric]]
831
+ HERE
832
+ act = capture{ run ["foo", "fri", "frak"] }
833
+ assert_no_diff(exp, act)
834
+ end
835
+ end
836
+
837
+
838
+ module Mod
839
+ include OptparseLite
840
+ opts {
841
+ banner 'Fun Options:'
842
+ opt '-a, --alpha', 'desco', :foo
843
+ opt '-b, --beta=<foo>', 'desc for beta', :fooey, 'more desc for beta'
844
+ banner 'Eric Banner:'
845
+ banner 'not eric banner, just some desco'
846
+ banner 'another not banner, just some chit chat:'
847
+ opt '--gamma[=<baz>]','gamma is where it\'s at'
848
+ opt '--[no-]mames', :juae
849
+ }
850
+ def foo opts, arg1, arg2
851
+ @ui.puts "rock on #{arg1} rock on #{arg2}"
852
+ end
853
+
854
+ def bar arg2
855
+ end
856
+ end
857
+ Mod.spec.invocation_name = "mod-app.rb"
858
+
859
+ describe Mod do
860
+ include NanDoc::SpecDoc
861
+
862
+ it 'mod-app.rb must work' do
863
+ exp = <<-HERE.noindent
864
+ rock on new york rock on chicago
865
+ HERE
866
+ act = capture{ run ["foo", "new york", "chicago"] }
867
+ assert_no_diff(exp, act)
868
+ end
869
+ it 'mod-app.rb supressed must work' do
870
+ OptparseLite.suppress_run!
871
+ out, err = capture2{ run [] }
872
+ OptparseLite.enable_run!
873
+ assert_equal "run disabled. (probably for gentesting)\n", err
874
+ assert_equal "", out
875
+ end
876
+ end
877
+
878
+ module ForeignParser
879
+ include OptparseLite
880
+ class MockParser
881
+ include OptparseLite::OptsLike
882
+ Response = OptparseLite::OptParser::Response
883
+ Error = OptparseLite::OptParser::Error
884
+ class VersionHaver
885
+ def version; 'awesome-foo 1.2.3' end
886
+ end
887
+ def parse argv
888
+ if argv.include?('-v')
889
+ return [
890
+ Response.new([
891
+ Error.new(
892
+ :help_requested, 'nosee',
893
+ :'version_requested?'=>true,
894
+ :parser => VersionHaver.new
895
+ )
896
+ ]),
897
+ {}]
898
+ end
899
+ if argv.include?('-h')
900
+ return [
901
+ Response.new([
902
+ Error.new(:help_requested, 'nosee')
903
+ ]),
904
+ {}]
905
+ end
906
+ if argv.include?('--help')
907
+ return [
908
+ Response.new([
909
+ Error.new(:help_requested, 'nosee', :'long_help?'=>true)
910
+ ]),
911
+ {}]
912
+ end
913
+
914
+ [Response.new(),{}]
915
+ end
916
+ def syntax_tokens; ['-h','-v'] end
917
+ def doc_sexp; [[:txt,'just pass -v or -h to test this']] end
918
+ end
919
+ opts MockParser.new
920
+ def foo opts
921
+ @ui.puts opts.inspect
922
+ end
923
+ end
924
+ ForeignParser.spec.invocation_name = "foreign-parser-app.rb"
925
+
926
+ describe ForeignParser do
927
+ include NanDoc::SpecDoc
928
+
929
+ it '"foreign-parser-app.rb -h" lists commands' do
930
+ exp = <<-HERE.noindent
931
+ \e[32;mUsage:\e[0m foreign-parser-app.rb foo [-h] [-v]
932
+ \e[32;mDescription:\e[0m
933
+ just pass -v or -h to test this
934
+ HERE
935
+ act = capture{ run ["-h", "foo"] }
936
+ assert_no_diff(exp, act)
937
+ end
938
+ it '"foreign-parser-app.rb <command> -h" gives short command help' do
939
+ exp = <<-HERE.noindent
940
+ \e[32;mUsage:\e[0m foreign-parser-app.rb foo [-h] [-v]
941
+ try \e[32;mforeign-parser-app.rb\e[0m \e[32;mhelp\e[0m \e[32;mfoo\e[0m for full syntax and usage.
942
+ HERE
943
+ act = capture{ run ["foo", "-h"] }
944
+ assert_no_diff(exp, act)
945
+ end
946
+ it '"foreign-parser-app.rb <command> --help" gives longer help' do
947
+ exp = <<-HERE.noindent
948
+ \e[32;mUsage:\e[0m foreign-parser-app.rb foo [-h] [-v]
949
+ \e[32;mDescription:\e[0m
950
+ just pass -v or -h to test this
951
+ HERE
952
+ act = capture{ run ["foo", "--help"] }
953
+ assert_no_diff(exp, act)
954
+ end
955
+ it '"foreign-parser-app.rb <command> -v" shows version' do
956
+ exp = <<-HERE.noindent
957
+ awesome-foo 1.2.3
958
+ HERE
959
+ act = capture{ run ["foo", "-v"] }
960
+ assert_no_diff(exp, act)
961
+ end
962
+ end
963
+ end