qed 2.2.2 → 2.3.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.
@@ -38,5 +38,3 @@ For instance, #define_method can be used.
38
38
 
39
39
  named_method.assert == true
40
40
 
41
-
42
-
@@ -12,15 +12,14 @@ module QED
12
12
  #
13
13
  # == Pattern Matchers (When)
14
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.
15
+ # Matchers are evaluated when they match a blocks
16
+ # commentary.
18
17
  #
19
18
  # == Event Signals (Before, After)
20
19
  #
21
20
  # Event advice are triggered on symbolic targets which
22
21
  # represent an event in the evaluation process, such as
23
- # before any demo is run, or after all demo finish running.
22
+ # before an example is run, or after a demo finishes.
24
23
  #
25
24
  class Advice
26
25
 
@@ -68,10 +67,9 @@ module QED
68
67
 
69
68
  #
70
69
  def call_matchers(scope, section)
71
- match = section.text
72
- args = section.args
73
-
74
- @matchers.each do |(patterns, proc)|
70
+ match = section.commentary
71
+ args = section.arguments
72
+ matchers.each do |(patterns, proc)|
75
73
  compare = match
76
74
  matched = true
77
75
  params = []
@@ -73,6 +73,9 @@ module QED
73
73
  # Move to root directory?
74
74
  attr_accessor :root
75
75
 
76
+ # Parse mode.
77
+ attr_accessor :mode
78
+
76
79
  #
77
80
  # TODO: Should extension and profile have a common reference?
78
81
  def initialize
@@ -121,6 +124,9 @@ module QED
121
124
  opt.on('--root', '-R', "run command from project's root directory") do
122
125
  @options[:root] = true
123
126
  end
127
+ opt.on('--comment', '-c', "Run comment code.") do
128
+ @options[:mode] = :comment
129
+ end
124
130
  opt.on('--ext', '-e NAME', "runtime extension [default]") do |name|
125
131
  @options[:extension] = name
126
132
  end
@@ -157,30 +163,51 @@ module QED
157
163
 
158
164
  # Default recognized demos file types.
159
165
  DEMO_TYPES = %w{qed rdoc md markdown}
166
+ CODE_TYPES = %w{rb}
160
167
 
161
- # Returns a list of demo files.
168
+ # Returns a list of demo files. The files returned depends on the
169
+ # +files+ attribute and if none given, then the current run mode.
162
170
  def demos
163
171
  @demos ||= (
164
- files = self.files
165
- if files.empty?
166
- files << DEMO_LOCATION
172
+ if mode == :comment
173
+ demos_in_comment_mode
174
+ else
175
+ demos_in_normal_mode
167
176
  end
168
- files = files.map{|pattern| Dir[pattern]}.flatten.uniq
169
- files = files.map do |file|
170
- if File.directory?(file)
171
- Dir[File.join(file,'**','*.{' + DEMO_TYPES.join(',') + '}')]
172
- else
173
- file
174
- end
175
- end
176
- files = files.flatten.uniq
177
- files.map{|f| File.expand_path(f) }.sort
178
177
  )
179
178
  end
180
179
 
181
- # Session instance.
182
- def session
183
- @session ||= Session.new(demos, :format=>format, :trace=>trace)
180
+ # Collect default files to process in normal demo mode.
181
+ def demos_in_normal_mode
182
+ demos_gather(DEMO_LOCATION, DEMO_TYPES)
183
+ end
184
+
185
+ # Collect default files to process in code comment mode.
186
+ #
187
+ # TODO: Sure removing applique files is the best approach?
188
+ #
189
+ # TODO: Either add environment alond with applique or deprecate environment
190
+ # as an alternate name.
191
+ def demos_in_comment_mode
192
+ files = demos_gather('lib', CODE_TYPES)
193
+ files = files.reject{ |f| f.index('applique/') } # don't include applique files ???
194
+ files
195
+ end
196
+
197
+ #
198
+ def demos_gather(default_location, extensions=DEMO_TYPES)
199
+ files = self.files
200
+ files << default_location if files.empty?
201
+ files = files.map{|pattern| Dir[pattern]}.flatten.uniq
202
+ files = files.map do |file|
203
+ if File.directory?(file)
204
+ Dir[File.join(file,'**','*.{' + extensions.join(',') + '}')]
205
+ else
206
+ file
207
+ end
208
+ end
209
+ files = files.flatten.uniq
210
+ files.map{|f| File.expand_path(f) }.sort
184
211
  end
185
212
 
186
213
  # Parse command-line options along with profile options.
@@ -221,6 +248,11 @@ module QED
221
248
  end
222
249
  end
223
250
 
251
+ # Session instance.
252
+ def session
253
+ @session ||= Session.new(demos, :format=>format, :trace=>trace, :mode=>mode)
254
+ end
255
+
224
256
  # Project's root directory.
225
257
  def root_directory
226
258
  @root_directory ||= find_root
@@ -6,9 +6,9 @@ module QED
6
6
  require 'qed/parser'
7
7
  require 'qed/evaluator'
8
8
 
9
- # = Script
9
+ # = Demo
10
10
  #
11
- class Script
11
+ class Demo
12
12
 
13
13
  #
14
14
  attr :applique
@@ -16,14 +16,18 @@ module QED
16
16
  # Demonstrandum file.
17
17
  attr :file
18
18
 
19
+ #
20
+ attr :mode
21
+
19
22
  #
20
23
  attr :scope
21
24
 
22
25
  # New Script
23
- def initialize(applique, file, scope=nil)
24
- @applique = applique.dup # localize copy of applique
26
+ def initialize(file, applique, options={})
25
27
  @file = file
26
- @scope = scope || Scope.new(applique, file)
28
+ @applique = applique.dup # localize copy of applique
29
+ @scope = options[:scope] || Scope.new(applique, file)
30
+ @mode = options[:mode]
27
31
  @binding = @scope.__binding__
28
32
  #@loadlist = []
29
33
  #apply_environment
@@ -77,7 +81,7 @@ module QED
77
81
  # Parse script.
78
82
  # Retruns an abstract syntax tree.
79
83
  def parse
80
- Parser.new(file).parse
84
+ Parser.new(file, :mode=>mode).parse
81
85
  end
82
86
 
83
87
  #
@@ -20,48 +20,47 @@ module QED
20
20
 
21
21
  #
22
22
  def run
23
- advise!(:before_document, @script)
23
+ advise!(:before_demo, @script)
24
24
  process
25
- advise!(:after_document, @script)
25
+ advise!(:after_demo, @script)
26
26
  end
27
27
 
28
28
  #
29
29
  def process
30
30
  @ast.each do |section|
31
- case section.type
32
- when :code
33
- evaluate_code(section)
34
- when :text
35
- evaluate_text(section)
36
- end
31
+ evaluate(section)
37
32
  end
38
33
  end
39
34
 
40
- #
41
- def evaluate_code(section)
42
- advise!(:before_code, section, @script.file)
35
+ # Evaluate a demo section.
36
+ def evaluate(section)
37
+ advise!(:text, section) # TODO: rename to :step?
38
+ evaluate_links(section)
39
+ advise!(:before_step, section, @script.file)
43
40
  begin
44
- advise!(:code, section)
45
- @script.evaluate(section.text, section.line)
46
- pass!(section)
47
- rescue Assertion => exception
48
- fail!(section, exception)
49
- rescue Exception => exception
50
- error!(section, exception)
41
+ advise!(:when, section)
42
+ # TODO: how to handle catching asserts in advice?
51
43
  end
52
- advise!(:after_code, section, @script.file)
53
- end
54
-
55
- #
56
- def evaluate_text(section)
57
- advise!(:text, section)
58
- evaluate_links(section)
59
- advise!(:when, section)
44
+ if section.code?
45
+ begin
46
+ advise!(:code, section)
47
+ @script.evaluate(section.eval_code, section.lineno)
48
+ rescue SystemExit
49
+ pass!(section)
50
+ rescue Assertion => exception
51
+ fail!(section, exception)
52
+ rescue Exception => exception
53
+ error!(section, exception)
54
+ else
55
+ pass!(section)
56
+ end
57
+ end
58
+ advise!(:after_step, section, @script.file)
60
59
  end
61
60
 
62
- #
61
+ # TODO: Not sure how to handle loading links in comment mode.
63
62
  def evaluate_links(section)
64
- section.text.scan(/\[qed:\/\/(.*?)\]/) do |match|
63
+ section.commentary.scan(/\[qed:\/\/(.*?)\]/) do |match|
65
64
  file = $1
66
65
  # relative to demo script
67
66
  if File.exist?(File.join(@script.directory,file))
@@ -72,7 +71,7 @@ module QED
72
71
  when '.rb'
73
72
  import!(file)
74
73
  else
75
- Script.new(@script.applique, file, @script.scope).run
74
+ Demo.new(file, @script.applique, :scope=>@script.scope).run
76
75
  end
77
76
  end
78
77
  end
@@ -1,5 +1,5 @@
1
1
  name : qed
2
2
  major: 2
3
- minor: 2
4
- patch: 2
5
- date : 2010-06-21
3
+ minor: 3
4
+ patch: 0
5
+ date : 2010-07-14
@@ -5,25 +5,80 @@ module QED
5
5
  # evaluator.
6
6
  #
7
7
  # Technically is defines it's own markup language
8
- # but for interoperability sake it ...
8
+ # but for interoperability sake it is RDoc and a bit of
9
+ # support for Markdown.
9
10
  class Parser
10
11
 
11
12
  #
12
- def initialize(file)
13
- @lines = File.readlines(file).to_a
14
- @ast = []
13
+ def initialize(file, options={})
14
+ @file = file
15
+ @options = options
16
+ @ast = []
15
17
  end
16
18
 
17
19
  # Abstract Syntax Tree
18
20
  attr :ast
19
21
 
22
+ # File to parse.
23
+ attr :file
24
+
25
+ # Parser options.
26
+ attr :options
27
+
28
+ #
29
+ def lines
30
+ @lines ||= parse_lines
31
+ end
32
+
33
+ #
34
+ def parse_lines
35
+ case options[:mode]
36
+ when :comment
37
+ parse_comment_lines
38
+ else
39
+ index = -1
40
+ File.readlines(file).to_a.map do |line|
41
+ [index += 1, line]
42
+ end
43
+ end
44
+ end
45
+
46
+ # TODO: It would be nice if we could get ther require statement for the
47
+ # comment mode to be relative to an actual loadpath.
48
+ def parse_comment_lines
49
+ omit = false
50
+ lines = [
51
+ [0, "Load #{File.basename(file)} script.\n"],
52
+ [0, "\n"],
53
+ [0, " require '#{file}'\n"]
54
+ ]
55
+ index = 0
56
+ File.readlines(file).each do |l|
57
+ case l
58
+ when /^\s*\#\-\-\s*$/
59
+ omit = true
60
+ when /^\s*\#\+\+\s*$/
61
+ omit = false
62
+ when /^\s*\#\ \-\-/ # ?
63
+ # -- skip internal comments
64
+ when /^\s*\#/
65
+ lines << [index, l.lstrip.sub(/^\#\ ?/, '')] unless omit
66
+ else
67
+ lines << [index, "\n"] unless lines.last[1] == "\n"
68
+ end
69
+ index += 1
70
+ end
71
+ lines
72
+ end
73
+
74
+ =begin
20
75
  # Parse the demo into an abstract syntax tree.
21
76
  #
22
77
  # TODO: I know there has to be a faster way to do this.
23
78
  def parse
24
79
  blocks = [[]]
25
80
  state = :none
26
- @lines.each_with_index do |line, lineno|
81
+ lines.each do |lineno, line|
27
82
  case line
28
83
  when /^$/
29
84
  case state
@@ -76,6 +131,39 @@ module QED
76
131
  #cont = (/\.\.\.\s*^/ =~ text ? true : false)
77
132
  end
78
133
  end
134
+ =end
135
+
136
+ def parse
137
+ tree = []
138
+ mode = :rem
139
+ pend = false
140
+ block = Block.new
141
+ lines.each do |lineno, line|
142
+ case line
143
+ when /^\s*$/
144
+ case mode
145
+ when :rem
146
+ pend = true unless line == 0
147
+ block.rem << [lineno, line]
148
+ when :raw
149
+ block.raw << [lineno, line]
150
+ end
151
+ when /\A\s+/
152
+ mode = :raw
153
+ block.raw << [lineno, line]
154
+ else
155
+ if pend || mode == :raw
156
+ pend = false
157
+ mode = :rem
158
+ tree << block.ready!
159
+ block = Block.new
160
+ end
161
+ block.rem << [lineno, line]
162
+ end
163
+ end
164
+ tree << block.ready!
165
+ @ast = tree
166
+ end
79
167
 
80
168
  # TODO: We need to preserve the indentation for the verbatim reporter.
81
169
  #def clean_quote(text)
@@ -86,82 +174,101 @@ module QED
86
174
  # text.rstrip
87
175
  #end
88
176
 
89
- #
90
- class Section
91
- attr :text
92
- attr :line
93
- def initialize(text, line)
94
- @text = text
95
- @line = line
177
+ # Section Block
178
+ class Block
179
+ # Block commentary.
180
+ attr :rem
181
+
182
+ # Block raw code/text.
183
+ attr :raw
184
+
185
+ #
186
+ def initialize
187
+ @rem = []
188
+ @raw = []
189
+ @has_code = true
96
190
  end
97
- end
98
191
 
99
- #
100
- class TextSection < Section
192
+ #
193
+ def ready!
194
+ @commentary = rem.map{ |lineno, line| line }.join
195
+ @example = raw.map{ |lineno, line| line }.join
196
+ @has_code = false if @raw.empty?
197
+ @has_code = false if continuation?
198
+ self
199
+ end
101
200
 
102
- attr :args
201
+ #
202
+ def commentary
203
+ @commentary
204
+ end
103
205
 
104
- attr :cont
206
+ #
207
+ def example
208
+ @example
209
+ end
105
210
 
106
- def initialize(text, line, *args)
107
- @text = text
108
- @line = line
109
- @args = args
110
- @cont = []
211
+ # Returns an Array of prepared example text
212
+ # for use in advice.
213
+ def arguments
214
+ continuation? ? [example_argument] : []
111
215
  end
112
216
 
113
217
  #
114
- def <<(text)
115
- @cont << clean_continuation(text)
116
- @args << block_continuation(text)
218
+ def code?
219
+ @has_code
220
+ end
221
+
222
+ # First line of example text.
223
+ def lineno
224
+ @line ||= @raw.first.first
117
225
  end
118
226
 
119
227
  #
120
- def type
121
- :text
228
+ def code
229
+ @example
122
230
  end
123
231
 
124
- # TODO: Use ':' or '...' ?
125
- def cont?
126
- #/\:\s*\Z/m =~ text
127
- /\.\.\.\s*\Z/m =~ text
232
+ #
233
+ def eval_code
234
+ @eval_code ||= tweak_code
128
235
  end
129
236
 
130
- # Clean up the text, removing unccesseary white lines and triple
131
- # quote brackets, but keep indention intact.
132
- def clean_continuation(text)
133
- text = text.chomp.sub(/\A\n/,'')
237
+ #
238
+ def tweak_code
239
+ code = example.dup
240
+ code.gsub!(/\n\s*\#\ ?\=\>/, '.assert == ')
241
+ code.gsub!(/\s*\#\ ?\=\>/, '.assert == ')
242
+ code
243
+ end
244
+
245
+ # Clean up the example text, removing unccesseary white lines
246
+ # and triple quote brackets, but keep indention intact.
247
+ def clean_example
248
+ text = example.chomp.sub(/\A\n/,'')
134
249
  if md = /\A["]{3,}(.*?)["]{3,}\Z/.match(text)
135
250
  text = md[1]
136
251
  end
137
252
  text.rstrip
138
253
  end
139
254
 
140
- # Block the text, removing white lines, triple quote brackets
141
- # and indention.
142
- def block_continuation(text)
143
- text = text.tabto(0).chomp.sub(/\A\n/,'')
255
+ # When the example is raw text and passed to an adivce block, this
256
+ # provides the prepared form of the example text, removing white lines,
257
+ # triple quote brackets and indention.
258
+ def example_argument
259
+ text = example.tabto(0).chomp.sub(/\A\n/,'')
144
260
  if md = /\A["]{3,}(.*?)["]{3,}\Z/.match(text)
145
261
  text = md[1]
146
262
  end
147
263
  text.rstrip
148
264
  end
149
- end
150
265
 
151
- #
152
- class CodeSection < Section
153
- #attr :args
154
- def intialize(text, line) #, *args)
155
- @text = text
156
- @line = line
157
- #@args = args
158
- end
159
- #def <<(arg)
160
- # @args << arg
161
- #end
162
- def type
163
- :code
266
+ # And commentary ending in `...` or `:` will mark the following
267
+ # example as plain text and not code to be evaluated.
268
+ def continuation?
269
+ /(\.\.\.|\:)\s*\Z/m =~ commentary
164
270
  end
271
+
165
272
  end
166
273
 
167
274
  end