docbert 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/docbert.rb +9 -0
- data/lib/docbert/converters/gherkin.rb +69 -0
- data/lib/docbert/converters/step_definitions.rb +52 -0
- data/lib/docbert/converters/step_definitions/parameterized_content.rb +38 -0
- data/lib/docbert/parser.rb +66 -0
- data/lib/docbert/parser/definition_node.rb +31 -0
- data/lib/docbert/parser/example_node.rb +83 -0
- data/lib/docbert/parser/parameterized_content.rb +43 -0
- data/lib/docbert/version.rb +3 -0
- metadata +102 -0
data/lib/docbert.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'kramdown'
|
2
|
+
|
3
|
+
require 'docbert/parser'
|
4
|
+
require 'docbert/parser/example_node'
|
5
|
+
require 'docbert/parser/definition_node'
|
6
|
+
require 'docbert/parser/parameterized_content'
|
7
|
+
require 'docbert/converters/gherkin'
|
8
|
+
require 'docbert/converters/step_definitions'
|
9
|
+
require 'docbert/converters/step_definitions/parameterized_content'
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'kramdown/parser/kramdown'
|
2
|
+
|
3
|
+
module Docbert
|
4
|
+
module Converters
|
5
|
+
class Gherkin < Kramdown::Converter::Base
|
6
|
+
Kramdown::Converter::Gherkin = self
|
7
|
+
|
8
|
+
def convert(root)
|
9
|
+
root.
|
10
|
+
children.
|
11
|
+
map { |el| send("convert_#{el.type}", el) }.
|
12
|
+
compact.
|
13
|
+
join("\n")
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def convert_example(el)
|
19
|
+
convert_example_generic('Scenario', el)
|
20
|
+
end
|
21
|
+
|
22
|
+
def convert_example_background(el)
|
23
|
+
_, body = el.children
|
24
|
+
|
25
|
+
" Background:\n" << convert_example_body(body, " ")
|
26
|
+
end
|
27
|
+
|
28
|
+
def convert_example_body(body, indent)
|
29
|
+
body.
|
30
|
+
value.
|
31
|
+
split(/\n/).
|
32
|
+
map { |step| "#{indent}#{step.strip}\n" }.
|
33
|
+
join
|
34
|
+
end
|
35
|
+
|
36
|
+
def convert_example_generic(type, el)
|
37
|
+
title, body = el.children
|
38
|
+
|
39
|
+
convert_example_title(title, " ", type) +
|
40
|
+
convert_example_body(body, " ")
|
41
|
+
end
|
42
|
+
|
43
|
+
def convert_example_title(title, indent, type)
|
44
|
+
"#{indent}#{type}: #{title.value}\n"
|
45
|
+
end
|
46
|
+
|
47
|
+
def convert_example_outline(el)
|
48
|
+
convert_example_generic('Scenario Outline', el)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Convert a level 1 header to a feature title.
|
52
|
+
#
|
53
|
+
# Current limitations:
|
54
|
+
# - Expects one and only one level 1 header to exist
|
55
|
+
# - Doesn't allow additional markup to be specified in the header
|
56
|
+
def convert_header(el)
|
57
|
+
if el.options[:level] == 1
|
58
|
+
feature_title = el.children.first.value
|
59
|
+
|
60
|
+
"Feature: #{feature_title}\n"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def method_missing(name, *args)
|
65
|
+
super if name.to_s !~ /^convert_/
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'kramdown/parser/kramdown'
|
2
|
+
|
3
|
+
module Docbert
|
4
|
+
module Converters
|
5
|
+
class StepDefinitions < Kramdown::Converter::Base
|
6
|
+
Kramdown::Converter::StepDefinitions = self
|
7
|
+
|
8
|
+
def convert(root)
|
9
|
+
root.
|
10
|
+
children.
|
11
|
+
map { |el| send("convert_#{el.type}", el) }.
|
12
|
+
compact.
|
13
|
+
join("\n")
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def convert_example_definition(el)
|
19
|
+
title_el, body_el = el.children
|
20
|
+
|
21
|
+
title = convert_example_definition_title(title_el)
|
22
|
+
par_list = if title.params.empty?
|
23
|
+
''
|
24
|
+
else
|
25
|
+
'|' << title.params.join(', ') << '|'
|
26
|
+
end
|
27
|
+
body = convert_example_definition_body(body_el)
|
28
|
+
|
29
|
+
<<-STEPD
|
30
|
+
Given(/^#{title}$/) do #{par_list}
|
31
|
+
steps <<-EOS
|
32
|
+
#{body}
|
33
|
+
EOS
|
34
|
+
end
|
35
|
+
|
36
|
+
STEPD
|
37
|
+
end
|
38
|
+
|
39
|
+
def convert_example_definition_body(el)
|
40
|
+
ParameterizedContent.new(el) { |p| '#{' + p + '}' }
|
41
|
+
end
|
42
|
+
|
43
|
+
def convert_example_definition_title(el)
|
44
|
+
ParameterizedContent.new(el) { |p| '(.+)' }
|
45
|
+
end
|
46
|
+
|
47
|
+
def method_missing(name, *args)
|
48
|
+
super if name.to_s !~ /^convert_/
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Docbert
|
2
|
+
module Converters
|
3
|
+
class StepDefinitions
|
4
|
+
class ParameterizedContent
|
5
|
+
def initialize(el, &block)
|
6
|
+
self.el = el
|
7
|
+
self.block = block
|
8
|
+
end
|
9
|
+
|
10
|
+
def params
|
11
|
+
@params ||= el.
|
12
|
+
children.
|
13
|
+
select { |e| param?(e) }.
|
14
|
+
map { |e| param(e) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
@s ||= el.
|
19
|
+
children.
|
20
|
+
map { |e| param?(e) ? block.(param(e)) : e.value }.
|
21
|
+
join
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
attr_accessor :el, :block
|
27
|
+
|
28
|
+
def param?(el)
|
29
|
+
el.type == :example_definition_param
|
30
|
+
end
|
31
|
+
|
32
|
+
def param(el)
|
33
|
+
el.value.gsub(' ', '_')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'kramdown/parser/kramdown'
|
2
|
+
|
3
|
+
module Docbert
|
4
|
+
class Parser < Kramdown::Parser::Kramdown
|
5
|
+
EXAMPLE_START = /#{BLANK_LINE}?^\s*Example:/
|
6
|
+
EXAMPLE_BACKGROUND_START = /#{BLANK_LINE}?^\s*Background:/
|
7
|
+
EXAMPLE_DEFINITION_START = /#{BLANK_LINE}?^\s*Definition:/
|
8
|
+
EXAMPLE_OUTLINE_START = /#{BLANK_LINE}?^\s*Example Outline:/
|
9
|
+
|
10
|
+
def initialize(source, options)
|
11
|
+
super
|
12
|
+
|
13
|
+
register_example_background_parser
|
14
|
+
register_example_definition_parser
|
15
|
+
register_example_outline_parser
|
16
|
+
register_example_parser
|
17
|
+
end
|
18
|
+
|
19
|
+
public :new_block_el
|
20
|
+
|
21
|
+
def new_el(type, value)
|
22
|
+
Element.new(type, value)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def parse_example
|
28
|
+
@tree.children << ExampleNode.as_example(self, @src).to_element
|
29
|
+
end
|
30
|
+
|
31
|
+
def parse_example_background
|
32
|
+
@tree.children << ExampleNode.as_background(self, @src).to_element
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse_example_definition
|
36
|
+
@tree.children << ExampleNode.as_definition(self, @src).to_element
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_example_outline
|
40
|
+
@tree.children << ExampleNode.as_example_outline(self, @src).to_element
|
41
|
+
end
|
42
|
+
|
43
|
+
def register_example_background_parser
|
44
|
+
@block_parsers.unshift(:example_background)
|
45
|
+
end
|
46
|
+
|
47
|
+
def register_example_definition_parser
|
48
|
+
@block_parsers.unshift(:example_definition)
|
49
|
+
end
|
50
|
+
|
51
|
+
def register_example_parser
|
52
|
+
@block_parsers.unshift(:example)
|
53
|
+
end
|
54
|
+
|
55
|
+
def register_example_outline_parser
|
56
|
+
@block_parsers.unshift(:example_outline)
|
57
|
+
end
|
58
|
+
|
59
|
+
Kramdown::Parser::Docbert = self
|
60
|
+
|
61
|
+
define_parser :example, /#{EXAMPLE_START}/
|
62
|
+
define_parser :example_background, /#{EXAMPLE_BACKGROUND_START}/
|
63
|
+
define_parser :example_definition, /#{EXAMPLE_DEFINITION_START}/
|
64
|
+
define_parser :example_outline, /#{EXAMPLE_OUTLINE_START}/
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Docbert
|
2
|
+
class Parser
|
3
|
+
class DefinitionNode < ExampleNode
|
4
|
+
def initialize(element_factory, fragment)
|
5
|
+
super :example_definition,
|
6
|
+
EXAMPLE_DEFINITION_START,
|
7
|
+
EXAMPLE_KEYWORDS,
|
8
|
+
element_factory,
|
9
|
+
fragment
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def parse_title(frag)
|
15
|
+
super.tap { |el|
|
16
|
+
content = ParameterizedContent.new(element_factory, el.value)
|
17
|
+
|
18
|
+
el.children.concat content.to_elements
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse_body(frag)
|
23
|
+
super.tap { |el|
|
24
|
+
content = ParameterizedContent.new(element_factory, el.value)
|
25
|
+
|
26
|
+
el.children.concat content.to_elements
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Docbert
|
2
|
+
class Parser
|
3
|
+
class ExampleNode
|
4
|
+
BLANK_LINE = Kramdown::Parser::Kramdown::BLANK_LINE
|
5
|
+
|
6
|
+
EXAMPLE_KEYWORDS = 'Given|When|Then|And|But|\\||"""'
|
7
|
+
EXAMPLE_OUTLINE_KEYWORDS = "#{EXAMPLE_KEYWORDS}|Examples:"
|
8
|
+
|
9
|
+
def self.as_background(element_factory, fragment)
|
10
|
+
new(:example_background,
|
11
|
+
EXAMPLE_BACKGROUND_START,
|
12
|
+
EXAMPLE_KEYWORDS,
|
13
|
+
element_factory,
|
14
|
+
fragment)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.as_definition(element_factory, fragment)
|
18
|
+
DefinitionNode.new(element_factory, fragment)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.as_example(element_factory, fragment)
|
22
|
+
new(:example, EXAMPLE_START, EXAMPLE_KEYWORDS, element_factory, fragment)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.as_example_outline(element_factory, fragment)
|
26
|
+
new(:example_outline,
|
27
|
+
EXAMPLE_OUTLINE_START,
|
28
|
+
EXAMPLE_OUTLINE_KEYWORDS,
|
29
|
+
element_factory,
|
30
|
+
fragment)
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(type, start_re, keywords, element_factory, fragment)
|
34
|
+
self.type = type
|
35
|
+
self.start_re = start_re
|
36
|
+
self.body_re = /(?:\s*(?:#{keywords}).+?\n|#{BLANK_LINE})+/m
|
37
|
+
self.element_factory = element_factory
|
38
|
+
self.fragment = fragment
|
39
|
+
|
40
|
+
parse
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_element
|
44
|
+
element
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
attr_accessor :type, :start_re, :body_re, :element_factory, :fragment, :element
|
50
|
+
|
51
|
+
# Parse an example block.
|
52
|
+
#
|
53
|
+
# Currently only creates 2 nodes: one for the title and another for the
|
54
|
+
# example body.
|
55
|
+
def parse
|
56
|
+
skip_start fragment
|
57
|
+
|
58
|
+
self.element = parse_root(fragment)
|
59
|
+
end
|
60
|
+
|
61
|
+
def parse_body(frag)
|
62
|
+
body = frag.scan(body_re).gsub(/^ +/, '').strip
|
63
|
+
|
64
|
+
element_factory.new_el(:example_body, body)
|
65
|
+
end
|
66
|
+
|
67
|
+
def parse_root(frag)
|
68
|
+
element_factory.new_block_el(type).
|
69
|
+
tap { |el| el.children << parse_title(frag) << parse_body(frag) }
|
70
|
+
end
|
71
|
+
|
72
|
+
def parse_title(frag)
|
73
|
+
title = frag.scan(/.*?\n/).strip
|
74
|
+
|
75
|
+
element_factory.new_el(:example_title, title)
|
76
|
+
end
|
77
|
+
|
78
|
+
def skip_start(frag)
|
79
|
+
frag.skip start_re
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Docbert
|
2
|
+
class Parser
|
3
|
+
class ParameterizedContent
|
4
|
+
WORDS = /\w(?:\w+| )*\w/
|
5
|
+
|
6
|
+
def initialize(element_factory, fragment)
|
7
|
+
self.element_factory = element_factory
|
8
|
+
self.scanner = StringScanner.new(fragment)
|
9
|
+
self.elements = build_elements
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_elements
|
13
|
+
elements
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
attr_accessor :element_factory, :scanner, :elements
|
19
|
+
|
20
|
+
def build_element
|
21
|
+
build_text || build_param
|
22
|
+
end
|
23
|
+
|
24
|
+
def build_elements(elements = [])
|
25
|
+
return elements if scanner.eos?
|
26
|
+
|
27
|
+
build_elements(elements << build_element)
|
28
|
+
end
|
29
|
+
|
30
|
+
def build_param
|
31
|
+
scanner.skip(/</) and name = scanner.scan(WORDS) and scanner.skip(/>/)
|
32
|
+
|
33
|
+
element_factory.new_el(:example_definition_param, name) if name
|
34
|
+
end
|
35
|
+
|
36
|
+
def build_text
|
37
|
+
if text = scanner.scan(/[^<]+/)
|
38
|
+
element_factory.new_el(:text, text)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
metadata
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: docbert
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- David Leal
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-06-15 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
version_requirements: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.0
|
20
|
+
none: false
|
21
|
+
name: kramdown
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
requirement: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ! '>='
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: 1.0.0
|
29
|
+
none: false
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
version_requirements: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ! '>='
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
none: false
|
37
|
+
name: cucumber
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
requirement: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
none: false
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
version_requirements: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ! '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
none: false
|
53
|
+
name: rspec-expectations
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ! '>='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
none: false
|
62
|
+
description: See https://github.com/mojotech/docbert/features/index.feature.md
|
63
|
+
email:
|
64
|
+
- dleal@mojotech.com
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- lib/docbert.rb
|
70
|
+
- lib/docbert/converters/gherkin.rb
|
71
|
+
- lib/docbert/converters/step_definitions.rb
|
72
|
+
- lib/docbert/converters/step_definitions/parameterized_content.rb
|
73
|
+
- lib/docbert/parser.rb
|
74
|
+
- lib/docbert/parser/definition_node.rb
|
75
|
+
- lib/docbert/parser/example_node.rb
|
76
|
+
- lib/docbert/parser/parameterized_content.rb
|
77
|
+
- lib/docbert/version.rb
|
78
|
+
homepage: https://github.com/mojotech/docbert
|
79
|
+
licenses: []
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options: []
|
82
|
+
require_paths:
|
83
|
+
- lib
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ! '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
none: false
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
none: false
|
96
|
+
requirements: []
|
97
|
+
rubyforge_project: ! '[none]'
|
98
|
+
rubygems_version: 1.8.23
|
99
|
+
signing_key:
|
100
|
+
specification_version: 3
|
101
|
+
summary: A tool to help write literate cucumber
|
102
|
+
test_files: []
|