qed 1.1.0 → 1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +40 -2
- data/MANIFEST +7 -12
- data/README.rdoc +30 -23
- data/bin/qed +1 -147
- data/demo/01_spec.qed +82 -53
- data/demo/data.txt +1 -0
- data/demo/{qed_helper.rb → helper.rb} +1 -0
- data/demo/table.yml +5 -0
- data/doc/qedoc/index.html +98 -53
- data/lib/qed.rb +1 -1
- data/lib/qed/command.rb +166 -0
- data/lib/qed/document.rb +43 -13
- data/lib/qed/reporter/base.rb +12 -5
- data/lib/qed/reporter/dotprogress.rb +1 -1
- data/lib/qed/reporter/summary.rb +2 -1
- data/lib/qed/reporter/verbatim.rb +11 -12
- data/lib/qed/script.rb +140 -33
- data/meta/description +2 -2
- data/meta/homepage +1 -1
- data/meta/{package → name} +0 -0
- data/meta/repository +1 -0
- data/meta/{project → suite} +0 -0
- data/meta/version +1 -1
- metadata +15 -13
- data/demo/01_spec.yaml +0 -4
data/demo/data.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
data/demo/table.yml
ADDED
data/doc/qedoc/index.html
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
<html>
|
2
2
|
<head>
|
3
|
-
<title>
|
3
|
+
<title>Demonstration</title>
|
4
4
|
|
5
5
|
<style>
|
6
6
|
#container{ margin: 0 auto; width: 800px; }
|
@@ -89,7 +89,7 @@
|
|
89
89
|
<div id="header">
|
90
90
|
<img src="img/icon/book.jpg" align="left" style="padding-right: 10px;" alt=""/>
|
91
91
|
|
92
|
-
<h1 class="title">
|
92
|
+
<h1 class="title">Demonstration</h1>
|
93
93
|
|
94
94
|
<h1>Table of Contents</h1>
|
95
95
|
|
@@ -115,31 +115,30 @@ occur then the code gets a “pass”.
|
|
115
115
|
For example, the following passes:
|
116
116
|
</p>
|
117
117
|
<pre>
|
118
|
-
|
118
|
+
(2 + 2).assert == 4
|
119
119
|
</pre>
|
120
120
|
<p>
|
121
121
|
While the following would “fail”, as indicated by the raising
|
122
122
|
of an Assertion error:
|
123
123
|
</p>
|
124
124
|
<pre>
|
125
|
-
|
126
|
-
|
127
|
-
|
125
|
+
expect Assertion do
|
126
|
+
(2 + 2).assert == 5
|
127
|
+
end
|
128
128
|
</pre>
|
129
129
|
<p>
|
130
130
|
And this would have raised a NameError:
|
131
131
|
</p>
|
132
132
|
<pre>
|
133
|
-
|
134
|
-
|
135
|
-
|
133
|
+
expect NameError do
|
134
|
+
nobody_knows_method
|
135
|
+
end
|
136
136
|
</pre>
|
137
137
|
<h1>Neutral Code</h1>
|
138
138
|
<p>
|
139
139
|
There is no means of specifying that a code clause is neutral code, i.e.
|
140
|
-
that it should be executed but not tested.
|
141
|
-
proven to be a YAGNI.
|
142
|
-
ultimately deemed necessary.
|
140
|
+
that it should be executed but not tested. Thus far, such a feature has
|
141
|
+
proven to be a YAGNI.
|
143
142
|
</p>
|
144
143
|
<h1>Defining Custom Assertions</h1>
|
145
144
|
<p>
|
@@ -147,30 +146,32 @@ The context in which the QED code is run is a self-extended module, thus
|
|
147
146
|
reusable macros can be created simply by defining a method.
|
148
147
|
</p>
|
149
148
|
<pre>
|
150
|
-
|
151
|
-
|
152
|
-
|
149
|
+
def assert_integer(x)
|
150
|
+
x.assert.is_a? Integer
|
151
|
+
end
|
153
152
|
</pre>
|
154
153
|
<p>
|
155
154
|
Now lets try out our new macro definition.
|
156
155
|
</p>
|
157
156
|
<pre>
|
158
|
-
|
157
|
+
assert_integer(4)
|
159
158
|
</pre>
|
160
159
|
<p>
|
161
160
|
Let’s prove that it can also fail:
|
162
161
|
</p>
|
163
162
|
<pre>
|
164
|
-
|
165
|
-
|
166
|
-
|
163
|
+
expect Assertion do
|
164
|
+
assert_integer("IV")
|
165
|
+
end
|
167
166
|
</pre>
|
168
167
|
<h1>Helper File</h1>
|
169
168
|
<p>
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
169
|
+
Helpers can be defined at the bottom of any QED document by placing the
|
170
|
+
code after a triple-dash divider (ie. “—”). You can use
|
171
|
+
that to load optional AE features, or define your own specialized assertion
|
172
|
+
methods. Helpers can be defined in a separate files using <tt>require</tt>
|
173
|
+
or <tt>load</tt> in the bottom section to import them. The bottom section
|
174
|
+
is run first, before any the steps.
|
174
175
|
</p>
|
175
176
|
<h1>Before and After Clauses</h1>
|
176
177
|
<p>
|
@@ -183,36 +184,36 @@ We use a <b>before</b> clause if we want to setup some code at the start of
|
|
183
184
|
each step.
|
184
185
|
</p>
|
185
186
|
<pre>
|
186
|
-
|
187
|
+
a, z = nil, nil
|
187
188
|
|
188
|
-
|
189
|
-
|
190
|
-
|
189
|
+
Before do
|
190
|
+
a = "BEFORE"
|
191
|
+
end
|
191
192
|
</pre>
|
192
193
|
<p>
|
193
|
-
And an <b>after</b> clause to
|
194
|
+
And an <b>after</b> clause to teardown objects after a step.
|
194
195
|
</p>
|
195
196
|
<pre>
|
196
|
-
|
197
|
-
|
198
|
-
|
197
|
+
After do
|
198
|
+
z = "AFTER"
|
199
|
+
end
|
199
200
|
</pre>
|
200
201
|
<p>
|
201
202
|
Notice we assigned <tt>a</tt> and <tt>z</tt> before the block. This was to
|
202
|
-
ensure their visibility in the scope later. Now, lets verify
|
203
|
-
<b>before</b> and <b>after</b>
|
203
|
+
ensure their visibility in the scope later. Now, lets verify that the
|
204
|
+
<b>before</b> and <b>after</b> clauses work.
|
204
205
|
</p>
|
205
206
|
<pre>
|
206
|
-
|
207
|
+
a.assert == "BEFORE"
|
207
208
|
|
208
|
-
|
209
|
-
|
209
|
+
a = "A"
|
210
|
+
z = "Z"
|
210
211
|
</pre>
|
211
212
|
<p>
|
212
213
|
And now.
|
213
214
|
</p>
|
214
215
|
<pre>
|
215
|
-
|
216
|
+
z.assert == "AFTER"
|
216
217
|
</pre>
|
217
218
|
<p>
|
218
219
|
There can only be one before or after clause at a time. So if we define a
|
@@ -223,28 +224,38 @@ replace the current clause(s) in use.
|
|
223
224
|
As a demonstration of this:
|
224
225
|
</p>
|
225
226
|
<pre>
|
226
|
-
|
227
|
-
|
228
|
-
|
227
|
+
Before do
|
228
|
+
a = "BEFORE AGAIN"
|
229
|
+
end
|
229
230
|
</pre>
|
230
231
|
<p>
|
231
232
|
We will see it is the case.
|
232
233
|
</p>
|
233
234
|
<pre>
|
234
|
-
|
235
|
+
a.assert == "BEFORE AGAIN"
|
235
236
|
</pre>
|
236
237
|
<p>
|
237
238
|
Only use <b>before</b> and <b>after</b> clauses when necessary
|
238
239
|
—specifications are generally more readable without them. Indeed,
|
239
240
|
some developers make a policy of avoiding them altogether. YMMV.
|
240
241
|
</p>
|
242
|
+
<h1>External Data</h1>
|
243
|
+
<p>
|
244
|
+
When creating testable demonstrations, there are times when sizable chunks
|
245
|
+
of data are needed. It is convenient to store such data in a separate file.
|
246
|
+
The <tt>Data</tt> method makes is easy to load such files.
|
247
|
+
</p>
|
248
|
+
<pre>
|
249
|
+
Data('data.txt').assert =~ /dolor/
|
250
|
+
</pre>
|
251
|
+
<p>
|
252
|
+
All files are looked for relative to the location of current document.
|
253
|
+
</p>
|
241
254
|
<h1>Tabular Steps</h1>
|
242
255
|
<p>
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
to the location of the document. If no name is given the
|
247
|
-
’<doc-name>.yaml’ is assumed.
|
256
|
+
The <tt>Table</tt> method is similar to the <tt>Data</tt> method except
|
257
|
+
that it expects a YAML file, and it can take a block to iterate the data
|
258
|
+
over. This makes it easy to test tables of examples.
|
248
259
|
</p>
|
249
260
|
<p>
|
250
261
|
The arity of the table block determines the number of columns each row in
|
@@ -252,20 +263,54 @@ the table should have. Each row is assigned in turn and run through the
|
|
252
263
|
coded step. Consider the following example:
|
253
264
|
</p>
|
254
265
|
<p>
|
255
|
-
Every row in
|
256
|
-
parameters and run through the
|
266
|
+
Every row in the <a href="http://table.yml">table.yml table</a> will be
|
267
|
+
assigned to the block parameters and run through the subsequent assertion.
|
257
268
|
</p>
|
258
269
|
<pre>
|
259
|
-
|
260
|
-
|
261
|
-
|
270
|
+
Table 'table.yml' do |x, y|
|
271
|
+
x.upcase.assert == y
|
272
|
+
end
|
262
273
|
</pre>
|
274
|
+
<h1>Comment Triggers</h1>
|
275
|
+
<p>
|
276
|
+
QED also supports comment match triggers. With the <tt>When</tt> method one
|
277
|
+
can define setup and teardown procedures by matching against comment text.
|
278
|
+
For example:
|
279
|
+
</p>
|
280
|
+
<pre>
|
281
|
+
When 'given a setting @a equal to (((\d+)))' do |n|
|
282
|
+
@a = n.to_i
|
283
|
+
end
|
284
|
+
</pre>
|
285
|
+
<p>
|
286
|
+
Now, @a will be set to 1 whenever a comment like this one contains,
|
287
|
+
“given a setting @a equal to 1”.
|
288
|
+
</p>
|
289
|
+
<pre>
|
290
|
+
@a.assert == 1
|
291
|
+
</pre>
|
292
|
+
<p>
|
293
|
+
A string pattern is translated into a regular expression. In fact, you can
|
294
|
+
use a regular expression if you need more control over the match. When
|
295
|
+
using a string all spaces are converted to <tt>\s+</tt> and anything within
|
296
|
+
double-parenthesis is treated as raw regular expression. Since the above
|
297
|
+
example has (((\d+))), the actual regular expression contains
|
298
|
+
<tt>(\d+)</tt>, so any number can be used. For example, “given a
|
299
|
+
setting @a equal to 2”.
|
300
|
+
</p>
|
301
|
+
<pre>
|
302
|
+
@a.assert == 2
|
303
|
+
</pre>
|
304
|
+
<p>
|
305
|
+
Typically you will want to put triggers is helper files, rather then place
|
306
|
+
them directly in the demonstration document.
|
307
|
+
</p>
|
263
308
|
<p>
|
264
309
|
This concludes the basic overview of QED’s specification system,
|
265
310
|
which is itself a QED document. Yes, we eat our own dog food.
|
266
311
|
</p>
|
267
|
-
<p>
|
268
|
-
|
312
|
+
<hr size="1"></hr><p>
|
313
|
+
require ‘helper’
|
269
314
|
</p>
|
270
315
|
|
271
316
|
|
data/lib/qed.rb
CHANGED
data/lib/qed/command.rb
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'qed'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
module QED
|
7
|
+
|
8
|
+
# = QED Commandline Tool
|
9
|
+
#
|
10
|
+
class Command
|
11
|
+
def self.execute
|
12
|
+
new.execute
|
13
|
+
end
|
14
|
+
|
15
|
+
#
|
16
|
+
attr :format
|
17
|
+
|
18
|
+
#
|
19
|
+
def initialize
|
20
|
+
@format = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
# Instance of OptionParser
|
24
|
+
def opts
|
25
|
+
@opts ||= OptionParser.new do |opt|
|
26
|
+
|
27
|
+
opt.on('--dotprogress', '-d', "use dot-progress reporter [default]") do
|
28
|
+
@format = :summary
|
29
|
+
end
|
30
|
+
|
31
|
+
opt.on('--verbatim', '-v', "use verbatim reporter") do
|
32
|
+
@format = :verbatim
|
33
|
+
end
|
34
|
+
|
35
|
+
opt.on('--summary', '-s', "use summary reporter") do
|
36
|
+
@format = :summary
|
37
|
+
end
|
38
|
+
|
39
|
+
opt.on('--script', "psuedo-reporter") do
|
40
|
+
@format = :script # psuedo-reporter
|
41
|
+
end
|
42
|
+
|
43
|
+
opt.on('--loadpath', "-I", "add paths to $LOAD_PATH") do |arg|
|
44
|
+
libs = arg.split(/[:;]/).map{ |dir| File.expand_path(dir) }
|
45
|
+
libs.each{|dir| $LOAD_PATH.unshift(dir)}
|
46
|
+
end
|
47
|
+
|
48
|
+
opt.on('--verbose', '-V', "extra verbose output") do
|
49
|
+
@verbose = true
|
50
|
+
$VERBOSE = true
|
51
|
+
end
|
52
|
+
|
53
|
+
opt.on('--debug', "demos will exit on error") do
|
54
|
+
$DEBUG = true
|
55
|
+
end
|
56
|
+
|
57
|
+
opt.on_tail('--version', "display version") do
|
58
|
+
puts "QED #{VERSION}"
|
59
|
+
exit
|
60
|
+
end
|
61
|
+
|
62
|
+
opt.on_tail('--copyright', "display copyrights") do
|
63
|
+
puts "Copyright (c) 2008, 2009 Thomas Sawyer, GPL License"
|
64
|
+
exit
|
65
|
+
end
|
66
|
+
|
67
|
+
opt.on_tail('--help', '-h', "display this help message") do
|
68
|
+
puts opt
|
69
|
+
exit
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
#def load_rc
|
77
|
+
# if rcfile = Dir['.config/qed{,rc}{,.rb}'].first
|
78
|
+
# load(rcfile)
|
79
|
+
# end
|
80
|
+
#end
|
81
|
+
|
82
|
+
# TODO: Better way to load helpers?
|
83
|
+
#
|
84
|
+
#def load_helpers
|
85
|
+
# dirs = spec_files.map{ |file| File.join(Dir.pwd, File.dirname(file)) }
|
86
|
+
# dirs = dirs.select{ |dir| File.directory?(dir) }
|
87
|
+
# dirs.each do |dir|
|
88
|
+
# while dir != '/' do
|
89
|
+
# helper = File.join(dir, 'qed_helper.rb')
|
90
|
+
# load(helper) if File.exist?(helper)
|
91
|
+
# break if Dir.pwd == dir
|
92
|
+
# dir = File.dirname(dir)
|
93
|
+
# end
|
94
|
+
# end
|
95
|
+
#end
|
96
|
+
|
97
|
+
#
|
98
|
+
def demos
|
99
|
+
demo_files
|
100
|
+
end
|
101
|
+
|
102
|
+
#
|
103
|
+
def demo_files
|
104
|
+
files = ARGV.map do |pattern|
|
105
|
+
Dir[pattern]
|
106
|
+
end.flatten.uniq
|
107
|
+
|
108
|
+
files = files.map do |file|
|
109
|
+
if File.directory?(file)
|
110
|
+
Dir[File.join(file,'**','*{.qed,.rd,.rdoc,.md,.markdown}')]
|
111
|
+
else
|
112
|
+
file
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
file = files.flatten.uniq
|
117
|
+
|
118
|
+
#files = files.select do |file|
|
119
|
+
# %w{.yml .yaml .rb}.include?(File.extname(file))
|
120
|
+
#end
|
121
|
+
|
122
|
+
files
|
123
|
+
end
|
124
|
+
|
125
|
+
#
|
126
|
+
def reporter
|
127
|
+
case format
|
128
|
+
when :dotprogress
|
129
|
+
Reporter::DotProgress.new(reporter_options)
|
130
|
+
when :verbatim
|
131
|
+
Reporter::Verbatim.new(reporter_options)
|
132
|
+
when :summary
|
133
|
+
Reporter::Summary.new(reporter_options)
|
134
|
+
else
|
135
|
+
nil
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
#
|
140
|
+
def reporter_options
|
141
|
+
{ :verbose => @verbose }
|
142
|
+
end
|
143
|
+
|
144
|
+
#
|
145
|
+
def runner
|
146
|
+
Runner.new(demos, reporter)
|
147
|
+
end
|
148
|
+
|
149
|
+
#
|
150
|
+
def execute
|
151
|
+
opts.parse!
|
152
|
+
#load_rc
|
153
|
+
#load_helpers
|
154
|
+
case reporter
|
155
|
+
when :script
|
156
|
+
specs.each do |spec|
|
157
|
+
puts spec.to_script
|
158
|
+
end
|
159
|
+
else
|
160
|
+
runner.check
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
data/lib/qed/document.rb
CHANGED
@@ -12,8 +12,8 @@ module QED
|
|
12
12
|
|
13
13
|
DEFAULT_TITLE = "Demonstration"
|
14
14
|
DEFAULT_CSS = nil #"../assets/styles/spec.css"
|
15
|
-
DEFAULT_OUTPUT = "doc/
|
16
|
-
DEFAULT_PATH =
|
15
|
+
DEFAULT_OUTPUT = "doc/qedoc"
|
16
|
+
DEFAULT_PATH = "test/demos"
|
17
17
|
|
18
18
|
attr_accessor :title
|
19
19
|
attr_accessor :css
|
@@ -35,12 +35,15 @@ module QED
|
|
35
35
|
@output ||= DEFAULT_OUTPUT
|
36
36
|
@paths ||= []
|
37
37
|
|
38
|
-
|
38
|
+
if @paths.empty?
|
39
|
+
dir = Dir['{test/demos,demo,demos}'].first || DEFAULT_PATH
|
40
|
+
@paths = File.join(dir, '**', '*')
|
41
|
+
end
|
39
42
|
end
|
40
43
|
|
41
|
-
#
|
42
|
-
def
|
43
|
-
@
|
44
|
+
# Demo files.
|
45
|
+
def demo_files
|
46
|
+
@demo_files ||= (
|
44
47
|
glob = paths.map{ |f| File.directory?(f) ? Dir["#{f}/**/*"] : Dir[f] }.flatten
|
45
48
|
glob = glob.select do |f|
|
46
49
|
File.file?(f) && f !~ /fixtures\/|helpers\// && f !~ /\.rb$/
|
@@ -66,7 +69,7 @@ module QED
|
|
66
69
|
|
67
70
|
#TODO: load .config/qedrc.rb
|
68
71
|
|
69
|
-
|
72
|
+
demo_files.each do |file|
|
70
73
|
puts file unless quiet?
|
71
74
|
|
72
75
|
#strio = StringIO.new('')
|
@@ -76,19 +79,26 @@ module QED
|
|
76
79
|
#iotext = strio.string
|
77
80
|
#strio.close
|
78
81
|
|
79
|
-
|
82
|
+
ext = File.extname(file)
|
83
|
+
txt = File.read(file)
|
84
|
+
|
85
|
+
if ext == '.qed'
|
86
|
+
ext = file_type(txt)
|
87
|
+
end
|
88
|
+
|
89
|
+
case ext
|
80
90
|
#when '.qed'
|
81
91
|
# require_qedoc
|
82
92
|
# markup = Markup.new(File.read(file))
|
83
93
|
# text << markup.to_html
|
84
|
-
when '.rd', '.rdoc'
|
94
|
+
when '.rd', '.rdoc'
|
85
95
|
require_rdoc
|
86
96
|
markup = RDoc::Markup::ToHtml.new
|
87
|
-
text << markup.convert(
|
97
|
+
text << markup.convert(txt)
|
88
98
|
#text << markup.convert(iotext, formatter)
|
89
99
|
when '.md', '.markdown'
|
90
100
|
require_rdiscount
|
91
|
-
markdown = RDiscount.new(
|
101
|
+
markdown = RDiscount.new(txt)
|
92
102
|
text << markdown.to_html
|
93
103
|
end
|
94
104
|
text << "\n"
|
@@ -135,6 +145,21 @@ module QED
|
|
135
145
|
|
136
146
|
private
|
137
147
|
|
148
|
+
#
|
149
|
+
def file_type(text)
|
150
|
+
rdoc = text.index(/^\=/)
|
151
|
+
markdown = text.index(/^\#/)
|
152
|
+
if markdown && rdoc
|
153
|
+
rdoc < markdown ? '.rdoc' : '.markdown'
|
154
|
+
elsif rdoc
|
155
|
+
'.rdoc'
|
156
|
+
elsif markdown
|
157
|
+
'.markdown'
|
158
|
+
else # fallback to rdoc
|
159
|
+
'.rdoc'
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
138
163
|
#
|
139
164
|
def require_qedoc
|
140
165
|
@require_rdoc ||= (
|
@@ -146,8 +171,13 @@ module QED
|
|
146
171
|
#
|
147
172
|
def require_rdoc
|
148
173
|
@require_rdoc ||= (
|
149
|
-
|
150
|
-
|
174
|
+
begin
|
175
|
+
require 'rdoc/markup/to_html'
|
176
|
+
rescue LoadError
|
177
|
+
require 'rubygems'
|
178
|
+
gem 'rdoc'
|
179
|
+
retry
|
180
|
+
end
|
151
181
|
true
|
152
182
|
)
|
153
183
|
end
|