qed 2.3.0 → 2.4.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.
- data/History.rdoc +15 -0
- data/eg/hello_world.rdoc +15 -0
- data/eg/view_error.rdoc +21 -0
- data/eg/website.rdoc +12 -0
- data/lib/qed/advice.rb +4 -3
- data/lib/qed/command.rb +2 -3
- data/lib/qed/core_ext/instance_exec.rb +36 -0
- data/lib/qed/demo.rb +0 -1
- data/lib/qed/evaluator.rb +75 -36
- data/lib/qed/extensions/filefixtures.rb +27 -0
- data/lib/qed/extensions/shell_session.rb +2 -0
- data/lib/qed/meta/data.rb +29 -0
- data/lib/qed/meta/gemfile +10 -0
- data/{PROFILE → lib/qed/meta/profile} +0 -0
- data/lib/qed/parser.rb +148 -74
- data/lib/qed/reporter/abstract.rb +175 -25
- data/lib/qed/reporter/bullet.rb +14 -10
- data/lib/qed/reporter/dotprogress.rb +26 -9
- data/lib/qed/reporter/verbatim.rb +36 -15
- data/lib/qed/scope.rb +18 -8
- data/lib/qed/session.rb +2 -2
- data/meta/data.rb +29 -0
- data/meta/gemfile +10 -0
- data/{lib/qed/profile.yml → meta/profile} +0 -0
- data/{demo → qed}/01_demos.rdoc +7 -13
- data/{demo → qed}/02_advice.rdoc +7 -7
- data/{demo → qed}/03_helpers.rdoc +2 -2
- data/{demo → qed}/04_samples.rdoc +0 -0
- data/{demo → qed}/05_quote.rdoc +0 -0
- data/{demo → qed}/07_toplevel.rdoc +0 -0
- data/{demo → qed}/08_cross_script.rdoc +0 -2
- data/{demo → qed}/09_cross_script.rdoc +5 -3
- data/{demo → qed}/10_constant_lookup.rdoc +0 -0
- data/{demo → qed}/applique/constant.rb +0 -0
- data/{demo → qed}/applique/env.rb +0 -0
- data/{demo → qed}/applique/fileutils.rb +0 -0
- data/{demo → qed}/applique/markup.rb +0 -0
- data/{demo → qed}/applique/quote.rb +0 -0
- data/{demo → qed}/applique/toplevel.rb +0 -0
- data/{demo → qed}/helpers/advice.rb +0 -0
- data/{demo → qed}/helpers/sample.rb +0 -0
- data/{demo → qed}/helpers/toplevel.rb +0 -0
- data/{demo → qed}/samples/data.txt +0 -0
- data/{demo → qed}/samples/table.yml +0 -0
- metadata +43 -38
- data/REQUIRE +0 -7
- data/VERSION +0 -5
- data/lib/qed/package.yml +0 -5
- data/script/qedoc +0 -2
- data/script/test +0 -4
data/History.rdoc
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
= RELEASE HISTORY
|
2
2
|
|
3
|
+
== 2.4.0 / 2010-09-02
|
4
|
+
|
5
|
+
All engines go! QED has not been tested against 1.8.6, 1.8.7 and 1.9.2.
|
6
|
+
Underthehood steps are not organized in doubely-linked lists, which makes
|
7
|
+
them much more robust and flexible. This release also improves scoping,
|
8
|
+
test counts, and inline documentation parsing.
|
9
|
+
|
10
|
+
Changes:
|
11
|
+
|
12
|
+
* Use new doubly-linked list step design.
|
13
|
+
* Fix -r option on command line.
|
14
|
+
* Provide #instance_exec core extension for Ruby 1.8.6.
|
15
|
+
* Scope is extended by and includes applique.
|
16
|
+
|
17
|
+
|
3
18
|
== 2.3.0 / 2010-07-14
|
4
19
|
|
5
20
|
Bug to the scurry! QED has broken through the code/document ceiling and
|
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
|
+
|
data/eg/view_error.rdoc
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
= Examples of Failure
|
2
|
+
|
3
|
+
This document is here simply to demonstrate what
|
4
|
+
a failed and error raising code steps looks like.
|
5
|
+
|
6
|
+
When run with the -v (verbatim) option, for instance, +qed+
|
7
|
+
will highlight the following sections in red and give a brief
|
8
|
+
error message.
|
9
|
+
|
10
|
+
== Failure
|
11
|
+
|
12
|
+
This step demonstrates a failed assertion.
|
13
|
+
|
14
|
+
1.assert == 2
|
15
|
+
|
16
|
+
== Error
|
17
|
+
|
18
|
+
This step demonstrates a raised error.
|
19
|
+
|
20
|
+
raise "Just because"
|
21
|
+
|
data/eg/website.rdoc
ADDED
data/lib/qed/advice.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'qed/core_ext/instance_exec'
|
2
|
+
|
1
3
|
module QED
|
2
4
|
|
3
5
|
# = Advice
|
@@ -12,8 +14,7 @@ module QED
|
|
12
14
|
#
|
13
15
|
# == Pattern Matchers (When)
|
14
16
|
#
|
15
|
-
# Matchers are evaluated when they match a
|
16
|
-
# commentary.
|
17
|
+
# Matchers are evaluated when they match a description.
|
17
18
|
#
|
18
19
|
# == Event Signals (Before, After)
|
19
20
|
#
|
@@ -67,7 +68,7 @@ module QED
|
|
67
68
|
|
68
69
|
#
|
69
70
|
def call_matchers(scope, section)
|
70
|
-
match = section.
|
71
|
+
match = section.text
|
71
72
|
args = section.arguments
|
72
73
|
matchers.each do |(patterns, proc)|
|
73
74
|
compare = match
|
data/lib/qed/command.rb
CHANGED
@@ -134,7 +134,7 @@ module QED
|
|
134
134
|
@options[:loadpath] ||= []
|
135
135
|
@options[:loadpath].concat(arg.split(/[:;]/).map{ |dir| File.expand_path(dir) })
|
136
136
|
end
|
137
|
-
opt.on('--require', "-r", "require library") do |arg|
|
137
|
+
opt.on('--require', "-r LIB", "require library") do |arg|
|
138
138
|
@options[:requires] ||= []
|
139
139
|
@options[:requires].concat(arg.split(/[:;]/)) #.map{ |dir| File.expand_path(dir) })
|
140
140
|
end
|
@@ -207,7 +207,7 @@ module QED
|
|
207
207
|
end
|
208
208
|
end
|
209
209
|
files = files.flatten.uniq
|
210
|
-
files.map{|f| File.expand_path(f) }.sort
|
210
|
+
files.map{|f| File.expand_path(f) }.uniq.sort
|
211
211
|
end
|
212
212
|
|
213
213
|
# Parse command-line options along with profile options.
|
@@ -349,4 +349,3 @@ module QED
|
|
349
349
|
end
|
350
350
|
|
351
351
|
end
|
352
|
-
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Object
|
2
|
+
|
3
|
+
unless method_defined?(:instance_exec) # 1.9
|
4
|
+
require 'thread'
|
5
|
+
|
6
|
+
module InstanceExecMethods #:nodoc:
|
7
|
+
end
|
8
|
+
|
9
|
+
include InstanceExecMethods
|
10
|
+
|
11
|
+
# Evaluate the block with the given arguments within the context of
|
12
|
+
# this object, so self is set to the method receiver.
|
13
|
+
#
|
14
|
+
# From Mauricio's http://eigenclass.org/hiki/bounded+space+instance_exec
|
15
|
+
#
|
16
|
+
# This version has been borrowed from Rails for compatibility sake.
|
17
|
+
def instance_exec(*args, &block)
|
18
|
+
begin
|
19
|
+
old_critical, Thread.critical = Thread.critical, true
|
20
|
+
n = 0
|
21
|
+
n += 1 while respond_to?(method_name = "__instance_exec#{n}")
|
22
|
+
InstanceExecMethods.module_eval { define_method(method_name, &block) }
|
23
|
+
ensure
|
24
|
+
Thread.critical = old_critical
|
25
|
+
end
|
26
|
+
|
27
|
+
begin
|
28
|
+
send(method_name, *args)
|
29
|
+
ensure
|
30
|
+
InstanceExecMethods.module_eval { remove_method(method_name) } rescue nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
data/lib/qed/demo.rb
CHANGED
data/lib/qed/evaluator.rb
CHANGED
@@ -8,7 +8,7 @@ module QED
|
|
8
8
|
#
|
9
9
|
def initialize(script, *observers)
|
10
10
|
@script = script
|
11
|
-
@
|
11
|
+
@steps = script.parse
|
12
12
|
|
13
13
|
#@file = script.file
|
14
14
|
#@scope = script.scope
|
@@ -21,46 +21,85 @@ module QED
|
|
21
21
|
#
|
22
22
|
def run
|
23
23
|
advise!(:before_demo, @script)
|
24
|
-
|
24
|
+
advise!(:demo, @script)
|
25
|
+
run_steps
|
25
26
|
advise!(:after_demo, @script)
|
26
27
|
end
|
27
28
|
|
28
29
|
#
|
29
|
-
def process
|
30
|
-
@
|
31
|
-
evaluate(
|
30
|
+
def run_steps #process
|
31
|
+
@steps.each do |step|
|
32
|
+
evaluate(step)
|
32
33
|
end
|
33
34
|
end
|
34
35
|
|
35
|
-
#
|
36
|
-
def evaluate(
|
37
|
-
|
38
|
-
|
39
|
-
advise!(
|
36
|
+
#
|
37
|
+
def evaluate(step)
|
38
|
+
type = step.type
|
39
|
+
advise!(:before_step, step) #, @script.file)
|
40
|
+
advise!("before_#{type}".to_sym, step) #, @script.file)
|
41
|
+
case type
|
42
|
+
when :head
|
43
|
+
evaluate_head(step)
|
44
|
+
when :desc
|
45
|
+
evaluate_desc(step)
|
46
|
+
when :data
|
47
|
+
evaluate_data(step)
|
48
|
+
when :code
|
49
|
+
evaluate_code(step)
|
50
|
+
else
|
51
|
+
raise "fatal: unknown #{type}"
|
52
|
+
end
|
53
|
+
advise!("after_#{type}".to_sym, step) #, @script.file)
|
54
|
+
advise!(:after_step, step) #, @script.file)
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
def evaluate_head(step)
|
59
|
+
advise!(:head, step)
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
def evaluate_desc(step)
|
64
|
+
evaluate_links(step)
|
40
65
|
begin
|
41
|
-
advise!(:
|
42
|
-
|
66
|
+
advise!(:desc, step)
|
67
|
+
advise!(:when, step) # triggers matchers
|
68
|
+
rescue SystemExit
|
69
|
+
pass!(step)
|
70
|
+
rescue Assertion => exception
|
71
|
+
fail!(step, exception)
|
72
|
+
rescue Exception => exception
|
73
|
+
error!(step, exception)
|
74
|
+
else
|
75
|
+
pass!(step)
|
43
76
|
end
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
77
|
+
end
|
78
|
+
|
79
|
+
#
|
80
|
+
def evaluate_data(step)
|
81
|
+
advise!(:data, step)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Evaluate a demo step.
|
85
|
+
def evaluate_code(step)
|
86
|
+
begin
|
87
|
+
advise!(:code, step)
|
88
|
+
@script.evaluate(step.code, step.lineno)
|
89
|
+
rescue SystemExit
|
90
|
+
pass!(step)
|
91
|
+
rescue Assertion => exception
|
92
|
+
fail!(step, exception)
|
93
|
+
rescue Exception => exception
|
94
|
+
error!(step, exception)
|
95
|
+
else
|
96
|
+
pass!(step)
|
57
97
|
end
|
58
|
-
advise!(:after_step, section, @script.file)
|
59
98
|
end
|
60
99
|
|
61
|
-
# TODO: Not sure how to handle loading links in comment mode.
|
62
|
-
def evaluate_links(
|
63
|
-
|
100
|
+
# TODO: Not sure how to handle loading links in --comment runner mode.
|
101
|
+
def evaluate_links(step)
|
102
|
+
step.text.scan(/\[qed:\/\/(.*?)\]/) do |match|
|
64
103
|
file = $1
|
65
104
|
# relative to demo script
|
66
105
|
if File.exist?(File.join(@script.directory,file))
|
@@ -77,25 +116,25 @@ module QED
|
|
77
116
|
end
|
78
117
|
|
79
118
|
#
|
80
|
-
def pass!(
|
81
|
-
advise!(:pass,
|
119
|
+
def pass!(step)
|
120
|
+
advise!(:pass, step)
|
82
121
|
end
|
83
122
|
|
84
123
|
#
|
85
|
-
def fail!(
|
86
|
-
advise!(:fail,
|
124
|
+
def fail!(step, exception)
|
125
|
+
advise!(:fail, step, exception)
|
87
126
|
#raise exception
|
88
127
|
end
|
89
128
|
|
90
129
|
#
|
91
|
-
def error!(
|
92
|
-
advise!(:error,
|
130
|
+
def error!(step, exception)
|
131
|
+
advise!(:error, step, exception)
|
93
132
|
#raise exception
|
94
133
|
end
|
95
134
|
|
96
135
|
#
|
97
136
|
def import!(file)
|
98
|
-
advise!(:unload)
|
137
|
+
advise!(:unload) # should this also occur just befor after_demo ?
|
99
138
|
eval(File.read(file), @script.binding, file)
|
100
139
|
advise!(:load, file)
|
101
140
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# This extension provides a simple means for
|
2
|
+
# create file-system fixtures.
|
3
|
+
|
4
|
+
require 'erb'
|
5
|
+
|
6
|
+
# Set global temporary directory.
|
7
|
+
$tmpdir = 'tmp'
|
8
|
+
|
9
|
+
#
|
10
|
+
def copy_fixture(name, tmpdir=$tmpdir)
|
11
|
+
FileUtils.mkdir(tmpdir)
|
12
|
+
srcdir = File.join(demo_directory, 'fixtures', name)
|
13
|
+
paths = Dir.glob(File.join(srcdir, '**', '*'), File::FNM_DOTMATCH)
|
14
|
+
paths.each do |path|
|
15
|
+
basename = File.basename(path)
|
16
|
+
next if basename == '.'
|
17
|
+
next if basename == '..'
|
18
|
+
dest = File.join(tmpdir, path.sub(srcdir+'/', ''))
|
19
|
+
if File.directory?(path)
|
20
|
+
FileUtils.mkdir(dest)
|
21
|
+
else
|
22
|
+
text = ERB.new(File.read(path)).result
|
23
|
+
File.open(dest, 'w'){ |f| f << text }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
Object.__send__(:remove_const, :VERSION) if Object.const_defined?(:VERSION) # becuase Ruby 1.8~ gets in the way
|
2
|
+
|
3
|
+
module QED
|
4
|
+
|
5
|
+
def self.__DIR__
|
6
|
+
File.dirname(__FILE__)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.gemfile
|
10
|
+
@gemfile ||= (
|
11
|
+
require 'yaml'
|
12
|
+
YAML.load(File.new(__DIR__ + '/gemfile'))
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.profile
|
17
|
+
@profile ||= (
|
18
|
+
require 'yaml'
|
19
|
+
YAML.load(File.new(__DIR__ + '/profile'))
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.const_missing(name)
|
24
|
+
key = name.to_s.downcase
|
25
|
+
gemfile[key] || profile[key] || super(name)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
File without changes
|
data/lib/qed/parser.rb
CHANGED
@@ -36,7 +36,7 @@ module QED
|
|
36
36
|
when :comment
|
37
37
|
parse_comment_lines
|
38
38
|
else
|
39
|
-
index =
|
39
|
+
index = 0 #-1
|
40
40
|
File.readlines(file).to_a.map do |line|
|
41
41
|
[index += 1, line]
|
42
42
|
end
|
@@ -46,25 +46,32 @@ module QED
|
|
46
46
|
# TODO: It would be nice if we could get ther require statement for the
|
47
47
|
# comment mode to be relative to an actual loadpath.
|
48
48
|
def parse_comment_lines
|
49
|
-
|
49
|
+
ruby_omit = false
|
50
|
+
rdoc_omit = false
|
50
51
|
lines = [
|
51
52
|
[0, "Load #{File.basename(file)} script.\n"],
|
52
53
|
[0, "\n"],
|
53
54
|
[0, " require '#{file}'\n"]
|
54
55
|
]
|
55
|
-
index =
|
56
|
+
index = 1
|
56
57
|
File.readlines(file).each do |l|
|
57
58
|
case l
|
59
|
+
when /^=begin(?!\s+qed)/
|
60
|
+
ruby_omit = true
|
61
|
+
when /^=end/
|
62
|
+
ruby_omit = false
|
58
63
|
when /^\s*\#\-\-\s*$/
|
59
|
-
|
64
|
+
rdoc_omit = true
|
60
65
|
when /^\s*\#\+\+\s*$/
|
61
|
-
|
62
|
-
when /^\s*\#\ \-\-/ #
|
63
|
-
|
64
|
-
when /^\s
|
65
|
-
|
66
|
+
rdoc_omit = false
|
67
|
+
##when /^\s*\#\ \-\-/ # not needed just double comment
|
68
|
+
## # -- skip internal comments
|
69
|
+
when /^\s*##/
|
70
|
+
## skip internal comments
|
71
|
+
when /^\s*\#/
|
72
|
+
lines << [index, l.lstrip.sub(/^\#\ ?/, '')] unless (ruby_omit or rdoc_omit)
|
66
73
|
else
|
67
|
-
lines << [index, "\n"] unless lines.last[1] == "\n"
|
74
|
+
lines << [index, "\n"] unless lines.last[1] == "\n" unless (ruby_omit or rdoc_omit)
|
68
75
|
end
|
69
76
|
index += 1
|
70
77
|
end
|
@@ -135,33 +142,37 @@ module QED
|
|
135
142
|
|
136
143
|
def parse
|
137
144
|
tree = []
|
138
|
-
|
145
|
+
flush = true
|
139
146
|
pend = false
|
140
|
-
block = Block.new
|
147
|
+
block = Block.new(file)
|
141
148
|
lines.each do |lineno, line|
|
142
149
|
case line
|
143
150
|
when /^\s*$/
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
when :raw
|
151
|
+
if flush
|
152
|
+
pend = true unless lineno == 0
|
153
|
+
block.raw << [lineno, line]
|
154
|
+
else
|
149
155
|
block.raw << [lineno, line]
|
150
156
|
end
|
151
157
|
when /\A\s+/
|
152
|
-
|
158
|
+
if flush
|
159
|
+
tree << block.ready!(flush, tree.last)
|
160
|
+
block = Block.new(file)
|
161
|
+
end
|
162
|
+
pend = false
|
163
|
+
flush = false
|
153
164
|
block.raw << [lineno, line]
|
154
165
|
else
|
155
|
-
if pend ||
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
block = Block.new
|
166
|
+
if pend || !flush
|
167
|
+
tree << block.ready!(flush, tree.last)
|
168
|
+
pend = false
|
169
|
+
flush = true
|
170
|
+
block = Block.new(file)
|
160
171
|
end
|
161
|
-
block.
|
172
|
+
block.raw << [lineno, line]
|
162
173
|
end
|
163
174
|
end
|
164
|
-
tree << block.ready!
|
175
|
+
tree << block.ready!(flush, tree.last)
|
165
176
|
@ast = tree
|
166
177
|
end
|
167
178
|
|
@@ -176,97 +187,160 @@ module QED
|
|
176
187
|
|
177
188
|
# Section Block
|
178
189
|
class Block
|
179
|
-
# Block commentary.
|
180
|
-
attr :rem
|
181
|
-
|
182
190
|
# Block raw code/text.
|
183
191
|
attr :raw
|
184
192
|
|
193
|
+
# previous block
|
194
|
+
attr :back_step
|
195
|
+
|
196
|
+
# next block
|
197
|
+
attr :next_step
|
198
|
+
|
185
199
|
#
|
186
|
-
def initialize
|
187
|
-
@
|
188
|
-
@raw
|
189
|
-
@
|
200
|
+
def initialize(file)
|
201
|
+
@file = file
|
202
|
+
@raw = []
|
203
|
+
@type = :description
|
204
|
+
@back_step = nil
|
205
|
+
@next_step = nil
|
190
206
|
end
|
191
207
|
|
192
208
|
#
|
193
|
-
def ready!
|
194
|
-
@
|
195
|
-
@
|
196
|
-
|
197
|
-
@
|
209
|
+
def ready!(flush, back_step)
|
210
|
+
@flush = flush
|
211
|
+
@back_step = back_step
|
212
|
+
|
213
|
+
@text = raw.map{ |lineno, line| line }.join
|
214
|
+
@type = parse_type
|
215
|
+
|
216
|
+
@back_step.next_step = self if @back_step
|
217
|
+
|
198
218
|
self
|
199
219
|
end
|
200
220
|
|
201
221
|
#
|
202
|
-
def
|
203
|
-
|
222
|
+
def to_s
|
223
|
+
case type
|
224
|
+
when :description
|
225
|
+
text
|
226
|
+
else
|
227
|
+
text
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
#
|
232
|
+
def text
|
233
|
+
@text
|
204
234
|
end
|
205
235
|
|
206
236
|
#
|
207
|
-
def
|
208
|
-
@
|
237
|
+
def flush?
|
238
|
+
@flush
|
209
239
|
end
|
210
240
|
|
211
241
|
# Returns an Array of prepared example text
|
212
242
|
# for use in advice.
|
213
243
|
def arguments
|
214
|
-
|
244
|
+
if next_step && next_step.data?
|
245
|
+
[next_step.sample_text]
|
246
|
+
else
|
247
|
+
[]
|
248
|
+
end
|
215
249
|
end
|
216
250
|
|
217
|
-
#
|
218
|
-
def
|
219
|
-
@
|
251
|
+
# What type of block is this?
|
252
|
+
def type
|
253
|
+
@type
|
220
254
|
end
|
221
255
|
|
222
|
-
#
|
223
|
-
def
|
224
|
-
@line ||= @raw.first.first
|
225
|
-
end
|
256
|
+
#
|
257
|
+
def head? ; @type == :head ; end
|
226
258
|
|
227
259
|
#
|
228
|
-
def
|
229
|
-
@example
|
230
|
-
end
|
260
|
+
def desc? ; @type == :desc ; end
|
231
261
|
|
232
262
|
#
|
233
|
-
def
|
234
|
-
|
263
|
+
def code? ; @type == :code ; end
|
264
|
+
|
265
|
+
# Any commentary ending in `...` or `:` will mark the following
|
266
|
+
# block as a plain text *sample* and not example code to be evaluated.
|
267
|
+
def data? ; @type == :data ; end
|
268
|
+
|
269
|
+
#
|
270
|
+
alias_method :header?, :head?
|
271
|
+
|
272
|
+
#
|
273
|
+
alias_method :description?, :desc?
|
274
|
+
|
275
|
+
|
276
|
+
# First line of example text.
|
277
|
+
def lineno
|
278
|
+
@line ||= @raw.first.first
|
235
279
|
end
|
236
280
|
|
237
281
|
#
|
238
|
-
def
|
239
|
-
code
|
240
|
-
code.gsub!(/\n\s*\#\ ?\=\>/, '.assert == ')
|
241
|
-
code.gsub!(/\s*\#\ ?\=\>/, '.assert == ')
|
242
|
-
code
|
282
|
+
def code
|
283
|
+
@code ||= tweak_code
|
243
284
|
end
|
244
285
|
|
245
286
|
# Clean up the example text, removing unccesseary white lines
|
246
287
|
# and triple quote brackets, but keep indention intact.
|
247
|
-
def
|
248
|
-
|
249
|
-
if md = /\A["]{3,}(.*?)["]{3,}\Z/.match(
|
250
|
-
|
288
|
+
def clean_text
|
289
|
+
str = text.chomp.sub(/\A\n/,'')
|
290
|
+
if md = /\A["]{3,}(.*?)["]{3,}\Z/.match(str)
|
291
|
+
str = md[1]
|
251
292
|
end
|
252
|
-
|
293
|
+
str.rstrip
|
253
294
|
end
|
254
295
|
|
255
|
-
# When the
|
296
|
+
# When the text is sample text and passed to an adivce block, this
|
256
297
|
# provides the prepared form of the example text, removing white lines,
|
257
298
|
# triple quote brackets and indention.
|
258
|
-
def
|
259
|
-
|
260
|
-
if md = /\A["]{3,}(.*?)["]{3,}\Z/.match(
|
261
|
-
|
299
|
+
def sample_text
|
300
|
+
str = text.tabto(0).chomp.sub(/\A\n/,'')
|
301
|
+
if md = /\A["]{3,}(.*?)["]{3,}\Z/.match(str)
|
302
|
+
str = md[1]
|
303
|
+
end
|
304
|
+
str.rstrip
|
305
|
+
end
|
306
|
+
|
307
|
+
# TODO: object_hexid
|
308
|
+
def inspect
|
309
|
+
%[#<Block:#{object_id} "#{text[0..25]} ...">]
|
310
|
+
end
|
311
|
+
|
312
|
+
protected
|
313
|
+
|
314
|
+
#
|
315
|
+
def next_step=(n)
|
316
|
+
@next_step = n
|
317
|
+
end
|
318
|
+
|
319
|
+
private
|
320
|
+
|
321
|
+
#
|
322
|
+
def parse_type
|
323
|
+
if flush?
|
324
|
+
if /\A[=#]/ =~ text
|
325
|
+
:head
|
326
|
+
else
|
327
|
+
:desc
|
328
|
+
end
|
329
|
+
else
|
330
|
+
if back_step && /(\.\.\.|\:)\s*\Z/m =~ back_step.text.strip
|
331
|
+
:data
|
332
|
+
else
|
333
|
+
:code
|
334
|
+
end
|
262
335
|
end
|
263
|
-
text.rstrip
|
264
336
|
end
|
265
337
|
|
266
|
-
#
|
267
|
-
|
268
|
-
|
269
|
-
|
338
|
+
#
|
339
|
+
def tweak_code
|
340
|
+
code = text.dup
|
341
|
+
code.gsub!(/\n\s*\#\ ?\=\>/, '.assert = ')
|
342
|
+
code.gsub!(/\s*\#\ ?\=\>/, '.assert = ')
|
343
|
+
code
|
270
344
|
end
|
271
345
|
|
272
346
|
end
|