qed 2.1.1 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +622 -344
- data/DIARY.rdoc +117 -0
- data/HISTORY +36 -0
- data/PROFILE +16 -0
- data/README.rdoc +69 -36
- data/REQUIRE +9 -0
- data/ROADMAP +12 -0
- data/VERSION +5 -0
- data/demo/01_demos.rdoc +56 -0
- data/demo/02_advice.rdoc +158 -0
- data/demo/03_helpers.rdoc +42 -0
- data/demo/04_fixtures.rdoc +29 -0
- data/demo/05_quote.rdoc +24 -0
- data/demo/07_toplevel.rdoc +42 -0
- data/demo/08_cross_script.rdoc +27 -0
- data/demo/09_cross_script.rdoc +27 -0
- data/demo/10_constant_lookup.rdoc +16 -0
- data/demo/applique/constant.rb +2 -0
- data/demo/applique/env.rb +5 -0
- data/demo/applique/fileutils.rb +1 -0
- data/demo/applique/markup.rb +10 -0
- data/demo/applique/quote.rb +4 -0
- data/demo/applique/toplevel.rb +15 -0
- data/demo/fixtures/data.txt +1 -0
- data/demo/fixtures/table.yml +5 -0
- data/demo/helpers/advice.rb +40 -0
- data/demo/helpers/sample.rb +4 -0
- data/demo/helpers/toplevel.rb +6 -0
- data/eg/hello_world.rdoc +15 -0
- data/{demo/error.rdoc → eg/view_error.rdoc} +0 -0
- data/{demo → eg}/website.rdoc +0 -0
- data/lib/qed.rb +20 -1
- data/lib/qed/advice.rb +4 -30
- data/lib/qed/advice/events.rb +6 -3
- data/lib/qed/advice/patterns.rb +37 -19
- data/lib/qed/applique.rb +85 -0
- data/lib/qed/command.rb +3 -5
- data/lib/qed/evaluator.rb +52 -56
- data/lib/qed/package.yml +5 -0
- data/lib/qed/parser.rb +149 -0
- data/lib/qed/profile.yml +16 -0
- data/lib/qed/reporter/{base.rb → abstract.rb} +17 -19
- data/lib/qed/reporter/bullet.rb +14 -16
- data/lib/qed/reporter/dotprogress.rb +7 -6
- data/lib/qed/reporter/html.rb +21 -3
- data/lib/qed/reporter/verbatim.rb +28 -26
- data/lib/qed/scope.rb +98 -82
- data/lib/qed/script.rb +21 -69
- data/lib/qed/session.rb +44 -3
- data/script/qedoc +2 -0
- data/script/test +2 -0
- metadata +74 -28
- data/doc/qedoc/index.html +0 -515
- data/doc/qedoc/jquery.js +0 -19
- data/meta/authors +0 -1
- data/meta/created +0 -1
- data/meta/description +0 -2
- data/meta/homepage +0 -1
- data/meta/name +0 -1
- data/meta/released +0 -1
- data/meta/repository +0 -1
- data/meta/requires +0 -5
- data/meta/ruby +0 -2
- data/meta/suite +0 -1
- data/meta/summary +0 -1
- data/meta/title +0 -1
- data/meta/version +0 -1
@@ -0,0 +1,42 @@
|
|
1
|
+
= Helpers
|
2
|
+
|
3
|
+
There are two ways to load advice scripts. Either per
|
4
|
+
demonstration or globally. Per demonstration helpers
|
5
|
+
apply only to the current demonstration. Global helpers
|
6
|
+
apply to all demonstrations.
|
7
|
+
|
8
|
+
== Global Helpers
|
9
|
+
|
10
|
+
Global helpers are loaded at the start of a session and
|
11
|
+
apply equally to all demonstrations in a suite. Global
|
12
|
+
helpers are simply Ruby scripts and are placed in an
|
13
|
+
+environment+ subdirectory. For instance this document
|
14
|
+
is used <a href="environment/env.rb">environment/env.rb</a>.
|
15
|
+
|
16
|
+
== Local Helpers
|
17
|
+
|
18
|
+
Helper scripts can be written just like demonstration scripts,
|
19
|
+
or they can be defined as pure Ruby scripts. Either way
|
20
|
+
they are loaded per-demonstration by using specially
|
21
|
+
marked links.
|
22
|
+
|
23
|
+
For example, because this link, Advice[qed://helpers/advice.rb],
|
24
|
+
begins with +qed:+, it will be used to load a global
|
25
|
+
helper. We can see this with the following:
|
26
|
+
|
27
|
+
pudding.assert.include?('load advice.rb')
|
28
|
+
|
29
|
+
No where in the demonstration have we defined +pudding+, but
|
30
|
+
it has been defined for us in the advice.rb helper script.
|
31
|
+
|
32
|
+
We can also see that the generic When clause in our advice
|
33
|
+
helper is keeping count of descriptions. Since the helper
|
34
|
+
script was loaded three paragraphs back, the count will be 3.
|
35
|
+
|
36
|
+
count.assert == 3
|
37
|
+
|
38
|
+
Helpers are vital to building test-demonstration suites for
|
39
|
+
applications. But here again, only use them as necessary.
|
40
|
+
The more helpers you use the more difficult your demos will
|
41
|
+
be to follow.
|
42
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
= Fixtures
|
2
|
+
|
3
|
+
== Flat-file Data
|
4
|
+
|
5
|
+
When creating testable demonstrations, there are times when sizable
|
6
|
+
chunks of data are needed. It is convenient to store such data in
|
7
|
+
separate files. The +Data+ method makes is easy to load such files.
|
8
|
+
|
9
|
+
Data('demo/fixtures/data.txt').assert =~ /dolor/
|
10
|
+
|
11
|
+
All files are found relative to the location of current document.
|
12
|
+
|
13
|
+
== Tabular Data
|
14
|
+
|
15
|
+
The +Table+ method is similar to the +Data+ method except that it
|
16
|
+
expects a YAML file, and it can take a block to iterate the data over.
|
17
|
+
This makes it easy to test tables of examples.
|
18
|
+
|
19
|
+
The arity of the table block corresponds to the number of columns in
|
20
|
+
each row of the table. Each row is assigned in turn and run through
|
21
|
+
the coded step. Consider the following example:
|
22
|
+
|
23
|
+
Every row in the {table.yml table}[table.yml] will be assigned to
|
24
|
+
the block parameters and run through the subsequent assertion.
|
25
|
+
|
26
|
+
Table 'demo/fixtures/table.yml' do |x, y|
|
27
|
+
x.upcase.assert == y
|
28
|
+
end
|
29
|
+
|
data/demo/05_quote.rdoc
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
= Quotes
|
2
|
+
|
3
|
+
We do not always want verbatum clauses to be interpreted as code.
|
4
|
+
Sometimes it would more useful to trest them a plan text to
|
5
|
+
which the preceeding paragraph can make use in a processing rule.
|
6
|
+
|
7
|
+
For example let say we want to make an example out of the following
|
8
|
+
text...
|
9
|
+
|
10
|
+
The file will contain
|
11
|
+
|
12
|
+
this text
|
13
|
+
|
14
|
+
The use of the ellipsis ('...') tells the processor that the next
|
15
|
+
segment is a continuation of the current segment. If the next segment
|
16
|
+
is varbatum it will be added to the end of the arguments list of
|
17
|
+
any applicable processing rule.
|
18
|
+
|
19
|
+
Behind the scenes we created a rule to set the text to an instance
|
20
|
+
variable called @quote_text, as we can now verify:
|
21
|
+
|
22
|
+
@quote_text.assert == "The file will contain\n\nthis text"
|
23
|
+
|
24
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
= Toplevel Simulation
|
2
|
+
|
3
|
+
QED simulates Ruby's TOPLEVEL environment in both the Demonstrandum
|
4
|
+
and the Applique contexts. This serves two important purposes.
|
5
|
+
First, it provides the tester the environment that is most intutive.
|
6
|
+
And second, and more importantly, it stays out of the actual
|
7
|
+
TOPLEVEL space to prevent any potential interferece with any of
|
8
|
+
the code it is intended to test.
|
9
|
+
|
10
|
+
Let's look at some examples. For starters, we have access to a class
|
11
|
+
defined at the "toplevel" in the applique.
|
12
|
+
|
13
|
+
ToplevelClass
|
14
|
+
|
15
|
+
We can also call a method defined in the toplevel.
|
16
|
+
|
17
|
+
toplevel_method.assert == true
|
18
|
+
|
19
|
+
At the demonstrandum level we can define reusable methods.
|
20
|
+
|
21
|
+
def demo_method
|
22
|
+
true
|
23
|
+
end
|
24
|
+
|
25
|
+
demo_method.assert == true
|
26
|
+
|
27
|
+
And at the demonstrandum level even singleton methods are accessible.
|
28
|
+
|
29
|
+
def self.singleton_method; true; end
|
30
|
+
|
31
|
+
singleton_method.assert == true
|
32
|
+
|
33
|
+
QED uses a self-extend modules to achieve this simulation, so the
|
34
|
+
contexts are in fact a bit more capable then even Ruby's TOPLEVEL.
|
35
|
+
For instance, #define_method can be used.
|
36
|
+
|
37
|
+
define_method(:named_method){ true }
|
38
|
+
|
39
|
+
named_method.assert == true
|
40
|
+
|
41
|
+
|
42
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
= Cross-Scripting Setup
|
2
|
+
|
3
|
+
We define some variables here to make sure it is
|
4
|
+
not visible in the next script.
|
5
|
+
|
6
|
+
Let's set two local variables.
|
7
|
+
|
8
|
+
a = 100
|
9
|
+
b = 200
|
10
|
+
|
11
|
+
And two instance varaibles.
|
12
|
+
|
13
|
+
@a = 1000
|
14
|
+
@b = 2000
|
15
|
+
|
16
|
+
Also let check how it effect constants.
|
17
|
+
|
18
|
+
CROSS_SCRIPT_CONSTANT = "cross?"
|
19
|
+
|
20
|
+
And a method.
|
21
|
+
|
22
|
+
def cross_script_method
|
23
|
+
"common"
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
= Cross-Scripting Check
|
2
|
+
|
3
|
+
Make sure local and instance variables from previous
|
4
|
+
QED scripts are not visible in this document.
|
5
|
+
|
6
|
+
expect NameError do
|
7
|
+
a.assert = 100
|
8
|
+
b.assert = 200
|
9
|
+
end
|
10
|
+
|
11
|
+
And two instance_varaibles
|
12
|
+
|
13
|
+
@a.assert! == 1000
|
14
|
+
@b.assert! == 2000
|
15
|
+
|
16
|
+
|
17
|
+
Method definitions also do not cross QED scripts.
|
18
|
+
|
19
|
+
expect NameError do
|
20
|
+
cross_script_method
|
21
|
+
end
|
22
|
+
|
23
|
+
Constants, on the other hand, like global variables do make
|
24
|
+
their way across.
|
25
|
+
|
26
|
+
CROSS_SCRIPT_CONSTANT.assert == "cross?"
|
27
|
+
|
@@ -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 the toplevel.
|
5
|
+
|
6
|
+
begin
|
7
|
+
UnknownConstant
|
8
|
+
rescue => err
|
9
|
+
# no colon means toplevel
|
10
|
+
/[^:]UnknownConstant/ =~ err.message
|
11
|
+
end
|
12
|
+
|
13
|
+
A constant defined in the applique is visible.
|
14
|
+
|
15
|
+
APPLIQUE_CONSTANT.assert = true
|
16
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'tmpdir'
|
@@ -0,0 +1,10 @@
|
|
1
|
+
When "lets say we have", "document called (((.*?))) with the following contents" do |file, text|
|
2
|
+
file = Dir.tmpdir + '/sow/examples/' + file
|
3
|
+
FileUtils.mkdir_p(File.dirname(file))
|
4
|
+
File.open(file, 'w'){ |f| f << text }
|
5
|
+
end
|
6
|
+
|
7
|
+
When 'when we run these examples' do
|
8
|
+
Dir.chdir(Dir.tmpdir + '/sow/examples/')
|
9
|
+
end
|
10
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
|
2
|
+
# Define a toplevel class to ensure it is accessible.
|
3
|
+
class ToplevelClass
|
4
|
+
end
|
5
|
+
|
6
|
+
# Define a toplevel method to ensure it is also accessible.
|
7
|
+
def toplevel_method
|
8
|
+
true
|
9
|
+
end
|
10
|
+
|
11
|
+
# Define a toplevel method to ensure it is also accessible.
|
12
|
+
def self.toplevel_singleton_method
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# This helper is used to demonstrate
|
2
|
+
# the use of advice --before, after
|
3
|
+
# and when clauses.
|
4
|
+
|
5
|
+
count = 0
|
6
|
+
pudding = []
|
7
|
+
|
8
|
+
When(:load) do
|
9
|
+
pudding << "load #{File.basename(__FILE__)}"
|
10
|
+
end
|
11
|
+
|
12
|
+
When(:unload) do
|
13
|
+
pudding << "unload #{File.basename(__FILE__)}"
|
14
|
+
end
|
15
|
+
|
16
|
+
#Before do
|
17
|
+
# pudding << :before_step
|
18
|
+
#end
|
19
|
+
|
20
|
+
#After do
|
21
|
+
# pudding << :after_step
|
22
|
+
#end
|
23
|
+
|
24
|
+
When /.*?/ do
|
25
|
+
count += 1
|
26
|
+
end
|
27
|
+
|
28
|
+
When /proof is in the pudding/ do
|
29
|
+
pudding << 'proof'
|
30
|
+
end
|
31
|
+
|
32
|
+
#When /proof is in the pussing/ do
|
33
|
+
# pudding << :proof
|
34
|
+
#end
|
35
|
+
|
36
|
+
#
|
37
|
+
def prepare_example
|
38
|
+
"Hello, World!"
|
39
|
+
end
|
40
|
+
|
data/eg/hello_world.rdoc
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
= Hello World
|
2
|
+
|
3
|
+
Did you know that famous `Hello World` moniker is
|
4
|
+
eleven characters long?
|
5
|
+
|
6
|
+
"Hello World".size.assert == 11
|
7
|
+
|
8
|
+
To pass a piece of literal text on with a description
|
9
|
+
we simply need to end it with a ...
|
10
|
+
|
11
|
+
Now this text will appear verbatim.
|
12
|
+
In the applique arguments.
|
13
|
+
|
14
|
+
That's all.
|
15
|
+
|
File without changes
|
data/{demo → eg}/website.rdoc
RENAMED
File without changes
|
data/lib/qed.rb
CHANGED
@@ -1,5 +1,24 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
1
3
|
module QED
|
2
|
-
|
4
|
+
DIRECTORY = File.dirname(__FILE__) + '/qed'
|
5
|
+
|
6
|
+
PROFILE = YAML.load(File.new(DIRECTORY + '/profile.yml')) rescue {}
|
7
|
+
PACKAGE = YAML.load(File.new(DIRECTORY + '/package.yml')) rescue {}
|
8
|
+
|
9
|
+
VERSION = PACKAGE.values_at('major','minor','patch','build').compact.join('.')
|
10
|
+
|
11
|
+
#
|
12
|
+
def self.const_missing(name)
|
13
|
+
key = name.to_s.downcase
|
14
|
+
if PACKAGE.key?(key)
|
15
|
+
PACKAGE[key]
|
16
|
+
elsif PROFILE.key?(key)
|
17
|
+
PROFILE[key]
|
18
|
+
else
|
19
|
+
super(name)
|
20
|
+
end
|
21
|
+
end
|
3
22
|
end
|
4
23
|
|
5
24
|
require 'qed/session'
|
data/lib/qed/advice.rb
CHANGED
@@ -8,7 +8,7 @@ module QED
|
|
8
8
|
# This class tracks advice defined by demo scripts
|
9
9
|
# and helpers. It is instantiated in Scope, so that
|
10
10
|
# the advice methods will have access to the same
|
11
|
-
# local binding and the
|
11
|
+
# local binding and the scripts themselves.
|
12
12
|
#
|
13
13
|
class Advice
|
14
14
|
|
@@ -21,41 +21,15 @@ module QED
|
|
21
21
|
@events = Events.new
|
22
22
|
end
|
23
23
|
|
24
|
-
def call(type, *args)
|
24
|
+
def call(scope, type, *args)
|
25
25
|
case type
|
26
26
|
when :when
|
27
|
-
@patterns.call(*args)
|
27
|
+
@patterns.call(scope, *args)
|
28
28
|
else
|
29
|
-
@events.call(type, *args)
|
29
|
+
@events.call(scope, type, *args)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
#
|
35
|
-
module Advisable
|
36
|
-
|
37
|
-
def __advice__
|
38
|
-
@__advice__ ||= Advice.new
|
39
|
-
end
|
40
|
-
|
41
|
-
def When(pattern, &procedure)
|
42
|
-
case pattern
|
43
|
-
when Symbol
|
44
|
-
__advice__.events.add(:"#{pattern}", &procedure)
|
45
|
-
else
|
46
|
-
__advice__.patterns.add(pattern, &procedure)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def Before(type=:code, &procedure)
|
51
|
-
__advice__.events.add(:"before_#{type}", &procedure)
|
52
|
-
end
|
53
|
-
|
54
|
-
def After(type=:code, &procedure)
|
55
|
-
__advice__.events.add(:"after_#{type}", &procedure)
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
59
|
-
|
60
34
|
end
|
61
35
|
|
data/lib/qed/advice/events.rb
CHANGED
@@ -2,7 +2,8 @@ module QED
|
|
2
2
|
|
3
3
|
class Advice
|
4
4
|
|
5
|
-
#
|
5
|
+
# This class encapsulates advice on symbolic targets,
|
6
|
+
# such as Before, After and Upon.
|
6
7
|
#
|
7
8
|
class Events
|
8
9
|
|
@@ -20,10 +21,12 @@ module QED
|
|
20
21
|
end
|
21
22
|
|
22
23
|
#
|
23
|
-
def call(type, *args)
|
24
|
+
def call(scope, type, *args)
|
25
|
+
|
24
26
|
@signals.each do |set|
|
25
27
|
proc = set[type.to_sym]
|
26
|
-
proc.call(*args) if proc
|
28
|
+
#proc.call(*args) if proc
|
29
|
+
scope.instance_exec(*args, &proc) if proc
|
27
30
|
end
|
28
31
|
end
|
29
32
|
|