optparse-lite 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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