qed 1.2 → 1.3
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.
- data/README.rdoc +2 -2
- data/Syckfile +70 -0
- data/demo/01_spec.qed +7 -7
- data/demo/02_err.qed +18 -0
- data/demo/03_site.qed +12 -0
- data/demo/helpers/sample.rb +4 -0
- data/doc/qedoc/index.html +31 -10
- data/lib/qed/command.rb +167 -61
- data/lib/qed/config.rb +25 -0
- data/lib/qed/document.rb +1 -1
- data/lib/qed/document/template.rhtml +1 -1
- data/lib/qed/reporter/ditto.rb +72 -0
- data/lib/qed/reporter/dotprogress.rb +11 -2
- data/lib/qed/runner.rb +69 -19
- data/lib/qed/script.rb +171 -13
- data/lib/qed/script1.rb +495 -0
- data/meta/description +2 -2
- data/meta/summary +1 -1
- data/meta/version +1 -1
- metadata +15 -13
- data/MANIFEST +0 -37
- data/demo/helper.rb +0 -2
data/lib/qed/config.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module QED
|
2
|
+
|
3
|
+
class Config
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@local = ['qed', 'demos', 'test/demos']
|
7
|
+
|
8
|
+
if file = File.glob('{.,}config/qed.{yml,yaml}')
|
9
|
+
YAML.load(File.new(file)).each do |k,v|
|
10
|
+
__send__("#{k}=", v)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_accessor :local
|
16
|
+
|
17
|
+
# How ot identify a header?
|
18
|
+
#attr_accessor :header
|
19
|
+
|
20
|
+
# How ot identify a footer?
|
21
|
+
#attr_accessor :footer
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/lib/qed/document.rb
CHANGED
@@ -19,7 +19,7 @@
|
|
19
19
|
h1 { border-bottom: 2px solid silver; }
|
20
20
|
h2 { border-bottom: 2px solid silver; padding-top: 0.5em; }
|
21
21
|
|
22
|
-
hr {
|
22
|
+
hr { color: #ccc; margin-top: 1.6em; }
|
23
23
|
|
24
24
|
p { color: #222; text-align: justify; margin-top: 0.5em; margin-bottom: 0.5em; line-height: 1.4em; }
|
25
25
|
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module QED
|
2
|
+
module Reporter #:nodoc:
|
3
|
+
|
4
|
+
require 'qed/reporter/base'
|
5
|
+
|
6
|
+
# = DotProgress Reporter
|
7
|
+
#
|
8
|
+
class Ditto < BaseClass
|
9
|
+
|
10
|
+
#
|
11
|
+
def report_intro
|
12
|
+
#@start_time = Time.now
|
13
|
+
#io.puts "Started"
|
14
|
+
end
|
15
|
+
|
16
|
+
#
|
17
|
+
def report_step(step)
|
18
|
+
super
|
19
|
+
#if step.code
|
20
|
+
io.print "."
|
21
|
+
#str = "(%s) %s" % [count.join('.'), str.tab(6).strip]
|
22
|
+
#puts "* #{step.text.tab(2).strip}"
|
23
|
+
#puts "\n#{step.code}\n" if $VERBOSE
|
24
|
+
#else
|
25
|
+
#puts "\n#{step.text}"
|
26
|
+
#end
|
27
|
+
end
|
28
|
+
|
29
|
+
#def report(str)
|
30
|
+
# count[-1] += 1 unless count.empty?
|
31
|
+
# str = str.chomp('.') + '.'
|
32
|
+
# str = count.join('.') + ' ' + str
|
33
|
+
# puts str.strip
|
34
|
+
#end
|
35
|
+
|
36
|
+
def report_summary
|
37
|
+
io.puts "\nFinished in #{Time.now - @start_time} seconds.\n\n"
|
38
|
+
|
39
|
+
@error.each do |step, exception|
|
40
|
+
backtrace = clean_backtrace(exception.backtrace[0])
|
41
|
+
io.puts ANSICode.red("***** ERROR *****")
|
42
|
+
io.puts "#{exception}"
|
43
|
+
io.puts ":#{backtrace}:"
|
44
|
+
#io.puts ":#{exception.backtrace[1]}:"
|
45
|
+
#io.puts exception.backtrace[1..-1] if $VERBOSE
|
46
|
+
io.puts
|
47
|
+
end
|
48
|
+
|
49
|
+
@fail.each do |step, assertion|
|
50
|
+
backtrace = clean_backtrace(assertion.backtrace[0])
|
51
|
+
io.puts ANSICode.red("***** FAIL *****")
|
52
|
+
io.puts ANSICode.bold("#{assertion}")
|
53
|
+
io.puts ":#{backtrace}:"
|
54
|
+
#io.puts assertion if $VERBOSE
|
55
|
+
io.puts
|
56
|
+
end
|
57
|
+
|
58
|
+
io.puts "%s demos, %s steps, %s failures, %s errors" % [@demos, @steps, @fail.size, @error.size] #, @pass.size ]
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
#
|
64
|
+
def clean_backtrace(btrace)
|
65
|
+
btrace.chomp(":in `_binding'")
|
66
|
+
end
|
67
|
+
|
68
|
+
end#class DotProgress
|
69
|
+
|
70
|
+
end#module Reporter
|
71
|
+
end#module QED
|
72
|
+
|
@@ -37,18 +37,20 @@ module Reporter #:nodoc:
|
|
37
37
|
io.puts "\nFinished in #{Time.now - @start_time} seconds.\n\n"
|
38
38
|
|
39
39
|
@error.each do |step, exception|
|
40
|
+
backtrace = clean_backtrace(exception.backtrace[0])
|
40
41
|
io.puts ANSICode.red("***** ERROR *****")
|
41
42
|
io.puts "#{exception}"
|
42
|
-
io.puts ":#{
|
43
|
+
io.puts ":#{backtrace}:"
|
43
44
|
#io.puts ":#{exception.backtrace[1]}:"
|
44
45
|
#io.puts exception.backtrace[1..-1] if $VERBOSE
|
45
46
|
io.puts
|
46
47
|
end
|
47
48
|
|
48
49
|
@fail.each do |step, assertion|
|
50
|
+
backtrace = clean_backtrace(assertion.backtrace[0])
|
49
51
|
io.puts ANSICode.red("***** FAIL *****")
|
50
52
|
io.puts ANSICode.bold("#{assertion}")
|
51
|
-
io.puts ":#{
|
53
|
+
io.puts ":#{backtrace}:"
|
52
54
|
#io.puts assertion if $VERBOSE
|
53
55
|
io.puts
|
54
56
|
end
|
@@ -56,6 +58,13 @@ module Reporter #:nodoc:
|
|
56
58
|
io.puts "%s demos, %s steps, %s failures, %s errors" % [@demos, @steps, @fail.size, @error.size] #, @pass.size ]
|
57
59
|
end
|
58
60
|
|
61
|
+
private
|
62
|
+
|
63
|
+
#
|
64
|
+
def clean_backtrace(btrace)
|
65
|
+
btrace.chomp(":in `_binding'")
|
66
|
+
end
|
67
|
+
|
59
68
|
end#class DotProgress
|
60
69
|
|
61
70
|
end#module Reporter
|
data/lib/qed/runner.rb
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
#require 'quarry/behave'
|
2
|
-
#require 'quarry/runner/context'
|
3
|
-
|
4
1
|
module QED
|
5
2
|
|
6
3
|
require 'qed/script'
|
@@ -16,7 +13,7 @@ module QED
|
|
16
13
|
#
|
17
14
|
class Runner
|
18
15
|
|
19
|
-
# QED::
|
16
|
+
# QED::Runner.configure do
|
20
17
|
# def setup(spec)
|
21
18
|
# ...
|
22
19
|
# end
|
@@ -35,8 +32,26 @@ module QED
|
|
35
32
|
# end
|
36
33
|
#end
|
37
34
|
|
35
|
+
def self.configure(&block)
|
36
|
+
class_eval(&block)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.start(&block)
|
40
|
+
define_method(:start, &block)
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.finish(&block)
|
44
|
+
define_method(:finish, &block)
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
38
48
|
attr :specs
|
39
|
-
|
49
|
+
|
50
|
+
#
|
51
|
+
attr_accessor :format
|
52
|
+
|
53
|
+
#
|
54
|
+
attr_accessor :trace
|
40
55
|
|
41
56
|
#attr :context
|
42
57
|
#attr :count
|
@@ -45,30 +60,59 @@ module QED
|
|
45
60
|
#attr_accessor :after
|
46
61
|
|
47
62
|
# New Specification
|
48
|
-
def initialize(specs,
|
49
|
-
@specs
|
50
|
-
|
63
|
+
def initialize(specs, options={})
|
64
|
+
@specs = [specs].flatten
|
65
|
+
|
66
|
+
@format = :dotprogress
|
67
|
+
@trace = false
|
68
|
+
|
69
|
+
options.each do |k,v|
|
70
|
+
__send__("#{k}=", v) if v
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Instance of selected Reporter subclass.
|
75
|
+
def reporter
|
76
|
+
case format
|
77
|
+
when :dotprogress
|
78
|
+
Reporter::DotProgress.new(reporter_options)
|
79
|
+
when :verbatim
|
80
|
+
Reporter::Verbatim.new(reporter_options)
|
81
|
+
when :summary
|
82
|
+
Reporter::Summary.new(reporter_options)
|
83
|
+
when :script #ditto ?
|
84
|
+
# TODO
|
85
|
+
else
|
86
|
+
Reporter::DotProgress.new(reporter_options)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Report options.
|
91
|
+
#--
|
92
|
+
# TODO: rename :verbose to :trace
|
93
|
+
#++
|
94
|
+
def reporter_options
|
95
|
+
{ :verbose => @trace }
|
96
|
+
end
|
97
|
+
|
98
|
+
#
|
99
|
+
def output
|
100
|
+
@output ||= reporter
|
51
101
|
end
|
52
102
|
|
53
103
|
#
|
54
104
|
def check
|
105
|
+
start
|
55
106
|
output.report_intro
|
56
|
-
# loop through each specification and run it
|
57
|
-
|
58
|
-
# create a run context for the spec
|
59
|
-
#@context = Context.new(spec)
|
60
|
-
# run the specification
|
61
|
-
run_spec(spec)
|
107
|
+
specs.each do |spec| # loop through each specification and run it
|
108
|
+
run_spec(spec) # run the specification
|
62
109
|
end
|
63
110
|
output.report_summary
|
111
|
+
finish
|
64
112
|
end
|
65
113
|
|
66
114
|
# Run a specification.
|
67
|
-
#
|
68
115
|
def run_spec(spec)
|
69
|
-
#report(spec.description)
|
70
|
-
|
71
|
-
#script = Script.load(spec, output)
|
72
116
|
script = Script.new(spec, output)
|
73
117
|
|
74
118
|
# pretty sure this is the thing to do
|
@@ -142,7 +186,13 @@ module QED
|
|
142
186
|
end
|
143
187
|
=end
|
144
188
|
|
189
|
+
def start
|
190
|
+
end
|
191
|
+
|
192
|
+
def finish
|
193
|
+
end
|
194
|
+
|
145
195
|
end#class Runner
|
146
196
|
|
147
|
-
end#module
|
197
|
+
end#module QED
|
148
198
|
|
data/lib/qed/script.rb
CHANGED
@@ -11,6 +11,18 @@ module QED
|
|
11
11
|
#Assertion = AE::Assertion
|
12
12
|
Expectation = Assertor
|
13
13
|
|
14
|
+
# Global Before
|
15
|
+
def self.Before(&procedure)
|
16
|
+
@_before = procedure if procedure
|
17
|
+
@_before
|
18
|
+
end
|
19
|
+
|
20
|
+
# Global After
|
21
|
+
def self.After(&procedure)
|
22
|
+
@_after = procedure if procedure
|
23
|
+
@_after
|
24
|
+
end
|
25
|
+
|
14
26
|
# New Specification
|
15
27
|
#def initialize(specs, output=nil)
|
16
28
|
# @specs = [specs].flatten
|
@@ -24,19 +36,20 @@ module QED
|
|
24
36
|
# new(File.read(file), output)
|
25
37
|
#end
|
26
38
|
|
39
|
+
# Path of demonstration script.
|
27
40
|
attr :file
|
41
|
+
|
42
|
+
# Reporter object to issue output calls.
|
28
43
|
attr :output
|
29
44
|
|
45
|
+
# List of helper scripts to require.
|
46
|
+
attr :helpers
|
47
|
+
|
30
48
|
# New Script
|
31
49
|
def initialize(file, output=nil)
|
32
|
-
@file
|
33
|
-
@output
|
34
|
-
|
35
|
-
source = File.read(file)
|
36
|
-
index = source.rindex('---') || source.size
|
37
|
-
|
38
|
-
@source = source[0...index]
|
39
|
-
@helper = source[index+3...-1].to_s.strip
|
50
|
+
@file = file
|
51
|
+
@output = output || Reporter::Verbatim.new #(self)
|
52
|
+
parse_document(file)
|
40
53
|
end
|
41
54
|
|
42
55
|
# File basename less extension.
|
@@ -44,14 +57,23 @@ module QED
|
|
44
57
|
@name ||= File.basename(file).chomp(File.extname(file))
|
45
58
|
end
|
46
59
|
|
60
|
+
#
|
61
|
+
def directory
|
62
|
+
@directory ||= Dir.pwd #File.dirname(File.expand_path(file))
|
63
|
+
end
|
64
|
+
|
47
65
|
#def convert
|
48
66
|
# @source.gsub(/^\w/, '# \1')
|
49
67
|
#end
|
50
68
|
|
51
69
|
# Run the script.
|
52
70
|
def run
|
53
|
-
|
54
|
-
|
71
|
+
@lineno = 0
|
72
|
+
|
73
|
+
$LOAD_PATH.unshift(directory)
|
74
|
+
|
75
|
+
import_helpers
|
76
|
+
|
55
77
|
steps.each do |step|
|
56
78
|
output.report_step(step)
|
57
79
|
case step
|
@@ -71,17 +93,31 @@ module QED
|
|
71
93
|
run_step(step)
|
72
94
|
#end
|
73
95
|
end
|
96
|
+
@lineno += step.count("\n")
|
74
97
|
end
|
98
|
+
|
99
|
+
$LOAD_PATH.index(directory){ |i| $LOAD_PATH.delete_at(i) }
|
75
100
|
end
|
76
101
|
|
77
|
-
|
102
|
+
#--
|
103
|
+
# NOTE: The Around code is in place should we decide
|
104
|
+
# to use it. I'm not sure yet if it's really neccessary,
|
105
|
+
# since we have Before and After.
|
106
|
+
#++
|
78
107
|
def run_step(step=nil, &blk)
|
108
|
+
QED.Before.call if QED.Before
|
79
109
|
context.Before.call if context.Before
|
80
110
|
begin
|
81
|
-
if blk
|
111
|
+
if blk # TODO: Is this still used?
|
82
112
|
blk.call #eval(step, context._binding)
|
83
113
|
else
|
84
|
-
|
114
|
+
#if context.Around
|
115
|
+
# context.Around.call do
|
116
|
+
# eval(step, context._binding, @file, @lineno+1)
|
117
|
+
# end
|
118
|
+
#else
|
119
|
+
eval(step, context._binding, @file, @lineno+1)
|
120
|
+
#end
|
85
121
|
end
|
86
122
|
output.report_pass(step) if step
|
87
123
|
rescue Assertion => error
|
@@ -90,6 +126,7 @@ module QED
|
|
90
126
|
output.report_error(step, error)
|
91
127
|
ensure
|
92
128
|
context.After.call if context.After
|
129
|
+
QED.After.call if QED.After
|
93
130
|
end
|
94
131
|
end
|
95
132
|
|
@@ -182,6 +219,88 @@ module QED
|
|
182
219
|
@context ||= Context.new(self)
|
183
220
|
end
|
184
221
|
|
222
|
+
#
|
223
|
+
def import(helper)
|
224
|
+
code = File.read(helper)
|
225
|
+
eval(code, context._binding)
|
226
|
+
end
|
227
|
+
|
228
|
+
private
|
229
|
+
|
230
|
+
# Splits the document into main source and footer
|
231
|
+
# and extract the helper document references from
|
232
|
+
# the footer.
|
233
|
+
#
|
234
|
+
def parse_document(file)
|
235
|
+
text = File.read(file)
|
236
|
+
index = text.rindex('---') || text.size
|
237
|
+
source = text[0...index]
|
238
|
+
footer = text[index+3..-1].to_s.strip
|
239
|
+
helpers = parse_helpers(footer)
|
240
|
+
@source = source
|
241
|
+
@helpers = helpers
|
242
|
+
end
|
243
|
+
|
244
|
+
#
|
245
|
+
def parse_helpers(footer)
|
246
|
+
helpers = []
|
247
|
+
footer.split("\n").each do |line|
|
248
|
+
next if line.strip == ''
|
249
|
+
case line
|
250
|
+
when /\[(.*?)\]\((.*?)\)/
|
251
|
+
helpers << $2
|
252
|
+
when /(.*?)\[(.*?)\]/
|
253
|
+
helpers << $2
|
254
|
+
end
|
255
|
+
end
|
256
|
+
helpers
|
257
|
+
end
|
258
|
+
|
259
|
+
=begin
|
260
|
+
# Looks for a master +helper.rb+ file and a special
|
261
|
+
# helpers/<name>.rb file. Both of these, when found, will
|
262
|
+
# be imported when this script is run.
|
263
|
+
|
264
|
+
def collect_helpers
|
265
|
+
dir = File.dirname(file)
|
266
|
+
list = []
|
267
|
+
list << "helper.rb" if File.exist?(File.join(dir, "helper.rb"))
|
268
|
+
list << "helpers/#{name}.rb" if File.exist?(File.join(dir, "helpers/#{name}.rb"))
|
269
|
+
list
|
270
|
+
end
|
271
|
+
=end
|
272
|
+
|
273
|
+
# TODO: How to determine where to find the env.rb file?
|
274
|
+
#def require_environment
|
275
|
+
# dir = File.dirname(file)
|
276
|
+
# dir = File.expand_path(dir)
|
277
|
+
# env = loop do
|
278
|
+
# file = File.join(dir, 'env.rb')
|
279
|
+
# break file if File.exist?(file)
|
280
|
+
# break nil if ['demo', 'demos', 'doc', 'docs', 'test', 'tests'].include? File.basename(dir)
|
281
|
+
# break nil if dir == Dir.pwd
|
282
|
+
# dir = File.dirname(dir)
|
283
|
+
# end
|
284
|
+
# require(env) if env
|
285
|
+
#end
|
286
|
+
|
287
|
+
# FIXME: where to stop looking for helpers.
|
288
|
+
def import_helpers
|
289
|
+
hlp = []
|
290
|
+
dir = Dir.pwd #File.expand_path(dir)
|
291
|
+
env = loop do
|
292
|
+
helpers.each do |helper|
|
293
|
+
file = File.join(dir, 'helpers', helper)
|
294
|
+
if File.exist?(file)
|
295
|
+
hlp << file
|
296
|
+
end
|
297
|
+
end
|
298
|
+
break if ['qed', 'demo', 'demos', 'doc', 'docs', 'test', 'tests'].include? File.basename(dir)
|
299
|
+
dir = File.dirname(dir)
|
300
|
+
end
|
301
|
+
hlp.each{ |helper| import(helper) }
|
302
|
+
end
|
303
|
+
|
185
304
|
end
|
186
305
|
|
187
306
|
#
|
@@ -211,6 +330,27 @@ module QED
|
|
211
330
|
@_after
|
212
331
|
end
|
213
332
|
|
333
|
+
# Run code around each step.
|
334
|
+
#
|
335
|
+
# Around procedures must take a block, in which the step is run.
|
336
|
+
#
|
337
|
+
# Around do |&step|
|
338
|
+
# ... do something here ...
|
339
|
+
# step.call
|
340
|
+
# ... do stiff stuff ...
|
341
|
+
# end
|
342
|
+
#
|
343
|
+
#def Around(&procedure)
|
344
|
+
# @_around = procedure if procedure
|
345
|
+
# @_around
|
346
|
+
#end
|
347
|
+
|
348
|
+
# Comment match procedure.
|
349
|
+
#
|
350
|
+
# This is useful for creating unobtrusive setup and (albeit more
|
351
|
+
# limited) teardown code. A pattern is matched against each comment
|
352
|
+
# as it is processed. If there is match, the code procedure is
|
353
|
+
# triggered, passing in any mathcing expression arguments.
|
214
354
|
#
|
215
355
|
def When(pattern=nil, &procedure)
|
216
356
|
return @_when unless procedure
|
@@ -221,6 +361,24 @@ module QED
|
|
221
361
|
@_when << [pattern, procedure]
|
222
362
|
end
|
223
363
|
|
364
|
+
# Code match-and-transform procedure.
|
365
|
+
#
|
366
|
+
# This is useful to transform human readable code examples
|
367
|
+
# into proper exectuable code. For example, say you want to
|
368
|
+
# run shell code, but want to make if look like typical
|
369
|
+
# shelle examples:
|
370
|
+
#
|
371
|
+
# $ cp fixture/a.rb fixture/b.rb
|
372
|
+
#
|
373
|
+
# You can use a transform to convert lines starting with '$'
|
374
|
+
# into executable Ruby using #system.
|
375
|
+
#
|
376
|
+
# system('cp fixture/a.rb fixture/b.rb')
|
377
|
+
#
|
378
|
+
#def Transform(pattern=nil, &procedure)
|
379
|
+
#
|
380
|
+
#end
|
381
|
+
|
224
382
|
# Table-based steps.
|
225
383
|
def Table(file=nil, &blk)
|
226
384
|
file = file || @_tables.last
|