qed 2.6.3 → 2.7.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 (55) hide show
  1. data/.ruby +4 -3
  2. data/.yardopts +3 -0
  3. data/HISTORY.rdoc +71 -35
  4. data/README.rdoc +9 -10
  5. data/bin/qed +1 -1
  6. data/bin/qedoc +2 -1
  7. data/lib/qed.rb +2 -5
  8. data/lib/qed.yml +4 -3
  9. data/lib/qed/applique.rb +57 -24
  10. data/lib/qed/cli.rb +8 -0
  11. data/lib/qed/cli/qed.rb +124 -0
  12. data/lib/qed/demo.rb +35 -39
  13. data/lib/qed/document.rb +5 -3
  14. data/lib/qed/document/template.rhtml +1 -0
  15. data/lib/qed/evaluator.rb +227 -199
  16. data/lib/qed/parser.rb +60 -282
  17. data/lib/qed/reporter/abstract.rb +54 -58
  18. data/lib/qed/reporter/dotprogress.rb +6 -4
  19. data/lib/qed/reporter/html.rb +112 -31
  20. data/lib/qed/reporter/tapy.rb +95 -125
  21. data/lib/qed/reporter/verbatim.rb +80 -38
  22. data/lib/qed/scope.rb +35 -48
  23. data/lib/qed/session.rb +35 -140
  24. data/lib/qed/settings.rb +104 -67
  25. data/lib/qed/step.rb +237 -0
  26. data/{spec → qed}/01_demos.rdoc +0 -0
  27. data/{spec → qed}/02_advice.rdoc +18 -7
  28. data/qed/03_helpers.rdoc +44 -0
  29. data/{spec → qed}/04_samples.rdoc +4 -4
  30. data/{spec → qed}/05_quote.rdoc +3 -3
  31. data/{spec → qed}/07_toplevel.rdoc +0 -0
  32. data/{spec → qed}/08_cross_script.rdoc +0 -0
  33. data/{spec → qed}/09_cross_script.rdoc +0 -0
  34. data/{spec → qed}/10_constant_lookup.rdoc +2 -2
  35. data/qed/11_embedded_rules.rdoc +46 -0
  36. data/{test/integration/topcode.rdoc → qed/99_issues/02_topcode.rdoc} +0 -0
  37. data/{spec → qed}/applique/constant.rb +0 -0
  38. data/{spec → qed}/applique/env.rb +0 -0
  39. data/{spec → qed}/applique/fileutils.rb +0 -0
  40. data/{spec → qed}/applique/markup.rb +0 -0
  41. data/{spec → qed}/applique/toplevel.rb +0 -0
  42. data/{spec → qed}/helpers/advice.rb +6 -7
  43. data/{spec → qed}/helpers/toplevel.rb +0 -0
  44. data/{spec → qed}/samples/data.txt +0 -0
  45. data/{spec → qed}/samples/table.yml +0 -0
  46. metadata +44 -39
  47. data/LICENSE.rdoc +0 -31
  48. data/SPECSHEET.rdoc +0 -456
  49. data/lib/qed/advice.rb +0 -158
  50. data/lib/qed/reporter/bullet.rb +0 -91
  51. data/lib/qed/reporter/dtrace.rb +0 -67
  52. data/lib/yard-qed.rb +0 -1
  53. data/spec/03_helpers.rdoc +0 -43
  54. data/spec/applique/quote.rb +0 -4
  55. data/spec/helpers/sample.rb +0 -4
@@ -1,456 +0,0 @@
1
- = Demonstrations
2
-
3
- == Steps
4
-
5
- QED demos are light-weight specification documents, highly suitable
6
- to interface-driven design. The documents are divided up into
7
- steps separated by blank lines. Steps that are flush to the
8
- left margin are always explanatory comments. Indented steps are
9
- either executable code or plain text samples.
10
-
11
- Each step is executed in order of appearance within a rescue wrapper
12
- that captures any failures or errors. If neither a failure or error
13
- occur then the step gets a "pass".
14
-
15
- For example, the following passes.
16
-
17
- (2 + 2).assert == 4
18
-
19
- While the following would "fail", as indicated by the raising of
20
- an Assertion error.
21
-
22
- expect Assertion do
23
- (2 + 2).assert == 5
24
- end
25
-
26
- And this would have raised a NameError.
27
-
28
- expect NameError do
29
- nobody_knows_method
30
- end
31
-
32
- == Defining Custom Assertions
33
-
34
- The context in which the QED code is run is a self-extended module, thus
35
- reusable macros can be created simply by defining a method.
36
-
37
- def assert_integer(x)
38
- x.assert.is_a? Integer
39
- end
40
-
41
- Now lets try out our new macro definition.
42
-
43
- assert_integer(4)
44
-
45
- Let's prove that it can also fail.
46
-
47
- expect Assertion do
48
- assert_integer("IV")
49
- end
50
-
51
-
52
- = Advice
53
-
54
- Advice are event-based procedures that augment demonstrations.
55
- They are used to keep demonstrations clean of extraneous,
56
- repetitive and merely adminstrative code that the reader does
57
- not need to see over and over.
58
-
59
- Typically you will want to put advice definitions is applique
60
- files, rather then place them directly in the demonstration
61
- document, but you can do so, as you will see in this document.
62
-
63
- == Before and After
64
-
65
- QED supports *before* and *after* clauses in a specification
66
- through the use of Before and After code blocks. These blocks
67
- are executed at the beginning and at the end of each indicated
68
- step.
69
-
70
- We use a *before* clause if we want to setup some code at the
71
- start of each code step.
72
-
73
- a, z = nil, nil
74
-
75
- Before do
76
- a = "BEFORE"
77
- end
78
-
79
- And an *after* clause to teardown objects after a code step.
80
-
81
- After do
82
- z = "AFTER"
83
- end
84
-
85
- Notice we assigned +a+ and +z+ before the block. This was to ensure
86
- their visibility in the scope later. Now, lets verify that the *before*
87
- and *after* clauses work.
88
-
89
- a.assert == "BEFORE"
90
-
91
- a = "A"
92
- z = "Z"
93
-
94
- And now.
95
-
96
- z.assert == "AFTER"
97
-
98
- There can be more than one before and after clause at a time. If we
99
- define a new *before* or *after* clause later in the document,
100
- it will be appended to the current list of clauses in use.
101
-
102
- As a demonstration of this,
103
-
104
- b = nil
105
-
106
- Before do
107
- b = "BEFORE AGAIN"
108
- end
109
-
110
- We will see it is the case.
111
-
112
- b.assert == "BEFORE AGAIN"
113
-
114
- Only use *before* and *after* clauses when necessary --specifications
115
- are generally more readable without them. Indeed, some developers
116
- make a policy of avoiding them altogether. YMMV.
117
-
118
- == Caveats of Before and After
119
-
120
- Instead of using Before and After clauses, it is wiser to
121
- define a reusable setup method. For example, in the helper
122
- if we define a method such as #prepare_example.
123
-
124
- def prepare_example
125
- "Hello, World!"
126
- end
127
-
128
- Then we can reuse it in later code blocks.
129
-
130
- example = prepare_example
131
- example.assert == "Hello, World!"
132
-
133
- The advantage to this is that it gives the reader an indication
134
- of what is going on behind the scenes, rather the having
135
- an object just magically appear.
136
-
137
- == Event Targets
138
-
139
- There is a small set of advice targets that do not come before or after,
140
- rather they occur *upon* a particular event. These include +:load+
141
- and +:unload+ for when a new helper is loaded; +:pass+, +:fail+ and +:error+
142
- for when a code block passes, fails or raises an error; and +:head+, +:desc:+,
143
- +:code+ and +:data:+ which targets the immediate processing of a text block
144
- and code excecution.
145
-
146
- These event targets can be advised by calling the +When+ method
147
- with the target type as an argument along with the code block
148
- to be run when the event is triggered.
149
-
150
- x = []
151
-
152
- When(:text) do |section|
153
- section.text.scan(/^\*(.*?)$/) do |m|
154
- x << $1.strip
155
- end
156
- end
157
-
158
- Not let see if it worked.
159
-
160
- * SampleA
161
- * SampleB
162
- * SampleC
163
-
164
- So +x+ should now contain these three list samples.
165
-
166
- x.assert == [ 'SampleA', 'SampleB', 'SampleC' ]
167
-
168
- == Pattern Matchers
169
-
170
- QED also supports comment match triggers. With the +When+ method one can
171
- define procedures to run when a given pattern matches comment text.
172
-
173
- When 'given a setting @a equal to (((\d+)))' do |n|
174
- @a = n.to_i
175
- end
176
-
177
- Now, @a will be set to 1 whenever a comment like this one contains,
178
- "given a setting @a equal to 1".
179
-
180
- @a.assert == 1
181
-
182
- A string pattern is translated into a regular expression. In fact, you can
183
- use a regular expression if you need more control over the match. When
184
- using a string all spaces are converted to <tt>\s+</tt> and anything within
185
- double-parenthesis is treated as raw regular expression. Since the above
186
- example has (((\d+))), the actual regular expression contains <tt>(\d+)</tt>,
187
- so any number can be used. For example, "given a setting @a equal to 2".
188
-
189
- @a.assert == 2
190
-
191
- When clauses can also use consecutive pattern matching. For instance
192
- we could write,
193
-
194
- When 'first match #(((\d+)))', 'then match #(((\d+)))' do |i1, i2|
195
- @a = [i1.to_i, i2.to_i]
196
- end
197
-
198
- So that 'first match #1' will be looked for first, and only after
199
- that if 'then match #2' is found, will it be condiered a complete match.
200
- All regular expression slots are collected from all matches and passed to
201
- the block. We can see that the rule matched this very paragraph.
202
-
203
- @a.assert == [1,2]
204
-
205
- This concludes the basic overview of QED's specification system, which
206
- is itself a QED document. Yes, we eat our own dog food.
207
-
208
-
209
- = Helpers
210
-
211
- There are two ways to load advice scripts. Either per
212
- demonstration or globally. Per demonstration helpers
213
- apply only to the current demonstration. Global helpers
214
- apply to all demonstrations.
215
-
216
- == Global Helpers
217
-
218
- Global helpers are loaded at the start of a session and
219
- apply equally to all demonstrations in a suite. Global
220
- helpers are simply Ruby scripts and are placed in an
221
- +environment+ subdirectory. For instance this document
222
- is used <a href="environment/env.rb">environment/env.rb</a>.
223
-
224
- == Local Helpers
225
-
226
- Helper scripts can be written just like demonstration scripts,
227
- or they can be defined as pure Ruby scripts. Either way
228
- they are loaded per-demonstration by using specially
229
- marked links.
230
-
231
- For example, because this link, Advice[qed://helpers/advice.rb],
232
- begins with +qed:+, it will be used to load a global
233
- helper. We can see this with the following assertion.
234
-
235
- pudding.assert.include?('load advice.rb')
236
-
237
- No where in the demonstration have we defined +pudding+, but
238
- it has been defined for us in the advice.rb helper script.
239
-
240
- We can also see that the generic When clause in our advice
241
- helper is keeping count of decriptive paragraphs. Since the
242
- helper script was loaded two paragraphs back, the next count
243
- will be 3.
244
-
245
- count.assert == 3
246
-
247
- Helpers are vital to building test-demonstration suites for
248
- applications. But here again, only use them as necessary.
249
- The more helpers you use the more difficult your demos will
250
- be to follow.
251
-
252
-
253
- = Test Samples
254
-
255
- == Flat-file Data
256
-
257
- When creating testable demonstrations, there are times when sizable
258
- chunks of data are needed. It is convenient to store such data in
259
- separate files. The +Data+ method makes is easy to utilize them.
260
-
261
- Data('qed/samples/data.txt').assert =~ /dolor/
262
-
263
- The +Data+ method can also take a block which passes the data
264
- as the block's only argument.
265
-
266
- Data('qed/samples/data.txt') do |data|
267
- data.assert =~ /dolor/
268
- end
269
-
270
- Files are looked-up relative to the location of the current document.
271
- If not found then they will be looked-up relative to the current
272
- working directory.
273
-
274
- == Tabular Data
275
-
276
- The +Table+ method is similar to the +Data+ method except that it
277
- expects a YAML file, and it can take a block to iterate the data over.
278
- This makes it easy to test tables of examples.
279
-
280
- The arity of the table block corresponds to the number of columns in
281
- each row of the table. Each row is assigned in turn and run through
282
- the coded step. Consider the following example.
283
-
284
- Every row in the {table.yml table}[table.yml] will be assigned to
285
- the block parameters and run through the subsequent assertion.
286
-
287
- Table 'qed/samples/table.yml' do |x, y|
288
- x.upcase.assert == y
289
- end
290
-
291
- Without the block, the +Table+ methods simply returns the sample data.
292
-
293
- == Considerations
294
-
295
- Both Data and Table are some what "old fashion" approches to sample
296
- data. New techinques using plain text blocks are more convenient
297
- in that the data can be stored directly in the demonstration itself.
298
- However, for especially large data sets and external file is still
299
- the better option, and +Data+ and +Table+ make them quite easy to
300
- access.
301
-
302
-
303
- = Quotes
304
-
305
- We do not always want verbatim clauses to be interpreted as code.
306
- Sometimes it would more useful to treat them a plain text to
307
- which the preceeding paragraph can make use in a processing rule.
308
-
309
- For example let say we want to make an example out of the following
310
- text...
311
-
312
- The file will contain
313
-
314
- this text
315
-
316
- The use of the ellipsis ('...') tells the processor that the next
317
- segment is a plain text continuation of the current segment, rather
318
- than example code. If the next segment is varbatim it will be added to
319
- the end of the arguments list of any applicable processing rule.
320
-
321
- Behind the scenes we created a rule to set the text to an instance
322
- variable called @quote_text, and we can verify it is so.
323
-
324
- @quote_text.assert == "The file will contain\n\nthis text"
325
-
326
- Alternately we can use a colon (':') instead of ellipsis. We can repeat
327
- the same statment as above.
328
-
329
- For example let say we want to make an example out of the following
330
- text:
331
-
332
- The file will contain
333
-
334
- different text
335
-
336
- And again we can verify that it did in fact set the @quote_text variable.
337
-
338
- @quote_text.assert == "The file will contain\n\ndifferent text"
339
-
340
-
341
- = Toplevel Simulation
342
-
343
- QED simulates Ruby's TOPLEVEL environment in both the Demonstrandum
344
- and the Applique contexts. This serves two important purposes.
345
- First, it provides the tester the environment that is most intutive.
346
- And second, and more importantly, it stays out of the actual
347
- TOPLEVEL space to prevent any potential interferece with any of
348
- the code it is intended to test.
349
-
350
- Let's look at some examples. For starters, we have access to a class
351
- defined at the "toplevel" in the applique.
352
-
353
- ToplevelClass
354
-
355
- We can also call a method defined in the toplevel.
356
-
357
- toplevel_method.assert == true
358
-
359
- At the demonstrandum level we can define reusable methods.
360
-
361
- def demo_method
362
- true
363
- end
364
-
365
- demo_method.assert == true
366
-
367
- And at the demonstrandum level even singleton methods are accessible.
368
-
369
- def self.singleton_method; true; end
370
-
371
- singleton_method.assert == true
372
-
373
- QED uses a self-extend modules to achieve this simulation, so the
374
- contexts are in fact a bit more capable then even Ruby's TOPLEVEL.
375
- For instance, #define_method can be used.
376
-
377
- define_method(:named_method){ true }
378
-
379
- named_method.assert == true
380
-
381
-
382
- = Cross-Scripting Setup
383
-
384
- We define some variables here to make sure it is
385
- not visible in the next script.
386
-
387
- Let's set two local variables.
388
-
389
- a = 100
390
- b = 200
391
-
392
- And two instance varaibles.
393
-
394
- @a = 1000
395
- @b = 2000
396
-
397
- Also let check how it effect constants.
398
-
399
- CROSS_SCRIPT_CONSTANT = "cross?"
400
-
401
- And a method.
402
-
403
- def cross_script_method
404
- "common"
405
- end
406
-
407
-
408
- = Cross-Scripting Check
409
-
410
- Make sure local and instance variables from previous
411
- QED scripts are not visible in this document.
412
-
413
- expect NameError do
414
- a.assert = 100
415
- b.assert = 200
416
- end
417
-
418
- And two instance_varaibles
419
-
420
- @a.assert! == 1000
421
- @b.assert! == 2000
422
-
423
-
424
- Method definitions also do not cross QED scripts.
425
-
426
- expect NameError do
427
- cross_script_method
428
- end
429
-
430
- Since each demo is encapsulated in a separated class scope, constants also
431
- do not make their way across.
432
-
433
- expect NameError do
434
- CROSS_SCRIPT_CONSTANT
435
- end
436
-
437
-
438
- = Missing Constant
439
-
440
- If a constant is missing it is because it was not found
441
- in either the demos scope, the applique or the toplevel.
442
-
443
- begin
444
- UnknownConstant
445
- rescue => err
446
- # no colon means toplevel
447
- /[^:]UnknownConstant/ =~ err.message
448
- end
449
-
450
- A constant defined in the applique is visible.
451
-
452
- APPLIQUE_CONSTANT.assert = true
453
-
454
-
455
-
456
-