qed 1.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.
- data/HISTORY +15 -0
- data/LICENSE +344 -0
- data/MANIFEST +56 -0
- data/README.rdoc +97 -0
- data/bin/qed +150 -0
- data/bin/qedoc +52 -0
- data/demo/01_spec.qed +143 -0
- data/demo/01_spec.yaml +4 -0
- data/demo/qed_helper.rb +1 -0
- data/doc/qedoc/index.html +355 -0
- data/doc/qedoc/jquery.js +19 -0
- data/lib/qed.rb +5 -0
- data/lib/qed/assertion.rb +23 -0
- data/lib/qed/document.rb +188 -0
- data/lib/qed/document/jquery.js +19 -0
- data/lib/qed/document/markup.rb +53 -0
- data/lib/qed/document/template.rhtml +190 -0
- data/lib/qed/doubles/mock.rb +94 -0
- data/lib/qed/doubles/spy.rb +191 -0
- data/lib/qed/doubles/stub.rb +94 -0
- data/lib/qed/expectation.rb +60 -0
- data/lib/qed/grammar/assert.rb +104 -0
- data/lib/qed/grammar/expect.rb +121 -0
- data/lib/qed/grammar/legacy/assert.rb +291 -0
- data/lib/qed/grammar/should.rb +52 -0
- data/lib/qed/reporter/base.rb +101 -0
- data/lib/qed/reporter/dotprogress.rb +63 -0
- data/lib/qed/reporter/summary.rb +67 -0
- data/lib/qed/reporter/verbatim.rb +90 -0
- data/lib/qed/runner.rb +148 -0
- data/lib/qed/script.rb +179 -0
- data/lib/qed/utilities/extract.rb +137 -0
- data/lib/qed/utilities/monitor.rb +23 -0
- data/meta/authors +1 -0
- data/meta/created +1 -0
- data/meta/description +2 -0
- data/meta/homepage +1 -0
- data/meta/package +1 -0
- data/meta/project +1 -0
- data/meta/requires +1 -0
- data/meta/ruby +2 -0
- data/meta/summary +1 -0
- data/meta/title +1 -0
- data/meta/version +1 -0
- metadata +115 -0
data/bin/qed
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'qed'
|
4
|
+
require 'getoptlong'
|
5
|
+
|
6
|
+
module QED
|
7
|
+
|
8
|
+
# = QED Commandline Tool
|
9
|
+
#
|
10
|
+
class Command
|
11
|
+
def self.execute
|
12
|
+
new.execute
|
13
|
+
end
|
14
|
+
|
15
|
+
attr :reporter
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@reporter = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def opts
|
22
|
+
@opts ||= GetoptLong.new(
|
23
|
+
[ '--version', GetoptLong::NO_ARGUMENT ],
|
24
|
+
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
|
25
|
+
[ '--debug', '-D', GetoptLong::NO_ARGUMENT ],
|
26
|
+
[ '--verbose', '-V', GetoptLong::NO_ARGUMENT ],
|
27
|
+
[ '--verbatim', '-v', GetoptLong::NO_ARGUMENT ],
|
28
|
+
[ '--summary', '-s', GetoptLong::NO_ARGUMENT ],
|
29
|
+
[ '--script', GetoptLong::NO_ARGUMENT ],
|
30
|
+
[ '--loadpath', '-I', GetoptLong::REQUIRED_ARGUMENT ]
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
def parse_options
|
36
|
+
opts.each do |opt, arg|
|
37
|
+
case opt
|
38
|
+
when '--help'
|
39
|
+
puts HELP
|
40
|
+
exit
|
41
|
+
when '--debug'
|
42
|
+
$RESPECT_DEBUG = true
|
43
|
+
when '--verbose'
|
44
|
+
$VERBOSE = true
|
45
|
+
when '--verbatim'
|
46
|
+
@reporter = :verbatim
|
47
|
+
when '--summary'
|
48
|
+
@reporter = :summary
|
49
|
+
when '--script'
|
50
|
+
@reporter = :script # psuedo-reporter
|
51
|
+
when '--loadpath'
|
52
|
+
libs = arg.split(/[:;]/).map{ |dir| File.expand_path(dir) }
|
53
|
+
libs.each{|dir| $LOAD_PATH.unshift(dir)}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
#def load_rc
|
60
|
+
# if rcfile = Dir['.config/qed{,rc}{,.rb}'].first
|
61
|
+
# load(rcfile)
|
62
|
+
# end
|
63
|
+
#end
|
64
|
+
|
65
|
+
# TODO: Better way to load helpers?
|
66
|
+
#
|
67
|
+
def load_helpers
|
68
|
+
dirs = spec_files.map{ |file| File.join(Dir.pwd, File.dirname(file)) }
|
69
|
+
dirs = dirs.select{ |dir| File.directory?(dir) }
|
70
|
+
dirs.each do |dir|
|
71
|
+
while dir != '/' do
|
72
|
+
helper = File.join(dir, 'qed_helper.rb')
|
73
|
+
load(helper) if File.exist?(helper)
|
74
|
+
break if Dir.pwd == dir
|
75
|
+
dir = File.dirname(dir)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
def specs
|
82
|
+
spec_files
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
def spec_files
|
87
|
+
files = ARGV.map do |pattern|
|
88
|
+
Dir[pattern]
|
89
|
+
end.flatten.uniq
|
90
|
+
|
91
|
+
files = files.map do |file|
|
92
|
+
File.directory?(file) ? Dir[File.join(file,'**','*')] : file
|
93
|
+
end.flatten.uniq
|
94
|
+
|
95
|
+
files = files.reject do |file|
|
96
|
+
%w{.yml .yaml .rb}.include?(File.extname(file))
|
97
|
+
end
|
98
|
+
|
99
|
+
files
|
100
|
+
end
|
101
|
+
|
102
|
+
#
|
103
|
+
def output
|
104
|
+
case reporter
|
105
|
+
when :verbatim
|
106
|
+
Reporter::Verbatim.new
|
107
|
+
when :summary
|
108
|
+
Reporter::Summary.new
|
109
|
+
else
|
110
|
+
nil
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
#
|
115
|
+
def runner
|
116
|
+
Runner.new(specs, output)
|
117
|
+
end
|
118
|
+
|
119
|
+
#
|
120
|
+
def execute
|
121
|
+
parse_options
|
122
|
+
#load_rc
|
123
|
+
load_helpers
|
124
|
+
case reporter
|
125
|
+
when :script
|
126
|
+
specs.each do |spec|
|
127
|
+
puts spec.to_script
|
128
|
+
end
|
129
|
+
else
|
130
|
+
runner.check
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
HELP = <<-END
|
135
|
+
qed [--options] [spec/tests...]
|
136
|
+
|
137
|
+
Options:
|
138
|
+
-v --verbatim use verbatim reporter
|
139
|
+
-s --summary use summary reporter
|
140
|
+
-V --verbose extra verbose output
|
141
|
+
-D --debug spec/tests will exit on error
|
142
|
+
-h --help show this help information
|
143
|
+
--version show quarry version
|
144
|
+
END
|
145
|
+
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
QED::Command.execute
|
150
|
+
|
data/bin/qedoc
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'qed/document'
|
5
|
+
|
6
|
+
options = {}
|
7
|
+
|
8
|
+
usage = OptionParser.new do |usage|
|
9
|
+
|
10
|
+
usage.banner = "Usage: qedoc [OPTIONS] <QEDFile1> [ <QEDFile2> ... ]"
|
11
|
+
|
12
|
+
usage.on("-o", "--output [DIR]", "Output directory") do |dir|
|
13
|
+
options[:output]= dir
|
14
|
+
end
|
15
|
+
|
16
|
+
usage.on("-t", "--title [TITLE]", "Title of Document") do |title|
|
17
|
+
options[:title]= title
|
18
|
+
end
|
19
|
+
|
20
|
+
usage.on("--css [URI]", "Specify a URI for a CSS file add to HTML header.") do |uri|
|
21
|
+
options[:css] = uri
|
22
|
+
end
|
23
|
+
|
24
|
+
usage.on("--dryrun", "") do
|
25
|
+
options[:dryrun] = true
|
26
|
+
end
|
27
|
+
|
28
|
+
usage.on("-q", "--quiet", "") do
|
29
|
+
options[:quiet] = true
|
30
|
+
end
|
31
|
+
|
32
|
+
usage.on_tail("-h", "--help", "display this help message") do
|
33
|
+
puts usage
|
34
|
+
exit
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
usage.parse!
|
40
|
+
|
41
|
+
options[:paths] = ARGV.dup
|
42
|
+
|
43
|
+
#opts[:output] = cli.options[:file]
|
44
|
+
#opts[:dryrun] = cli.options[:dryrun]
|
45
|
+
#opts[:quiet] = cli.options[:quiet]
|
46
|
+
#opts[:css] = cli.options[:css]
|
47
|
+
#opts[:title] = cli.options[:title]
|
48
|
+
|
49
|
+
doc = QED::Document.new(options)
|
50
|
+
|
51
|
+
doc.generate
|
52
|
+
|
data/demo/01_spec.qed
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
= Standard Sections
|
2
|
+
|
3
|
+
QED demos are light-weight specification documents, suitable
|
4
|
+
for Interface-driven Development. The documents are divided up into
|
5
|
+
clauses separated by blank lines. Clauses that are flush to the
|
6
|
+
left margin are always explanation or comment clauses. Indented
|
7
|
+
clauses are always executable code.
|
8
|
+
|
9
|
+
Each code section is executed in order of appearance, within a
|
10
|
+
rescue wrapper that captures any failures or errors. If neither
|
11
|
+
a failure or error occur then the code gets a "pass".
|
12
|
+
|
13
|
+
For example, the following passes:
|
14
|
+
|
15
|
+
(2 + 2).assert == 4
|
16
|
+
|
17
|
+
While the following would "fail", as indicated by the raising of
|
18
|
+
an Assertion error:
|
19
|
+
|
20
|
+
expect Assertion do
|
21
|
+
(2 + 2).assert == 5
|
22
|
+
end
|
23
|
+
|
24
|
+
And this would have raised a NameError:
|
25
|
+
|
26
|
+
expect NameError do
|
27
|
+
nobody_knows_method
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
= Neutral Code
|
32
|
+
|
33
|
+
There is no means of specifying that a code clause is neutral code,
|
34
|
+
i.e. that it should be executed but not tested. So far this
|
35
|
+
such a feature has proven to be a YAGNI. Yet we may add such a
|
36
|
+
feature in the future if it is ultimately deemed necessary.
|
37
|
+
|
38
|
+
|
39
|
+
= Defining Custom Assertions
|
40
|
+
|
41
|
+
The context in which the QED code is run is a self-extended module, thus
|
42
|
+
reusable macros can be created simply by defining a method.
|
43
|
+
|
44
|
+
def assert_integer(x)
|
45
|
+
x.assert.is_a? Integer
|
46
|
+
end
|
47
|
+
|
48
|
+
Now lets try out our new macro definition.
|
49
|
+
|
50
|
+
assert_integer(4)
|
51
|
+
|
52
|
+
Let's prove that it can also fail:
|
53
|
+
|
54
|
+
expect Assertion do
|
55
|
+
assert_integer("IV")
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
= Helper File
|
60
|
+
|
61
|
+
If you create a file called `qed_helper.rb` located in the directory with the
|
62
|
+
QED documents you are running via the `qed` command, it will be loaded first.
|
63
|
+
You can use that to load optional AE features, or define your own specialized
|
64
|
+
assertion methods.
|
65
|
+
|
66
|
+
|
67
|
+
= Before and After Clauses
|
68
|
+
|
69
|
+
QED supports *before* and *after* clauses in a specification
|
70
|
+
through the use of before and after code blocks. Before and after
|
71
|
+
clauses are executed at the beginning and at the end of each
|
72
|
+
subsequent step.
|
73
|
+
|
74
|
+
We use a *before* clause if we want to setup some code at the
|
75
|
+
start of each step.
|
76
|
+
|
77
|
+
a, z = nil, nil
|
78
|
+
|
79
|
+
before do
|
80
|
+
a = "BEFORE"
|
81
|
+
end
|
82
|
+
|
83
|
+
And an *after* clause to tear down objects after a step.
|
84
|
+
|
85
|
+
after do
|
86
|
+
z = "AFTER"
|
87
|
+
end
|
88
|
+
|
89
|
+
Notice we assigned +a+ and +z+ before the block. This was to ensure
|
90
|
+
their visibility in the scope later. Now, lets verify this the *before*
|
91
|
+
and *after* clause work.
|
92
|
+
|
93
|
+
a.assert == "BEFORE"
|
94
|
+
|
95
|
+
a = "A"
|
96
|
+
z = "Z"
|
97
|
+
|
98
|
+
And now.
|
99
|
+
|
100
|
+
z.assert == "AFTER"
|
101
|
+
|
102
|
+
There can only be one before or after clause at a time. So if we
|
103
|
+
define a new *before* or *after* clause later in the document,
|
104
|
+
it will replace the current clause(s) in use.
|
105
|
+
|
106
|
+
As a demonstration of this:
|
107
|
+
|
108
|
+
before do
|
109
|
+
a = "BEFORE AGAIN"
|
110
|
+
end
|
111
|
+
|
112
|
+
We will see it is the case.
|
113
|
+
|
114
|
+
a.assert == "BEFORE AGAIN"
|
115
|
+
|
116
|
+
Only use *before* and *after* clauses when necessary --specifications
|
117
|
+
are generally more readable without them. Indeed, some developers
|
118
|
+
make a policy of avoiding them altogether. YMMV.
|
119
|
+
|
120
|
+
|
121
|
+
= Tabular Steps
|
122
|
+
|
123
|
+
Finally we will demonstrate a tabular step. +table+ method is used
|
124
|
+
for this. We supply a file name to the method telling QED where to
|
125
|
+
find the table data to be used in the test. All table files are looked
|
126
|
+
for relative to the location of the document. If no name is given the
|
127
|
+
'<doc-name>.yaml' is assumed.
|
128
|
+
|
129
|
+
The arity of the table block determines the number of columns each row
|
130
|
+
in the table should have. Each row is assigned in turn and run
|
131
|
+
through the coded step. Consider the following example:
|
132
|
+
|
133
|
+
Every row in 'table.yaml' will be assigned to the block parameters
|
134
|
+
and run through the following assertion.
|
135
|
+
|
136
|
+
table do |x,y|
|
137
|
+
x.upcase.assert == y
|
138
|
+
end
|
139
|
+
|
140
|
+
This concludes the basic overview of QED's specification system, which
|
141
|
+
is itself a QED document. Yes, we eat our own dog food.
|
142
|
+
|
143
|
+
Q.E.D.
|
data/demo/01_spec.yaml
ADDED
data/demo/qed_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'ae/expect'
|
@@ -0,0 +1,355 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>QED Overview</title>
|
4
|
+
|
5
|
+
<style>
|
6
|
+
#container{ margin: 0 auto; width: 800px; }
|
7
|
+
|
8
|
+
/* Debug borders */
|
9
|
+
/* p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { border: 1px solid red; } */
|
10
|
+
|
11
|
+
body { font-size: 14px; line-height: 20px; margin: 1em 5% 1em 5%; font-family: Verdana, Arial, Helvetica, sans-serif; }
|
12
|
+
a { color: #336; text-decoration: underline; }
|
13
|
+
a:visited { color: #334; }
|
14
|
+
em { font-style: italic; }
|
15
|
+
strong { font-weight: bold; }
|
16
|
+
tt { color: navy; }
|
17
|
+
|
18
|
+
h1, h2, h3, h4, h5, h6 { color: #223; margin-top: 1.2em; margin-bottom: 0.5em; line-height: 1.3; }
|
19
|
+
h1 { border-bottom: 2px solid silver; }
|
20
|
+
h2 { border-bottom: 2px solid silver; padding-top: 0.5em; }
|
21
|
+
|
22
|
+
hr { border: 1px solid silver; }
|
23
|
+
|
24
|
+
p { color: #222; text-align: justify; margin-top: 0.5em; margin-bottom: 0.5em; line-height: 1.4em; }
|
25
|
+
|
26
|
+
pre { padding: 10; margin: 0; font-family: monospace; font-size: 0.9em; }
|
27
|
+
pre.pass { color: green; }
|
28
|
+
pre.fail { color: red; }
|
29
|
+
pre.error { color: red; font-weight: bold; }
|
30
|
+
|
31
|
+
span#author { color: #527bbd; font-weight: bold; font-size: 1.1em; }
|
32
|
+
span#email { }
|
33
|
+
span#revision { }
|
34
|
+
|
35
|
+
div#footer { font-size: small; border-top: 2px solid silver; padding-top: 0.5em; margin-top: 4.0em; }
|
36
|
+
div#footer-text { float: left; padding-bottom: 0.5em; }
|
37
|
+
div#footer-badges { float: right; padding-bottom: 0.5em; }
|
38
|
+
|
39
|
+
/* Block element content. */
|
40
|
+
div.content { padding: 0; }
|
41
|
+
|
42
|
+
/* Block element titles. */
|
43
|
+
h1.title { font-weight: bold; text-align: left; font-size: 3em; margin-top: 1.0em; margin-bottom: 0.5em; }
|
44
|
+
|
45
|
+
/* Block element titles. */
|
46
|
+
div.title, caption.title { font-weight: bold; text-align: left; margin-top: 1.0em; margin-bottom: 0.5em; }
|
47
|
+
div.title + * { margin-top: 0; }
|
48
|
+
td div.title:first-child { margin-top: 0.0em; }
|
49
|
+
div.content div.title:first-child { margin-top: 0.0em; }
|
50
|
+
div.content + div.title { margin-top: 0.0em; }
|
51
|
+
div.sidebarblock > div.content { background: #ffffee; border: 1px solid silver; padding: 0.5em; }
|
52
|
+
|
53
|
+
img { border-style: none; }
|
54
|
+
|
55
|
+
dl { margin-top: 0.8em; margin-bottom: 0.8em; }
|
56
|
+
dt { margin-top: 0.5em; margin-bottom: 0; font-style: italic; }
|
57
|
+
dd > *:first-child { margin-top: 0; }
|
58
|
+
ul, ol { list-style-position: outside; }
|
59
|
+
|
60
|
+
thead { font-weight: bold; }
|
61
|
+
tfoot { font-weight: bold; }
|
62
|
+
</style>
|
63
|
+
|
64
|
+
<!-- TODO: only include if these files exists -->
|
65
|
+
<link href="../assets/styles/spec.css" type="text/css" rel="stylesheet">
|
66
|
+
<!-- spec.css might be a problem with clobber -->
|
67
|
+
<link href="spec.css" type="text/css" rel="stylesheet">
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
<!-- JQuery is needed -->
|
72
|
+
<script src="jquery.js" type="text/javascript" language="javascript"></script>
|
73
|
+
|
74
|
+
</head>
|
75
|
+
|
76
|
+
<body>
|
77
|
+
|
78
|
+
<!-- Side Table of Contents -->
|
79
|
+
<div id="sidebar" style="position: fixed; top: 10; right: 10; background: white;">
|
80
|
+
<a href="javascript: toc_toggle();">
|
81
|
+
<img src="img/icon/book.jpg" height="30px;" style="border: none;" alt="TOC" align="right"/>
|
82
|
+
</a>
|
83
|
+
|
84
|
+
<div id="toc_side" class="toc">
|
85
|
+
</div>
|
86
|
+
</div>
|
87
|
+
|
88
|
+
<div id="container">
|
89
|
+
<div id="header">
|
90
|
+
<img src="img/icon/book.jpg" align="left" style="padding-right: 10px;" alt=""/>
|
91
|
+
|
92
|
+
<h1 class="title">QED Overview</h1>
|
93
|
+
|
94
|
+
<h1>Table of Contents</h1>
|
95
|
+
|
96
|
+
<div class="toc">
|
97
|
+
</div>
|
98
|
+
</div>
|
99
|
+
|
100
|
+
<div id="content">
|
101
|
+
<h1>Standard Sections</h1>
|
102
|
+
<p>
|
103
|
+
QED demos are light-weight specification documents, suitable for
|
104
|
+
Interface-driven Development. The documents are divided up into clauses
|
105
|
+
separated by blank lines. Clauses that are flush to the left margin are
|
106
|
+
always explanation or comment clauses. Indented clauses are always
|
107
|
+
executable code.
|
108
|
+
</p>
|
109
|
+
<p>
|
110
|
+
Each code section is executed in order of appearance, within a rescue
|
111
|
+
wrapper that captures any failures or errors. If neither a failure or error
|
112
|
+
occur then the code gets a "pass".
|
113
|
+
</p>
|
114
|
+
<p>
|
115
|
+
For example, the following passes:
|
116
|
+
</p>
|
117
|
+
<pre>
|
118
|
+
(2 + 2).assert == 4
|
119
|
+
</pre>
|
120
|
+
<p>
|
121
|
+
While the following would "fail", as indicated by the raising of
|
122
|
+
an Assertion error:
|
123
|
+
</p>
|
124
|
+
<pre>
|
125
|
+
Assertion.assert.raised? do
|
126
|
+
(2 + 2).assert == 5
|
127
|
+
end
|
128
|
+
|
129
|
+
#expect Assertion do
|
130
|
+
# (2 + 2).assert == 5
|
131
|
+
#end
|
132
|
+
</pre>
|
133
|
+
<p>
|
134
|
+
And this would have raised a NameError:
|
135
|
+
</p>
|
136
|
+
<pre>
|
137
|
+
expect NameError do
|
138
|
+
nobody_knows_method
|
139
|
+
end
|
140
|
+
</pre>
|
141
|
+
<h1>Neutral Code</h1>
|
142
|
+
<p>
|
143
|
+
There is no means of specifying that a code clause is neutral code, i.e.
|
144
|
+
that it should be executed but not tested. So far this such a feature has
|
145
|
+
proven to be a YAGNI. Yet we may add such a feature in the future if it is
|
146
|
+
ultimately deemed necessary.
|
147
|
+
</p>
|
148
|
+
<h1>Defining Macros</h1>
|
149
|
+
<p>
|
150
|
+
The context in which the QED code is run is a self-extended module, thus
|
151
|
+
reusable macros can be created simply by defining a method.
|
152
|
+
</p>
|
153
|
+
<pre>
|
154
|
+
def assert_integer(x)
|
155
|
+
x.assert.is_a? Integer
|
156
|
+
end
|
157
|
+
</pre>
|
158
|
+
<p>
|
159
|
+
Now lets try out our new macro definition.
|
160
|
+
</p>
|
161
|
+
<pre>
|
162
|
+
assert_integer(4)
|
163
|
+
</pre>
|
164
|
+
<p>
|
165
|
+
Let’s prove that it can also fail:
|
166
|
+
</p>
|
167
|
+
<pre>
|
168
|
+
expect Assertion do
|
169
|
+
assert_integer("IV")
|
170
|
+
end
|
171
|
+
</pre>
|
172
|
+
<h1>Before and After Clauses</h1>
|
173
|
+
<p>
|
174
|
+
QED supports <b>before</b> and <b>after</b> clauses in a specification
|
175
|
+
through the use of before and after code blocks. Before and after clauses
|
176
|
+
are executed at the beginning and at the end of each subsequent step.
|
177
|
+
</p>
|
178
|
+
<p>
|
179
|
+
We use a <b>before</b> clause if we want to setup some code at the start of
|
180
|
+
each step.
|
181
|
+
</p>
|
182
|
+
<pre>
|
183
|
+
a, z = nil, nil
|
184
|
+
|
185
|
+
before do
|
186
|
+
a = "BEFORE"
|
187
|
+
end
|
188
|
+
</pre>
|
189
|
+
<p>
|
190
|
+
And an <b>after</b> clause to tear down objects after a step.
|
191
|
+
</p>
|
192
|
+
<pre>
|
193
|
+
after do
|
194
|
+
z = "AFTER"
|
195
|
+
end
|
196
|
+
</pre>
|
197
|
+
<p>
|
198
|
+
Notice we assigned <tt>a</tt> and <tt>z</tt> before the block. This was to
|
199
|
+
ensure their visibility in the scope later. Now, lets verify this the
|
200
|
+
<b>before</b> and <b>after</b> clause work.
|
201
|
+
</p>
|
202
|
+
<pre>
|
203
|
+
a.assert == "BEFORE"
|
204
|
+
|
205
|
+
a = "A"
|
206
|
+
z = "Z"
|
207
|
+
</pre>
|
208
|
+
<p>
|
209
|
+
And now.
|
210
|
+
</p>
|
211
|
+
<pre>
|
212
|
+
z.assert == "AFTER"
|
213
|
+
</pre>
|
214
|
+
<p>
|
215
|
+
There can only be one before or after clause at a time. So if we define a
|
216
|
+
new <b>before</b> or <b>after</b> clause later in the document, it will
|
217
|
+
replace the current clause(s) in use.
|
218
|
+
</p>
|
219
|
+
<p>
|
220
|
+
As a demonstration of this:
|
221
|
+
</p>
|
222
|
+
<pre>
|
223
|
+
before do
|
224
|
+
a = "BEFORE AGAIN"
|
225
|
+
end
|
226
|
+
</pre>
|
227
|
+
<p>
|
228
|
+
We will see it is the case.
|
229
|
+
</p>
|
230
|
+
<pre>
|
231
|
+
a.assert == "BEFORE AGAIN"
|
232
|
+
</pre>
|
233
|
+
<p>
|
234
|
+
Only use <b>before</b> and <b>after</b> clauses when necessary
|
235
|
+
—specifications are generally more readable without them. Indeed,
|
236
|
+
some developers make a policy of avoiding them altogether. YMMV.
|
237
|
+
</p>
|
238
|
+
<h1>Tabular Steps</h1>
|
239
|
+
<p>
|
240
|
+
Finally we will demonstrate a tabular step. <tt>table</tt> method is used
|
241
|
+
for this. We supply a file name to the method telling QED where to find the
|
242
|
+
table data to be used in the test. All table files are looked for relative
|
243
|
+
to the location of the document. If no name is given the
|
244
|
+
’<doc-name>.yaml’ is assumed.
|
245
|
+
</p>
|
246
|
+
<p>
|
247
|
+
The arity of the table block determines the number of columns each row in
|
248
|
+
the table should have. Each row is assigned in turn and run through the
|
249
|
+
coded step. Consider the following example:
|
250
|
+
</p>
|
251
|
+
<p>
|
252
|
+
Every row in ‘table.yaml’ will be assigned to the block
|
253
|
+
parameters and run through the following assertion.
|
254
|
+
</p>
|
255
|
+
<pre>
|
256
|
+
table do |x,y|
|
257
|
+
x.upcase.assert == y
|
258
|
+
end
|
259
|
+
</pre>
|
260
|
+
<p>
|
261
|
+
This concludes the basic overview of QED’s specification system,
|
262
|
+
which is itself a QED document. Yes, we eat our own dog food.
|
263
|
+
</p>
|
264
|
+
<p>
|
265
|
+
Q.E.D.
|
266
|
+
</p>
|
267
|
+
|
268
|
+
|
269
|
+
</div>
|
270
|
+
</div>
|
271
|
+
|
272
|
+
</body>
|
273
|
+
|
274
|
+
</html>
|
275
|
+
|
276
|
+
<script src="../assets/scripts/spec.js" type="text/javascript" language="javascript"></script>
|
277
|
+
|
278
|
+
<script type="text/javascript" language="javascript">
|
279
|
+
/*****************************************************************
|
280
|
+
* $.toc()
|
281
|
+
* by rebecca murphey
|
282
|
+
* rmurphey gmail com
|
283
|
+
*
|
284
|
+
* This function is called on its own and takes as an argument
|
285
|
+
* a list of selectors with which it will build a table of
|
286
|
+
* contents.
|
287
|
+
*
|
288
|
+
* The first selector will make up the top level of the TOC;
|
289
|
+
* the second selector will make up the second level of the TOC;
|
290
|
+
* etc.
|
291
|
+
*
|
292
|
+
* This function returns a div containing nested unordered lists;
|
293
|
+
* each list item is linked to an anchor tag added before the item
|
294
|
+
* on the page.
|
295
|
+
*
|
296
|
+
* usage: $.toc('h1,h2,h3').prependTo('body');
|
297
|
+
************************************************************************/
|
298
|
+
(function($) {
|
299
|
+
$.toc = function(tocList) {
|
300
|
+
$(tocList).addClass('jquery-toc');
|
301
|
+
var tocListArray = tocList.split(',');
|
302
|
+
$.each(tocListArray, function(i,v) { tocListArray[i] = $.trim(v); });
|
303
|
+
var $elements = $('.jquery-toc');
|
304
|
+
$('body').append('<div></div>');
|
305
|
+
var $toc = $('body div:last');
|
306
|
+
var lastLevel = 1;
|
307
|
+
$toc.append('<ul class="jquery-toc-1"></ul>');
|
308
|
+
$elements.each(function() {
|
309
|
+
var $e = $(this);
|
310
|
+
var text = $e.text();
|
311
|
+
var anchor = text.replace(/ /g,'-');
|
312
|
+
$e.before('<a name="' + anchor + '"></a>');
|
313
|
+
var level;
|
314
|
+
$.each(tocListArray, function(i,v) {
|
315
|
+
if (v.match(' ')) {
|
316
|
+
var vArray = v.split(' ');
|
317
|
+
var e = vArray[vArray.length - 1];
|
318
|
+
} else { e = v; }
|
319
|
+
if ($e.is(e)) { level = i+1; }
|
320
|
+
});
|
321
|
+
var className = 'jquery-toc-' + level;
|
322
|
+
var li = '<li><a href="#' + anchor + '">' + text + '</a></li>';
|
323
|
+
if (level == lastLevel) {
|
324
|
+
$('ul.' + className + ':last',$toc).append(li);
|
325
|
+
} else if (level > lastLevel) {
|
326
|
+
var parentLevel = level - 1;
|
327
|
+
var parentClassName = 'jquery-toc-' + parentLevel;
|
328
|
+
$('ul.' + parentClassName + ':last',$toc).
|
329
|
+
append('<ul class="' + className + '"></ul>');
|
330
|
+
$('ul.' + className + ':last',$toc).append(li);
|
331
|
+
} else if (level < lastLevel) {
|
332
|
+
$('ul.' + className + ':last',$toc).append(li);
|
333
|
+
}
|
334
|
+
lastLevel = level;
|
335
|
+
});
|
336
|
+
var $toc_ul = $('ul.jquery-toc-1',$toc);
|
337
|
+
$toc.remove();
|
338
|
+
return($toc_ul);
|
339
|
+
}
|
340
|
+
})(jQuery);
|
341
|
+
</script>
|
342
|
+
|
343
|
+
<script>
|
344
|
+
function toc_toggle() {
|
345
|
+
$('#toc_side').toggle();
|
346
|
+
$("pre").addClass("pass");
|
347
|
+
$("pre:contains('FAIL:')").addClass("fail");
|
348
|
+
$("pre:contains('ERROR:')").addClass("error");
|
349
|
+
};
|
350
|
+
|
351
|
+
$.toc('#content h1,h2,h3,h4').appendTo('.toc');
|
352
|
+
|
353
|
+
toc_toggle();
|
354
|
+
</script>
|
355
|
+
|