qed 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
+
@@ -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
+
@@ -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.
@@ -0,0 +1,4 @@
1
+ ---
2
+ - [ try , TRY ]
3
+ - [ me , ME ]
4
+
@@ -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 &quot;pass&quot;.
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 &quot;fail&quot;, 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&#8217;s prove that it can also fail:
166
+ </p>
167
+ <pre>
168
+ expect Assertion do
169
+ assert_integer(&quot;IV&quot;)
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 = &quot;BEFORE&quot;
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 = &quot;AFTER&quot;
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 == &quot;BEFORE&quot;
204
+
205
+ a = &quot;A&quot;
206
+ z = &quot;Z&quot;
207
+ </pre>
208
+ <p>
209
+ And now.
210
+ </p>
211
+ <pre>
212
+ z.assert == &quot;AFTER&quot;
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 = &quot;BEFORE AGAIN&quot;
225
+ end
226
+ </pre>
227
+ <p>
228
+ We will see it is the case.
229
+ </p>
230
+ <pre>
231
+ a.assert == &quot;BEFORE AGAIN&quot;
232
+ </pre>
233
+ <p>
234
+ Only use <b>before</b> and <b>after</b> clauses when necessary
235
+ &#8212;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
+ &#8217;&lt;doc-name&gt;.yaml&#8217; 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 &#8216;table.yaml&#8217; 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&#8217;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
+