qed 1.2 → 1.3

Sign up to get free protection for your applications and to get access to all the features.
data/lib/qed/config.rb ADDED
@@ -0,0 +1,25 @@
1
+ module QED
2
+
3
+ class Config
4
+
5
+ def initialize
6
+ @local = ['qed', 'demos', 'test/demos']
7
+
8
+ if file = File.glob('{.,}config/qed.{yml,yaml}')
9
+ YAML.load(File.new(file)).each do |k,v|
10
+ __send__("#{k}=", v)
11
+ end
12
+ end
13
+ end
14
+
15
+ attr_accessor :local
16
+
17
+ # How ot identify a header?
18
+ #attr_accessor :header
19
+
20
+ # How ot identify a footer?
21
+ #attr_accessor :footer
22
+
23
+ end
24
+
25
+ end
data/lib/qed/document.rb CHANGED
@@ -36,7 +36,7 @@ module QED
36
36
  @paths ||= []
37
37
 
38
38
  if @paths.empty?
39
- dir = Dir['{test/demos,demo,demos}'].first || DEFAULT_PATH
39
+ dir = Dir['{test/demos,demos,demo}'].first || DEFAULT_PATH
40
40
  @paths = File.join(dir, '**', '*')
41
41
  end
42
42
  end
@@ -19,7 +19,7 @@
19
19
  h1 { border-bottom: 2px solid silver; }
20
20
  h2 { border-bottom: 2px solid silver; padding-top: 0.5em; }
21
21
 
22
- hr { border: 1px solid silver; }
22
+ hr { color: #ccc; margin-top: 1.6em; }
23
23
 
24
24
  p { color: #222; text-align: justify; margin-top: 0.5em; margin-bottom: 0.5em; line-height: 1.4em; }
25
25
 
@@ -0,0 +1,72 @@
1
+ module QED
2
+ module Reporter #:nodoc:
3
+
4
+ require 'qed/reporter/base'
5
+
6
+ # = DotProgress Reporter
7
+ #
8
+ class Ditto < BaseClass
9
+
10
+ #
11
+ def report_intro
12
+ #@start_time = Time.now
13
+ #io.puts "Started"
14
+ end
15
+
16
+ #
17
+ def report_step(step)
18
+ super
19
+ #if step.code
20
+ io.print "."
21
+ #str = "(%s) %s" % [count.join('.'), str.tab(6).strip]
22
+ #puts "* #{step.text.tab(2).strip}"
23
+ #puts "\n#{step.code}\n" if $VERBOSE
24
+ #else
25
+ #puts "\n#{step.text}"
26
+ #end
27
+ end
28
+
29
+ #def report(str)
30
+ # count[-1] += 1 unless count.empty?
31
+ # str = str.chomp('.') + '.'
32
+ # str = count.join('.') + ' ' + str
33
+ # puts str.strip
34
+ #end
35
+
36
+ def report_summary
37
+ io.puts "\nFinished in #{Time.now - @start_time} seconds.\n\n"
38
+
39
+ @error.each do |step, exception|
40
+ backtrace = clean_backtrace(exception.backtrace[0])
41
+ io.puts ANSICode.red("***** ERROR *****")
42
+ io.puts "#{exception}"
43
+ io.puts ":#{backtrace}:"
44
+ #io.puts ":#{exception.backtrace[1]}:"
45
+ #io.puts exception.backtrace[1..-1] if $VERBOSE
46
+ io.puts
47
+ end
48
+
49
+ @fail.each do |step, assertion|
50
+ backtrace = clean_backtrace(assertion.backtrace[0])
51
+ io.puts ANSICode.red("***** FAIL *****")
52
+ io.puts ANSICode.bold("#{assertion}")
53
+ io.puts ":#{backtrace}:"
54
+ #io.puts assertion if $VERBOSE
55
+ io.puts
56
+ end
57
+
58
+ io.puts "%s demos, %s steps, %s failures, %s errors" % [@demos, @steps, @fail.size, @error.size] #, @pass.size ]
59
+ end
60
+
61
+ private
62
+
63
+ #
64
+ def clean_backtrace(btrace)
65
+ btrace.chomp(":in `_binding'")
66
+ end
67
+
68
+ end#class DotProgress
69
+
70
+ end#module Reporter
71
+ end#module QED
72
+
@@ -37,18 +37,20 @@ module Reporter #:nodoc:
37
37
  io.puts "\nFinished in #{Time.now - @start_time} seconds.\n\n"
38
38
 
39
39
  @error.each do |step, exception|
40
+ backtrace = clean_backtrace(exception.backtrace[0])
40
41
  io.puts ANSICode.red("***** ERROR *****")
41
42
  io.puts "#{exception}"
42
- io.puts ":#{exception.backtrace[0]}:"
43
+ io.puts ":#{backtrace}:"
43
44
  #io.puts ":#{exception.backtrace[1]}:"
44
45
  #io.puts exception.backtrace[1..-1] if $VERBOSE
45
46
  io.puts
46
47
  end
47
48
 
48
49
  @fail.each do |step, assertion|
50
+ backtrace = clean_backtrace(assertion.backtrace[0])
49
51
  io.puts ANSICode.red("***** FAIL *****")
50
52
  io.puts ANSICode.bold("#{assertion}")
51
- io.puts ":#{assertion.backtrace[2]}:"
53
+ io.puts ":#{backtrace}:"
52
54
  #io.puts assertion if $VERBOSE
53
55
  io.puts
54
56
  end
@@ -56,6 +58,13 @@ module Reporter #:nodoc:
56
58
  io.puts "%s demos, %s steps, %s failures, %s errors" % [@demos, @steps, @fail.size, @error.size] #, @pass.size ]
57
59
  end
58
60
 
61
+ private
62
+
63
+ #
64
+ def clean_backtrace(btrace)
65
+ btrace.chomp(":in `_binding'")
66
+ end
67
+
59
68
  end#class DotProgress
60
69
 
61
70
  end#module Reporter
data/lib/qed/runner.rb CHANGED
@@ -1,6 +1,3 @@
1
- #require 'quarry/behave'
2
- #require 'quarry/runner/context'
3
-
4
1
  module QED
5
2
 
6
3
  require 'qed/script'
@@ -16,7 +13,7 @@ module QED
16
13
  #
17
14
  class Runner
18
15
 
19
- # QED::Spec::Runner.configure do
16
+ # QED::Runner.configure do
20
17
  # def setup(spec)
21
18
  # ...
22
19
  # end
@@ -35,8 +32,26 @@ module QED
35
32
  # end
36
33
  #end
37
34
 
35
+ def self.configure(&block)
36
+ class_eval(&block)
37
+ end
38
+
39
+ def self.start(&block)
40
+ define_method(:start, &block)
41
+ end
42
+
43
+ def self.finish(&block)
44
+ define_method(:finish, &block)
45
+ end
46
+
47
+ #
38
48
  attr :specs
39
- attr :output
49
+
50
+ #
51
+ attr_accessor :format
52
+
53
+ #
54
+ attr_accessor :trace
40
55
 
41
56
  #attr :context
42
57
  #attr :count
@@ -45,30 +60,59 @@ module QED
45
60
  #attr_accessor :after
46
61
 
47
62
  # New Specification
48
- def initialize(specs, output=nil)
49
- @specs = [specs].flatten
50
- @output = output || Reporter::DotProgress.new #(self)
63
+ def initialize(specs, options={})
64
+ @specs = [specs].flatten
65
+
66
+ @format = :dotprogress
67
+ @trace = false
68
+
69
+ options.each do |k,v|
70
+ __send__("#{k}=", v) if v
71
+ end
72
+ end
73
+
74
+ # Instance of selected Reporter subclass.
75
+ def reporter
76
+ case format
77
+ when :dotprogress
78
+ Reporter::DotProgress.new(reporter_options)
79
+ when :verbatim
80
+ Reporter::Verbatim.new(reporter_options)
81
+ when :summary
82
+ Reporter::Summary.new(reporter_options)
83
+ when :script #ditto ?
84
+ # TODO
85
+ else
86
+ Reporter::DotProgress.new(reporter_options)
87
+ end
88
+ end
89
+
90
+ # Report options.
91
+ #--
92
+ # TODO: rename :verbose to :trace
93
+ #++
94
+ def reporter_options
95
+ { :verbose => @trace }
96
+ end
97
+
98
+ #
99
+ def output
100
+ @output ||= reporter
51
101
  end
52
102
 
53
103
  #
54
104
  def check
105
+ start
55
106
  output.report_intro
56
- # loop through each specification and run it
57
- specs.each do |spec|
58
- # create a run context for the spec
59
- #@context = Context.new(spec)
60
- # run the specification
61
- run_spec(spec)
107
+ specs.each do |spec| # loop through each specification and run it
108
+ run_spec(spec) # run the specification
62
109
  end
63
110
  output.report_summary
111
+ finish
64
112
  end
65
113
 
66
114
  # Run a specification.
67
- #
68
115
  def run_spec(spec)
69
- #report(spec.description)
70
-
71
- #script = Script.load(spec, output)
72
116
  script = Script.new(spec, output)
73
117
 
74
118
  # pretty sure this is the thing to do
@@ -142,7 +186,13 @@ module QED
142
186
  end
143
187
  =end
144
188
 
189
+ def start
190
+ end
191
+
192
+ def finish
193
+ end
194
+
145
195
  end#class Runner
146
196
 
147
- end#module Quarry
197
+ end#module QED
148
198
 
data/lib/qed/script.rb CHANGED
@@ -11,6 +11,18 @@ module QED
11
11
  #Assertion = AE::Assertion
12
12
  Expectation = Assertor
13
13
 
14
+ # Global Before
15
+ def self.Before(&procedure)
16
+ @_before = procedure if procedure
17
+ @_before
18
+ end
19
+
20
+ # Global After
21
+ def self.After(&procedure)
22
+ @_after = procedure if procedure
23
+ @_after
24
+ end
25
+
14
26
  # New Specification
15
27
  #def initialize(specs, output=nil)
16
28
  # @specs = [specs].flatten
@@ -24,19 +36,20 @@ module QED
24
36
  # new(File.read(file), output)
25
37
  #end
26
38
 
39
+ # Path of demonstration script.
27
40
  attr :file
41
+
42
+ # Reporter object to issue output calls.
28
43
  attr :output
29
44
 
45
+ # List of helper scripts to require.
46
+ attr :helpers
47
+
30
48
  # New Script
31
49
  def initialize(file, output=nil)
32
- @file = file
33
- @output = output || Reporter::Verbatim.new #(self)
34
-
35
- source = File.read(file)
36
- index = source.rindex('---') || source.size
37
-
38
- @source = source[0...index]
39
- @helper = source[index+3...-1].to_s.strip
50
+ @file = file
51
+ @output = output || Reporter::Verbatim.new #(self)
52
+ parse_document(file)
40
53
  end
41
54
 
42
55
  # File basename less extension.
@@ -44,14 +57,23 @@ module QED
44
57
  @name ||= File.basename(file).chomp(File.extname(file))
45
58
  end
46
59
 
60
+ #
61
+ def directory
62
+ @directory ||= Dir.pwd #File.dirname(File.expand_path(file))
63
+ end
64
+
47
65
  #def convert
48
66
  # @source.gsub(/^\w/, '# \1')
49
67
  #end
50
68
 
51
69
  # Run the script.
52
70
  def run
53
- #steps = @source.split(/\n\s*$/)
54
- eval(@helper, context._binding, @file) if @helper
71
+ @lineno = 0
72
+
73
+ $LOAD_PATH.unshift(directory)
74
+
75
+ import_helpers
76
+
55
77
  steps.each do |step|
56
78
  output.report_step(step)
57
79
  case step
@@ -71,17 +93,31 @@ module QED
71
93
  run_step(step)
72
94
  #end
73
95
  end
96
+ @lineno += step.count("\n")
74
97
  end
98
+
99
+ $LOAD_PATH.index(directory){ |i| $LOAD_PATH.delete_at(i) }
75
100
  end
76
101
 
77
- #
102
+ #--
103
+ # NOTE: The Around code is in place should we decide
104
+ # to use it. I'm not sure yet if it's really neccessary,
105
+ # since we have Before and After.
106
+ #++
78
107
  def run_step(step=nil, &blk)
108
+ QED.Before.call if QED.Before
79
109
  context.Before.call if context.Before
80
110
  begin
81
- if blk
111
+ if blk # TODO: Is this still used?
82
112
  blk.call #eval(step, context._binding)
83
113
  else
84
- eval(step, context._binding, @file) # TODO: would be nice to know file and lineno here
114
+ #if context.Around
115
+ # context.Around.call do
116
+ # eval(step, context._binding, @file, @lineno+1)
117
+ # end
118
+ #else
119
+ eval(step, context._binding, @file, @lineno+1)
120
+ #end
85
121
  end
86
122
  output.report_pass(step) if step
87
123
  rescue Assertion => error
@@ -90,6 +126,7 @@ module QED
90
126
  output.report_error(step, error)
91
127
  ensure
92
128
  context.After.call if context.After
129
+ QED.After.call if QED.After
93
130
  end
94
131
  end
95
132
 
@@ -182,6 +219,88 @@ module QED
182
219
  @context ||= Context.new(self)
183
220
  end
184
221
 
222
+ #
223
+ def import(helper)
224
+ code = File.read(helper)
225
+ eval(code, context._binding)
226
+ end
227
+
228
+ private
229
+
230
+ # Splits the document into main source and footer
231
+ # and extract the helper document references from
232
+ # the footer.
233
+ #
234
+ def parse_document(file)
235
+ text = File.read(file)
236
+ index = text.rindex('---') || text.size
237
+ source = text[0...index]
238
+ footer = text[index+3..-1].to_s.strip
239
+ helpers = parse_helpers(footer)
240
+ @source = source
241
+ @helpers = helpers
242
+ end
243
+
244
+ #
245
+ def parse_helpers(footer)
246
+ helpers = []
247
+ footer.split("\n").each do |line|
248
+ next if line.strip == ''
249
+ case line
250
+ when /\[(.*?)\]\((.*?)\)/
251
+ helpers << $2
252
+ when /(.*?)\[(.*?)\]/
253
+ helpers << $2
254
+ end
255
+ end
256
+ helpers
257
+ end
258
+
259
+ =begin
260
+ # Looks for a master +helper.rb+ file and a special
261
+ # helpers/<name>.rb file. Both of these, when found, will
262
+ # be imported when this script is run.
263
+
264
+ def collect_helpers
265
+ dir = File.dirname(file)
266
+ list = []
267
+ list << "helper.rb" if File.exist?(File.join(dir, "helper.rb"))
268
+ list << "helpers/#{name}.rb" if File.exist?(File.join(dir, "helpers/#{name}.rb"))
269
+ list
270
+ end
271
+ =end
272
+
273
+ # TODO: How to determine where to find the env.rb file?
274
+ #def require_environment
275
+ # dir = File.dirname(file)
276
+ # dir = File.expand_path(dir)
277
+ # env = loop do
278
+ # file = File.join(dir, 'env.rb')
279
+ # break file if File.exist?(file)
280
+ # break nil if ['demo', 'demos', 'doc', 'docs', 'test', 'tests'].include? File.basename(dir)
281
+ # break nil if dir == Dir.pwd
282
+ # dir = File.dirname(dir)
283
+ # end
284
+ # require(env) if env
285
+ #end
286
+
287
+ # FIXME: where to stop looking for helpers.
288
+ def import_helpers
289
+ hlp = []
290
+ dir = Dir.pwd #File.expand_path(dir)
291
+ env = loop do
292
+ helpers.each do |helper|
293
+ file = File.join(dir, 'helpers', helper)
294
+ if File.exist?(file)
295
+ hlp << file
296
+ end
297
+ end
298
+ break if ['qed', 'demo', 'demos', 'doc', 'docs', 'test', 'tests'].include? File.basename(dir)
299
+ dir = File.dirname(dir)
300
+ end
301
+ hlp.each{ |helper| import(helper) }
302
+ end
303
+
185
304
  end
186
305
 
187
306
  #
@@ -211,6 +330,27 @@ module QED
211
330
  @_after
212
331
  end
213
332
 
333
+ # Run code around each step.
334
+ #
335
+ # Around procedures must take a block, in which the step is run.
336
+ #
337
+ # Around do |&step|
338
+ # ... do something here ...
339
+ # step.call
340
+ # ... do stiff stuff ...
341
+ # end
342
+ #
343
+ #def Around(&procedure)
344
+ # @_around = procedure if procedure
345
+ # @_around
346
+ #end
347
+
348
+ # Comment match procedure.
349
+ #
350
+ # This is useful for creating unobtrusive setup and (albeit more
351
+ # limited) teardown code. A pattern is matched against each comment
352
+ # as it is processed. If there is match, the code procedure is
353
+ # triggered, passing in any mathcing expression arguments.
214
354
  #
215
355
  def When(pattern=nil, &procedure)
216
356
  return @_when unless procedure
@@ -221,6 +361,24 @@ module QED
221
361
  @_when << [pattern, procedure]
222
362
  end
223
363
 
364
+ # Code match-and-transform procedure.
365
+ #
366
+ # This is useful to transform human readable code examples
367
+ # into proper exectuable code. For example, say you want to
368
+ # run shell code, but want to make if look like typical
369
+ # shelle examples:
370
+ #
371
+ # $ cp fixture/a.rb fixture/b.rb
372
+ #
373
+ # You can use a transform to convert lines starting with '$'
374
+ # into executable Ruby using #system.
375
+ #
376
+ # system('cp fixture/a.rb fixture/b.rb')
377
+ #
378
+ #def Transform(pattern=nil, &procedure)
379
+ #
380
+ #end
381
+
224
382
  # Table-based steps.
225
383
  def Table(file=nil, &blk)
226
384
  file = file || @_tables.last