cuke-steps 0.0.1
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.
- checksums.yaml +7 -0
- data/lib/confluence_step_outputter.rb +64 -0
- data/lib/cuke-steps.rb +96 -0
- data/lib/cuke-tags.rb +49 -0
- data/lib/html_step_outputter.rb +119 -0
- data/lib/step_parser.rb +75 -0
- data/lib/tag_parser.rb +80 -0
- metadata +50 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: daf09884012622405d6940dc98da89ee1de820aa
|
4
|
+
data.tar.gz: 2bbbf2c368ee08721e5ade74bfccb53851f60b9f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 398a85ade3e4d2cc46a5253fbd41af919987b4dd34500c9055ca7a7e2839f9cf5af4556ea0578f3664379e8581e6172b0ca8121745a005d356eea54bf620a021
|
7
|
+
data.tar.gz: 1be067cd1c81a005dff578017b7f9728af8f1c0b30ec5672d70424a0926c6153955e12ae389382c353f05f0207205a0a5a1000072e4d205c6fa1d1fb3881d60c
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# Outputter that generates Confluence markup
|
2
|
+
|
3
|
+
require 'cgi'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
class ConfluenceStepOutputter
|
7
|
+
def initialize(file)
|
8
|
+
@file = File.open(file, 'w')
|
9
|
+
@previous_type = ""
|
10
|
+
end
|
11
|
+
|
12
|
+
def header
|
13
|
+
# No-op
|
14
|
+
end
|
15
|
+
def footer
|
16
|
+
@file.puts %(<p> </p>)
|
17
|
+
@file.puts %(<p><em>Documentation generated #{Time.now}</em></p>)
|
18
|
+
end
|
19
|
+
|
20
|
+
def close
|
21
|
+
@file.close
|
22
|
+
end
|
23
|
+
|
24
|
+
def start_directory(dir)
|
25
|
+
@file.puts %(<p> </p>)
|
26
|
+
@file.puts "<h2>#{dir}</h2>"
|
27
|
+
@previous_type = ""
|
28
|
+
end
|
29
|
+
|
30
|
+
def end_directory
|
31
|
+
# No-op
|
32
|
+
end
|
33
|
+
|
34
|
+
def start_all
|
35
|
+
@file.puts %(<p> </p>)
|
36
|
+
@file.puts "<h2>All definitions alphabetically</h2>"
|
37
|
+
@previous_type = ""
|
38
|
+
end
|
39
|
+
|
40
|
+
def end_all
|
41
|
+
# No-op
|
42
|
+
end
|
43
|
+
|
44
|
+
def step(step)
|
45
|
+
if @previous_type != step[:type]
|
46
|
+
@file.puts %(<h3>#{step[:type]} definitions</h3>)
|
47
|
+
@previous_type = step[:type]
|
48
|
+
end
|
49
|
+
@file.puts %(<ac:macro ac:name="expand">)
|
50
|
+
@file.puts %( <ac:parameter ac:name="title">#{CGI.escapeHTML(step[:name])}</ac:parameter>)
|
51
|
+
@file.puts %( <ac:rich-text-body>)
|
52
|
+
# TODO: Add link to source repo or Jenkins workspace
|
53
|
+
# <p><a href=".../#{CGI.escapeHTML(step[:filename])}" style="color: #888;">#{CGI.escapeHTML(step[:filename])}:#{step[:line_number]}</a></p>
|
54
|
+
@file.puts %( <p style="color: #888;">#{CGI.escapeHTML(step[:filename])}:#{step[:line_number]}</p>)
|
55
|
+
@file.puts %( <pre style="background-color: #ddd; padding-top: 1.2em;">)
|
56
|
+
step[:code].each do |line|
|
57
|
+
@file.puts %( #{CGI.escapeHTML(line)})
|
58
|
+
end
|
59
|
+
@file.puts %( </pre>)
|
60
|
+
@file.puts %( </ac:rich-text-body>)
|
61
|
+
@file.puts %(</ac:macro>)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
data/lib/cuke-steps.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#-*- encoding: utf-8 -*-
|
3
|
+
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
require_relative 'step_parser'
|
7
|
+
require_relative 'confluence_step_outputter'
|
8
|
+
require_relative 'html_step_outputter'
|
9
|
+
|
10
|
+
|
11
|
+
# Parse command line
|
12
|
+
options = {}
|
13
|
+
opts = OptionParser.new do |opts|
|
14
|
+
opts.banner = "Usage: cuke-steps.rb [options] <directories...>"
|
15
|
+
|
16
|
+
opts.on("-o", "--output FILE", "Output to FILE") do |file|
|
17
|
+
options[:file] = file
|
18
|
+
end
|
19
|
+
opts.on("-f", "--format FMT", "Select output format: cf, html") do |format|
|
20
|
+
options[:format] = format
|
21
|
+
end
|
22
|
+
end
|
23
|
+
opts.parse!(ARGV)
|
24
|
+
|
25
|
+
# Default output options
|
26
|
+
if options[:file] && !options[:format]
|
27
|
+
options[:format] = options[:file].sub(/^.*\./, "")
|
28
|
+
end
|
29
|
+
if !options[:format]
|
30
|
+
options[:format] = "html"
|
31
|
+
end
|
32
|
+
if options[:format] && !options[:file]
|
33
|
+
options[:file] = "steps.#{options[:format]}"
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
# All other arguments are treated as input directories
|
38
|
+
dirs = ARGV
|
39
|
+
if dirs.size == 0
|
40
|
+
puts "No source directories provided, use -h for help"
|
41
|
+
exit 1
|
42
|
+
end
|
43
|
+
|
44
|
+
# Setup output
|
45
|
+
case options[:format]
|
46
|
+
when 'cf'
|
47
|
+
output = ConfluenceStepOutputter.new(options[:file])
|
48
|
+
when 'html'
|
49
|
+
output = HtmlStepOutputter.new(options[:file])
|
50
|
+
else
|
51
|
+
puts "Unknown output format: #{options[:format]}"
|
52
|
+
exit 1
|
53
|
+
end
|
54
|
+
puts "Writing output to file '#{options[:file]}'"
|
55
|
+
|
56
|
+
|
57
|
+
# Sort primarily by step type, secondarily by step definition
|
58
|
+
sorter = lambda do |a,b|
|
59
|
+
if a[:type] == b[:type]
|
60
|
+
a[:name].downcase <=> b[:name].downcase
|
61
|
+
else
|
62
|
+
weight = { "Given" => 1, "When" => 2, "Then" => 3, "Transform" => 4, "Before" => 5, "After" => 6, "AfterStep" => 7 }
|
63
|
+
wa = weight[a[:type]]
|
64
|
+
wb = weight[b[:type]]
|
65
|
+
wa <=> wb
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
# Read files and output
|
71
|
+
all_steps = []
|
72
|
+
output.header
|
73
|
+
dirs.each do |dir|
|
74
|
+
dir = dir.sub(/\/+$/, "")
|
75
|
+
s = StepParser.new
|
76
|
+
Dir.glob("#{dir}/**/*.rb") do |file|
|
77
|
+
s.read(file)
|
78
|
+
end
|
79
|
+
steps = s.steps
|
80
|
+
all_steps += steps
|
81
|
+
|
82
|
+
output.start_directory(dir)
|
83
|
+
steps.sort!(&sorter)
|
84
|
+
steps.each { |s| output.step(s) }
|
85
|
+
output.end_directory
|
86
|
+
end
|
87
|
+
|
88
|
+
if dirs.size > 1
|
89
|
+
output.start_all
|
90
|
+
all_steps.sort!(&sorter)
|
91
|
+
all_steps.each { |s| output.step(s) }
|
92
|
+
output.end_all
|
93
|
+
end
|
94
|
+
|
95
|
+
output.footer
|
96
|
+
output.close
|
data/lib/cuke-tags.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#-*- encoding: utf-8 -*-
|
3
|
+
require 'json'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
require_relative 'step_parser'
|
7
|
+
require_relative 'tag_parser'
|
8
|
+
require_relative 'confluence_step_outputter'
|
9
|
+
require_relative 'html_step_outputter'
|
10
|
+
|
11
|
+
# Parse command line
|
12
|
+
options = {}
|
13
|
+
opts = OptionParser.new do |opts|
|
14
|
+
opts.banner = "Usage: cuke-tags.rb [options] <directories...>"
|
15
|
+
|
16
|
+
opts.on("-o", "--output FILE", "Output to FILE") do |file|
|
17
|
+
options[:file] = file
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
opts.parse!(ARGV)
|
22
|
+
|
23
|
+
# Default output options
|
24
|
+
if !options[:file]
|
25
|
+
options[:file] = "tags.json"
|
26
|
+
end
|
27
|
+
|
28
|
+
# All other arguments are treated as input directories
|
29
|
+
dirs = ARGV
|
30
|
+
if dirs.size == 0
|
31
|
+
puts "No source directory provided, use -h for help"
|
32
|
+
exit 1
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
puts "Writing output to file '#{options[:file]}'"
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
# Read files and output
|
41
|
+
all_tags = []
|
42
|
+
dir = Dir.new(dirs[0]).to_path
|
43
|
+
t = TagParser.new
|
44
|
+
Dir.glob("#{dir}/*.feature") do |file|
|
45
|
+
t.read(file)
|
46
|
+
tags = t.tags
|
47
|
+
all_tags += tags
|
48
|
+
end
|
49
|
+
File.open(options[:file], 'w') {|f| f.write(all_tags.to_json) }
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# Outputter that generates HTML markup
|
2
|
+
# Feel free to customize the below code for your needs
|
3
|
+
|
4
|
+
require 'cgi'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
class HtmlStepOutputter
|
8
|
+
|
9
|
+
def initialize(file)
|
10
|
+
@file = File.open(file, 'w')
|
11
|
+
@previous_type = ""
|
12
|
+
@id_number = 0
|
13
|
+
end
|
14
|
+
|
15
|
+
# HTML file header - customize as needed
|
16
|
+
def header
|
17
|
+
@file.puts <<-eos
|
18
|
+
<!DOCTYPE html>
|
19
|
+
<html>
|
20
|
+
<head>
|
21
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
22
|
+
<title>Cucumber step documentation</title>
|
23
|
+
<style>
|
24
|
+
.stepdefs {
|
25
|
+
font-size: smaller;
|
26
|
+
}
|
27
|
+
.stepdefs li {
|
28
|
+
margin-bottom: 0.25em;
|
29
|
+
list-style-type: none;
|
30
|
+
}
|
31
|
+
.stepdefs li:before {
|
32
|
+
content: "\u00BB ";
|
33
|
+
font-size: larger;
|
34
|
+
padding-right: 0.3em;
|
35
|
+
}
|
36
|
+
.stepdef {
|
37
|
+
color: #111;
|
38
|
+
text-decoration: none;
|
39
|
+
}
|
40
|
+
.extrainfo {
|
41
|
+
display: none;
|
42
|
+
overflow: hidden; /* Fixes jumping issue in jQuery slideToggle() */
|
43
|
+
}
|
44
|
+
</style>
|
45
|
+
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
|
46
|
+
</head>
|
47
|
+
<body>
|
48
|
+
eos
|
49
|
+
end
|
50
|
+
|
51
|
+
def footer
|
52
|
+
@file.puts <<-eos
|
53
|
+
</ul>
|
54
|
+
<p> </p>
|
55
|
+
<p><em>Documentation generated #{Time.now}</em></p>
|
56
|
+
</body>
|
57
|
+
</html>
|
58
|
+
eos
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
def close
|
63
|
+
@file.close
|
64
|
+
end
|
65
|
+
|
66
|
+
def start_directory(dir)
|
67
|
+
@file.puts %(</ul>) if @previous_type != ""
|
68
|
+
@file.puts %(<p> </p>)
|
69
|
+
@file.puts %(<h2>Step definitions in #{dir}/</h2>)
|
70
|
+
@previous_type = ""
|
71
|
+
end
|
72
|
+
|
73
|
+
def end_directory
|
74
|
+
# No-op
|
75
|
+
end
|
76
|
+
|
77
|
+
def start_all
|
78
|
+
@file.puts %(</ul>)
|
79
|
+
@file.puts %(<p> </p>)
|
80
|
+
@file.puts %(<h2>All definitions alphabetically</h2>)
|
81
|
+
@previous_type = ""
|
82
|
+
end
|
83
|
+
|
84
|
+
def end_all
|
85
|
+
# No-op
|
86
|
+
end
|
87
|
+
|
88
|
+
def step(step)
|
89
|
+
if @previous_type != step[:type]
|
90
|
+
@file.puts %(</ul>) if @previous_type != ""
|
91
|
+
@file.puts %(<h3>#{step[:type]} definitions</h3>)
|
92
|
+
@file.puts %(<ul class="stepdefs">)
|
93
|
+
@previous_type = step[:type]
|
94
|
+
end
|
95
|
+
|
96
|
+
id = new_id
|
97
|
+
@file.puts %(<li>)
|
98
|
+
@file.puts %( <a href="#" onclick="$('##{id}').slideToggle(); return false;" class="stepdef">#{CGI.escapeHTML(step[:name])}</a>)
|
99
|
+
@file.puts %( <div id="#{id}" class="extrainfo">)
|
100
|
+
# TODO: Add link to source repo or Jenkins workspace
|
101
|
+
# <p><a href=".../#{CGI.escapeHTML(step[:filename])}" style="color: #888;">#{CGI.escapeHTML(step[:filename])}:#{step[:line_number]}</a></p>
|
102
|
+
@file.puts %( <p style="color: #888;">#{CGI.escapeHTML(step[:filename])}:#{step[:line_number]}</p>)
|
103
|
+
@file.puts %( <pre style="background-color: #ddd; padding-top: 1.2em;">)
|
104
|
+
step[:code].each do |line|
|
105
|
+
@file.puts %( #{CGI.escapeHTML(line)})
|
106
|
+
end
|
107
|
+
@file.puts %( </pre>)
|
108
|
+
@file.puts %( </div>)
|
109
|
+
@file.puts %(</li>)
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def new_id
|
115
|
+
@id_number += 1
|
116
|
+
"id#{@id_number}"
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
data/lib/step_parser.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# Class that parses step definitions from Ruby files
|
2
|
+
|
3
|
+
class StepParser
|
4
|
+
|
5
|
+
attr_reader :steps
|
6
|
+
def initialize
|
7
|
+
@steps = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def read(file)
|
11
|
+
@current_file = file
|
12
|
+
@line_number = 0
|
13
|
+
@lines = IO.read(file).split(/\r?\n/)
|
14
|
+
parse_lines
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def next_line
|
21
|
+
@line_number += 1
|
22
|
+
@lines.shift
|
23
|
+
end
|
24
|
+
|
25
|
+
def unread(line)
|
26
|
+
@line_number -= 1
|
27
|
+
@lines.unshift(line)
|
28
|
+
end
|
29
|
+
|
30
|
+
def parse_lines
|
31
|
+
@comments = []
|
32
|
+
while not @lines.empty?
|
33
|
+
|
34
|
+
line = next_line
|
35
|
+
case line
|
36
|
+
when /^ *#/
|
37
|
+
@comments << line
|
38
|
+
when /^(Given|When|Then|Before|After|AfterStep|Transform) /
|
39
|
+
unread(line)
|
40
|
+
parse_step
|
41
|
+
@comments = []
|
42
|
+
when /^\s+(Given|When|Then|Before|After|AfterStep|Transform) /
|
43
|
+
puts "WARNING: Indented step definition in file #{@current_file}: #{line}"
|
44
|
+
@comments = []
|
45
|
+
else
|
46
|
+
@comments = []
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def parse_step
|
53
|
+
type = parse_step_type(@lines.first)
|
54
|
+
name = parse_step_name(@lines.first)
|
55
|
+
line_number = @line_number + 1
|
56
|
+
code = @comments
|
57
|
+
line = ""
|
58
|
+
while !@lines.empty? && !(line =~ /^end\s*$/)
|
59
|
+
line = next_line
|
60
|
+
code << line
|
61
|
+
end
|
62
|
+
@steps << { :type => type, :name => name, :filename => @current_file, :code => code, :line_number => line_number }
|
63
|
+
end
|
64
|
+
|
65
|
+
def parse_step_type(line)
|
66
|
+
line.sub(/^([A-Za-z]+).*/, '\1')
|
67
|
+
end
|
68
|
+
|
69
|
+
def parse_step_name(line)
|
70
|
+
line = line.sub(/^(Given|When|Then|Transform) +\/\^?(.*?)\$?\/.*/, '\1 \2')
|
71
|
+
line = line.gsub('\ ', ' ')
|
72
|
+
line
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
data/lib/tag_parser.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# Class that parses step definitions from Ruby files
|
2
|
+
|
3
|
+
class TagParser
|
4
|
+
|
5
|
+
attr_reader :tags
|
6
|
+
def initialize
|
7
|
+
@tags = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def read(file)
|
11
|
+
@current_file = file
|
12
|
+
@line_number = 0
|
13
|
+
@lines = IO.read(file).split(/\r?\n/)
|
14
|
+
parse_lines
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def next_line
|
20
|
+
@line_number += 1
|
21
|
+
@lines.shift
|
22
|
+
end
|
23
|
+
|
24
|
+
def unread(line)
|
25
|
+
@line_number -= 1
|
26
|
+
@lines.unshift(line)
|
27
|
+
end
|
28
|
+
|
29
|
+
def parse_lines
|
30
|
+
@comments = []
|
31
|
+
while not @lines.empty?
|
32
|
+
line = next_line
|
33
|
+
case line
|
34
|
+
when /^ *#/
|
35
|
+
@comments << line
|
36
|
+
when /^\s+@.*/
|
37
|
+
unread(line)
|
38
|
+
parse_tag
|
39
|
+
@comments = []
|
40
|
+
when /^@.*/
|
41
|
+
unread(line)
|
42
|
+
parse_tag
|
43
|
+
else
|
44
|
+
@comments = []
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def parse_tag
|
51
|
+
line = next_line
|
52
|
+
tag_names = parse_tag_names(line)
|
53
|
+
line_number =@line_number
|
54
|
+
code = ""
|
55
|
+
line = ""
|
56
|
+
scenario = ""
|
57
|
+
while !@lines.empty? && !(line =~ /^\s+@.*/)
|
58
|
+
line = next_line
|
59
|
+
case line
|
60
|
+
|
61
|
+
when /^\s+Scenario:.*/
|
62
|
+
scenario = line
|
63
|
+
else
|
64
|
+
code << line
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
@tags << { :names => tag_names, :filename => @current_file, :comments => @comments,:code => code, :scenario=>scenario, :line_number => line_number }
|
69
|
+
end
|
70
|
+
|
71
|
+
def parse_step_type(line)
|
72
|
+
line.sub(/^([A-Za-z]+).*/, '\1')
|
73
|
+
end
|
74
|
+
|
75
|
+
def parse_tag_names(line)
|
76
|
+
tags = line.split(' ')
|
77
|
+
tags
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
metadata
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cuke-steps
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ali Khan
|
8
|
+
- plaa
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-05-02 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Cucumber Steps and Tags documentation generator.
|
15
|
+
email: alikhan@himindz.ie
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/confluence_step_outputter.rb
|
21
|
+
- lib/cuke-steps.rb
|
22
|
+
- lib/cuke-tags.rb
|
23
|
+
- lib/html_step_outputter.rb
|
24
|
+
- lib/step_parser.rb
|
25
|
+
- lib/tag_parser.rb
|
26
|
+
homepage: https://github.com/himindz/cuke-steps
|
27
|
+
licenses:
|
28
|
+
- BSD
|
29
|
+
metadata: {}
|
30
|
+
post_install_message:
|
31
|
+
rdoc_options: []
|
32
|
+
require_paths:
|
33
|
+
- lib
|
34
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
requirements: []
|
45
|
+
rubyforge_project:
|
46
|
+
rubygems_version: 2.2.1
|
47
|
+
signing_key:
|
48
|
+
specification_version: 4
|
49
|
+
summary: Cucumber Steps and Tags documentation generator
|
50
|
+
test_files: []
|