webkit-rspec-formatter 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data.tar.gz.sig +0 -0
  2. data/ChangeLog +81 -0
  3. data/LICENSE +27 -0
  4. data/README.md +26 -0
  5. data/Rakefile +370 -0
  6. data/data/webkit-rspec-formatter/css/textmate-rspec.css +332 -0
  7. data/data/webkit-rspec-formatter/images/clock.png +0 -0
  8. data/data/webkit-rspec-formatter/images/cross_circle.png +0 -0
  9. data/data/webkit-rspec-formatter/images/cross_circle_frame.png +0 -0
  10. data/data/webkit-rspec-formatter/images/cross_octagon.png +0 -0
  11. data/data/webkit-rspec-formatter/images/cross_octagon_frame.png +0 -0
  12. data/data/webkit-rspec-formatter/images/cross_shield.png +0 -0
  13. data/data/webkit-rspec-formatter/images/exclamation.png +0 -0
  14. data/data/webkit-rspec-formatter/images/exclamation_frame.png +0 -0
  15. data/data/webkit-rspec-formatter/images/exclamation_shield.png +0 -0
  16. data/data/webkit-rspec-formatter/images/exclamation_small.png +0 -0
  17. data/data/webkit-rspec-formatter/images/plus_circle.png +0 -0
  18. data/data/webkit-rspec-formatter/images/plus_circle_frame.png +0 -0
  19. data/data/webkit-rspec-formatter/images/question.png +0 -0
  20. data/data/webkit-rspec-formatter/images/question_frame.png +0 -0
  21. data/data/webkit-rspec-formatter/images/question_shield.png +0 -0
  22. data/data/webkit-rspec-formatter/images/question_small.png +0 -0
  23. data/data/webkit-rspec-formatter/images/tick.png +0 -0
  24. data/data/webkit-rspec-formatter/images/tick_circle.png +0 -0
  25. data/data/webkit-rspec-formatter/images/tick_circle_frame.png +0 -0
  26. data/data/webkit-rspec-formatter/images/tick_shield.png +0 -0
  27. data/data/webkit-rspec-formatter/images/tick_small.png +0 -0
  28. data/data/webkit-rspec-formatter/images/tick_small_circle.png +0 -0
  29. data/data/webkit-rspec-formatter/images/ticket.png +0 -0
  30. data/data/webkit-rspec-formatter/images/ticket_arrow.png +0 -0
  31. data/data/webkit-rspec-formatter/images/ticket_exclamation.png +0 -0
  32. data/data/webkit-rspec-formatter/images/ticket_minus.png +0 -0
  33. data/data/webkit-rspec-formatter/images/ticket_pencil.png +0 -0
  34. data/data/webkit-rspec-formatter/images/ticket_plus.png +0 -0
  35. data/data/webkit-rspec-formatter/images/ticket_small.png +0 -0
  36. data/data/webkit-rspec-formatter/js/jquery-1.4.2.min.js +154 -0
  37. data/data/webkit-rspec-formatter/js/textmate-rspec.js +402 -0
  38. data/data/webkit-rspec-formatter/templates/failed.rhtml +35 -0
  39. data/data/webkit-rspec-formatter/templates/footer.rhtml +9 -0
  40. data/data/webkit-rspec-formatter/templates/header.rhtml +35 -0
  41. data/data/webkit-rspec-formatter/templates/page.rhtml +131 -0
  42. data/data/webkit-rspec-formatter/templates/passed.rhtml +10 -0
  43. data/data/webkit-rspec-formatter/templates/pending-fixed.rhtml +25 -0
  44. data/data/webkit-rspec-formatter/templates/pending.rhtml +14 -0
  45. data/lib/rspec/core/formatters/web_kit.rb +4 -0
  46. data/lib/rspec/core/formatters/webkit.rb +222 -0
  47. data/lib/rspec/mate/runner.rb +65 -0
  48. data/rake/191_compat.rb +26 -0
  49. data/rake/dependencies.rb +76 -0
  50. data/rake/documentation.rb +123 -0
  51. data/rake/helpers.rb +502 -0
  52. data/rake/hg.rb +287 -0
  53. data/rake/manual.rb +787 -0
  54. data/rake/packaging.rb +129 -0
  55. data/rake/publishing.rb +339 -0
  56. data/rake/style.rb +62 -0
  57. data/rake/svn.rb +668 -0
  58. data/rake/testing.rb +151 -0
  59. data/rake/verifytask.rb +64 -0
  60. metadata +217 -0
  61. metadata.gz.sig +0 -0
@@ -0,0 +1,131 @@
1
+ <div class="example-group">
2
+ <dl>
3
+ <dt id="example-group-1">Treequel::Filter</dt>
4
+ <dd class="spec passed"><span class="spec-name">knows that it is promiscuous (will match any entry) if its component is promiscuous</span></dd>
5
+ <dd class="spec passed"><span class="spec-name">knows that it isn't promiscuous if its component isn't promiscuous</span></dd>
6
+ <dd class="spec passed"><span class="spec-name">defaults to selecting everything</span></dd>
7
+ <dd class="spec passed"><span class="spec-name">can be created from a string literal</span></dd>
8
+ <dd class="spec passed"><span class="spec-name">wraps string literal instances in parens if it requires them</span></dd>
9
+ <dd class="spec passed"><span class="spec-name">parses a single Symbol argument as a presence filter</span></dd>
10
+ <dd class="spec passed"><span class="spec-name">parses a single-element Array with a Symbol as a presence filter</span></dd>
11
+ <dd class="spec passed"><span class="spec-name">parses a Symbol+value pair as a simple item equal filter</span></dd>
12
+ <dd class="spec passed"><span class="spec-name">parses a Symbol+value pair in an Array as a simple item equal filter</span></dd>
13
+ <dd class="spec passed"><span class="spec-name">parses an AND expression with only a single clause</span></dd>
14
+ <dd class="spec passed"><span class="spec-name">parses an AND expression with multiple clauses</span></dd>
15
+ <dd class="spec passed"><span class="spec-name">parses an OR expression with only a single clause</span></dd>
16
+ <dd class="spec passed"><span class="spec-name">parses an OR expression with multiple clauses</span></dd>
17
+ <dd class="spec passed"><span class="spec-name">parses an OR expression with String literal clauses</span></dd>
18
+ <dd class="spec passed"><span class="spec-name">parses the hash form of OR expression</span></dd>
19
+ <dd class="spec passed"><span class="spec-name">parses a NOT expression with only a single clause</span></dd>
20
+ <dd class="spec passed"><span class="spec-name">raises an exception with a NOT expression that contains more than one clause</span></dd>
21
+ <dd class="spec passed"><span class="spec-name">parses a Substring item from a filter that includes an asterisk</span></dd>
22
+ <dd class="spec passed"><span class="spec-name">parses a Present item from a filter that is only an asterisk</span></dd>
23
+ <dd class="spec passed"><span class="spec-name">raises an error when an extensible item filter is given</span></dd>
24
+ <dd class="spec passed"><span class="spec-name">parses a complex nested expression</span></dd>
25
+ </dl>
26
+ </div>
27
+ <div class="example-group">
28
+ <dl>
29
+ <dt id="example-group-2">Treequel::Filter operator methods</dt>
30
+ <dd class="spec passed"><span class="spec-name">compares as equal with another filter if their components are equal</span></dd>
31
+ <dd class="spec passed"><span class="spec-name">creates a new AND filter out of two filters that are added together</span></dd>
32
+ <dd class="spec passed"><span class="spec-name">creates a new AND filter out of two filters that are bitwise-ANDed together</span></dd>
33
+ <dd class="spec passed"><span class="spec-name">doesn't include the left operand in an AND filter if it is promiscuous</span></dd>
34
+ <dd class="spec passed"><span class="spec-name">doesn't include the right operand in an AND filter if it is promiscuous</span></dd>
35
+ </dl>
36
+ </div>
37
+ <div class="example-group">
38
+ <dl>
39
+ <dt id="example-group-3">Treequel::Filter components: Treequel::Filter::FilterList</dt>
40
+ <dd class="spec passed"><span class="spec-name">stringifies by joining its stringified members</span></dd>
41
+ </dl>
42
+ </div>
43
+ <div class="example-group">
44
+ <dl>
45
+ <dt id="example-group-4">Treequel::Filter components: Treequel::Filter::Component</dt>
46
+ <dd class="spec passed"><span class="spec-name">is an abstract class</span></dd>
47
+ <dd class="spec passed"><span class="spec-name">is non-promiscuous by default</span></dd>
48
+ </dl>
49
+ </div>
50
+ <div class="example-group">
51
+ <dl>
52
+ <dt id="example-group-5">Treequel::Filter components: Treequel::Filter::SimpleItemComponent</dt>
53
+ <dd class="spec passed"><span class="spec-name">can parse a component object from a string literal</span></dd>
54
+ <dd class="spec passed"><span class="spec-name">raises an ExpressionError if it can't parse a string literal</span></dd>
55
+ <dd class="spec passed"><span class="spec-name">uses the 'equal' operator if none is specified</span></dd>
56
+ <dd class="spec passed"><span class="spec-name">knows what the appropriate operator is for its filtertype</span></dd>
57
+ <dd class="spec passed"><span class="spec-name">knows what the appropriate operator is for its filtertype even if it's set to a string</span></dd>
58
+ <dd class="spec passed"><span class="spec-name">stringifies as &lt;attribute&gt;&lt;operator&gt;&lt;value&gt;</span></dd>
59
+ <dd class="spec passed"><span class="spec-name">uses the '~=' operator if its filtertype is 'approx'</span></dd>
60
+ <dd class="spec passed"><span class="spec-name">uses the '&gt;=' operator if its filtertype is 'greater'</span></dd>
61
+ <dd class="spec pending"><span class="spec-name">uses the '&lt;=' operator if its filtertype is 'less' (PENDING: Because I can)</span></dd>
62
+ <dd class="spec passed"><span class="spec-name">raises an error if it's created with an unknown filtertype</span></dd>
63
+ </dl>
64
+ </div>
65
+ <div class="example-group">
66
+ <dl>
67
+ <dt id="example-group-6">Treequel::Filter components: Treequel::Filter::SubstringItemComponent</dt>
68
+ <dd class="spec failed">
69
+ <span class="spec-name">can parse a component object from a string literal</span>
70
+ <div class="failure" id="failure-1">
71
+ <div class="message"><code>undefined local variable or method `saadsdf' for #&lt;Spec::Example::ExampleGroup::Subclass_1::Subclass_2::Subclass_4:0x1b343d0&gt;</code></div>
72
+ <div class="backtrace">
73
+ <code><a href="txmt://open?url=file:///Users/ged/source/ruby/Treequel/spec/treequel/filter_spec.rb&amp;line=296">/Users/ged/source/ruby/Treequel/spec/treequel/filter_spec.rb:296</a> -:3</code></div>
74
+ <pre class="ruby"><code>
75
+ <span class="linenum">294</span> <span class="ident">comp</span><span class="punct">.</span><span class="ident">attribute</span><span class="punct">.</span><span class="ident">should</span> <span class="punct">==</span> <span class="punct">'</span><span class="string">description</span><span class="punct">'</span>
76
+ <span class="linenum">295</span> <span class="ident">comp</span><span class="punct">.</span><span class="ident">options</span><span class="punct">.</span><span class="ident">should</span> <span class="punct">==</span> <span class="punct">'</span><span class="string"></span><span class="punct">'</span>
77
+ <span class="offending"><span class="linenum">296</span> <span class="ident">saadsdf</span></span>
78
+ <span class="linenum">297</span> <span class="ident">comp</span><span class="punct">.</span><span class="ident">pattern</span><span class="punct">.</span><span class="ident">should</span> <span class="punct">==</span> <span class="punct">'</span><span class="string">*basecamp*</span><span class="punct">'</span>
79
+ <span class="linenum">298</span> <span class="keyword">end</span>
80
+ </code></pre>
81
+ </div>
82
+ </dd>
83
+ <dd class="spec passed"><span class="spec-name">can parse a component object from a string literal with attribute options</span></dd>
84
+ <dd class="spec passed"><span class="spec-name">raises an ExpressionError if it can't parse a string literal</span></dd>
85
+ </dl>
86
+ </div>
87
+ <div class="example-group">
88
+ <dl>
89
+ <dt id="example-group-7">Treequel::Filter components: Treequel::Filter::AndComponent</dt>
90
+ <dd class="spec passed"><span class="spec-name">stringifies as its filters ANDed together</span></dd>
91
+ <dd class="spec passed"><span class="spec-name">allows a single filter</span></dd>
92
+ </dl>
93
+ </div>
94
+ <div class="example-group">
95
+ <dl>
96
+ <dt id="example-group-8">Treequel::Filter components: Treequel::Filter::OrComponent</dt>
97
+ <dd class="spec passed"><span class="spec-name">stringifies as its filters ORed together</span></dd>
98
+ <dd class="spec failed">
99
+ <span class="spec-name">allows a single filter</span>
100
+ <div class="failure" id="failure-2">
101
+ <div class="message"><code>undefined local variable or method `sdsdf' for #&lt;Spec::Example::ExampleGroup::Subclass_1::Subclass_2::Subclass_6:0x1af8308&gt;</code></div>
102
+ <div class="backtrace"><code><a href="txmt://open?url=file:///Users/ged/source/ruby/Treequel/spec/treequel/filter_spec.rb&amp;line=335">/Users/ged/source/ruby/Treequel/spec/treequel/filter_spec.rb:335</a> -:3</code></div>
103
+ <pre class="ruby"><code>
104
+ <span class="linenum">333</span>
105
+ <span class="linenum">334</span> <span class="ident">it</span> <span class="punct">&quot;</span><span class="string">allows a single filter</span><span class="punct">&quot;</span> <span class="keyword">do</span>
106
+ <span class="offending"><span class="linenum">335</span> <span class="ident">sdsdf</span></span>
107
+ <span class="linenum">336</span> <span class="constant">Treequel</span><span class="punct">::</span><span class="constant">Filter</span><span class="punct">::</span><span class="constant">OrComponent</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span> <span class="attribute">@filter1</span> <span class="punct">).</span><span class="ident">to_s</span><span class="punct">.</span>
108
+ <span class="linenum">337</span> <span class="ident">should</span> <span class="punct">==</span> <span class="punct">'</span><span class="string">|(filter1)</span><span class="punct">'</span>
109
+ </code></pre>
110
+ </div>
111
+ </dd>
112
+ </dl>
113
+ </div>
114
+ <div class="example-group">
115
+ <dl>
116
+ <dt id="example-group-9">Treequel::Filter components: Treequel::Filter::NotComponent</dt>
117
+ <dd class="spec passed"><span class="spec-name">stringifies as the negation of its filter</span></dd>
118
+ <dd class="spec passed"><span class="spec-name">can't be created with multiple filters</span></dd>
119
+ </dl>
120
+ </div>
121
+ <div class="example-group">
122
+ <dl>
123
+ <dt id="example-group-10">Treequel::Filter support for Sequel expressions</dt>
124
+ <dd class="spec passed"><span class="spec-name">supports the boolean expression syntax</span></dd>
125
+ </dl>
126
+ </div>
127
+ </div>
128
+ </div>
129
+
130
+ </body>
131
+ </html>
@@ -0,0 +1,10 @@
1
+ <dd class="spec passed">
2
+ <span class="spec-name"><%= h(example.description) %></span>
3
+
4
+ % unless log_messages.nil? || log_messages.empty?
5
+ <div class="log-messages">
6
+ <%= log_messages.join("\n") %>
7
+ </div>
8
+ % end
9
+ </dd>
10
+
@@ -0,0 +1,25 @@
1
+
2
+ <dd class="spec pending-fixed">
3
+ <span class="spec-name"><%= h(example.description) %></span>
4
+ <div class="failure" id="failure-<%= counter %>">
5
+
6
+ <div class="message">Expected pending
7
+ <code><%= h(example.metadata[:execution_result][:pending_message]) %></code>
8
+ to fail. No Error was raised.
9
+ </div>
10
+
11
+ <div class="backtrace"><p><code>
12
+ % format_backtrace(exception.backtrace, example).each do |backtrace_info|
13
+ <span class="backtrace-frame"><%= backtrace_info %></span><br />
14
+ % end
15
+ </code></p></div>
16
+ <%= extra %>
17
+ </div>
18
+
19
+ % unless log_messages.nil? || log_messages.empty?
20
+ <div class="log-messages">
21
+ <%= log_messages.join("\n") %>
22
+ </div>
23
+ % end
24
+ </dd>
25
+
@@ -0,0 +1,14 @@
1
+
2
+ <dd class="spec pending">
3
+ <span class="spec-name"><%= h(example.description) %></span>
4
+ <span class="pending-message">
5
+ (Pending <%= example.execution_result[:pending_message] %>)
6
+ </span>
7
+
8
+ % unless log_messages.nil? || log_messages.empty?
9
+ <div class="log-messages">
10
+ <%= log_messages.join("\n") %>
11
+ </div>
12
+ % end
13
+ </dd>
14
+
@@ -0,0 +1,4 @@
1
+ # Alow the formatter to be loaded as rspec/core/formatters/web_kit
2
+
3
+ require 'rspec/core/formatters/webkit'
4
+
@@ -0,0 +1,222 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pp'
4
+ require 'rbconfig'
5
+ require 'erb'
6
+ require 'pathname'
7
+
8
+ require 'rspec'
9
+ require 'rspec/core/formatters/base_text_formatter'
10
+ require 'rspec/core/formatters/snippet_extractor'
11
+
12
+ class RSpec::Core::Formatters::WebKit < RSpec::Core::Formatters::BaseTextFormatter
13
+ include ERB::Util
14
+
15
+ # Version constant
16
+ VERSION = '2.0.0'
17
+
18
+ # Look up the datadir falling back to a relative path (mostly for prerelease testing)
19
+ DEFAULT_DATADIR = Pathname( Config.datadir('webkit-rspec-formatter') )
20
+ if DEFAULT_DATADIR.exist?
21
+ BASE_PATH = DEFAULT_DATADIR
22
+ else
23
+ BASE_PATH = Pathname( __FILE__ ).dirname.parent.parent.parent.parent +
24
+ 'data/webkit-rspec-formatter'
25
+ end
26
+
27
+ # The base HREF used in the header to map stuff to the datadir
28
+ BASE_HREF = "file://#{BASE_PATH}/"
29
+
30
+ # The directory to grab ERb templates out of
31
+ TEMPLATE_DIR = BASE_PATH + 'templates'
32
+
33
+ # The page part templates
34
+ HEADER_TEMPLATE = TEMPLATE_DIR + 'header.rhtml'
35
+ PASSED_EXAMPLE_TEMPLATE = TEMPLATE_DIR + 'passed.rhtml'
36
+ FAILED_EXAMPLE_TEMPLATE = TEMPLATE_DIR + 'failed.rhtml'
37
+ PENDING_EXAMPLE_TEMPLATE = TEMPLATE_DIR + 'pending.rhtml'
38
+ PENDFIX_EXAMPLE_TEMPLATE = TEMPLATE_DIR + 'pending-fixed.rhtml'
39
+ FOOTER_TEMPLATE = TEMPLATE_DIR + 'footer.rhtml'
40
+
41
+
42
+ ### Create a new formatter
43
+ def initialize( output ) # :notnew:
44
+ super
45
+ @previous_nesting_depth = 0
46
+ @example_number = 0
47
+ @failcounter = 0
48
+ @snippet_extractor = RSpec::Core::Formatters::SnippetExtractor.new
49
+ @example_templates = {
50
+ :passed => self.load_template(PASSED_EXAMPLE_TEMPLATE),
51
+ :failed => self.load_template(FAILED_EXAMPLE_TEMPLATE),
52
+ :pending => self.load_template(PENDING_EXAMPLE_TEMPLATE),
53
+ :pending_fixed => self.load_template(PENDFIX_EXAMPLE_TEMPLATE),
54
+ }
55
+
56
+ Thread.current['logger-output'] = []
57
+ end
58
+
59
+
60
+ ######
61
+ public
62
+ ######
63
+
64
+ # Attributes made readable for ERb
65
+ attr_reader :example_group_number, :example_number, :example_count
66
+
67
+ # The counter for failed example IDs
68
+ attr_accessor :failcounter
69
+
70
+
71
+ ### Start the page by rendering the header.
72
+ def start( example_count )
73
+ @output.puts self.render_header( example_count )
74
+ @output.flush
75
+ end
76
+
77
+
78
+ ### Callback called by each example group when it's entered --
79
+ def example_group_started( example_group )
80
+ super
81
+ nesting_depth = example_group.ancestors.length
82
+
83
+ # Close the previous example groups if this one isn't a
84
+ # descendent of the previous one
85
+ if @previous_nesting_depth.nonzero? && @previous_nesting_depth >= nesting_depth
86
+ ( @previous_nesting_depth - nesting_depth + 1 ).times do
87
+ @output.puts " </dl>", "</section>", " </dd>"
88
+ end
89
+ end
90
+
91
+ @output.puts "<!-- nesting: %d, previous: %d -->" %
92
+ [ nesting_depth, @previous_nesting_depth ]
93
+ @previous_nesting_depth = nesting_depth
94
+
95
+ if @previous_nesting_depth == 1
96
+ @output.puts %{<section class="example-group">}
97
+ else
98
+ @output.puts %{<dd class="nested-group"><section class="example-group">}
99
+ end
100
+
101
+ @output.puts %{ <dl>},
102
+ %{ <dt id="%s">%s</dt>} % [
103
+ example_group.name.gsub(/[\W_]+/, '-').downcase,
104
+ h(example_group.description)
105
+ ]
106
+ @output.flush
107
+ end
108
+ alias_method :add_example_group, :example_group_started
109
+
110
+
111
+ ### Fetch any log messages added to the thread-local Array
112
+ def log_messages
113
+ return Thread.current[ 'logger-output' ] || []
114
+ end
115
+
116
+
117
+ ### Callback -- called when the examples are finished.
118
+ def start_dump
119
+ @previous_nesting_depth.downto( 1 ) do |i|
120
+ @output.puts " </dl>",
121
+ "</section>"
122
+ @output.puts " </dd>" unless i == 1
123
+ end
124
+
125
+ @output.flush
126
+ end
127
+
128
+
129
+ ### Callback -- called when an example is entered
130
+ def example_started( example )
131
+ @example_number += 1
132
+ Thread.current[ 'logger-output' ] ||= []
133
+ Thread.current[ 'logger-output' ].clear
134
+ end
135
+
136
+
137
+ ### Callback -- called when an example is exited with no failures.
138
+ def example_passed( example )
139
+ status = 'passed'
140
+ @output.puts( @example_templates[:passed].result(binding()) )
141
+ @output.flush
142
+ end
143
+
144
+
145
+ ### Callback -- called when an example is exited with a failure.
146
+ def example_failed( example )
147
+ super
148
+
149
+ counter = self.failcounter += 1
150
+ exception = example.metadata[:execution_result][:exception_encountered]
151
+ extra = self.extra_failure_content( exception )
152
+ template = if exception.is_a?( RSpec::Core::PendingExampleFixedError )
153
+ then @example_templates[:pending_fixed]
154
+ else @example_templates[:failed]
155
+ end
156
+
157
+ @output.puts( template.result(binding()) )
158
+ @output.flush
159
+ end
160
+
161
+
162
+ ### Callback -- called when an example is exited via a 'pending'.
163
+ def example_pending( example )
164
+ status = 'pending'
165
+ @output.puts( @example_templates[:pending].result(binding()) )
166
+ @output.flush
167
+ end
168
+
169
+
170
+ ### Format backtrace lines to include a textmate link to the file/line in question.
171
+ def backtrace_line( line )
172
+ return nil unless line = super
173
+ return nil if line =~ %r{r?spec/mate|textmate-command}
174
+ return h( line.strip ).gsub( /([^:]*\.rb):(\d*)/ ) do
175
+ "<a href=\"txmt://open?url=file://#{File.expand_path($1)}&amp;line=#{$2}\">#{$1}:#{$2}</a> "
176
+ end
177
+ end
178
+
179
+
180
+ ### Return any stuff that should be appended to the current example
181
+ ### because it's failed. Returns a snippet of the source around the
182
+ ### failure.
183
+ def extra_failure_content( exception )
184
+ snippet = @snippet_extractor.snippet( exception )
185
+ return " <pre class=\"ruby\"><code>#{snippet}</code></pre>"
186
+ end
187
+
188
+
189
+ ### Returns content to be output when a failure occurs during the run; overridden to
190
+ ### do nothing, as failures are handled by #example_failed.
191
+ def dump_failures( *unused )
192
+ end
193
+
194
+
195
+ ### Output the content generated at the end of the run.
196
+ def dump_summary( duration, example_count, failure_count, pending_count )
197
+ @output.puts self.render_footer( duration, example_count, failure_count, pending_count )
198
+ @output.flush
199
+ end
200
+
201
+
202
+ ### Render the header template in the context of the receiver.
203
+ def render_header( example_count )
204
+ template = self.load_template( HEADER_TEMPLATE )
205
+ return template.result( binding() )
206
+ end
207
+
208
+
209
+ ### Render the footer template in the context of the receiver.
210
+ def render_footer( duration, example_count, failure_count, pending_count )
211
+ template = self.load_template( FOOTER_TEMPLATE )
212
+ return template.result( binding() )
213
+ end
214
+
215
+
216
+ ### Load the ERB template at +templatepath+ and return it.
217
+ ### @param [Pathname] templatepath the fully-qualified path to the template file
218
+ def load_template( templatepath )
219
+ return ERB.new( templatepath.read, nil, '%<>' ).freeze
220
+ end
221
+
222
+ end # class RSpec::Core::Formatter::WebKitFormatter
@@ -0,0 +1,65 @@
1
+
2
+ rspec_rails_plugin = File.join( ENV['TM_PROJECT_DIRECTORY'], 'vendor', 'plugins', 'rspec', 'lib' )
3
+
4
+ if File.directory?( rspec_rails_plugin )
5
+ $LOAD_PATH.unshift( rspec_rails_plugin )
6
+ elsif ENV['TM_RSPEC_HOME']
7
+ rspec_lib = File.join( ENV['TM_RSPEC_HOME'], 'lib' )
8
+ raise "TM_RSPEC_HOME points to a bad location: #{ENV['TM_RSPEC_HOME']}" unless
9
+ File.directory?( rspec_lib )
10
+ $LOAD_PATH.unshift( rspec_lib )
11
+ end
12
+
13
+ begin
14
+ require 'spec'
15
+ require 'spec/runner/formatter/webkit'
16
+ rescue LoadError => err
17
+ unless Object.const_defined?( :Gem )
18
+ require 'rubygems'
19
+ retry
20
+ end
21
+ raise
22
+ end
23
+
24
+ class SpecMate
25
+ def run_files(stdout, options={})
26
+ files = ENV['TM_SELECTED_FILES'].split(" ").map do |path|
27
+ File.expand_path(path[1..-2])
28
+ end
29
+ options.merge!({:files => files})
30
+ run(stdout, options)
31
+ end
32
+
33
+ def run_file(stdout, options={})
34
+ options.merge!({:files => [single_file]})
35
+ run(stdout, options)
36
+ end
37
+
38
+ def run_focussed(stdout, options={})
39
+ options.merge!({:files => [single_file], :line => ENV['TM_LINE_NUMBER']})
40
+ run(stdout, options)
41
+ end
42
+
43
+ def run(stdout, options)
44
+ formatter = ENV['TM_RSPEC_FORMATTER'] || 'RSpec::Core::Formatter::WebKit'
45
+
46
+ argv = []
47
+ argv += ENV['TM_RSPEC_OPTS'].split(" ") if ENV['TM_RSPEC_OPTS']
48
+ argv += options[:files].dup
49
+ argv << '--format' << formatter
50
+ argv << '--line' << options[:line] if options[:line]
51
+
52
+ Dir.chdir(ENV['TM_PROJECT_DIRECTORY']) do
53
+ ::RSpec::Core::CommandLine.run(RSpec::Core::OptionParser.parse(argv, STDERR, stdout))
54
+ end
55
+ end
56
+
57
+ protected
58
+ def single_file
59
+ File.expand_path(ENV['TM_FILEPATH'])
60
+ end
61
+
62
+ def project_directory
63
+ File.expand_path(ENV['TM_PROJECT_DIRECTORY'])
64
+ end
65
+ end