qed 2.1.1 → 2.2.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.
Files changed (67) hide show
  1. data/COPYING +622 -344
  2. data/DIARY.rdoc +117 -0
  3. data/HISTORY +36 -0
  4. data/PROFILE +16 -0
  5. data/README.rdoc +69 -36
  6. data/REQUIRE +9 -0
  7. data/ROADMAP +12 -0
  8. data/VERSION +5 -0
  9. data/demo/01_demos.rdoc +56 -0
  10. data/demo/02_advice.rdoc +158 -0
  11. data/demo/03_helpers.rdoc +42 -0
  12. data/demo/04_fixtures.rdoc +29 -0
  13. data/demo/05_quote.rdoc +24 -0
  14. data/demo/07_toplevel.rdoc +42 -0
  15. data/demo/08_cross_script.rdoc +27 -0
  16. data/demo/09_cross_script.rdoc +27 -0
  17. data/demo/10_constant_lookup.rdoc +16 -0
  18. data/demo/applique/constant.rb +2 -0
  19. data/demo/applique/env.rb +5 -0
  20. data/demo/applique/fileutils.rb +1 -0
  21. data/demo/applique/markup.rb +10 -0
  22. data/demo/applique/quote.rb +4 -0
  23. data/demo/applique/toplevel.rb +15 -0
  24. data/demo/fixtures/data.txt +1 -0
  25. data/demo/fixtures/table.yml +5 -0
  26. data/demo/helpers/advice.rb +40 -0
  27. data/demo/helpers/sample.rb +4 -0
  28. data/demo/helpers/toplevel.rb +6 -0
  29. data/eg/hello_world.rdoc +15 -0
  30. data/{demo/error.rdoc → eg/view_error.rdoc} +0 -0
  31. data/{demo → eg}/website.rdoc +0 -0
  32. data/lib/qed.rb +20 -1
  33. data/lib/qed/advice.rb +4 -30
  34. data/lib/qed/advice/events.rb +6 -3
  35. data/lib/qed/advice/patterns.rb +37 -19
  36. data/lib/qed/applique.rb +85 -0
  37. data/lib/qed/command.rb +3 -5
  38. data/lib/qed/evaluator.rb +52 -56
  39. data/lib/qed/package.yml +5 -0
  40. data/lib/qed/parser.rb +149 -0
  41. data/lib/qed/profile.yml +16 -0
  42. data/lib/qed/reporter/{base.rb → abstract.rb} +17 -19
  43. data/lib/qed/reporter/bullet.rb +14 -16
  44. data/lib/qed/reporter/dotprogress.rb +7 -6
  45. data/lib/qed/reporter/html.rb +21 -3
  46. data/lib/qed/reporter/verbatim.rb +28 -26
  47. data/lib/qed/scope.rb +98 -82
  48. data/lib/qed/script.rb +21 -69
  49. data/lib/qed/session.rb +44 -3
  50. data/script/qedoc +2 -0
  51. data/script/test +2 -0
  52. metadata +74 -28
  53. data/doc/qedoc/index.html +0 -515
  54. data/doc/qedoc/jquery.js +0 -19
  55. data/meta/authors +0 -1
  56. data/meta/created +0 -1
  57. data/meta/description +0 -2
  58. data/meta/homepage +0 -1
  59. data/meta/name +0 -1
  60. data/meta/released +0 -1
  61. data/meta/repository +0 -1
  62. data/meta/requires +0 -5
  63. data/meta/ruby +0 -2
  64. data/meta/suite +0 -1
  65. data/meta/summary +0 -1
  66. data/meta/title +0 -1
  67. data/meta/version +0 -1
data/doc/qedoc/index.html DELETED
@@ -1,515 +0,0 @@
1
- <html>
2
- <head>
3
- <title>QED Demonstrandum</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 { color: #ccc; margin-top: 1.6em; }
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 Demonstrandum</h1>
93
-
94
- <h1>Table of Contents</h1>
95
-
96
- <div class="toc">
97
- </div>
98
- </div>
99
-
100
- <div id="content">
101
- <body>
102
- <h1>Demonstrations</h1>
103
- <h2>Standard Sections</h2>
104
- <p>
105
- QED demos are light-weight specification documents, highly suitable to
106
- interface-driven design. The documents are divided up into clauses
107
- separated by blank lines. Clauses that are flush to the left margin are
108
- always explanation or comment clauses. Indented clauses are always
109
- executable code.
110
- </p>
111
- <p>
112
- Each code section is executed in order of appearance, within a rescue
113
- wrapper that captures any failures or errors. If neither a failure or error
114
- occur then the code gets a “pass”.
115
- </p>
116
- <p>
117
- For example, the following passes:
118
- </p>
119
- <pre>
120
- (2 + 2).assert == 4
121
- </pre>
122
- <p>
123
- While the following would “fail”, as indicated by the raising
124
- of an Assertion error:
125
- </p>
126
- <pre>
127
- expect Assertion do
128
- (2 + 2).assert == 5
129
- end
130
- </pre>
131
- <p>
132
- And this would have raised a NameError:
133
- </p>
134
- <pre>
135
- expect NameError do
136
- nobody_knows_method
137
- end
138
- </pre>
139
- <h2>Neutral Code Blocks</h2>
140
- <p>
141
- There is no means of specifying that a code clause is neutral code, i.e.
142
- that it should be executed but not tested. Thus far, such a feature has
143
- proven to be a YAGNI.
144
- </p>
145
- <h2>Defining Custom Assertions</h2>
146
- <p>
147
- The context in which the QED code is run is a self-extended module, thus
148
- reusable macros can be created simply by defining a method.
149
- </p>
150
- <pre>
151
- def assert_integer(x)
152
- x.assert.is_a? Integer
153
- end
154
- </pre>
155
- <p>
156
- Now lets try out our new macro definition.
157
- </p>
158
- <pre>
159
- assert_integer(4)
160
- </pre>
161
- <p>
162
- Let’s prove that it can also fail:
163
- </p>
164
- <pre>
165
- expect Assertion do
166
- assert_integer("IV")
167
- end
168
- </pre>
169
- </body>
170
- <body>
171
- <h1>Advice</h1>
172
- <p>
173
- Advice are wrapper methods that augment demonstrations. They are used to
174
- keep demonstrations clean of extraneous, repetitive and merely
175
- adminstrative code that the reader does not need to see over and over.
176
- </p>
177
- <h2>Before and After</h2>
178
- <p>
179
- QED supports <b>before</b> and <b>after</b> clauses in a specification
180
- through the use of Before and After code blocks. These blocks are executed
181
- at the beginning and at the end of each indicated step.
182
- </p>
183
- <p>
184
- We use a <b>before</b> clause if we want to setup some code at the start of
185
- each code step.
186
- </p>
187
- <pre>
188
- a, z = nil, nil
189
-
190
- Before do
191
- a = "BEFORE"
192
- end
193
- </pre>
194
- <p>
195
- And an <b>after</b> clause to teardown objects after a code step.
196
- </p>
197
- <pre>
198
- After do
199
- z = "AFTER"
200
- end
201
- </pre>
202
- <p>
203
- Notice we assigned <tt>a</tt> and <tt>z</tt> before the block. This was to
204
- ensure their visibility in the scope later. Now, lets verify that the
205
- <b>before</b> and <b>after</b> clauses work.
206
- </p>
207
- <pre>
208
- a.assert == "BEFORE"
209
-
210
- a = "A"
211
- z = "Z"
212
- </pre>
213
- <p>
214
- And now.
215
- </p>
216
- <pre>
217
- z.assert == "AFTER"
218
- </pre>
219
- <p>
220
- There can be more than one before and after clause at a time. If we define
221
- a new <b>before</b> or <b>after</b> clause later in the document, it will
222
- be appended to the current list of clauses in use.
223
- </p>
224
- <p>
225
- As a demonstration of this:
226
- </p>
227
- <pre>
228
- b = nil
229
-
230
- Before do
231
- b = "BEFORE AGAIN"
232
- end
233
- </pre>
234
- <p>
235
- We will see it is the case.
236
- </p>
237
- <pre>
238
- b.assert == "BEFORE AGAIN"
239
- </pre>
240
- <p>
241
- Only use <b>before</b> and <b>after</b> clauses when necessary
242
- —specifications are generally more readable without them. Indeed,
243
- some developers make a policy of avoiding them altogether. YMMV.
244
- </p>
245
- <h2>Caveats of Before and After</h2>
246
- <p>
247
- Instead of using Before and After clauses, it is wiser to define a reusable
248
- setup method. For example, in the helper if we define a method such as
249
- #prepare_example.
250
- </p>
251
- <pre>
252
- def prepare_example
253
- "Hello, World!"
254
- end
255
- </pre>
256
- <p>
257
- Then we can reuse it in later code blocks.
258
- </p>
259
- <pre>
260
- example = prepare_example
261
- example.assert == "Hello, World!"
262
- </pre>
263
- <p>
264
- The advantage to this is that it gives the reader an indication of what is
265
- going on behind the scenes, rather the having an object just magically
266
- appear.
267
- </p>
268
- <h2>Event Targets</h2>
269
- <p>
270
- There is a small set of advice targets that do not come before or after an
271
- event, rather they occur <b>upon</b> a particular event. These include
272
- <tt>:load</tt> and <tt>:unload</tt>, for when a new helper is loaded;
273
- <tt>:pass</tt>, <tt>:fail</tt> and <tt>:error</tt> for when a code block
274
- passes, fails or raises an error; and <tt>:tag</tt> which is a low-level
275
- target triggered upon parsing each element in the HTML conversion of the
276
- demonstration.
277
- </p>
278
- <p>
279
- These event targets can be advised by calling the <tt>When</tt> method with
280
- the target type as an argument along with the code block to be run when the
281
- event is triggered.
282
- </p>
283
- <pre>
284
- x = []
285
-
286
- When(:tag) do |element|
287
- x &lt;&lt; element.text.strip if element.name == 'li'
288
- end
289
- </pre>
290
- <p>
291
- Not let see it is worked:
292
- </p>
293
- <ul>
294
- <li>SampleA
295
-
296
- </li>
297
- <li>SampleB
298
-
299
- </li>
300
- <li>SampleC
301
-
302
- </li>
303
- </ul>
304
- <p>
305
- So <tt>x</tt> should now contain these three list samples.
306
- </p>
307
- <pre>
308
- x.assert == [ 'SampleA', 'SampleB', 'SampleC' ]
309
- </pre>
310
- <h2>Pattern Matchers</h2>
311
- <p>
312
- QED also supports comment match triggers. With the <tt>When</tt> method one
313
- can define procedures to run when a given pattern matches comment text. For
314
- example:
315
- </p>
316
- <pre>
317
- When 'given a setting @a equal to (((\d+)))' do |n|
318
- @a = n.to_i
319
- end
320
- </pre>
321
- <p>
322
- Now, @a will be set to 1 whenever a comment like this one contains,
323
- “given a setting @a equal to 1”.
324
- </p>
325
- <pre>
326
- @a.assert == 1
327
- </pre>
328
- <p>
329
- A string pattern is translated into a regular expression. In fact, you can
330
- use a regular expression if you need more control over the match. When
331
- using a string all spaces are converted to <tt>\s+</tt> and anything within
332
- double-parenthesis is treated as raw regular expression. Since the above
333
- example has (((\d+))), the actual regular expression contains
334
- <tt>(\d+)</tt>, so any number can be used. For example, “given a
335
- setting @a equal to 2”.
336
- </p>
337
- <pre>
338
- @a.assert == 2
339
- </pre>
340
- <p>
341
- Typically you will want to put triggers is helper files, rather then place
342
- them directly in the demonstration document.
343
- </p>
344
- <p>
345
- This concludes the basic overview of QED’s specification system,
346
- which is itself a QED document. Yes, we eat our own dog food.
347
- </p>
348
- </body>
349
- <body>
350
- <h1>Helpers</h1>
351
- <p>
352
- There are two ways to load advice scripts. Either per demonstration or
353
- globally. Per demonstration helpers apply only to the current
354
- demonstration. Global helpers apply to all demonstrations.
355
- </p>
356
- <h2>Global Helpers</h2>
357
- <p>
358
- Global helpers are loaded at the start of a session and apply equally to
359
- all demonstrations in a suite.
360
- </p>
361
- <h2>Local Helpers</h2>
362
- <p>
363
- Helper scripts can be written just a demonstration scripts, or they can be
364
- defined as pure Ruby scripts. Either way they are loaded per-demonstration
365
- by using specially marked links.
366
- </p>
367
- <p>
368
- For example, because this link, <a href="qed://helpers/advice.rb">Advice</a>, begins with <tt>require:</tt>,
369
- it will be used to load a global helper. We can see this with the
370
- following:
371
- </p>
372
- <pre>
373
- pudding.assert.include?('load advice.rb')
374
- </pre>
375
- <p>
376
- No where in the demonstration have we defined <tt>pudding</tt>, but it has
377
- been defined for us in the advice.rb helper script.
378
- </p>
379
- <p>
380
- We can also see that the generic When clause in our advice helper is
381
- keeping count of descriptions. Since the helper script was loaded three
382
- paragraphs back, the count will be 3.
383
- </p>
384
- <pre>
385
- count.assert == 3
386
- </pre>
387
- <p>
388
- Helpers are vital to building test-demonstration suites for applications.
389
- But here again, only use them as necessary. The more helpers you use the
390
- more difficult your demos will be to follow.
391
- </p>
392
- </body>
393
- <body>
394
- <h1>Fixtures</h1>
395
- <h2>Flat-file Data</h2>
396
- <p>
397
- When creating testable demonstrations, there are times when sizable chunks
398
- of data are needed. It is convenient to store such data in separate files.
399
- The <tt>Data</tt> method makes is easy to load such files.
400
- </p>
401
- <pre>
402
- Data('fixtures/data.txt').assert =~ /dolor/
403
- </pre>
404
- <p>
405
- All files are found relative to the location of current document.
406
- </p>
407
- <h2>Tabular Data</h2>
408
- <p>
409
- The <tt>Table</tt> method is similar to the <tt>Data</tt> method except
410
- that it expects a YAML file, and it can take a block to iterate the data
411
- over. This makes it easy to test tables of examples.
412
- </p>
413
- <p>
414
- The arity of the table block corresponds to the number of columns in each
415
- row of the table. Each row is assigned in turn and run through the coded
416
- step. Consider the following example:
417
- </p>
418
- <p>
419
- Every row in the <a href="http://table.yml">table.yml table</a> will be
420
- assigned to the block parameters and run through the subsequent assertion.
421
- </p>
422
- <pre>
423
- Table 'fixtures/table.yml' do |x, y|
424
- x.upcase.assert == y
425
- end
426
- </pre>
427
- </body>
428
-
429
- </div>
430
- </div>
431
-
432
- </body>
433
-
434
- </html>
435
-
436
- <script src="../assets/scripts/spec.js" type="text/javascript" language="javascript"></script>
437
-
438
- <script type="text/javascript" language="javascript">
439
- /*****************************************************************
440
- * $.toc()
441
- * by rebecca murphey
442
- * rmurphey gmail com
443
- *
444
- * This function is called on its own and takes as an argument
445
- * a list of selectors with which it will build a table of
446
- * contents.
447
- *
448
- * The first selector will make up the top level of the TOC;
449
- * the second selector will make up the second level of the TOC;
450
- * etc.
451
- *
452
- * This function returns a div containing nested unordered lists;
453
- * each list item is linked to an anchor tag added before the item
454
- * on the page.
455
- *
456
- * usage: $.toc('h1,h2,h3').prependTo('body');
457
- ************************************************************************/
458
- (function($) {
459
- $.toc = function(tocList) {
460
- $(tocList).addClass('jquery-toc');
461
- var tocListArray = tocList.split(',');
462
- $.each(tocListArray, function(i,v) { tocListArray[i] = $.trim(v); });
463
- var $elements = $('.jquery-toc');
464
- $('body').append('<div></div>');
465
- var $toc = $('body div:last');
466
- var lastLevel = 1;
467
- $toc.append('<ul class="jquery-toc-1"></ul>');
468
- $elements.each(function() {
469
- var $e = $(this);
470
- var text = $e.text();
471
- var anchor = text.replace(/ /g,'-');
472
- $e.before('<a name="' + anchor + '"></a>');
473
- var level;
474
- $.each(tocListArray, function(i,v) {
475
- if (v.match(' ')) {
476
- var vArray = v.split(' ');
477
- var e = vArray[vArray.length - 1];
478
- } else { e = v; }
479
- if ($e.is(e)) { level = i+1; }
480
- });
481
- var className = 'jquery-toc-' + level;
482
- var li = '<li><a href="#' + anchor + '">' + text + '</a></li>';
483
- if (level == lastLevel) {
484
- $('ul.' + className + ':last',$toc).append(li);
485
- } else if (level > lastLevel) {
486
- var parentLevel = level - 1;
487
- var parentClassName = 'jquery-toc-' + parentLevel;
488
- $('ul.' + parentClassName + ':last',$toc).
489
- append('<ul class="' + className + '"></ul>');
490
- $('ul.' + className + ':last',$toc).append(li);
491
- } else if (level < lastLevel) {
492
- $('ul.' + className + ':last',$toc).append(li);
493
- }
494
- lastLevel = level;
495
- });
496
- var $toc_ul = $('ul.jquery-toc-1',$toc);
497
- $toc.remove();
498
- return($toc_ul);
499
- }
500
- })(jQuery);
501
- </script>
502
-
503
- <script>
504
- function toc_toggle() {
505
- $('#toc_side').toggle();
506
- $("pre").addClass("pass");
507
- $("pre:contains('FAIL:')").addClass("fail");
508
- $("pre:contains('ERROR:')").addClass("error");
509
- };
510
-
511
- $.toc('#content h1,h2,h3,h4').appendTo('.toc');
512
-
513
- toc_toggle();
514
- </script>
515
-