turnip_formatter 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/Rakefile +13 -1
  4. data/lib/rspec/core/formatters/turnip_formatter/for_rspec2.rb +8 -13
  5. data/lib/rspec/core/formatters/turnip_formatter/for_rspec3.rb +8 -13
  6. data/lib/rspec/core/formatters/turnip_formatter.rb +6 -21
  7. data/lib/turnip_formatter/ext/turnip/rspec.rb +19 -77
  8. data/lib/turnip_formatter/printer/runtime_error.rb +7 -9
  9. data/lib/turnip_formatter/printer.rb +4 -4
  10. data/lib/turnip_formatter/scenario/base.rb +1 -5
  11. data/lib/turnip_formatter/scenario/failure.rb +24 -14
  12. data/lib/turnip_formatter/scenario/pending.rb +22 -16
  13. data/lib/turnip_formatter/step.rb +12 -6
  14. data/lib/turnip_formatter/step_template/base.rb +5 -1
  15. data/lib/turnip_formatter/step_template/exception.rb +14 -29
  16. data/lib/turnip_formatter/step_template/exception.slim +10 -0
  17. data/lib/turnip_formatter/step_template/source.rb +13 -11
  18. data/lib/turnip_formatter/template/exception.slim +8 -0
  19. data/lib/turnip_formatter/template/index.slim +86 -0
  20. data/lib/turnip_formatter/template/runtime_exception.slim +13 -0
  21. data/lib/turnip_formatter/template/scenario.slim +15 -0
  22. data/lib/turnip_formatter/template/step.slim +6 -0
  23. data/lib/turnip_formatter/template/step_multiline.slim +1 -0
  24. data/lib/turnip_formatter/template/step_outline.slim +6 -0
  25. data/lib/turnip_formatter/template/tab_feature_statistics.slim +18 -0
  26. data/lib/turnip_formatter/template/tab_speed_statistics.slim +16 -0
  27. data/lib/turnip_formatter/template/tab_tag_statistics.slim +18 -0
  28. data/lib/turnip_formatter/template/turnip_formatter.css +1 -0
  29. data/lib/turnip_formatter/template.rb +20 -35
  30. data/lib/turnip_formatter/version.rb +1 -1
  31. data/spec/support/example_helper.rb +16 -17
  32. data/spec/support/step_helper.rb +1 -1
  33. data/spec/turnip_formatter/printer/tab_speed_statistics_spec.rb +1 -1
  34. data/spec/turnip_formatter/scenario/failure_spec.rb +28 -1
  35. data/spec/turnip_formatter/scenario/pending_spec.rb +24 -1
  36. data/spec/turnip_formatter/step_template/exception_spec.rb +2 -2
  37. data/spec/turnip_formatter/template_spec.rb +114 -2
  38. data/turnip_formatter.gemspec +4 -5
  39. metadata +42 -54
  40. data/lib/turnip_formatter/template/exception.haml +0 -8
  41. data/lib/turnip_formatter/template/index.haml +0 -88
  42. data/lib/turnip_formatter/template/runtime_exception.haml +0 -13
  43. data/lib/turnip_formatter/template/scenario.haml +0 -14
  44. data/lib/turnip_formatter/template/step.haml +0 -6
  45. data/lib/turnip_formatter/template/step_multiline.haml +0 -1
  46. data/lib/turnip_formatter/template/step_outline.haml +0 -6
  47. data/lib/turnip_formatter/template/tab_feature_statistics.haml +0 -18
  48. data/lib/turnip_formatter/template/tab_speed_statistics.haml +0 -16
  49. data/lib/turnip_formatter/template/tab_tag_statistics.haml +0 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ea1f372fc6ecf5a43d8f00841896ca2d51c04f50
4
- data.tar.gz: 78bdffd1e4b1326bd44ff556fb4697d269776855
3
+ metadata.gz: b6ea6e7c30acce995aed363bc6c336fb599191c3
4
+ data.tar.gz: 32e82be9d23f41ca9b413fa8a5ea837dd4eeabdb
5
5
  SHA512:
6
- metadata.gz: 8f54ee9957426623ccafed4561f8d3d219eaaa6bf74e5a73e891a878f6442aae0424ecf0e2009d3c5ea3e823345b98da386cf50c89632c8bcecaa3103ec08cfa
7
- data.tar.gz: 78bbdd9833dea112843c297303e12c60df6ddfead24a9a3b87b27473a4e01c55e41d4ece88b042b9b1b79ff763dcb565b26d0a3c8ce9fc34b54f30c9fac06fc4
6
+ metadata.gz: 0469f34a5cf7f6da1f7345a7089a3c2ef610f6a43872e2129e63196813d5f67ee5adfd2d4d3c15ee8bc559beb8c74912d6829679a99417a29133ebf9480da1bf
7
+ data.tar.gz: 0fbbe1f9020621b623ed4da5dcf5f0db40461e6199a55aa244ed4bf4046bfde0efba6d0df27804e8ff37a231f7edef214895781bcd32b80dd95cf473b637e0a8
data/.gitignore CHANGED
@@ -16,5 +16,4 @@ test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
18
  vendor/bundle
19
- .sass-cache
20
19
  report.html
data/Rakefile CHANGED
@@ -1 +1,13 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
+ require 'sass'
3
+ require 'bootstrap-sass'
4
+
5
+ desc 'Compile report CSS file'
6
+ task :compile do
7
+ input = open('lib/turnip_formatter/template/turnip_formatter.scss').read
8
+ engine = Sass::Engine.new(input, syntax: :scss, style: :compressed)
9
+
10
+ File.open('lib/turnip_formatter/template/turnip_formatter.css', 'w') do |f|
11
+ f.write engine.render
12
+ end
13
+ end
@@ -10,35 +10,30 @@ module RSpec
10
10
  scenarios: scenarios,
11
11
  failed_count: failure_count,
12
12
  pending_count: pending_count,
13
- total_time: duration,
14
- scenario_files: scenario_output_files
13
+ total_time: duration
15
14
  }
16
15
  output_html(print_params)
17
16
  end
18
17
 
19
18
  def example_passed(example)
20
19
  scenario = ::TurnipFormatter::Scenario::Pass.new(example)
21
- output_scenario(scenario)
20
+ scenarios << scenario
22
21
  end
23
22
 
24
23
  def example_pending(example)
25
- clean_backtrace(example)
26
24
  scenario = ::TurnipFormatter::Scenario::Pending.new(example)
27
- output_scenario(scenario)
25
+ scenarios << scenario
28
26
  end
29
27
 
30
28
  def example_failed(example)
31
- clean_backtrace(example)
32
29
  scenario = ::TurnipFormatter::Scenario::Failure.new(example)
33
- output_scenario(scenario)
30
+ scenarios << scenario
34
31
  end
35
32
 
36
- private
37
-
38
- def clean_backtrace(example)
39
- return if example.exception.nil?
40
- formatted = format_backtrace(example.exception.backtrace, example)
41
- example.exception.set_backtrace(formatted)
33
+ module Helper
34
+ def formatted_backtrace(example)
35
+ RSpec::Core::BacktraceFormatter.format_backtrace(example.exception.backtrace, example.metadata)
36
+ end
42
37
  end
43
38
  end
44
39
  end
@@ -14,35 +14,30 @@ module RSpec
14
14
  scenarios: scenarios,
15
15
  failed_count: summary.failure_count,
16
16
  pending_count: summary.pending_count,
17
- total_time: summary.duration,
18
- scenario_files: scenario_output_files
17
+ total_time: summary.duration
19
18
  }
20
19
  output_html(print_params)
21
20
  end
22
21
 
23
22
  def example_passed(notification)
24
23
  scenario = ::TurnipFormatter::Scenario::Pass.new(notification.example)
25
- output_scenario(scenario)
24
+ scenarios << scenario
26
25
  end
27
26
 
28
27
  def example_pending(notification)
29
- clean_backtrace(notification)
30
28
  scenario = ::TurnipFormatter::Scenario::Pending.new(notification.example)
31
- output_scenario(scenario)
29
+ scenarios << scenario
32
30
  end
33
31
 
34
32
  def example_failed(notification)
35
- clean_backtrace(notification)
36
33
  scenario = ::TurnipFormatter::Scenario::Failure.new(notification.example)
37
- output_scenario(scenario)
34
+ scenarios << scenario
38
35
  end
39
36
 
40
- private
41
-
42
- def clean_backtrace(notification)
43
- if notification.respond_to?(:formatted_backtrace)
44
- formatted = notification.formatted_backtrace
45
- notification.example.exception.set_backtrace(formatted)
37
+ module Helper
38
+ def formatted_backtrace(example)
39
+ formatter = RSpec.configuration.backtrace_formatter
40
+ formatter.format_backtrace(example.exception.backtrace, example.metadata)
46
41
  end
47
42
  end
48
43
  end
@@ -13,41 +13,26 @@ module RSpec
13
13
  module Core
14
14
  module Formatters
15
15
  class TurnipFormatter < BaseFormatter
16
- attr_reader :scenarios, :scenario_output_files
17
-
18
- SCENARIO_TEMPORARY_OUTPUT_DIR = File.expand_path('./turnip_tmp')
16
+ attr_accessor :scenarios
19
17
 
20
18
  if Formatters.respond_to?(:register)
21
19
  include TurnipFormatter::ForRSpec3
20
+ extend TurnipFormatter::ForRSpec3::Helper
22
21
  else
23
22
  include TurnipFormatter::ForRSpec2
23
+ extend TurnipFormatter::ForRSpec2::Helper
24
24
  end
25
25
 
26
26
  def initialize(output)
27
27
  super(output)
28
28
  @scenarios = []
29
- @scenario_output_files = []
30
-
31
- FileUtils.mkdir_p(SCENARIO_TEMPORARY_OUTPUT_DIR)
32
29
  end
33
30
 
34
31
  private
35
32
 
36
- def output_html(params)
37
- output.puts ::TurnipFormatter::Printer::Index.print_out(params)
38
- FileUtils.rm_rf(SCENARIO_TEMPORARY_OUTPUT_DIR)
39
- end
40
-
41
- def output_scenario(scenario)
42
- filepath = SCENARIO_TEMPORARY_OUTPUT_DIR + "/#{scenario.id}.html"
43
-
44
- File.open(filepath, 'w') do |io|
45
- io.puts ::TurnipFormatter::Printer::Scenario.print_out(scenario)
46
- end
47
-
48
- @scenario_output_files << filepath
49
- @scenarios << scenario
50
- end
33
+ def output_html(params)
34
+ output.puts ::TurnipFormatter::Printer::Index.print_out(params)
35
+ end
51
36
  end
52
37
  end
53
38
  end
@@ -4,90 +4,32 @@ require 'turnip/rspec'
4
4
 
5
5
  module Turnip
6
6
  module RSpec
7
- module Execute
8
- def run_step(feature_file, step, index)
9
- example = Turnip::RSpec.fetch_current_example(self)
10
-
11
- begin
12
- step(step)
13
- rescue Turnip::Pending => e
14
- example.metadata[:line_number] = step.line
15
- example.metadata[:location] = "#{example.metadata[:file_path]}:#{step.line}"
16
-
17
- if ::RSpec::Version::STRING >= '2.99.0'
18
- skip("No such step(#{index}): '#{e}'")
19
- else
20
- pending("No such step(#{index}): '#{e}'")
21
- end
22
- rescue StandardError, ::RSpec::Expectations::ExpectationNotMetError => e
23
- example.metadata[:line_number] = step.line
24
- e.backtrace.push "#{feature_file}:#{step.line}:in step:#{index} `#{step.description}'"
25
- raise e
26
- end
27
- end
7
+ class << self
8
+ alias_method :original_run, :run
28
9
 
29
- def push_scenario_metadata(scenario)
30
- example = Turnip::RSpec.fetch_current_example(self)
10
+ def run(feature_file)
11
+ features = original_run(feature_file)
12
+ example_groups = ::RSpec.world.example_groups[-features.length..-1]
31
13
 
32
- steps = scenario.steps
33
- example.metadata[:turnip_formatter].tap do |turnip|
34
- steps.each do |step|
35
- turnip[:steps] << {
36
- name: step.description,
37
- extra_args: step.extra_args,
38
- keyword: step.keyword
39
- }
40
- end
41
- turnip[:tags] += scenario.tags if scenario.respond_to?(:tags)
14
+ features.zip(example_groups).each do |feature, example_group|
15
+ update_metadata(feature, example_group)
42
16
  end
43
17
  end
44
- end
45
-
46
- class << self
47
- def run(feature_file)
48
- Turnip::Builder.build(feature_file).features.each do |feature|
49
- ::RSpec.describe feature.name, feature.metadata_hash do
50
- let(:backgrounds) do
51
- feature.backgrounds
52
- end
53
-
54
- let(:background_steps) do
55
- backgrounds.map(&:steps).flatten
56
- end
57
-
58
- before do
59
- example = Turnip::RSpec.fetch_current_example(self)
60
-
61
- example.metadata[:file_path] = feature_file
62
- example.metadata[:turnip_formatter] = {
63
- steps: [], tags: feature.tags
64
- }
65
-
66
- backgrounds.each do |background|
67
- push_scenario_metadata(background)
68
- end
69
18
 
70
- background_steps.each.with_index do |step, index|
71
- run_step(feature_file, step, index)
72
- end
73
- end
19
+ #
20
+ # @param [Turnip::Builder::Feature] feature
21
+ # @param [RSpec::Core::ExampleGroup] example_group
22
+ #
23
+ def update_metadata(feature, example_group)
24
+ background_steps = feature.backgrounds.map(&:steps).flatten
25
+ examples = example_group.children
74
26
 
75
- feature.scenarios.each do |scenario|
76
- instance_eval <<-EOS, feature_file, scenario.line
77
- describe scenario.name, scenario.metadata_hash do
78
- before do
79
- push_scenario_metadata(scenario)
80
- end
27
+ feature.scenarios.zip(examples).each do |scenario, parent_example|
28
+ example = parent_example.examples.first
29
+ steps = background_steps + scenario.steps
30
+ tags = (feature.tags + scenario.tags).uniq
81
31
 
82
- it scenario.steps.map(&:description).join(' -> ') do
83
- scenario.steps.each.with_index(background_steps.size) do |step, index|
84
- run_step(feature_file, step, index)
85
- end
86
- end
87
- end
88
- EOS
89
- end
90
- end
32
+ example.metadata[:turnip_formatter] = { steps: steps, tags: tags }
91
33
  end
92
34
  end
93
35
  end
@@ -23,15 +23,13 @@ module TurnipFormatter
23
23
  end
24
24
 
25
25
  def example_exception(example)
26
- unless example.exception
27
- ''
28
- else
29
- render_template(:exception, {
30
- title: 'Example',
31
- exception: example.exception
32
- }
33
- )
34
- end
26
+ return '' unless example.exception
27
+
28
+ render_template(:exception, {
29
+ title: 'Example',
30
+ exception: example.exception
31
+ }
32
+ )
35
33
  end
36
34
  end
37
35
  end
@@ -1,4 +1,4 @@
1
- require 'tilt'
1
+ require 'slim'
2
2
 
3
3
  module TurnipFormatter
4
4
  module Printer
@@ -11,12 +11,12 @@ module TurnipFormatter
11
11
  render_template_list(name).render(self, params)
12
12
  end
13
13
 
14
- private
14
+ private
15
15
 
16
16
  def render_template_list(name)
17
17
  if templates[name].nil?
18
- path = File.dirname(__FILE__) + "/template/#{name}.haml"
19
- templates[name] = Tilt.new(path)
18
+ path = File.dirname(__FILE__) + "/template/#{name}.slim"
19
+ templates[name] = Slim::Template.new(path)
20
20
  end
21
21
 
22
22
  templates[name]
@@ -3,7 +3,7 @@ require 'turnip_formatter/step'
3
3
  module TurnipFormatter
4
4
  module Scenario
5
5
  class Base
6
- attr_reader :errors
6
+ attr_reader :errors, :example
7
7
 
8
8
  #
9
9
  # @param [RSpec::Core::Example] example
@@ -63,10 +63,6 @@ module TurnipFormatter
63
63
  example.metadata[:turnip_formatter][:tags]
64
64
  end
65
65
 
66
- def example
67
- @example
68
- end
69
-
70
66
  protected
71
67
 
72
68
  def validation
@@ -5,30 +5,40 @@ module TurnipFormatter
5
5
  class Failure < Base
6
6
  def steps
7
7
  steps = super
8
- steps[@offending_line].status = :failed
9
- steps[(@offending_line + 1)..-1].each do |step|
10
- step.status = :unexecuted
8
+ return steps unless failed_line_number
9
+
10
+ steps.each do |step|
11
+ case
12
+ when step.line == failed_line_number
13
+ step.status = :failed
14
+ when step.line > failed_line_number
15
+ step.status = :unexecuted
16
+ end
11
17
  end
18
+
12
19
  steps
13
20
  end
14
21
 
15
22
  protected
16
23
 
17
- def validation
18
- if failed_message =~ /:in step:(?<stepno>\d+) `/
19
- @offending_line = $~[:stepno].to_i
20
- else
21
- @errors << 'has no failed step information'
22
- end
23
-
24
- super
25
- end
24
+ def validation
25
+ @errors << 'has no failed step information' unless failed_line_number
26
+ super
27
+ end
26
28
 
27
29
  private
28
30
 
29
- def failed_message
30
- example.exception.backtrace.last
31
+ def failed_line_number
32
+ return @failed_line_number if @failed_line_number
33
+ return unless example.exception
34
+
35
+ filepath = File.basename(feature_file_path)
36
+ line = example.exception.backtrace.find do |backtrace|
37
+ backtrace.match(/#{filepath}:(\d+)/)
31
38
  end
39
+
40
+ @failed_line_number = Regexp.last_match[1].to_i if line
41
+ end
32
42
  end
33
43
  end
34
44
  end
@@ -5,31 +5,37 @@ module TurnipFormatter
5
5
  class Pending < Base
6
6
  def steps
7
7
  steps = super
8
- steps[@offending_line].status = :pending
9
- steps[(@offending_line + 1)..-1].each do |step|
10
- step.status = :unexecuted
8
+ return steps unless pending_line_number
9
+
10
+ steps.each do |step|
11
+ case
12
+ when step.line == pending_line_number
13
+ step.status = :pending
14
+ when step.line > pending_line_number
15
+ step.status = :unexecuted
16
+ end
11
17
  end
18
+
12
19
  steps
13
20
  end
14
21
 
15
22
  protected
16
23
 
17
- def validation
18
- if pending_message =~ /^No such step\((?<stepno>\d+)\): /
19
- @offending_line = $~[:stepno].to_i
20
- else
21
- @errors << 'has no pending step information'
22
- end
23
-
24
- super
25
- end
24
+ def validation
25
+ @errors << 'has no pending step information' unless pending_line_number
26
+ super
27
+ end
26
28
 
27
29
  private
28
30
 
29
- def pending_message
30
- result = TurnipFormatter::Helper.example_execution_result(example)
31
- result.pending_message
32
- end
31
+ def pending_line_number
32
+ example.metadata[:line_number]
33
+ end
34
+
35
+ def pending_message
36
+ result = TurnipFormatter::Helper.example_execution_result(example)
37
+ result.pending_message
38
+ end
33
39
  end
34
40
  end
35
41
  end
@@ -1,17 +1,23 @@
1
+ require 'forwardable'
2
+
1
3
  module TurnipFormatter
2
4
  class Step
5
+ extend Forwardable
6
+
3
7
  attr_reader :name, :example, :extra_args
4
8
  attr_accessor :status
5
9
 
10
+ def_delegators :@raw, :extra_args, :line, :keyword, :description
11
+
6
12
  #
7
- # @param [RSpec::Core::Example] example
8
- # @param [Hash] raw
13
+ # @param [RSpec::Core::Example] example
14
+ # @param [Turnip::Builder::Step] raw
9
15
  #
10
16
  def initialize(example, raw)
11
- @example = example
12
- @name = raw[:keyword].strip + ' ' + raw[:name]
13
- @extra_args = raw[:extra_args]
14
- @status = :passed
17
+ @example = example
18
+ @raw = raw
19
+ @name = raw.keyword.strip + ' ' + raw.description
20
+ @status = :passed
15
21
  end
16
22
  end
17
23
  end
@@ -25,10 +25,14 @@ module TurnipFormatter
25
25
  #
26
26
  # Return SCSS string that be used in this class
27
27
  #
28
- def scss
28
+ def css
29
29
  ''
30
30
  end
31
31
  end
32
+
33
+ def formatted_backtrace(example)
34
+ RSpec::Core::Formatters::TurnipFormatter.formatted_backtrace(example)
35
+ end
32
36
  end
33
37
  end
34
38
  end
@@ -1,5 +1,5 @@
1
1
  require 'turnip_formatter/step_template/base'
2
- require 'haml'
2
+ require 'slim'
3
3
 
4
4
  module TurnipFormatter
5
5
  module StepTemplate
@@ -7,23 +7,19 @@ module TurnipFormatter
7
7
  on_failed :build_failed
8
8
  on_pending :build_pending
9
9
 
10
- def self.scss
10
+ def self.css
11
11
  <<-EOS
12
- div#steps-statistics section.scenario {
13
- div.steps {
14
- div.step_exception {
15
- margin: 1em 0em;
16
- padding: 1em;
17
- border: 1px solid #999999;
18
- background-color: #eee8d5;
19
- color: #586e75;
12
+ section.scenario div.steps div.step_exception {
13
+ margin: 1em 0em;
14
+ padding: 1em;
15
+ border: 1px solid #999999;
16
+ background-color: #eee8d5;
17
+ color: #586e75;
18
+ }
20
19
 
21
- dd {
22
- margin-top: 1em;
23
- margin-left: 1em;
24
- }
25
- }
26
- }
20
+ section.scenario div.steps div.step_exception dd {
21
+ margin-top: 1em;
22
+ margin-left: 1em;
27
23
  }
28
24
  EOS
29
25
  end
@@ -32,7 +28,7 @@ module TurnipFormatter
32
28
  # @param [RSpec::Core::Example] example
33
29
  #
34
30
  def build_failed(example)
35
- build(example.exception.to_s, example.exception.backtrace)
31
+ build(example.exception.to_s, formatted_backtrace(example))
36
32
  end
37
33
 
38
34
  #
@@ -50,18 +46,7 @@ module TurnipFormatter
50
46
  end
51
47
 
52
48
  def template_step_exception
53
- @template_step_exception ||= Haml::Engine.new(<<-EOS)
54
- %div.step_exception
55
- %dl
56
- %dt Failure:
57
- %dd
58
- %pre&= message
59
- %dt Backtrace:
60
- %dd
61
- %ol
62
- - backtrace.each do |line|
63
- %li&= line
64
- EOS
49
+ @template_step_exception ||= Slim::Template.new(File.dirname(__FILE__) + "/exception.slim")
65
50
  end
66
51
  end
67
52
  end
@@ -0,0 +1,10 @@
1
+ div.step_exception
2
+ dl
3
+ dt Failure:
4
+ dd
5
+ pre= message
6
+ dt Backtrace:
7
+ dd
8
+ ol
9
+ - backtrace.each do |line|
10
+ li= line
@@ -6,25 +6,27 @@ module TurnipFormatter
6
6
  class Source < Base
7
7
  on_failed :build
8
8
 
9
- def self.scss
9
+ def self.css
10
10
  <<-EOS
11
11
  pre.source {
12
12
  font-size: 12px;
13
13
  font-family: monospace;
14
14
  background-color: #073642;
15
15
  color: #dddddd;
16
+ }
16
17
 
17
- code.ruby {
18
- padding: 0.1em 0 0.2em 0;
18
+ pre.source code.ruby {
19
+ padding: 0.1em 0 0.2em 0;
20
+ }
19
21
 
20
- .linenum {
21
- width: 75px;
22
- color: #fffbd3;
23
- padding-right: 1em;
24
- }
22
+ pre.source code.ruby .linenum {
23
+ width: 75px;
24
+ color: #fffbd3;
25
+ padding-right: 1em;
26
+ }
25
27
 
26
- .offending { background-color: gray; }
27
- }
28
+ pre.source code.ruby .offending {
29
+ background-color: gray;
28
30
  }
29
31
  EOS
30
32
  end
@@ -37,7 +39,7 @@ module TurnipFormatter
37
39
  private
38
40
 
39
41
  def location(example)
40
- example.exception.backtrace.first
42
+ formatted_backtrace(example).first
41
43
  end
42
44
 
43
45
  def extractor
@@ -0,0 +1,8 @@
1
+ dt= "#{title} Exception"
2
+ dd
3
+ pre= exception.to_s
4
+ dt= "#{title} Exception Backtrace"
5
+ dd
6
+ ol
7
+ - exception.backtrace.each do |line|
8
+ li= line