manager 0.0.0 → 0.1.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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHART.html +1270 -0
  3. data/MANUAL.html +1252 -0
  4. data/bin/manager +43 -0
  5. data/examples/array/CHART.html +1376 -0
  6. data/examples/array/MANUAL.html +1126 -0
  7. data/examples/array/spec +3438 -0
  8. data/lib/manager.rb +528 -0
  9. data/lib/manager/annotation +96 -0
  10. data/lib/manager/input +189 -0
  11. data/lib/manager/js +257 -0
  12. data/lib/manager/refine_module +142 -0
  13. data/lib/manager/refine_object_mapping +143 -0
  14. data/lib/manager/refine_test +97 -0
  15. data/lib/manager/render +1228 -0
  16. data/lib/manager/spell_check +49 -0
  17. data/lib/manager/test +404 -0
  18. data/lib/manager/test_helper +9 -0
  19. data/license +9 -0
  20. data/manager.gemspec +21 -0
  21. data/spec/alternatives_implemented.png +0 -0
  22. data/spec/alternatives_unimplemented.png +0 -0
  23. data/spec/annotations.png +0 -0
  24. data/spec/benchmark_test.png +0 -0
  25. data/spec/citation.png +0 -0
  26. data/spec/code_block.png +0 -0
  27. data/spec/context_module.png +0 -0
  28. data/spec/documentation +1289 -0
  29. data/spec/external_link.png +0 -0
  30. data/spec/image.png +0 -0
  31. data/spec/list.png +0 -0
  32. data/spec/long.png +0 -0
  33. data/spec/main_and_object.png +0 -0
  34. data/spec/markup.png +0 -0
  35. data/spec/module_diagram.png +0 -0
  36. data/spec/navigation.png +0 -0
  37. data/spec/nested_section_headers.png +0 -0
  38. data/spec/ruby.png +0 -0
  39. data/spec/setup_teardown.png +0 -0
  40. data/spec/short.png +0 -0
  41. data/spec/signature.png +0 -0
  42. data/spec/spec +76 -0
  43. data/spec/spec_example.png +0 -0
  44. data/spec/table.png +0 -0
  45. data/spec/test_header.png +0 -0
  46. data/spec/test_non_unit_spec +184 -0
  47. data/spec/test_program +71 -0
  48. data/spec/test_unit_spec +790 -0
  49. data/spec/tutorial_1.png +0 -0
  50. data/spec/tutorial_2.png +0 -0
  51. data/spec/tutorial_3.png +0 -0
  52. data/spec/tutorial_4.png +0 -0
  53. data/spec/tutorial_5.png +0 -0
  54. data/spec/tutorial_6.png +0 -0
  55. data/spec/tutorial_7.png +0 -0
  56. data/spec/tutorial_8.png +0 -0
  57. data/spec/unambiguous_links.png +0 -0
  58. data/spec/unit_test_failure.png +0 -0
  59. data/spec/unit_test_raise.png +0 -0
  60. data/spec/unit_test_receiver.png +0 -0
  61. data/spec/unit_test_succeed.png +0 -0
  62. data/spec/unit_test_success.png +0 -0
  63. data/spec/unit_test_throw.png +0 -0
  64. data/spec/valid_heading.png +0 -0
  65. data/spec/with_expr.png +0 -0
  66. data/spec/without_expr.png +0 -0
  67. data/theme/2016a.css +670 -0
  68. data/theme/coderay_github.css +132 -0
  69. metadata +140 -11
@@ -0,0 +1,49 @@
1
+ #!ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Copyright (c) 2016 sawa
5
+
6
+ module Manager::Spellcheck
7
+ def self.prepare
8
+ require "ffi/aspell"
9
+ rescue LoadError
10
+ raise "Configuration is set to use spell checking, which requires the `ffi-aspell` gem. "\
11
+ "Either install this gem, or turn off spell checking."
12
+ end
13
+ def self.list
14
+ prepare
15
+ speller = FFI::Aspell::Speller.new
16
+ speller.send(:available_dictionaries)
17
+ ensure
18
+ speller &.close
19
+ end
20
+ def self.language? language
21
+ prepare
22
+ speller = FFI::Aspell::Speller.new
23
+ speller.dictionary_available?(language)
24
+ ensure
25
+ speller &.close
26
+ end
27
+ def self.new language
28
+ prepare
29
+ FFI::Aspell::Speller.new(language)
30
+ end
31
+ def self.regex language
32
+ #!Make it multilingual
33
+ /[a-zA-Z][a-zA-Z']*[a-zA-Z]/
34
+ end
35
+ def self.filter language, words
36
+ raise "No dictionary given." unless language
37
+ begin
38
+ require "ffi/aspell"
39
+ speller = FFI::Aspell::Speller.new(language)
40
+ rescue LoadError
41
+ raise "Needs the `ffi-aspell` gem."
42
+ rescue ArgumentError
43
+ raise "Dictionary `#{language}` is not available."
44
+ end
45
+ words.reject{|w| speller.correct?(w)}
46
+ ensure
47
+ speller &.close
48
+ end
49
+ end
@@ -0,0 +1,404 @@
1
+ #!ruby
2
+ #frozen_string_literal: true
3
+
4
+ # Copyright (c) 2016 sawa
5
+
6
+ using Manager::ModuleRefinement
7
+ using Manager::TesterRefinement
8
+
9
+ class Manager::Binding
10
+ #!Wrapping in new module to make bare method definitions in `exp` (which would otherwise
11
+ # be evaluated in the `main` environment) to be evaluated locally. The methods will be
12
+ # defined in the singleton class of `@module`.
13
+ def initialize; @binding = Module.new.instance_eval{binding} end
14
+ def eval exp, f = nil, l = nil; @binding.eval(exp, *f, *l) end
15
+ end
16
+
17
+ class Manager::ExprProc < Proc
18
+ def initialize exp; @exp = exp end
19
+ def inspect; @exp end
20
+ end
21
+
22
+ class Manager::Setup
23
+ def initialize exp, bt
24
+ @exp, @f, @l = exp, bt.absolute_path, bt.lineno
25
+ end
26
+ end
27
+
28
+ class Manager::Expr
29
+ def initialize s, caller_locations
30
+ @s = s
31
+ @modifiers, @modifiers_args = [], []
32
+ bt = caller_locations.first
33
+ @location = [bt.absolute_path, bt.lineno]
34
+ end
35
+ def to_proc
36
+ # if @s.respond_to?(:to_proc)
37
+ # s = @s
38
+ # @s.to_proc.tap{|pr| def pr.inspect; s end}
39
+ # else
40
+ esc_exp = "\"#{@s.gsub('"', '\\"')}\""
41
+ ::Kernel.eval("Manager::ExprProc.new(#{esc_exp})#@s", nil, *@location)
42
+ # end
43
+ end
44
+ def method_missing modifier, *args, **kargs, &pr
45
+ @modifiers.push(modifier)
46
+ @modifiers_args.push([args, kargs, pr])
47
+ self
48
+ end
49
+ def respond_to_missing? method, private = false
50
+ #! `respond_to_missing?` is called with `:to_hash` (and that is applied if positive) by Ruby
51
+ # when `expr` occurs as an argument. Need to override the `true` being returned due to
52
+ # `method_missing` being defined.
53
+ method == :to_hash ? false : super
54
+ end
55
+ def inspect
56
+ @exp ||= ::Manager::Render::Expression.new(@s).push(@modifiers, @modifiers_args)
57
+ @exp.to_s
58
+ end
59
+ end
60
+
61
+ class Manager::UnitTest
62
+ def initialize referer, sample, feature_args
63
+ @referer, @sample, @feature_args = referer, sample, feature_args
64
+ @verifiers, @verifiers_args = [], []
65
+ end
66
+ def method_missing verifier, *args, **kargs, &pr
67
+ @verifiers.push(verifier)
68
+ @verifiers_args.push([args, kargs, pr])
69
+ self
70
+ end
71
+ end
72
+
73
+ class Manager::Benchmark
74
+ def initialize sample, feature_args
75
+ @sample, @feature_args = sample, feature_args
76
+ end
77
+ end
78
+
79
+ class Manager::Context
80
+ #! `All` cannot be made private constant because it is used in `Expr#tainted?`.
81
+ All, Alt = Object.new, Object.new
82
+ InterruptTest = Proc.new{
83
+ StdoutOrig.print "\b\b\b\b\b"
84
+ throw All, [:untestable, "Skipped by user.", nil]
85
+ }
86
+ attr_reader :modul, :type, :alts
87
+ def initialize
88
+ @master_binding = Manager::Binding.new
89
+ @setups = []
90
+ end
91
+ alias teardown initialize
92
+ public :teardown
93
+ def set_master_binding exp
94
+ @setups.push(exp)
95
+ end
96
+ def set_branched_binding
97
+ @branched_bindings = @alts.each_with_object({}) do
98
+ |alt, h| h[alt] = @binding = Manager::Binding.new
99
+ @setups.each{|exp| begin silent_evaluate(exp); rescue Exception; end}
100
+ end
101
+ @receivers, @returns, @exceptions, @throws = {}, {}, {}, {}
102
+ end
103
+ def new_feature modul, type, alts
104
+ @modul, @type, @alts = modul, type, alts
105
+ @receivers, @returns, @exceptions, @throws = {}, {}, {}, {}
106
+ end
107
+ def setup exp, f, l
108
+ set_master_binding(exp)
109
+ catch(All) do catch(Alt) do
110
+ @binding = @master_binding
111
+ begin
112
+ evaluate(exp, f, l)
113
+ throw Alt, nil
114
+ rescue Exception => e
115
+ throw All, [:bad_test, e, @output]
116
+ end
117
+ end end || [:success, nil, @output]
118
+ ensure
119
+ @output = nil
120
+ end
121
+ def unit_test sample, feature_args, referer, verifiers, verifiers_args
122
+ if referer.!
123
+ set_branched_binding
124
+ elsif @branched_bindings.!
125
+ return [:untestable, "Missing a preceding successful unit test.", nil]
126
+ end
127
+ catch(All) do begin
128
+ Signal.trap("INT", &InterruptTest)
129
+ @alts.each_with_object({}) do
130
+ |alt, h|
131
+ @binding = @branched_bindings[alt]
132
+ result = catch(Alt) do
133
+ exercise(alt, sample, feature_args) unless referer
134
+ first_verify(alt, referer, verifiers.first, verifiers_args.first) unless verifiers.empty?
135
+ verifiers.zip(verifiers_args).drop(1).each{|a| verify(*a)}
136
+ nil
137
+ end
138
+ if result
139
+ h[alt] = result
140
+ elsif @verifee.!
141
+ h[alt] = [
142
+ :bug,
143
+ begin
144
+ _referer = referer || "return"
145
+ referer_value = instance_variable_get("@#{_referer}s")[alt]
146
+ "The receiver of verification `#{verifiers.last}` is "\
147
+ "`#{@prev_verifee.inspect}`."\
148
+ # "The receiver of verification `#{verifiers.last}` is "\
149
+ # "`#{@prev_verifee.inspect}`. "\
150
+ # "The arguments are: "\
151
+ # "#{@last_verifier_args[0].map{|e| "`#{e.inspect}`"}.join(", ")},"\
152
+ # " keyword arguments are: "\
153
+ # "#{@last_verifier_args[1].map{|k, v| "`#{e.inspect}`: `#{e.inspect}`"}.join(", ")},"\
154
+ # " proc is: `#{@last_verifier_args[2].inspect}`."
155
+ end,
156
+ @output,
157
+ ]
158
+ end
159
+ @output = nil
160
+ end
161
+ .tap{|h| return h.empty? ? [:success, nil, @output] : h}
162
+ ensure
163
+ Signal.trap("INT", &Manager::InterruptionInactive)
164
+ end end
165
+ end
166
+ def exercise alt, sample, feature_args
167
+ @exceptions.delete(alt)
168
+ @throws.delete(alt)
169
+ case @type
170
+ when :constant
171
+ @receivers.delete(alt)
172
+ unless feature_args.nil?
173
+ throw All, [:bad_test, "Constant invocation cannot take an argument.", nil]
174
+ end
175
+ unless alt =~ /\A[A-Z]\w*\z/ and @modul.const_defined?(alt)
176
+ @returns.delete(alt)
177
+ throw All, [:untestable, "The constant is unimplemented.", nil]
178
+ else
179
+ @returns[alt] = @modul.const_get(alt.to_s)
180
+ end
181
+ when :instance, :singleton
182
+ begin
183
+ @receivers[alt] = sample.itself
184
+ rescue Exception => e
185
+ @returns.delete(alt)
186
+ throw All, [:bad_test, e, @output]
187
+ end
188
+ args, kargs, pr = itself_all(feature_args) || [[], {}, nil]
189
+ #! Not using `@receivers[alt].kind_of?` and not putting `@receivers[alt]` on the left side
190
+ # of `!=` since it may be `BasicObject` and undefined.
191
+ if (@type == :instance and (@modul === @receivers[alt]).!) or
192
+ (@type == :singleton and @modul != @receivers[alt])
193
+ @receivers.delete(alt)
194
+ throw All, [:untestable, "Receiver is not an instance of the appropriate class.", nil]
195
+ else
196
+ begin
197
+ if @receivers[alt].respond_to?(alt, true).!
198
+ @receivers.delete(alt)
199
+ throw All, [:untestable, "The method is unimplemented.", nil]
200
+ end
201
+ rescue NoMethodError
202
+ #! `BasicObject` not responding to `respond_to?`. Continue in this case.
203
+ end
204
+ end
205
+ begin
206
+ if kargs.empty? #! Ruby bug
207
+ @returns[alt] = in_terminal{@receivers[alt].__send__(alt, *args, &pr)}
208
+ else
209
+ @returns[alt] = in_terminal{@receivers[alt].__send__(alt, *args, **kargs, &pr)}
210
+ end
211
+ rescue UncaughtThrowError => e
212
+ @throws[alt] = e
213
+ @receivers.delete(alt)
214
+ rescue Exception => e
215
+ @exceptions[alt] = e
216
+ @receivers.delete(alt)
217
+ end
218
+ end
219
+ ensure
220
+ @output = nil
221
+ end
222
+ def first_verify alt, referer, verifier, verifier_args
223
+ args, kargs, pr = itself_all(verifier_args)
224
+ if referer and @type == :constant
225
+ throw All, [:bad_test, "Cannot use `#{referer.upcase}` for a constant.", nil]
226
+ elsif referer and @receivers.key?(alt).!
227
+ throw All, [:untestable, "Missing a preceding successful unit test.", nil]
228
+ elsif verifier == :raise?
229
+ raise?(alt, verifier_args)
230
+ elsif @exceptions.key?(alt)
231
+ throw Alt, [:bug, @exceptions[alt], @output]
232
+ elsif verifier == :throw?
233
+ throw?(alt, verifier_args)
234
+ elsif @throws.key?(alt)
235
+ throw Alt, [:bug, @throws[alt], @output]
236
+ elsif verifier == :succeed?
237
+ @verifee = true
238
+ else
239
+ @prev_verifee = @verifee = (instance_variable_get("@#{referer || "return"}s"))[alt]
240
+ @last_verifier_args = [args, kargs, pr]
241
+ begin
242
+ if kargs.empty? #Ruby bug#
243
+ @verifee = in_terminal{@prev_verifee.__send__(verifier, *args, &pr)}
244
+ else
245
+ @verifee = in_terminal{@prev_verifee.__send__(verifier, *args, **kargs, &pr)}
246
+ end
247
+ rescue Exception => e
248
+ #! Unlike with `exercise`, exception is a bug here.
249
+ throw Alt, [:bug, e, @output]
250
+ end
251
+ end
252
+ end
253
+ def verify verifier, verifier_args
254
+ args, kargs, pr = itself_all(verifier_args)
255
+ @prev_verifee = @verifee
256
+ @last_verifier_args = [args, kargs, pr]
257
+ begin
258
+ if kargs.empty? #Ruby bug#
259
+ @verifee = in_terminal{@prev_verifee.__send__(verifier, *args, &pr)}
260
+ else
261
+ @verifee = in_terminal{@prev_verifee.__send__(verifier, *args, **kargs, &pr)}
262
+ end
263
+ rescue Exception => e
264
+ #! Unlike with `exercise`, exception is a bug here.
265
+ throw Alt, [:bug, e, @output]
266
+ end
267
+ end
268
+ def expr s, location, modifiers, modifiers_args
269
+ modifiers.zip(modifiers_args).inject(evaluate(s, *location)){|ret, a| _expr(ret, *a)}
270
+ end
271
+ def _expr ret, modifier, modifier_args
272
+ args, kargs, pr = itself_all(modifier_args)
273
+ if kargs.empty? #Ruby bug#
274
+ silent{ret.__send__(modifier, *args, &pr)}
275
+ else
276
+ silent{ret.__send__(modifier, *args, **kargs, &pr)}
277
+ end
278
+ end
279
+ def benchmark sample, feature_args
280
+ set_branched_binding
281
+ @binding = @branched_bindings.values.first
282
+ catch(All) do begin
283
+ Signal.trap("INT", &InterruptTest)
284
+ catch(Alt) do
285
+ begin
286
+ @receiver = sample.itself
287
+ rescue Exception => e
288
+ throw All, [:bad_test, e, nil]
289
+ end
290
+ args, kargs, pr = itself_all(feature_args) || [[], {}, nil]
291
+ job = ::Benchmark::IPS::Job.new(suite: false, quiet: true)
292
+ job.config(warmup: 0.1, time: 1)
293
+ Manager.context.alts.each do
294
+ |alt|
295
+ # job.item(alt, Manager::Render::Expression.new.to_s(@receiver.inspect, false, alt, args, kargs, pr))
296
+ #! By using `__send__`, private and protected methods can be tested as well as public ones.
297
+ if kargs.empty? #! Ruby bug
298
+ job.item(alt){@receiver.__send__(alt, *args, &pr)}
299
+ else
300
+ job.item(alt){@receiver.__send__(alt, *args, **kargs, &pr)}
301
+ end
302
+ end
303
+ begin
304
+ job.run_warmup
305
+ job.run
306
+ throw Alt, [:success, job.full_report.entries
307
+ .each.with_object({}){|rp, h| h[rp.label] = {ips: rp.ips, sd: rp.stddev_percentage}}]
308
+ rescue NoMethodError
309
+ throw All, [:untestable, "The method is unimplemented.", nil]
310
+ rescue Exception => e
311
+ throw Alt, [:bug, e, nil]
312
+ end
313
+ end
314
+ ensure
315
+ Signal.trap("INT", &Manager::InterruptionInactive)
316
+ end end
317
+ ensure
318
+ @output = nil
319
+ end
320
+ def raise? alt, verifier_args
321
+ exception_class = verifier_args[0][0] || ::StandardError
322
+ include_subclass = verifier_args[0][1]
323
+ include_subclass = true if include_subclass.nil?
324
+ verifier = include_subclass ? :kind_of? : :instance_of?
325
+ kargs = verifier_args[1]
326
+ if @exceptions.key?(alt).!
327
+ throw Alt, [:bug, "Did not raise an exception.", @output]
328
+ elsif @exceptions[alt].send(verifier, exception_class) and
329
+ (kargs.key?(:message).! or kargs[:message] === @exceptions[alt].message)
330
+ @verifee = true
331
+ else
332
+ throw Alt, [:bug, @exceptions[alt], @output]
333
+ end
334
+ end
335
+ def throw? alt, verifier_args
336
+ tag = verifier_args[0][0]
337
+ kargs = verifier_args[1]
338
+ if @throws.key?(alt).!
339
+ throw Alt, [:bug, "Did not throw.", @output]
340
+ elsif @throws[alt].tag == tag and
341
+ (kargs.key?(:value).! or kargs[:value] == @throws[alt].value)
342
+ @verifee = true
343
+ else
344
+ throw Alt, [:bug, "Threw tag `#{@throws[alt].tag.inspect}`"\
345
+ " with value `#{@throws[alt].value.inspect}`.", @output]
346
+ end
347
+ end
348
+ def itself_all arg_suite
349
+ return nil unless arg_suite
350
+ args, kargs, pr = arg_suite
351
+ #! Cannot use symbol to proc because of refinement
352
+ [args.map{|e| e.itself}, kargs.dup.each{|k, e| kargs[k] = e.itself}, pr.itself]
353
+ rescue Exception => e
354
+ throw All, [:bad_test, e, @output]
355
+ ensure
356
+ @output = nil
357
+ end
358
+ def syntax_check_all sample, *argument_suites
359
+ old, $stderr = $stderr, StringIO.new
360
+ catch(All) do
361
+ #! The result of `tainted?` is insignificant. Its only pupose is to throw `:bad_test`
362
+ # when the object is a `Manager::Expr` instance that has illicit string.
363
+ sample.tainted?
364
+ argument_suites.each do
365
+ |argument_suite|
366
+ next unless argument_suite
367
+ args, kargs, pr = argument_suite
368
+ #! symbol to proc cannot be used becuase `tainted?` is a refinement for
369
+ # `Manager::Expr`.
370
+ args.each{|obj| obj.tainted?}
371
+ kargs.each_value{|obj| obj.tainted?}
372
+ end
373
+ nil
374
+ end
375
+ ensure
376
+ $stderr, @output = old, nil
377
+ end
378
+ def evaluate exp, f = nil, l = nil; in_terminal{@binding.eval(exp, f, l)} end
379
+ def silent_evaluate exp, f = nil, l = nil; silent{@binding.eval(exp, f, l)} end
380
+ StdoutOrig, StderrOrig = $stdout, $stderr
381
+ Terminal = StringIO.new
382
+ def in_terminal
383
+ return yield if Manager.config(:debug)
384
+ $stdout = $stderr = Terminal
385
+ yield
386
+ ensure
387
+ @output = (Terminal.string unless Terminal.length.zero?)
388
+ $stdout, $stderr = StdoutOrig, StderrOrig
389
+ Terminal.reopen
390
+ end
391
+ def silent
392
+ return yield if Manager.config(:debug)
393
+ stdout_old = $stdout.dup
394
+ stderr_old = $stderr.dup
395
+ $stderr.reopen(IO::NULL)
396
+ $stdout.reopen(IO::NULL)
397
+ yield
398
+ ensure
399
+ $stdout.flush
400
+ $stderr.flush
401
+ $stdout.reopen(stdout_old)
402
+ $stderr.reopen(stderr_old)
403
+ end
404
+ end