docbert 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,3 @@
1
+ module Docbert
2
+ VERSION = "0.1.0"
3
+ 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: []