specdown 0.3.0 → 0.4.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.markdown +7 -0
- data/README.markdown +84 -8
- data/VERSION +1 -1
- data/features/command.feature +3 -1
- data/features/config.feature +3 -3
- data/features/fixtures/codeblocks_and_implicits.markdown +7 -0
- data/features/implicit_parser.feature +113 -0
- data/features/implicit_specs.feature +135 -0
- data/features/parser.feature +69 -1
- data/features/pending_specs.feature +49 -0
- data/features/report_summary.feature +1 -1
- data/features/specdown_examples/complete_implicit/specdown/implicit.specdown +4 -0
- data/features/specdown_examples/complete_implicit/specdown/test.markdown +3 -0
- data/features/specdown_examples/no_implicit/specdown/test.markdown +3 -0
- data/features/specdown_examples/pending_implicit/specdown/implicit.specdown +4 -0
- data/features/specdown_examples/pending_implicit/specdown/test.markdown +3 -0
- data/features/specdown_examples/pending_specs/specdown/test.markdown +7 -0
- data/features/step_definitions/command.rb +7 -3
- data/features/step_definitions/implicit_parser.rb +19 -0
- data/features/step_definitions/implicit_specs.rb +18 -0
- data/features/step_definitions/parser.rb +24 -0
- data/features/step_definitions/pending_specs.rb +7 -0
- data/features/support/env.rb +6 -0
- data/lib/specdown.rb +6 -0
- data/lib/specdown/config.rb +12 -1
- data/lib/specdown/event_handlers/test_pending.rb +3 -0
- data/lib/specdown/event_handlers/test_undefined.rb +3 -0
- data/lib/specdown/implicit_parser.rb +47 -0
- data/lib/specdown/node.rb +2 -1
- data/lib/specdown/parser.rb +40 -6
- data/lib/specdown/pending.rb +7 -0
- data/lib/specdown/pending_exception.rb +4 -0
- data/lib/specdown/reporter.rb +8 -0
- data/lib/specdown/reporters/color_terminal_reporter.rb +12 -0
- data/lib/specdown/reporters/terminal_reporter.rb +16 -0
- data/lib/specdown/reporters/text_reporter.rb +8 -0
- data/lib/specdown/runner.rb +25 -16
- data/lib/specdown/runner/report_summary.rb +8 -0
- data/lib/specdown/runner/stats.rb +13 -2
- data/lib/specdown/sandbox_decorators/pending.rb +3 -0
- data/lib/specdown/templates/color_summary.erb +20 -4
- data/lib/specdown/templates/summary.erb +17 -0
- metadata +45 -9
data/features/parser.feature
CHANGED
@@ -171,7 +171,6 @@ Feature: Specdown Parser
|
|
171
171
|
"""
|
172
172
|
|
173
173
|
|
174
|
-
@focus
|
175
174
|
Scenario: Multiple code blocks in a section should join together with newlines
|
176
175
|
|
177
176
|
Given the following specdown example file containing multiple executable codeblocks in a single section:
|
@@ -198,3 +197,72 @@ Feature: Specdown Parser
|
|
198
197
|
"""
|
199
198
|
@tree.root.code.should == "hi = 'hello'\nputs hi"
|
200
199
|
"""
|
200
|
+
|
201
|
+
@focus
|
202
|
+
Scenario: Code blocks + Undefined Implicit Specs
|
203
|
+
|
204
|
+
Given the following README:
|
205
|
+
"""
|
206
|
+
@readme = <<-README.undent
|
207
|
+
# Specdown Example
|
208
|
+
|
209
|
+
**This is an implicit spec.**
|
210
|
+
|
211
|
+
This text has two implicit specs: **one** and **two**.
|
212
|
+
|
213
|
+
```ruby
|
214
|
+
hi = "explicit spec"
|
215
|
+
```
|
216
|
+
README
|
217
|
+
"""
|
218
|
+
|
219
|
+
When I parse it into a tree:
|
220
|
+
"""
|
221
|
+
@tree = Specdown::Parser.parse @readme
|
222
|
+
"""
|
223
|
+
|
224
|
+
Then the root node should include the explicit code:
|
225
|
+
"""
|
226
|
+
@tree.root.code.should == %{hi = "explicit spec"}
|
227
|
+
"""
|
228
|
+
|
229
|
+
And the root node should include the undefined implicit specs:
|
230
|
+
"""
|
231
|
+
@tree.root.undefined_implicits.should == ["This is an implicit spec.", "one", "two"]
|
232
|
+
"""
|
233
|
+
|
234
|
+
@focus
|
235
|
+
Scenario: Code blocks + Defined Implicit Specs
|
236
|
+
|
237
|
+
Given the following README:
|
238
|
+
"""
|
239
|
+
@readme = <<-README.undent
|
240
|
+
# Specdown Example
|
241
|
+
|
242
|
+
**This is an implicit spec.**
|
243
|
+
|
244
|
+
```ruby
|
245
|
+
hi = "explicit spec"
|
246
|
+
```
|
247
|
+
README
|
248
|
+
"""
|
249
|
+
|
250
|
+
And the following implicit specs:
|
251
|
+
"""
|
252
|
+
@implicits = <<-SPECDOWN.undent
|
253
|
+
This is an implicit spec.
|
254
|
+
-----------------------------
|
255
|
+
|
256
|
+
puts "howdy"
|
257
|
+
SPECDOWN
|
258
|
+
"""
|
259
|
+
|
260
|
+
When I parse it into a tree:
|
261
|
+
"""
|
262
|
+
@tree = Specdown::Parser.parse @readme, Specdown::ImplicitParser.parse(@implicits)
|
263
|
+
"""
|
264
|
+
|
265
|
+
Then the code block and the implicit spec should be joined together:
|
266
|
+
"""
|
267
|
+
@tree.root.code.should == %{puts "howdy"\nhi = "explicit spec"}
|
268
|
+
"""
|
@@ -0,0 +1,49 @@
|
|
1
|
+
Feature: Pending specs
|
2
|
+
|
3
|
+
You can mark a spec as pending by using the "pending" method.
|
4
|
+
|
5
|
+
For example, consider the following markdown file:
|
6
|
+
|
7
|
+
Example of Pending Specification
|
8
|
+
-----------------------------------
|
9
|
+
|
10
|
+
This spec is pending.
|
11
|
+
|
12
|
+
pending
|
13
|
+
|
14
|
+
|
15
|
+
If you ran this with specdown, you'd receive the following output:
|
16
|
+
|
17
|
+
|
18
|
+
P
|
19
|
+
|
20
|
+
1 markdown
|
21
|
+
1 test
|
22
|
+
1 pending
|
23
|
+
0 successes
|
24
|
+
0 failures
|
25
|
+
|
26
|
+
|
27
|
+
Scenario: Pending specification
|
28
|
+
|
29
|
+
Given the following markdown with a pending spec:
|
30
|
+
"""
|
31
|
+
# Example of Pending Specification
|
32
|
+
|
33
|
+
This spec is pending.
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
pending
|
37
|
+
```
|
38
|
+
"""
|
39
|
+
|
40
|
+
Then the `specdown` command should return the following output:
|
41
|
+
"""
|
42
|
+
P
|
43
|
+
|
44
|
+
1 markdown
|
45
|
+
1 test
|
46
|
+
1 pending
|
47
|
+
0 successes
|
48
|
+
0 failures
|
49
|
+
"""
|
@@ -12,7 +12,7 @@ Feature: Specdown::ReportSummary
|
|
12
12
|
|
13
13
|
Scenario: A Specdown::Reporter instantiated with a single stats object
|
14
14
|
|
15
|
-
Given the following specdown example file
|
15
|
+
Given the following specdown example file:
|
16
16
|
"""
|
17
17
|
# Specdown Example
|
18
18
|
|
@@ -3,9 +3,7 @@ When /^I run `specdown` from the command line in a directory that contains no 's
|
|
3
3
|
end
|
4
4
|
|
5
5
|
Then /^I should see the following output:$/ do |string|
|
6
|
-
string
|
7
|
-
@output.should include(line.strip)
|
8
|
-
end
|
6
|
+
ensure_included! string, @output
|
9
7
|
end
|
10
8
|
|
11
9
|
Given /^I have a specdown directory containing a (?:single )?markdown file:$/ do |string|
|
@@ -106,6 +104,12 @@ Given /^`specdown \-\-format=condensed`$/ do
|
|
106
104
|
ensure_condensed! bundle_exec!("specdown --format=condensed")
|
107
105
|
end
|
108
106
|
|
107
|
+
def ensure_included!(desired, actual)
|
108
|
+
desired.split("\n").each do |line|
|
109
|
+
actual.should include(line.strip)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
109
113
|
def ensure_condensed!(output)
|
110
114
|
output.strip.should_not be_empty
|
111
115
|
output.should match(/^[^\. ]+\.markdown: .*$/)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Given /^the following implicit specification:$/ do |string|
|
2
|
+
eval string
|
3
|
+
end
|
4
|
+
|
5
|
+
When /^I parse it with the implicit parser:$/ do |string|
|
6
|
+
eval string
|
7
|
+
end
|
8
|
+
|
9
|
+
Then /^I should receive a hash lookup of implicit definitions:$/ do |string|
|
10
|
+
eval string
|
11
|
+
end
|
12
|
+
|
13
|
+
Given /^two implicit specification strings:$/ do |string|
|
14
|
+
eval string
|
15
|
+
end
|
16
|
+
|
17
|
+
When /^I pass both off to the Specdown::ImplicitParser:$/ do |string|
|
18
|
+
eval string
|
19
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Given /^a markdown file with an implicit spec:$/ do |string|
|
2
|
+
end
|
3
|
+
|
4
|
+
Given /^no implicit specification$/ do
|
5
|
+
@directory = "features/specdown_examples/no_implicit/"
|
6
|
+
end
|
7
|
+
|
8
|
+
When /^I run the `specdown` command$/ do
|
9
|
+
@output = bundle_exec! "specdown"
|
10
|
+
end
|
11
|
+
|
12
|
+
Given /^a specdown file with a pending specification:$/ do |string|
|
13
|
+
@directory = "features/specdown_examples/pending_implicit/"
|
14
|
+
end
|
15
|
+
|
16
|
+
Given /^a specdown file with a complete specification:$/ do |string|
|
17
|
+
@directory = "features/specdown_examples/complete_implicit/"
|
18
|
+
end
|
@@ -10,6 +10,30 @@ Given /^the following specdown example file containing multiple executable codeb
|
|
10
10
|
@readme = File.read "features/fixtures/multiple_codeblocks_per_section_example.markdown"
|
11
11
|
end
|
12
12
|
|
13
|
+
Given /^the following specdown example file containing both codeblocks and implicit specs:$/ do |string|
|
14
|
+
@readme = File.read "features/fixtures/codeblocks_and_implicits.markdown"
|
15
|
+
end
|
16
|
+
|
17
|
+
Given /^the following README:$/ do |string|
|
18
|
+
eval string
|
19
|
+
end
|
20
|
+
|
21
|
+
Then /^the root node should include the explicit code:$/ do |string|
|
22
|
+
eval string
|
23
|
+
end
|
24
|
+
|
25
|
+
Then /^the root node should include the undefined implicit specs:$/ do |string|
|
26
|
+
eval string
|
27
|
+
end
|
28
|
+
|
29
|
+
Given /^the following implicit specs:$/ do |string|
|
30
|
+
eval string
|
31
|
+
end
|
32
|
+
|
33
|
+
Then /^the code block and the implicit spec should be joined together:$/ do |string|
|
34
|
+
eval string
|
35
|
+
end
|
36
|
+
|
13
37
|
When /^I parse it into a tree:$/ do |string|
|
14
38
|
eval string
|
15
39
|
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
Given /^the following markdown with a pending spec:$/ do |string|
|
2
|
+
@directory = "features/specdown_examples/pending_specs/"
|
3
|
+
end
|
4
|
+
|
5
|
+
Then /^the `specdown` command should return the following output:$/ do |string|
|
6
|
+
ensure_included! string, bundle_exec!("specdown")
|
7
|
+
end
|
data/features/support/env.rb
CHANGED
data/lib/specdown.rb
CHANGED
@@ -3,6 +3,7 @@ require 'term/ansicolor'
|
|
3
3
|
require 'erb'
|
4
4
|
require 'optparse'
|
5
5
|
require 'specdown/parser'
|
6
|
+
require 'specdown/implicit_parser'
|
6
7
|
require 'specdown/node'
|
7
8
|
require 'specdown/tree'
|
8
9
|
require 'specdown/runner'
|
@@ -17,6 +18,10 @@ require 'specdown/event_handlers/run_complete'
|
|
17
18
|
require 'specdown/event_handlers/run_started'
|
18
19
|
require 'specdown/event_handlers/test_failed'
|
19
20
|
require 'specdown/event_handlers/test_passed'
|
21
|
+
require 'specdown/event_handlers/test_pending'
|
22
|
+
require 'specdown/event_handlers/test_undefined'
|
23
|
+
require 'specdown/pending'
|
24
|
+
require 'specdown/pending_exception'
|
20
25
|
require 'specdown/config'
|
21
26
|
require 'specdown/specdown'
|
22
27
|
require 'specdown/sandbox_factory'
|
@@ -31,3 +36,4 @@ require 'specdown/reporters/text_reporter'
|
|
31
36
|
require 'specdown/sandbox_decorators/default_assertion_library'
|
32
37
|
require 'specdown/sandbox_decorators/rspec_expectations'
|
33
38
|
require 'specdown/sandbox_decorators/test_unit_assertions'
|
39
|
+
require 'specdown/sandbox_decorators/pending'
|
data/lib/specdown/config.rb
CHANGED
@@ -9,7 +9,7 @@ module Specdown
|
|
9
9
|
attr_accessor :format
|
10
10
|
|
11
11
|
def format
|
12
|
-
@format ||= :
|
12
|
+
@format ||= :condensed
|
13
13
|
end
|
14
14
|
|
15
15
|
def reporter
|
@@ -35,6 +35,12 @@ module Specdown
|
|
35
35
|
@tests ||= find_tests_in root
|
36
36
|
end
|
37
37
|
|
38
|
+
def implicit_specs
|
39
|
+
return @implicit_specs if @implicit_specs
|
40
|
+
implicit_spec_files = find_implicit_specs_in(root).map {|file| File.read(file)}
|
41
|
+
@implicit_specs = Specdown::ImplicitParser.parse *implicit_spec_files
|
42
|
+
end
|
43
|
+
|
38
44
|
def tests=(test_files)
|
39
45
|
unless test_files.empty?
|
40
46
|
@tests = test_files
|
@@ -66,6 +72,11 @@ module Specdown
|
|
66
72
|
Dir["#{directory}/**/*.markdown"] + Dir["#{directory}/**/*.md"]
|
67
73
|
end
|
68
74
|
|
75
|
+
def find_implicit_specs_in(directory)
|
76
|
+
directory = strip_trailing_slash directory
|
77
|
+
Dir["#{directory}/**/*.specdown"]
|
78
|
+
end
|
79
|
+
|
69
80
|
def strip_trailing_slash(string)
|
70
81
|
if string[-1..-1] == "/"
|
71
82
|
string[0...-1]
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Specdown
|
2
|
+
class ImplicitParser
|
3
|
+
def self.parse(*implicit_specifications)
|
4
|
+
self.new(*implicit_specifications).parse
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize(*implicit_specifications)
|
8
|
+
@specs = implicit_specifications
|
9
|
+
@lookups = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse
|
13
|
+
@specs.each do |spec|
|
14
|
+
kramdown = Kramdown::Document.new spec, :input => "GithubMarkdown"
|
15
|
+
build_lookup kramdown.root.children
|
16
|
+
end
|
17
|
+
|
18
|
+
@lookups
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def build_lookup(parsed_elements)
|
23
|
+
scan_for_header parsed_elements
|
24
|
+
consume_section parsed_elements until parsed_elements.empty?
|
25
|
+
end
|
26
|
+
|
27
|
+
def consume_section(parsed_elements)
|
28
|
+
key = parsed_elements.shift.options[:raw_text]
|
29
|
+
value = ""
|
30
|
+
|
31
|
+
while !parsed_elements.empty? && parsed_elements.first.type != :header
|
32
|
+
element = parsed_elements.shift
|
33
|
+
value += "\n" + element.value.to_s.strip if element.type == :codeblock && ([nil, "ruby", ""].include? element.options["language"])
|
34
|
+
end
|
35
|
+
|
36
|
+
@lookups[key] = value.strip
|
37
|
+
end
|
38
|
+
|
39
|
+
def scan_for_header(parsed_elements)
|
40
|
+
until parsed_elements.empty? || (
|
41
|
+
parsed_elements.first.type == :header
|
42
|
+
)
|
43
|
+
parsed_elements.shift
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/specdown/node.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
module Specdown
|
2
2
|
class Node
|
3
|
-
attr_accessor :name, :code, :contents, :children, :parent
|
3
|
+
attr_accessor :name, :code, :undefined_implicits, :contents, :children, :parent
|
4
4
|
|
5
5
|
def initialize
|
6
6
|
@code = ''
|
7
7
|
@contents = ''
|
8
8
|
@children = []
|
9
|
+
@undefined_implicits = []
|
9
10
|
end
|
10
11
|
|
11
12
|
def code
|
data/lib/specdown/parser.rb
CHANGED
@@ -1,15 +1,22 @@
|
|
1
1
|
module Specdown
|
2
|
-
|
3
|
-
|
2
|
+
class Parser
|
3
|
+
def self.parse(readme, lookups={})
|
4
|
+
self.new(readme, lookups).parse
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize(readme, lookups={})
|
8
|
+
@readme = readme
|
9
|
+
@lookups = lookups
|
10
|
+
end
|
4
11
|
|
5
|
-
def parse
|
6
|
-
kramdown = Kramdown::Document.new readme, :input => "GithubMarkdown"
|
12
|
+
def parse
|
13
|
+
kramdown = Kramdown::Document.new @readme, :input => "GithubMarkdown"
|
7
14
|
build_tree kramdown.root.children
|
8
15
|
end
|
9
16
|
|
10
17
|
private
|
11
18
|
def build_tree(parsed_elements)
|
12
|
-
tree = Tree.new
|
19
|
+
tree = Specdown::Tree.new
|
13
20
|
scan_for_root_node parsed_elements
|
14
21
|
tree.root = consume_section parsed_elements unless parsed_elements.empty?
|
15
22
|
consume_children parsed_elements, tree.root unless parsed_elements.empty?
|
@@ -43,7 +50,22 @@ module Specdown
|
|
43
50
|
|
44
51
|
while !parsed_elements.empty? && parsed_elements.first.type != :header
|
45
52
|
element = parsed_elements.shift
|
46
|
-
|
53
|
+
|
54
|
+
if element.type == :codeblock && element.options["language"] == "ruby"
|
55
|
+
node.code += "\n" + element.value.to_s.strip
|
56
|
+
|
57
|
+
elsif has_implicits?(element)
|
58
|
+
gather_implicit_keys(element).each do |key|
|
59
|
+
value = @lookups[key]
|
60
|
+
|
61
|
+
if value
|
62
|
+
node.code += "\n" + value
|
63
|
+
else
|
64
|
+
node.undefined_implicits << key
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
47
69
|
node.contents += element.value.to_s + element.children.map(&:value).join
|
48
70
|
end
|
49
71
|
node
|
@@ -56,5 +78,17 @@ module Specdown
|
|
56
78
|
parsed_elements.shift
|
57
79
|
end
|
58
80
|
end
|
81
|
+
|
82
|
+
def has_implicits?(element)
|
83
|
+
element.type == :strong || element.children.map {|child| has_implicits?(child) }.any?
|
84
|
+
end
|
85
|
+
|
86
|
+
def gather_implicit_keys(element)
|
87
|
+
if element.type == :strong
|
88
|
+
[element.children.map(&:value).compact.join(" ")]
|
89
|
+
else
|
90
|
+
element.children.map {|child| gather_implicit_keys(child)}.flatten
|
91
|
+
end
|
92
|
+
end
|
59
93
|
end
|
60
94
|
end
|