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 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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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
@@ -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: []