qed 2.1.1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
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
-