qed 2.6.3 → 2.7.0

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