qed 2.5.1 → 2.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.rdoc +259 -0
- data/LICENSE.rdoc +35 -0
- data/README.rdoc +20 -28
- data/bin/qedoc +2 -2
- data/lib/{qedoc/command.rb → qed/cli/qedoc.rb} +9 -26
- data/lib/qed/demo.rb +16 -4
- data/lib/{qedoc → qed}/document.rb +82 -36
- data/lib/{qedoc → qed}/document/jquery.js +0 -0
- data/lib/{qedoc → qed}/document/markup.rb +0 -0
- data/lib/{qedoc → qed}/document/template.rhtml +3 -8
- data/lib/qed/evaluator.rb +1 -1
- data/lib/qed/parser.rb +7 -0
- data/lib/qed/reporter/abstract.rb +136 -18
- data/lib/qed/reporter/bullet.rb +29 -17
- data/lib/qed/reporter/dotprogress.rb +14 -11
- data/lib/qed/reporter/dtrace.rb +67 -0
- data/lib/qed/reporter/tapy.rb +224 -0
- data/lib/qed/reporter/verbatim.rb +2 -2
- data/lib/qed/scope.rb +46 -31
- data/lib/qed/session.rb +28 -7
- metadata +12 -33
- data/LICENSE +0 -204
@@ -13,57 +13,86 @@ module QED
|
|
13
13
|
|
14
14
|
DEFAULT_TITLE = "Demonstration"
|
15
15
|
DEFAULT_CSS = nil #"../assets/styles/spec.css"
|
16
|
-
DEFAULT_OUTPUT = "
|
17
|
-
DEFAULT_PATH = "
|
16
|
+
DEFAULT_OUTPUT = "qed.html"
|
17
|
+
DEFAULT_PATH = "qed"
|
18
18
|
|
19
19
|
attr_accessor :title
|
20
|
+
|
20
21
|
attr_accessor :css
|
21
|
-
|
22
|
+
|
22
23
|
attr_accessor :dryrun
|
24
|
+
|
23
25
|
attr_accessor :quiet
|
24
26
|
|
25
27
|
# Ouput file.
|
26
28
|
attr_accessor :output
|
27
29
|
|
30
|
+
# Either html or plain.
|
31
|
+
# Defaults to extension of output file.
|
32
|
+
attr_accessor :format
|
33
|
+
|
34
|
+
#
|
35
|
+
attr_reader :paths
|
36
|
+
|
37
|
+
#
|
38
|
+
def paths=(paths)
|
39
|
+
@paths = [paths].flatten
|
40
|
+
end
|
41
|
+
|
28
42
|
# New Spec Document object.
|
29
43
|
def initialize(options={})
|
30
44
|
options.each do |k,v|
|
31
45
|
__send__("#{k}=", v)
|
32
46
|
end
|
33
47
|
|
48
|
+
@paths ||= []
|
49
|
+
|
50
|
+
@output ||= DEFAULT_OUTPUT
|
34
51
|
@title ||= DEFAULT_TITLE
|
35
52
|
@css ||= DEFAULT_CSS
|
36
|
-
|
37
|
-
@
|
53
|
+
|
54
|
+
if File.directory?(@output)
|
55
|
+
@output = File.join(@output, 'qed.html')
|
56
|
+
end
|
57
|
+
|
58
|
+
@format ||= File.extname(@output).sub('.','')
|
38
59
|
|
39
60
|
if @paths.empty?
|
40
|
-
dir = Dir['{test/demos,demos,demo}'].first || DEFAULT_PATH
|
41
|
-
|
61
|
+
#dir = Dir['{test/demos,demos,demo}'].first || DEFAULT_PATH
|
62
|
+
#@paths = File.join(dir, '**', '*')
|
63
|
+
abort "No files to document."
|
42
64
|
end
|
43
65
|
end
|
44
66
|
|
45
67
|
# Demo files.
|
46
68
|
def demo_files
|
47
69
|
@demo_files ||= (
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
70
|
+
files = []
|
71
|
+
paths.each do |f|
|
72
|
+
if File.directory?(f)
|
73
|
+
files.concat Dir[File.join(f,'**','*')]
|
74
|
+
else
|
75
|
+
files.concat Dir[f]
|
76
|
+
end
|
53
77
|
end
|
54
|
-
|
78
|
+
files = files.reject{ |f| File.directory?(f) }
|
79
|
+
files = files.reject{ |f| File.extname(f) == '.rb' }
|
80
|
+
files = files.reject{ |f| /(fixtures|helpers)\// =~ f }
|
81
|
+
files.sort
|
55
82
|
)
|
56
83
|
end
|
57
84
|
|
58
85
|
# Supress output.
|
59
|
-
def quiet?
|
86
|
+
def quiet?
|
87
|
+
@quiet
|
88
|
+
end
|
60
89
|
|
61
90
|
# Generate specification document.
|
62
91
|
def generate
|
63
|
-
copy_support_files
|
92
|
+
#copy_support_files
|
64
93
|
|
65
|
-
|
66
|
-
files
|
94
|
+
out = ''
|
95
|
+
files = []
|
67
96
|
|
68
97
|
#paths.each do |path|
|
69
98
|
# files.concat(Dir.glob(path).select{ |f| File.file?(f) })
|
@@ -102,33 +131,49 @@ module QED
|
|
102
131
|
when '.rd', '.rdoc'
|
103
132
|
require_rdoc
|
104
133
|
require_qedoc
|
105
|
-
|
106
|
-
|
107
|
-
|
134
|
+
if html?
|
135
|
+
markup = Markup.new(txt)
|
136
|
+
text << markup.to_html
|
137
|
+
#text << markup.convert(iotext, formatter)
|
138
|
+
else
|
139
|
+
text << txt
|
140
|
+
end
|
108
141
|
when '.md', '.markdown'
|
109
142
|
require_rdiscount
|
110
|
-
|
111
|
-
|
143
|
+
if html?
|
144
|
+
markdown = RDiscount.new(txt)
|
145
|
+
text << markdown.to_html
|
146
|
+
else
|
147
|
+
text << txt
|
148
|
+
end
|
112
149
|
end
|
113
150
|
|
114
|
-
|
151
|
+
out << "#{text}\n"
|
115
152
|
end
|
116
153
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
154
|
+
if html?
|
155
|
+
temp = Template.new(template, output, title, css)
|
156
|
+
html = temp.parse_template
|
157
|
+
save(html)
|
158
|
+
else
|
159
|
+
save(out)
|
160
|
+
end
|
121
161
|
end
|
122
162
|
|
123
163
|
#
|
124
|
-
def
|
125
|
-
|
126
|
-
%w{jquery.js}.each do |fname|
|
127
|
-
file = File.join(File.dirname(__FILE__), 'document', fname)
|
128
|
-
FileUtils.cp(file, output)
|
129
|
-
end
|
164
|
+
def html?
|
165
|
+
format == 'html'
|
130
166
|
end
|
131
167
|
|
168
|
+
#
|
169
|
+
#def copy_support_files
|
170
|
+
# make_output_directory
|
171
|
+
# %w{jquery.js}.each do |fname|
|
172
|
+
# file = File.join(File.dirname(__FILE__), 'document', fname)
|
173
|
+
# FileUtils.cp(file, output)
|
174
|
+
# end
|
175
|
+
#end
|
176
|
+
|
132
177
|
# Load specification HTML template.
|
133
178
|
def template
|
134
179
|
@template ||= (
|
@@ -143,14 +188,15 @@ module QED
|
|
143
188
|
puts "\nwrite #{output}"
|
144
189
|
else
|
145
190
|
make_output_directory
|
146
|
-
File.open(output
|
191
|
+
File.open(output, 'wb') do |f|
|
147
192
|
f << text
|
148
193
|
end
|
149
194
|
end
|
150
195
|
end
|
151
196
|
|
152
197
|
def make_output_directory
|
153
|
-
|
198
|
+
dir = File.dirname(output)
|
199
|
+
FileUtils.mkdir_p(dir) unless File.directory?(dir)
|
154
200
|
end
|
155
201
|
|
156
202
|
private
|
@@ -173,7 +219,7 @@ module QED
|
|
173
219
|
#
|
174
220
|
def require_qedoc
|
175
221
|
@require_qedoc ||= (
|
176
|
-
require '
|
222
|
+
require 'qed/document/markup'
|
177
223
|
true
|
178
224
|
)
|
179
225
|
end
|
File without changes
|
File without changes
|
@@ -103,17 +103,12 @@
|
|
103
103
|
.title { font-size: 2em; }
|
104
104
|
</style>
|
105
105
|
|
106
|
-
<!-- TODO: only include if these files exists -->
|
107
|
-
<link href="../assets/styles/spec.css" type="text/css" rel="stylesheet">
|
108
|
-
<!-- spec.css might be a problem with clobber -->
|
109
|
-
<link href="spec.css" type="text/css" rel="stylesheet">
|
110
|
-
|
111
106
|
<% if css %>
|
112
107
|
<link rel="stylesheet" href="<%= css %>" type="text/css">
|
113
108
|
<% end %>
|
114
109
|
|
115
110
|
<!-- JQuery is needed -->
|
116
|
-
<script src="jquery.js" type="text/javascript" language="javascript"></script>
|
111
|
+
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.6.1/jquery.min.js" type="text/javascript" language="javascript"></script>
|
117
112
|
|
118
113
|
</head>
|
119
114
|
|
@@ -122,7 +117,7 @@
|
|
122
117
|
<!-- Side Table of Contents -->
|
123
118
|
<div id="sidebar" style="position: fixed; top: 10; right: 10; background: white;">
|
124
119
|
<a href="javascript: toc_toggle();">
|
125
|
-
<img src="
|
120
|
+
<img src="http://www.cdnjs.com/images/poweredbycloudflare.png" style="border: none;" alt="TOC" align="right"/>
|
126
121
|
</a>
|
127
122
|
|
128
123
|
<div id="toc_side" class="toc">
|
@@ -131,7 +126,7 @@
|
|
131
126
|
|
132
127
|
<div id="container">
|
133
128
|
<div id="header">
|
134
|
-
<img src="
|
129
|
+
<img src="http://www.cdnjs.com/images/poweredbycloudflare.png" align="left" style="padding-right: 10px;" alt=""/>
|
135
130
|
|
136
131
|
<div class="title"><%= title %></div>
|
137
132
|
|
data/lib/qed/evaluator.rb
CHANGED
data/lib/qed/parser.rb
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
module QED
|
2
2
|
|
3
|
+
#
|
4
|
+
def self.all_steps
|
5
|
+
@all_steps ||= []
|
6
|
+
end
|
7
|
+
|
3
8
|
# The parser breaks down a demonstandum into
|
4
9
|
# structured object to passed thru the script
|
5
10
|
# evaluator.
|
@@ -198,6 +203,8 @@ module QED
|
|
198
203
|
|
199
204
|
#
|
200
205
|
def initialize(file)
|
206
|
+
QED.all_steps << self
|
207
|
+
|
201
208
|
@file = file
|
202
209
|
@raw = []
|
203
210
|
@type = :description
|
@@ -2,16 +2,25 @@ module QED
|
|
2
2
|
module Reporter
|
3
3
|
|
4
4
|
require 'facets/string'
|
5
|
-
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'ansi/core'
|
8
|
+
rescue LoadError
|
9
|
+
require 'ansi/code'
|
10
|
+
end
|
6
11
|
|
7
12
|
# = Reporter Absract Base Class
|
8
13
|
#
|
9
14
|
# Serves as the base class for all other output formats.
|
10
15
|
class Abstract
|
11
16
|
|
17
|
+
attr :session
|
18
|
+
|
12
19
|
attr :io
|
20
|
+
|
13
21
|
attr :record
|
14
22
|
|
23
|
+
# TODO: pass session into initialize
|
15
24
|
def initialize(options={})
|
16
25
|
@io = options[:io] || STDOUT
|
17
26
|
@trace = options[:trace]
|
@@ -110,6 +119,7 @@ module Reporter
|
|
110
119
|
|
111
120
|
# At the start of a session, before running any demonstrations.
|
112
121
|
def before_session(session)
|
122
|
+
@session = session
|
113
123
|
@start_time = Time.now
|
114
124
|
end
|
115
125
|
|
@@ -248,12 +258,24 @@ module Reporter
|
|
248
258
|
end
|
249
259
|
|
250
260
|
#
|
251
|
-
|
252
|
-
|
261
|
+
INTERNALS = /(lib|bin)[\\\/](qed|ae)/
|
262
|
+
|
263
|
+
#
|
264
|
+
def sane_backtrace(exception)
|
265
|
+
if trace_count
|
266
|
+
clean_backtrace(*exception.backtrace[0, trace_count])
|
267
|
+
else
|
268
|
+
clean_backtrace(*exception.backtrace)
|
269
|
+
end
|
253
270
|
end
|
254
271
|
|
255
272
|
#
|
256
|
-
|
273
|
+
def clean_backtrace(*btrace)
|
274
|
+
stack = btrace.reject{ |bt| bt =~ INTERNALS } unless $DEBUG
|
275
|
+
stack.map do |bt|
|
276
|
+
bt.chomp(":in \`__binding__'")
|
277
|
+
end
|
278
|
+
end
|
257
279
|
|
258
280
|
=begin
|
259
281
|
# Clean the backtrace of any reference to ko/ paths and code.
|
@@ -269,44 +291,140 @@ module Reporter
|
|
269
291
|
end
|
270
292
|
=end
|
271
293
|
|
294
|
+
# Produce a pretty code snippet given an exception.
|
272
295
|
#
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
296
|
+
# @param exception [Exception, String]
|
297
|
+
# An exception or backtrace.
|
298
|
+
#
|
299
|
+
# @param radius [Integer]
|
300
|
+
# The number of surrounding lines to show.
|
301
|
+
#
|
302
|
+
# @return [String] pretty code snippet
|
303
|
+
def code_snippet(exception, radius=2)
|
304
|
+
radius = radius.to_i
|
305
|
+
|
306
|
+
file, lineno = file_and_line(exception)
|
277
307
|
|
278
|
-
|
308
|
+
return nil if file.empty?
|
309
|
+
|
310
|
+
source = source(file)
|
279
311
|
|
280
|
-
|
281
|
-
|
282
|
-
[source_line + radius, source.length].min
|
312
|
+
region = [lineno - radius, 1].max ..
|
313
|
+
[lineno + radius, source.length].min
|
283
314
|
|
284
315
|
# ensure proper alignment by zero-padding line numbers
|
285
316
|
format = " %2s %0#{region.last.to_s.length}d %s"
|
286
317
|
|
287
318
|
pretty = region.map do |n|
|
288
|
-
format % [('=>' if n ==
|
319
|
+
format % [('=>' if n == lineno), n, source[n-1].chomp]
|
289
320
|
end #.unshift "[#{region.inspect}] in #{source_file}"
|
290
321
|
|
291
322
|
pretty
|
292
323
|
end
|
293
324
|
|
325
|
+
# Return a structure code snippet in an array of lineno=>line
|
326
|
+
# hash elements.
|
327
|
+
#
|
328
|
+
# @param exception [Exception, String]
|
329
|
+
# An exception or backtrace.
|
330
|
+
#
|
331
|
+
# @param radius [Integer]
|
332
|
+
# The number of surrounding lines to show.
|
333
|
+
#
|
334
|
+
# @return [Hash] structured code snippet
|
335
|
+
def structured_code_snippet(exception, radius=2)
|
336
|
+
radius = radius.to_i
|
337
|
+
|
338
|
+
file, lineno = file_and_line(exception)
|
339
|
+
|
340
|
+
return {} if file.empty?
|
341
|
+
|
342
|
+
source = source(file)
|
343
|
+
|
344
|
+
region = [lineno - radius, 1].max ..
|
345
|
+
[lineno + radius, source.length].min
|
346
|
+
|
347
|
+
region.map do |n|
|
348
|
+
{n => source[n-1].chomp}
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
# Cache the source code of a file.
|
353
|
+
#
|
354
|
+
# @param file [String] full pathname to file
|
294
355
|
#
|
356
|
+
# @return [String] source code
|
295
357
|
def source(file)
|
296
358
|
@source[file] ||= (
|
297
359
|
File.readlines(file)
|
298
360
|
)
|
299
361
|
end
|
300
362
|
|
363
|
+
# @param exception [Exception,Array,String]
|
364
|
+
# An exception or backtrace.
|
365
|
+
#
|
366
|
+
#--
|
301
367
|
# TODO: Show more of the file name than just the basename.
|
368
|
+
#++
|
302
369
|
def file_and_line(exception)
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
370
|
+
backtrace = case exception
|
371
|
+
when Exception
|
372
|
+
exception.backtrace.reject{ |bt| bt =~ INTERNALS }.first
|
373
|
+
when Array
|
374
|
+
exception.first
|
375
|
+
else
|
376
|
+
exception
|
377
|
+
end
|
378
|
+
|
379
|
+
backtrace =~ /(.+?):(\d+(?=:|\z))/ or return ""
|
380
|
+
|
381
|
+
file, lineno = $1, $2.to_i
|
382
|
+
|
383
|
+
return file, lineno
|
384
|
+
|
385
|
+
#i = backtrace.rindex(':in')
|
386
|
+
#line = i ? line[0...i] : line
|
387
|
+
#relative_file(line)
|
308
388
|
end
|
309
389
|
|
390
|
+
# Same as file_and_line, exception return file path is relative.
|
391
|
+
def file_line(exception)
|
392
|
+
file, lineno = file_and_line(exception)
|
393
|
+
return relative_file(file), lineno
|
394
|
+
end
|
395
|
+
|
396
|
+
# Default trace count. This is the number of backtrace lines that
|
397
|
+
# will be provided on errors and failed assertions, unless otherwise
|
398
|
+
# overridden with ENV['trace'].
|
399
|
+
DEFAULT_TRACE_COUNT = 3
|
400
|
+
|
401
|
+
# Looks at ENV['trace'] to determine how much trace output to provide.
|
402
|
+
# If it is not set, or set to`false` or `off`, then the default trace count
|
403
|
+
# is used. If set to `0`, `true`, 'on' or 'all' then aa complete trace dump
|
404
|
+
# is provided. Otherwise the value is converted to an integer and that many
|
405
|
+
# line of trace is given.
|
406
|
+
#
|
407
|
+
# @return [Integer, nil] trace count
|
408
|
+
def trace_count
|
409
|
+
cnt = ENV['trace']
|
410
|
+
case cnt
|
411
|
+
when nil, 'false', 'off'
|
412
|
+
DEFAULT_TRACE_COUNT
|
413
|
+
when 0, 'all', 'true', 'on'
|
414
|
+
nil
|
415
|
+
else
|
416
|
+
Integer(cnt)
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
#
|
421
|
+
def relative_file(file)
|
422
|
+
pwd = Dir.pwd
|
423
|
+
idx = (0...pwd.size).find do |i|
|
424
|
+
file[i,1] != pwd[i,1]
|
425
|
+
end
|
426
|
+
file[(idx || 0)..-1]
|
427
|
+
end
|
310
428
|
end
|
311
429
|
|
312
430
|
end
|