cuke-steps 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []