qed 2.2.2 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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