manager 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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