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.
@@ -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: []