qed 2.2.0 → 2.2.1
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.
- data/HISTORY +12 -0
- data/REQUIRE +0 -2
- data/VERSION +1 -1
- data/lib/qed/advice.rb +130 -12
- data/lib/qed/applique.rb +5 -7
- data/lib/qed/evaluator.rb +11 -12
- data/lib/qed/package.yml +1 -1
- data/lib/qed/script.rb +13 -0
- metadata +6 -36
- data/lib/qed/advice/events.rb +0 -57
- data/lib/qed/advice/patterns.rb +0 -82
data/HISTORY
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
= RELEASE HISTORY
|
2
2
|
|
3
|
+
== 2.2.1 / 2010-06-21
|
4
|
+
|
5
|
+
Remove dependencies to Tilt and Nokogiri. Should have
|
6
|
+
done this in last release but alas --there is so
|
7
|
+
much to do.
|
8
|
+
|
9
|
+
Change:
|
10
|
+
|
11
|
+
* Removed HTML parsing dependencies.
|
12
|
+
* Reduce Advice to a single class.
|
13
|
+
|
14
|
+
|
3
15
|
== 2.2.0 / 2010-06-20
|
4
16
|
|
5
17
|
This release returns to a text-based evaluator, rather
|
data/REQUIRE
CHANGED
data/VERSION
CHANGED
data/lib/qed/advice.rb
CHANGED
@@ -1,34 +1,152 @@
|
|
1
1
|
module QED
|
2
2
|
|
3
|
-
require 'qed/advice/events'
|
4
|
-
require 'qed/advice/patterns'
|
5
|
-
|
6
3
|
# = Advice
|
7
4
|
#
|
8
|
-
# This class tracks advice defined by
|
9
|
-
# and
|
5
|
+
# This class tracks advice defined by demonstrandum
|
6
|
+
# and applique. It is instantiated in Scope, so that
|
10
7
|
# the advice methods will have access to the same
|
11
|
-
# local binding
|
8
|
+
# local binding as the scripts themselves.
|
9
|
+
#
|
10
|
+
# There are two types of advice: *pattern matchers*
|
11
|
+
# and *event signals*.
|
12
|
+
#
|
13
|
+
# == Pattern Matchers (When)
|
14
|
+
#
|
15
|
+
# Matchers are evaluated in Scope context, via #instance_exec,
|
16
|
+
# so that the advice methods will have access to the same
|
17
|
+
# scope as the demonstrandum themselves.
|
18
|
+
#
|
19
|
+
# == Event Signals (Before, After)
|
20
|
+
#
|
21
|
+
# Event advice are triggered on symbolic targets which
|
22
|
+
# represent an event in the evaluation process, such as
|
23
|
+
# before any demo is run, or after all demo finish running.
|
12
24
|
#
|
13
25
|
class Advice
|
14
26
|
|
15
|
-
|
27
|
+
#
|
28
|
+
attr :matchers
|
16
29
|
|
17
|
-
|
30
|
+
#
|
31
|
+
attr :signals
|
18
32
|
|
33
|
+
#
|
19
34
|
def initialize
|
20
|
-
@
|
21
|
-
@
|
35
|
+
@matchers = []
|
36
|
+
@signals = [{}]
|
22
37
|
end
|
23
38
|
|
39
|
+
#
|
24
40
|
def call(scope, type, *args)
|
25
41
|
case type
|
26
42
|
when :when
|
27
|
-
|
43
|
+
call_matchers(scope, *args)
|
44
|
+
else
|
45
|
+
#@events.call(scope, type, *args)
|
46
|
+
call_signals(scope, type, *args)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
def add_event(type, &procedure)
|
52
|
+
@signals.last[type.to_sym] = procedure
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
def add_match(patterns, &procedure)
|
57
|
+
@matchers << [patterns, procedure]
|
58
|
+
end
|
59
|
+
|
60
|
+
# React to an event.
|
61
|
+
def call_signals(scope, type, *args)
|
62
|
+
@signals.each do |set|
|
63
|
+
proc = set[type.to_sym]
|
64
|
+
#proc.call(*args) if proc
|
65
|
+
scope.instance_exec(*args, &proc) if proc
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
def call_matchers(scope, section)
|
71
|
+
match = section.text
|
72
|
+
args = section.args
|
73
|
+
|
74
|
+
@matchers.each do |(patterns, proc)|
|
75
|
+
compare = match
|
76
|
+
matched = true
|
77
|
+
params = []
|
78
|
+
patterns.each do |pattern|
|
79
|
+
case pattern
|
80
|
+
when Regexp
|
81
|
+
regex = pattern
|
82
|
+
else
|
83
|
+
regex = match_string_to_regexp(pattern)
|
84
|
+
end
|
85
|
+
if md = regex.match(compare)
|
86
|
+
params.concat(md[1..-1])
|
87
|
+
compare = md.post_match
|
88
|
+
else
|
89
|
+
matched = false
|
90
|
+
break
|
91
|
+
end
|
92
|
+
end
|
93
|
+
if matched
|
94
|
+
params += args
|
95
|
+
#proc.call(*params)
|
96
|
+
scope.instance_exec(*params, &proc)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Clear last set of advice.
|
102
|
+
def signals_reset
|
103
|
+
@signals.pop
|
104
|
+
end
|
105
|
+
|
106
|
+
#
|
107
|
+
def signals_setup
|
108
|
+
@signals.push({})
|
109
|
+
end
|
110
|
+
|
111
|
+
# Clear advice.
|
112
|
+
def signals_clear(type=nil)
|
113
|
+
if type
|
114
|
+
@signals.each{ |set| set.delete(type.to_sym) }
|
28
115
|
else
|
29
|
-
@
|
116
|
+
@signals = [{}]
|
30
117
|
end
|
31
118
|
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
# Convert matching string into a regular expression. If the string
|
123
|
+
# contains double parenthesis, such as ((.*?)), then the text within
|
124
|
+
# them is treated as in regular expression and kept verbatium.
|
125
|
+
#
|
126
|
+
# TODO: Better way to isolate regexp. Maybe "?:(.*?)".
|
127
|
+
#
|
128
|
+
# TODO: Now that we can use multi-patterns, do we still need this?
|
129
|
+
#
|
130
|
+
def match_string_to_regexp(str)
|
131
|
+
str = str.split(/(\(\(.*?\)\))(?!\))/).map{ |x|
|
132
|
+
x =~ /\A\(\((.*)\)\)\Z/ ? $1 : Regexp.escape(x)
|
133
|
+
}.join
|
134
|
+
str = str.gsub(/\\\s+/, '\s+')
|
135
|
+
Regexp.new(str, Regexp::IGNORECASE)
|
136
|
+
|
137
|
+
#rexps = []
|
138
|
+
#str = str.gsub(/\(\((.*?)\)\)/) do |m|
|
139
|
+
# rexps << '(' + $1 + ')'
|
140
|
+
# "\0"
|
141
|
+
#end
|
142
|
+
#str = Regexp.escape(str)
|
143
|
+
#rexps.each do |r|
|
144
|
+
# str = str.sub("\0", r)
|
145
|
+
#end
|
146
|
+
#str = str.gsub(/(\\\ )+/, '\s+')
|
147
|
+
#Regexp.new(str, Regexp::IGNORECASE)
|
148
|
+
end
|
149
|
+
|
32
150
|
end
|
33
151
|
|
34
152
|
end
|
data/lib/qed/applique.rb
CHANGED
@@ -40,25 +40,23 @@ module QED
|
|
40
40
|
@__advice__
|
41
41
|
end
|
42
42
|
|
43
|
-
#
|
44
|
-
# HTML special charaters +<+, +>+ and +&+ should not be
|
45
|
-
# used.
|
43
|
+
# Pattern matchers and "upon" events.
|
46
44
|
def When(*patterns, &procedure)
|
47
45
|
if patterns.size == 1 && Symbol === patterns.first
|
48
|
-
__advice__.
|
46
|
+
__advice__.add_event(patterns.first, &procedure)
|
49
47
|
else
|
50
|
-
__advice__.
|
48
|
+
__advice__.add_match(patterns, &procedure)
|
51
49
|
end
|
52
50
|
end
|
53
51
|
|
54
52
|
# Before advice.
|
55
53
|
def Before(type=:code, &procedure)
|
56
|
-
__advice__.
|
54
|
+
__advice__.add_event(:"before_#{type}", &procedure)
|
57
55
|
end
|
58
56
|
|
59
57
|
# After advice.
|
60
58
|
def After(type=:code, &procedure)
|
61
|
-
__advice__.
|
59
|
+
__advice__.add_event(:"after_#{type}", &procedure)
|
62
60
|
end
|
63
61
|
|
64
62
|
# Code match-and-transform procedure.
|
data/lib/qed/evaluator.rb
CHANGED
@@ -8,11 +8,12 @@ module QED
|
|
8
8
|
#
|
9
9
|
def initialize(script, *observers)
|
10
10
|
@script = script
|
11
|
-
@file = script.file
|
12
11
|
@ast = script.parse
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
|
13
|
+
#@file = script.file
|
14
|
+
#@scope = script.scope
|
15
|
+
#@binding = script.binding
|
16
|
+
#@advice = script.advice
|
16
17
|
|
17
18
|
@observers = observers
|
18
19
|
end
|
@@ -38,18 +39,17 @@ module QED
|
|
38
39
|
|
39
40
|
#
|
40
41
|
def evaluate_code(section)
|
41
|
-
advise!(:before_code, section, @file)
|
42
|
+
advise!(:before_code, section, @script.file)
|
42
43
|
begin
|
43
44
|
advise!(:code, section)
|
44
|
-
|
45
|
-
#@scope.module_eval(section.text, @file, section.line)
|
45
|
+
@script.evaluate(section.text, section.line)
|
46
46
|
pass!(section)
|
47
47
|
rescue Assertion => exception
|
48
48
|
fail!(section, exception)
|
49
49
|
rescue Exception => exception
|
50
50
|
error!(section, exception)
|
51
51
|
end
|
52
|
-
advise!(:after_code, section, @file)
|
52
|
+
advise!(:after_code, section, @script.file)
|
53
53
|
end
|
54
54
|
|
55
55
|
#
|
@@ -97,15 +97,14 @@ module QED
|
|
97
97
|
#
|
98
98
|
def import!(file)
|
99
99
|
advise!(:unload)
|
100
|
-
eval(File.read(file), @binding, file)
|
100
|
+
eval(File.read(file), @script.binding, file)
|
101
101
|
advise!(:load, file)
|
102
102
|
end
|
103
103
|
|
104
|
-
#
|
104
|
+
# Dispatch event to observers and advice.
|
105
105
|
def advise!(signal, *args)
|
106
106
|
@observers.each{ |o| o.update(signal, *args) }
|
107
|
-
|
108
|
-
@advice.call(@scope, signal, *args)
|
107
|
+
@script.advise(signal, *args)
|
109
108
|
end
|
110
109
|
|
111
110
|
#
|
data/lib/qed/package.yml
CHANGED
data/lib/qed/script.rb
CHANGED
@@ -40,6 +40,11 @@ module QED
|
|
40
40
|
@applique.__advice__
|
41
41
|
end
|
42
42
|
|
43
|
+
#
|
44
|
+
def advise(signal, *args)
|
45
|
+
advice.call(@scope, signal, *args)
|
46
|
+
end
|
47
|
+
|
43
48
|
# Expanded dirname of +file+.
|
44
49
|
def directory
|
45
50
|
@directory ||= File.expand_path(File.dirname(file))
|
@@ -50,6 +55,12 @@ module QED
|
|
50
55
|
@name ||= File.basename(file).chomp(File.extname(file))
|
51
56
|
end
|
52
57
|
|
58
|
+
#
|
59
|
+
def evaluate(code, line)
|
60
|
+
eval(code, @binding, @file, line)
|
61
|
+
#@scope.module_eval(section.text, @file, section.line)
|
62
|
+
end
|
63
|
+
|
53
64
|
#
|
54
65
|
#def source
|
55
66
|
# @source ||= (
|
@@ -63,6 +74,8 @@ module QED
|
|
63
74
|
# )
|
64
75
|
#end
|
65
76
|
|
77
|
+
# Parse script.
|
78
|
+
# Retruns an abstract syntax tree.
|
66
79
|
def parse
|
67
80
|
Parser.new(file).parse
|
68
81
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qed
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 5
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 2
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 2.2.
|
9
|
+
- 1
|
10
|
+
version: 2.2.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Thomas Sawyer <transfire@gmail.com>
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-06-
|
18
|
+
date: 2010-06-20 00:00:00 -04:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -60,38 +60,10 @@ dependencies:
|
|
60
60
|
version: "0"
|
61
61
|
type: :runtime
|
62
62
|
version_requirements: *id003
|
63
|
-
- !ruby/object:Gem::Dependency
|
64
|
-
name: tilt
|
65
|
-
prerelease: false
|
66
|
-
requirement: &id004 !ruby/object:Gem::Requirement
|
67
|
-
none: false
|
68
|
-
requirements:
|
69
|
-
- - ">="
|
70
|
-
- !ruby/object:Gem::Version
|
71
|
-
hash: 3
|
72
|
-
segments:
|
73
|
-
- 0
|
74
|
-
version: "0"
|
75
|
-
type: :runtime
|
76
|
-
version_requirements: *id004
|
77
|
-
- !ruby/object:Gem::Dependency
|
78
|
-
name: nokogiri
|
79
|
-
prerelease: false
|
80
|
-
requirement: &id005 !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
|
-
requirements:
|
83
|
-
- - ">="
|
84
|
-
- !ruby/object:Gem::Version
|
85
|
-
hash: 3
|
86
|
-
segments:
|
87
|
-
- 0
|
88
|
-
version: "0"
|
89
|
-
type: :runtime
|
90
|
-
version_requirements: *id005
|
91
63
|
- !ruby/object:Gem::Dependency
|
92
64
|
name: syckle
|
93
65
|
prerelease: false
|
94
|
-
requirement: &
|
66
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
95
67
|
none: false
|
96
68
|
requirements:
|
97
69
|
- - ">="
|
@@ -101,7 +73,7 @@ dependencies:
|
|
101
73
|
- 0
|
102
74
|
version: "0"
|
103
75
|
type: :development
|
104
|
-
version_requirements: *
|
76
|
+
version_requirements: *id004
|
105
77
|
description: QED (Quality Ensured Demonstrations) is a TDD/BDD framework utilizing Literate Programming techniques.
|
106
78
|
email:
|
107
79
|
executables:
|
@@ -137,8 +109,6 @@ files:
|
|
137
109
|
- eg/hello_world.rdoc
|
138
110
|
- eg/view_error.rdoc
|
139
111
|
- eg/website.rdoc
|
140
|
-
- lib/qed/advice/events.rb
|
141
|
-
- lib/qed/advice/patterns.rb
|
142
112
|
- lib/qed/advice.rb
|
143
113
|
- lib/qed/applique.rb
|
144
114
|
- lib/qed/command.rb
|
data/lib/qed/advice/events.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
module QED
|
2
|
-
|
3
|
-
class Advice
|
4
|
-
|
5
|
-
# This class encapsulates advice on symbolic targets,
|
6
|
-
# such as Before, After and Upon.
|
7
|
-
#
|
8
|
-
class Events
|
9
|
-
|
10
|
-
#
|
11
|
-
attr :signals
|
12
|
-
|
13
|
-
#
|
14
|
-
def initialize
|
15
|
-
@signals = [{}]
|
16
|
-
end
|
17
|
-
|
18
|
-
#
|
19
|
-
def add(type, &procedure)
|
20
|
-
@signals.last[type.to_sym] = procedure
|
21
|
-
end
|
22
|
-
|
23
|
-
#
|
24
|
-
def call(scope, type, *args)
|
25
|
-
|
26
|
-
@signals.each do |set|
|
27
|
-
proc = set[type.to_sym]
|
28
|
-
#proc.call(*args) if proc
|
29
|
-
scope.instance_exec(*args, &proc) if proc
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
# Clear last set of advice.
|
34
|
-
def reset
|
35
|
-
@signals.pop
|
36
|
-
end
|
37
|
-
|
38
|
-
#
|
39
|
-
def setup
|
40
|
-
@signals.push {}
|
41
|
-
end
|
42
|
-
|
43
|
-
# Clear advice.
|
44
|
-
def clear(type=nil)
|
45
|
-
if type
|
46
|
-
@signals.each{ |set| set.delete(type.to_sym) }
|
47
|
-
else
|
48
|
-
@signals = [{}]
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
53
|
-
|
54
|
-
end
|
55
|
-
|
56
|
-
end
|
57
|
-
|
data/lib/qed/advice/patterns.rb
DELETED
@@ -1,82 +0,0 @@
|
|
1
|
-
module QED
|
2
|
-
|
3
|
-
# = Pattern Advice (When)
|
4
|
-
#
|
5
|
-
# This class encapsulates "When" advice on plain text.
|
6
|
-
#
|
7
|
-
# Matches are evaluated in Scope context, via #instance_exec,
|
8
|
-
# so that the advice methods will have access to the same
|
9
|
-
# scope as the demonstrandum themselves.
|
10
|
-
#
|
11
|
-
class Patterns
|
12
|
-
|
13
|
-
attr :when
|
14
|
-
|
15
|
-
def initialize
|
16
|
-
@when = []
|
17
|
-
end
|
18
|
-
|
19
|
-
#
|
20
|
-
def add(patterns, &procedure)
|
21
|
-
@when << [patterns, procedure]
|
22
|
-
end
|
23
|
-
|
24
|
-
#
|
25
|
-
def call(scope, section)
|
26
|
-
match = section.text
|
27
|
-
args = section.args
|
28
|
-
|
29
|
-
@when.each do |(patterns, proc)|
|
30
|
-
compare = match
|
31
|
-
matched = true
|
32
|
-
params = []
|
33
|
-
patterns.each do |pattern|
|
34
|
-
case pattern
|
35
|
-
when Regexp
|
36
|
-
regex = pattern
|
37
|
-
else
|
38
|
-
regex = when_string_to_regexp(pattern)
|
39
|
-
end
|
40
|
-
if md = regex.match(compare)
|
41
|
-
params.concat(md[1..-1])
|
42
|
-
compare = md.post_match
|
43
|
-
else
|
44
|
-
matched = false
|
45
|
-
break
|
46
|
-
end
|
47
|
-
end
|
48
|
-
if matched
|
49
|
-
params += args
|
50
|
-
#proc.call(*params)
|
51
|
-
scope.instance_exec(*params, &proc)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
private
|
57
|
-
|
58
|
-
# TODO: Now that we can use multi-patterns, we might not need this any more.
|
59
|
-
def when_string_to_regexp(str)
|
60
|
-
str = str.split(/(\(\(.*?\)\))(?!\))/).map{ |x|
|
61
|
-
x =~ /\A\(\((.*)\)\)\Z/ ? $1 : Regexp.escape(x)
|
62
|
-
}.join
|
63
|
-
str = str.gsub(/\\\s+/, '\s+')
|
64
|
-
Regexp.new(str, Regexp::IGNORECASE)
|
65
|
-
|
66
|
-
#rexps = []
|
67
|
-
#str = str.gsub(/\(\((.*?)\)\)/) do |m|
|
68
|
-
# rexps << '(' + $1 + ')'
|
69
|
-
# "\0"
|
70
|
-
#end
|
71
|
-
#str = Regexp.escape(str)
|
72
|
-
#rexps.each do |r|
|
73
|
-
# str = str.sub("\0", r)
|
74
|
-
#end
|
75
|
-
#str = str.gsub(/(\\\ )+/, '\s+')
|
76
|
-
#Regexp.new(str, Regexp::IGNORECASE)
|
77
|
-
end
|
78
|
-
|
79
|
-
end
|
80
|
-
|
81
|
-
end
|
82
|
-
|