qed 2.9.0 → 2.9.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.index +69 -0
- data/.yardopts +3 -2
- data/{HISTORY.rdoc → HISTORY.md} +44 -32
- data/LICENSE.txt +25 -0
- data/{README.rdoc → README.md} +60 -51
- data/{qed/01_demos.rdoc → demo/01_demos.md} +3 -3
- data/{qed/02_advice.rdoc → demo/02_advice.md} +17 -17
- data/{qed/03_helpers.rdoc → demo/03_helpers.md} +10 -10
- data/{qed/04_samples.rdoc → demo/04_samples.md} +5 -5
- data/{qed/05_quote.rdoc → demo/05_quote.md} +7 -7
- data/{qed/07_toplevel.rdoc → demo/07_toplevel.md} +11 -11
- data/{qed/08_cross_script.rdoc → demo/08_cross_script.md} +9 -9
- data/{qed/09_cross_script.rdoc → demo/09_cross_script.md} +13 -14
- data/demo/10_constant_lookup.md +16 -0
- data/{qed/11_embedded_rules.rdoc → demo/11_embedded_rules.md} +13 -13
- data/{qed/99_issues/02_topcode.rdoc → demo/99_issues/02_topcode.md} +0 -0
- data/{qed → demo}/applique/ae.rb +0 -0
- data/{qed → demo}/applique/constant.rb +0 -0
- data/{qed → demo}/applique/env.rb +0 -0
- data/{qed → demo}/applique/fileutils.rb +0 -0
- data/{qed → demo}/applique/markup.rb +0 -0
- data/demo/applique/quote.md +8 -0
- data/{qed → demo}/applique/toplevel.rb +0 -0
- data/{qed → demo}/helpers/advice.rb +0 -0
- data/{qed → demo}/helpers/toplevel.rb +0 -0
- data/{qed → demo}/samples/data.txt +0 -0
- data/{qed → demo}/samples/table.yml +0 -0
- data/lib/qed.yml +41 -42
- data/lib/qed/cli.rb +2 -4
- data/lib/qed/cli/qed.rb +30 -3
- data/lib/qed/evaluator.rb +4 -1
- data/lib/qed/reporter/abstract.rb +1 -1
- data/lib/qed/session.rb +9 -2
- data/lib/qed/settings.rb +6 -122
- data/lib/qed/utils.rb +125 -0
- metadata +80 -56
- data/.config.rb +0 -24
- data/.ruby +0 -70
- data/COPYING.rdoc +0 -31
- data/lib/qed/rc.rb +0 -12
- data/qed/10_constant_lookup.rdoc +0 -16
- data/qed/applique/quote.rdoc +0 -8
@@ -1,6 +1,6 @@
|
|
1
|
-
|
1
|
+
# QED Demonstrandum
|
2
2
|
|
3
|
-
|
3
|
+
## Steps
|
4
4
|
|
5
5
|
QED demos are light-weight specification documents, highly suitable
|
6
6
|
to interface-driven design. The documents are divided up into
|
@@ -29,7 +29,7 @@ And this would have raised a NameError.
|
|
29
29
|
nobody_knows_method
|
30
30
|
end
|
31
31
|
|
32
|
-
|
32
|
+
## Defining Custom Assertions
|
33
33
|
|
34
34
|
The context in which the QED code is run is a self-extended module, thus
|
35
35
|
reusable macros can be created simply by defining a method.
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# Advice
|
2
2
|
|
3
3
|
Advice are event-based procedures that augment demonstrations.
|
4
4
|
They are used to keep demonstrations clean of extraneous,
|
@@ -9,7 +9,7 @@ Typically you will want to put advice definitions in applique
|
|
9
9
|
files, rather then place them directly in the demonstration
|
10
10
|
document, but you can do so, as you will see in this document.
|
11
11
|
|
12
|
-
|
12
|
+
## Before and After
|
13
13
|
|
14
14
|
QED supports *before* and *after* clauses in a specification
|
15
15
|
through the use of Before and After code blocks. These blocks
|
@@ -64,26 +64,26 @@ Only use *before* and *after* clauses when necessary --specifications
|
|
64
64
|
are generally more readable without them. Indeed, some developers
|
65
65
|
make a policy of avoiding them altogether. YMMV.
|
66
66
|
|
67
|
-
|
67
|
+
## Caveats of Before and After
|
68
68
|
|
69
69
|
Instead of using Before and After clauses, it is wiser to
|
70
70
|
define a reusable setup method. For example, in the helper
|
71
71
|
if we define a method such as #prepare_example.
|
72
72
|
|
73
|
-
|
74
|
-
|
75
|
-
|
73
|
+
def prepare_example
|
74
|
+
"Hello, World!"
|
75
|
+
end
|
76
76
|
|
77
77
|
Then we can reuse it in later code blocks.
|
78
78
|
|
79
|
-
|
80
|
-
|
79
|
+
example = prepare_example
|
80
|
+
example.assert == "Hello, World!"
|
81
81
|
|
82
82
|
The advantage to this is that it gives the reader an indication
|
83
83
|
of what is going on behind the scenes, rather the having
|
84
84
|
an object just magically appear.
|
85
85
|
|
86
|
-
|
86
|
+
## Event Targets
|
87
87
|
|
88
88
|
There is a small set of advice targets that do not come before or after,
|
89
89
|
rather they occur *upon* a particular event. These include +:pass+, +:fail+
|
@@ -95,13 +95,13 @@ These event targets can be advised by calling the +When+ method
|
|
95
95
|
with the target type as an argument along with the code block
|
96
96
|
to be run when the event is triggered.
|
97
97
|
|
98
|
-
|
98
|
+
x = []
|
99
99
|
|
100
|
-
|
101
|
-
|
102
|
-
|
100
|
+
When(:step) do |section|
|
101
|
+
section.text.scan(/^\*(.*?)$/) do |m|
|
102
|
+
x << $1.strip
|
103
|
+
end
|
103
104
|
end
|
104
|
-
end
|
105
105
|
|
106
106
|
Now let's see if it worked.
|
107
107
|
|
@@ -111,9 +111,9 @@ Now let's see if it worked.
|
|
111
111
|
|
112
112
|
So +x+ should now contain these three list samples.
|
113
113
|
|
114
|
-
|
114
|
+
x.assert == [ 'SampleA', 'SampleB', 'SampleC' ]
|
115
115
|
|
116
|
-
|
116
|
+
## Pattern Matchers
|
117
117
|
|
118
118
|
QED also supports comment match triggers. With the +When+ method one can
|
119
119
|
define procedures to run when a given pattern matches comment text.
|
@@ -159,7 +159,7 @@ that if 'then match #2' is found, will it be considered a complete match.
|
|
159
159
|
All regular expression slots are collected from all matches and passed to
|
160
160
|
the block. We can see that the rule matched this very paragraph.
|
161
161
|
|
162
|
-
|
162
|
+
@a.assert == [1,2]
|
163
163
|
|
164
164
|
This concludes the basic overview of QED's specification system, which
|
165
165
|
is itself a QED document. Yes, we eat our own dog food.
|
@@ -1,31 +1,31 @@
|
|
1
|
-
|
1
|
+
# Helpers
|
2
2
|
|
3
3
|
There are two ways to load advice scripts. Manually loaded
|
4
|
-
helpers act
|
4
|
+
helpers act pe-demonstrandum and so apply only to the currently
|
5
5
|
executing demo. Automaticly loaded helpers apply to all
|
6
6
|
demonstrandum within their preview.
|
7
7
|
|
8
8
|
Helper scripts can be written just like demonstration scripts,
|
9
9
|
or they can be defined as pure Ruby scripts.
|
10
10
|
|
11
|
-
|
11
|
+
## Automatic Helpers
|
12
12
|
|
13
13
|
Automatic helpers, known as the "applique" are loaded at the
|
14
14
|
start of a session and apply equally to all demonstrandum within
|
15
|
-
the same or lower directory as
|
15
|
+
the same or lower directory as the demo. These helpers are placed
|
16
16
|
in an +applique+ subdirectory. For instance this document uses,
|
17
|
-
|
17
|
+
[applique/env.rb](applique/env.rb).
|
18
18
|
|
19
|
-
|
19
|
+
## Manual Helpers
|
20
20
|
|
21
21
|
Manual helpers are loaded per-demonstration by using specially
|
22
22
|
marked links.
|
23
23
|
|
24
|
-
For example, because this link, Advice
|
25
|
-
begins with
|
24
|
+
For example, because this link, [Advice](qed://helpers/advice.rb),
|
25
|
+
begins with `qed:`, it will be used to load a helper. We can
|
26
26
|
see this with the following assertion.
|
27
27
|
|
28
|
-
|
28
|
+
pudding.assert.include?('loaded advice.rb')
|
29
29
|
|
30
30
|
No where in the demonstration have we defined +pudding+, but
|
31
31
|
it has been defined for us in the advice.rb helper script.
|
@@ -35,7 +35,7 @@ helper is keeping count of decriptive paragraphs. Since the
|
|
35
35
|
helper script was loaded two paragraphs back, the next count
|
36
36
|
will be 3.
|
37
37
|
|
38
|
-
|
38
|
+
count.assert == 3
|
39
39
|
|
40
40
|
Helpers are vital to building test-demonstration suites for
|
41
41
|
applications. But here again, only use them as necessary.
|
@@ -1,6 +1,6 @@
|
|
1
|
-
|
1
|
+
# Test Samples
|
2
2
|
|
3
|
-
|
3
|
+
## Flat-file Data
|
4
4
|
|
5
5
|
When creating testable demonstrations, there are times when sizable
|
6
6
|
chunks of data are needed. It is convenient to store such data in
|
@@ -19,7 +19,7 @@ Files are looked-up relative to the location of the current document.
|
|
19
19
|
If not found then they will be looked-up relative to the current
|
20
20
|
working directory.
|
21
21
|
|
22
|
-
|
22
|
+
## Tabular Data
|
23
23
|
|
24
24
|
The +Table+ method is similar to the +Data+ method except that it
|
25
25
|
expects a YAML file, and it can take a block to iterate the data over.
|
@@ -29,7 +29,7 @@ The arity of the table block corresponds to the number of columns in
|
|
29
29
|
each row of the table. Each row is assigned in turn and run through
|
30
30
|
the coded step. Consider the following example.
|
31
31
|
|
32
|
-
Every row in the
|
32
|
+
Every row in the [table.yml table](table.yml) will be assigned to
|
33
33
|
the block parameters and run through the subsequent assertion.
|
34
34
|
|
35
35
|
Table File.dirname(__FILE__) + '/samples/table.yml' do |x, y|
|
@@ -38,7 +38,7 @@ the block parameters and run through the subsequent assertion.
|
|
38
38
|
|
39
39
|
Without the block, the +Table+ methods simply returns the sample data.
|
40
40
|
|
41
|
-
|
41
|
+
## Considerations
|
42
42
|
|
43
43
|
Both Data and Table are some what "old fashion" approches to sample
|
44
44
|
data. New techinques using plain text blocks are more convenient
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# Quotes
|
2
2
|
|
3
3
|
We do not always want verbatim clauses to be interpreted as code.
|
4
4
|
Sometimes it would more useful to treat them a plain text to
|
@@ -7,9 +7,9 @@ which the preceeding paragraph can make use in a processing rule.
|
|
7
7
|
For example let say we want to make an example out of the following
|
8
8
|
text:
|
9
9
|
|
10
|
-
|
10
|
+
The file will contain
|
11
11
|
|
12
|
-
|
12
|
+
this text
|
13
13
|
|
14
14
|
The use of the colon (`:`) tells the processor that the next
|
15
15
|
segment is a plain text continuation of the current segment, rather
|
@@ -19,7 +19,7 @@ the end of the arguments list of any applicable processing rule.
|
|
19
19
|
Behind the scenes we created a rule to set the text to an instance
|
20
20
|
variable called @quote_text, and we can verify it is so.
|
21
21
|
|
22
|
-
|
22
|
+
@quote_text.assert == "The file will contain\n\nthis text"
|
23
23
|
|
24
24
|
Alternately we can use a colon (':') instead of ellipsis. We can repeat
|
25
25
|
the same statment as above.
|
@@ -27,11 +27,11 @@ the same statment as above.
|
|
27
27
|
For example let say we want to make an example out of the following
|
28
28
|
text:
|
29
29
|
|
30
|
-
|
30
|
+
The file will contain
|
31
31
|
|
32
|
-
|
32
|
+
different text
|
33
33
|
|
34
34
|
And again we can verify that it did in fact set the @quote_text variable.
|
35
35
|
|
36
|
-
|
36
|
+
@quote_text.assert == "The file will contain\n\ndifferent text"
|
37
37
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# Toplevel Simulation
|
2
2
|
|
3
3
|
QED simulates Ruby's TOPLEVEL environment in both the Demonstrandum
|
4
4
|
and the Applique contexts. This serves two important purposes.
|
@@ -10,31 +10,31 @@ the code it is intended to test.
|
|
10
10
|
Let's look at some examples. For starters, we have access to a class
|
11
11
|
defined at the "toplevel" in the applique.
|
12
12
|
|
13
|
-
|
13
|
+
ToplevelClass
|
14
14
|
|
15
15
|
We can also call a method defined in the toplevel.
|
16
16
|
|
17
|
-
|
17
|
+
toplevel_method.assert == true
|
18
18
|
|
19
19
|
At the demonstrandum level we can define reusable methods.
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
def demo_method
|
22
|
+
true
|
23
|
+
end
|
24
24
|
|
25
|
-
|
25
|
+
demo_method.assert == true
|
26
26
|
|
27
27
|
And at the demonstrandum level even singleton methods are accessible.
|
28
28
|
|
29
|
-
|
29
|
+
def self.singleton_method; true; end
|
30
30
|
|
31
|
-
|
31
|
+
singleton_method.assert == true
|
32
32
|
|
33
33
|
QED uses a self-extend modules to achieve this simulation, so the
|
34
34
|
contexts are in fact a bit more capable then even Ruby's TOPLEVEL.
|
35
35
|
For instance, #define_method can be used.
|
36
36
|
|
37
|
-
|
37
|
+
define_method(:named_method){ true }
|
38
38
|
|
39
|
-
|
39
|
+
named_method.assert == true
|
40
40
|
|
@@ -1,25 +1,25 @@
|
|
1
|
-
|
1
|
+
# Cross-Scripting Setup
|
2
2
|
|
3
3
|
We define some variables here to make sure it is
|
4
4
|
not visible in the next script.
|
5
5
|
|
6
6
|
Let's set two local variables.
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
a = 100
|
9
|
+
b = 200
|
10
10
|
|
11
11
|
And two instance varaibles.
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
@a = 1000
|
14
|
+
@b = 2000
|
15
15
|
|
16
16
|
Also let check how it effect constants.
|
17
17
|
|
18
|
-
|
18
|
+
CROSS_SCRIPT_CONSTANT = "cross?"
|
19
19
|
|
20
20
|
And a method.
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
def cross_script_method
|
23
|
+
"common"
|
24
|
+
end
|
25
25
|
|
@@ -1,29 +1,28 @@
|
|
1
|
-
|
1
|
+
# Cross-Scripting Check
|
2
2
|
|
3
3
|
Make sure local and instance variables from previous
|
4
4
|
QED scripts are not visible in this document.
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
expect NameError do
|
7
|
+
a.assert = 100
|
8
|
+
b.assert = 200
|
9
|
+
end
|
10
10
|
|
11
11
|
And two instance_varaibles
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
@a.assert! == 1000
|
14
|
+
@b.assert! == 2000
|
16
15
|
|
17
16
|
Method definitions also do not cross QED scripts.
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
expect NameError do
|
19
|
+
cross_script_method
|
20
|
+
end
|
22
21
|
|
23
22
|
Since each demo is encapsulated in a separated class scope, constants also
|
24
23
|
do not make their way across.
|
25
24
|
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
expect NameError do
|
26
|
+
CROSS_SCRIPT_CONSTANT
|
27
|
+
end
|
29
28
|
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Missing Constant
|
2
|
+
|
3
|
+
If a constant is missing it is because it was not found
|
4
|
+
in either the demos scope, the applique or at the toplevel.
|
5
|
+
|
6
|
+
begin
|
7
|
+
UnknownConstant
|
8
|
+
rescue => err
|
9
|
+
# no colon means toplevel
|
10
|
+
err.name.to_s.refute.include?('::')
|
11
|
+
end
|
12
|
+
|
13
|
+
A constant defined in the applique is visible.
|
14
|
+
|
15
|
+
APPLIQUE_CONSTANT.assert = true
|
16
|
+
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# Meta Code
|
2
2
|
|
3
3
|
All code steps are evaluated in a rescue clause. If an error occurs, it
|
4
4
|
is captured and reported through the test report, and execution continues.
|
@@ -6,20 +6,20 @@ However, sometimes this is not desired. To evaluate a step without the
|
|
6
6
|
rescue clause, and effective *fail fast*, append `^` mark to the end of
|
7
7
|
the desription text, like so. ^
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
When 'this is cool' do |text|
|
10
|
+
@text = text
|
11
|
+
end
|
12
12
|
|
13
13
|
Now, let's try it by saying, "this is cool":
|
14
14
|
|
15
|
-
|
15
|
+
And this is the text.
|
16
16
|
|
17
17
|
Did it work?
|
18
18
|
|
19
|
-
|
19
|
+
@text.assert == "And this is the text."
|
20
20
|
|
21
21
|
|
22
|
-
|
22
|
+
## Match Separator
|
23
23
|
|
24
24
|
The `When` method can take a list of String or Regexp as arguments.
|
25
25
|
If any of the strings contain `...`, the string will be split into
|
@@ -27,20 +27,20 @@ two at this point, which effective means that any text can occur
|
|
27
27
|
within this space. It behaves much like adding `((*.?))`, but parses
|
28
28
|
more quickly by dividing the string into multiple matches.
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
When 'Let /(\w+)/ be ... scared of /(\w+)/' do |name, monster|
|
31
|
+
@name = name
|
32
|
+
@monster = monster
|
33
|
+
end
|
34
34
|
|
35
35
|
Okay let's try it: Let John be very scared of Zombies.
|
36
36
|
|
37
37
|
So now what is the name?
|
38
38
|
|
39
|
-
|
39
|
+
@name.assert == "John"
|
40
40
|
|
41
41
|
What is the monster?
|
42
42
|
|
43
|
-
|
43
|
+
@monster.assert == "Zombies"
|
44
44
|
|
45
45
|
Did it work?
|
46
46
|
|
File without changes
|
data/{qed → demo}/applique/ae.rb
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|