gherkin_readability 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: c95a0fbaeb4d85bd01be2e5d236fe64e0377b813
4
+ data.tar.gz: b667a4d2006fb2c9ad2d8bbaea60d51f4990741d
5
+ SHA512:
6
+ metadata.gz: 883d17fff6f2e77d72607430d8dc5511fd1949b55d4b120e9f8310700ce13537fc266034e8c28a6f5ac39f3aaeaa84f1f27626931c3164dc60b80e62b07ef147
7
+ data.tar.gz: bdfe3af27284bb00b0a771cdee0989a127e8e98a5d6ae005d04a76255397a27efe80dde024fbcb56671e25416a8794e6362e970046e68cac9c154a51142b5ff1
data/.rubocop.yml ADDED
@@ -0,0 +1,26 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2015-10-31 21:09:23 +0100 using RuboCop version 0.34.2.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 3
10
+ Metrics/AbcSize:
11
+ Max: 22
12
+
13
+ # Offense count: 1
14
+ # Configuration parameters: CountComments.
15
+ Metrics/ClassLength:
16
+ Max: 121
17
+
18
+ # Offense count: 8
19
+ # Configuration parameters: AllowURI, URISchemes.
20
+ Metrics/LineLength:
21
+ Max: 115
22
+
23
+ # Offense count: 2
24
+ # Configuration parameters: CountComments.
25
+ Metrics/MethodLength:
26
+ Max: 21
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.0
4
+ - 2.0.0
data/Dockerfile ADDED
@@ -0,0 +1,7 @@
1
+ FROM ruby
2
+ MAINTAINER think@hotmail.de
3
+
4
+ RUN \
5
+ gem install gherkin_readability --no-format-exec
6
+
7
+ CMD gherkin_readability
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+ gem 'aruba'
3
+ gem 'gherkin'
4
+ gem 'gherkin_lint'
5
+ gem 'gherkin_format'
6
+ gem 'rake'
7
+ gem 'rubocop'
8
+ gem 'simplecov', require: false, group: :test
9
+ gem 'syllables'
10
+ gem 'term-ansicolor'
data/Guardfile ADDED
@@ -0,0 +1,3 @@
1
+ guard 'rake', task: :default do
2
+ watch(%r{^lib/.*$})
3
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Funkwerk AG
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,13 @@
1
+ Check Readability of Gherkin Files
2
+ ==================================
3
+
4
+ [![Build Status](https://travis-ci.org/funkwerk/gherkin_readability.svg)](https://travis-ci.org/funkwerk/gherkin_readability)
5
+
6
+ This tool checks the readability of gherkin files.
7
+
8
+ Usage
9
+ -----
10
+
11
+ run `gherkin_readability` on a list of files
12
+
13
+ gherkin_readability FEATURE_FILES
data/Rakefile ADDED
@@ -0,0 +1,35 @@
1
+ task default: :build
2
+
3
+ desc 'Builds the Gem.'
4
+ task build: :test do
5
+ sh 'gem build gherkin_readability.gemspec'
6
+ end
7
+
8
+ task test: :format
9
+ task test: :lint
10
+ task test: :rubocop
11
+ task test: :cucumber
12
+
13
+ desc 'Publishes the Gem'
14
+ task push: :build do
15
+ sh 'gem push gherkin_readability-0.0.1.gem'
16
+ end
17
+
18
+ desc 'Checks ruby style'
19
+ task :rubocop do
20
+ sh 'rubocop'
21
+ end
22
+
23
+ task :cucumber do
24
+ options = %w()
25
+ options.push '--tags ~@slow' unless ENV['slow']
26
+ sh "cucumber #{options * ' '}"
27
+ end
28
+
29
+ task :lint do
30
+ sh 'gherkin_lint features/*.feature'
31
+ end
32
+
33
+ task :format do
34
+ sh 'gherkin_format features/*.feature'
35
+ end
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ require 'gherkin_readability'
3
+ require 'optparse'
4
+
5
+ options = {}
6
+ OptionParser.new do |opts|
7
+ opts.banner = 'Usage: gherkin_readability [files]'
8
+ opts.on('--[no-]summary', 'Print summary') do |summary|
9
+ options[:summary] = summary
10
+ end
11
+ end.parse!
12
+
13
+ readability = GherkinReadability.new
14
+
15
+ readability.analyze ARGV
16
+
17
+ readability.report if options.key? :summary
@@ -0,0 +1,57 @@
1
+ Feature: Rate
2
+ As a Business Analyst
3
+ I want to be informed about non readable features
4
+ so that I know when I need to restructure
5
+
6
+ Background:
7
+ Given a file named "readability.rb" with:
8
+ """
9
+ $LOAD_PATH << '../../lib'
10
+ require 'gherkin_readability'
11
+
12
+ readability = GherkinReadability.new
13
+
14
+ readability.analyze %w(default.feature test.feature)
15
+
16
+ """
17
+ And a file named "default.feature" with:
18
+ """
19
+ Feature: Default
20
+ Scenario: Tag
21
+ Given a test
22
+ When execute
23
+ Then pass
24
+ """
25
+
26
+ Scenario: Sort poor readable
27
+ Given a file named "test.feature" with:
28
+ """
29
+ Feature: Unreadable busting complexity check
30
+ Scenario: nonsense and unreadable
31
+ Given a fancy-hyper non-readable and quite complex test specification
32
+ When consider to execute that
33
+ Then verification is successful
34
+ """
35
+ When I run `ruby readability.rb`
36
+ Then it should pass with exactly:
37
+ """
38
+ 119: default.feature
39
+ 30: test.feature
40
+
41
+ """
42
+
43
+ Scenario: Sort highly readable
44
+ Given a file named "test.feature" with:
45
+ """
46
+ Feature: Test
47
+ Scenario: Test
48
+ When execute
49
+ Then test
50
+ """
51
+ When I run `ruby readability.rb`
52
+ Then it should pass with exactly:
53
+ """
54
+ 120: test.feature
55
+ 119: default.feature
56
+
57
+ """
@@ -0,0 +1,56 @@
1
+ Feature: Summary
2
+ As a Business Analyst
3
+ I want to be informed about non readable features
4
+ so that I know about the average readabilty of my feature files
5
+
6
+ Background:
7
+ Given a file named "readability.rb" with:
8
+ """
9
+ $LOAD_PATH << '../../lib'
10
+ require 'gherkin_readability'
11
+
12
+ readability = GherkinReadability.new
13
+
14
+ readability.analyze %w(default.feature test.feature)
15
+ readability.report
16
+
17
+ """
18
+ And a file named "default.feature" with:
19
+ """
20
+ Feature: Default
21
+ Scenario: Tag
22
+ Given a test
23
+ When execute
24
+ Then pass
25
+ """
26
+
27
+ Scenario: Sort poor readable
28
+ Given a file named "test.feature" with:
29
+ """
30
+ Feature: Unreadable busting complexity check
31
+ Scenario: nonsense and unreadable
32
+ Given a fancy-hyper non-readable and quite complex test specification
33
+ When consider to execute that
34
+ Then verification is successful
35
+ """
36
+ When I run `ruby readability.rb`
37
+ Then it should pass with:
38
+ """
39
+ 2 files analyzed. Average readability is 74
40
+
41
+ """
42
+
43
+ Scenario: Sort highly readable
44
+ Given a file named "test.feature" with:
45
+ """
46
+ Feature: Test
47
+ Scenario: Test
48
+ When execute
49
+ Then test
50
+ """
51
+ When I run `ruby readability.rb`
52
+ Then it should pass with:
53
+ """
54
+ 2 files analyzed. Average readability is 120
55
+
56
+ """
@@ -0,0 +1 @@
1
+ require 'aruba/cucumber'
@@ -0,0 +1,15 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'gherkin_readability'
3
+ s.version = '0.0.1'
4
+ s.date = '2015-10-31'
5
+ s.summary = 'Gherkin Readability'
6
+ s.description = 'Check readability of Gherkin Files'
7
+ s.authors = ['Stefan Rohe']
8
+ s.homepage = 'http://github.com/funkwerk/gherkin_readability/'
9
+ s.files = `git ls-files`.split("\n")
10
+ s.executables = s.files.grep(%r{^bin/}) { |file| File.basename(file) }
11
+ s.add_runtime_dependency 'gherkin', ['>= 2.12.2']
12
+ s.add_runtime_dependency 'term-ansicolor', ['>= 1.3.2']
13
+ s.add_runtime_dependency 'syllables', ['>= 0.1.4']
14
+ s.add_development_dependency 'aruba', ['>= 0.6.2']
15
+ end
@@ -0,0 +1,155 @@
1
+ # encoding: utf-8
2
+ require 'gherkin/formatter/json_formatter'
3
+ require 'gherkin/parser/parser'
4
+ require 'rexml/document'
5
+ require 'stringio'
6
+ require 'multi_json'
7
+ require 'term/ansicolor'
8
+ include Term::ANSIColor
9
+ require 'tmpdir'
10
+ require 'fileutils'
11
+ require 'yaml'
12
+ require 'set'
13
+ require 'digest'
14
+
15
+ # gherkin utilities
16
+ class GherkinReadability
17
+ def initialize
18
+ @readability_by_file = {}
19
+ end
20
+
21
+ def analyze(files)
22
+ files.each do |file|
23
+ sentences = extract_sentences parse(file)
24
+ @readability_by_file[file] = readability sentences
25
+ end
26
+ @readability_by_file.sort { |lhs, rhs| lhs[1] <=> rhs[1] }.reverse_each do |file, rating|
27
+ puts "#{rating.round}: #{file}"
28
+ end
29
+ end
30
+
31
+ def report
32
+ average_readability = 0
33
+ @readability_by_file.each do |_, rating|
34
+ average_readability += rating
35
+ end
36
+ average_readability /= @readability_by_file.length
37
+ puts "\n#{@readability_by_file.length} files analyzed. Average readability is #{average_readability.round}"
38
+ end
39
+
40
+ def readability(sentences)
41
+ require 'syllables'
42
+
43
+ total_words = 0
44
+ total_syllabels = 0
45
+ Syllables.new(sentences.join '\n').to_h.each do |_word, syllabels|
46
+ total_words += 1
47
+ total_syllabels += syllabels
48
+ end
49
+ 206.835 - 1.015 * (total_words / sentences.length) - 84.6 * (total_syllabels / total_words)
50
+ end
51
+
52
+ def parse(file)
53
+ content = File.read file
54
+ to_json(content, file)
55
+ end
56
+
57
+ def extract_sentences(parsed)
58
+ feature_names = lambda do |input|
59
+ input.map { |feature| feature['name'] unless feature['name'] == '' }
60
+ end
61
+
62
+ descriptions = lambda do |input|
63
+ input.map { |feature| feature['description'] unless feature['description'] == '' }
64
+ end
65
+
66
+ sentences = feature_names.call(parsed) + descriptions.call(parsed) + scenario_names(parsed) + sentences(parsed)
67
+ sentences.select! { |sentence| sentence }
68
+ sentences.map { |sentence| sentence.gsub(/ «.+»/, '') }
69
+ end
70
+
71
+ def to_json(input, file = 'generated.feature')
72
+ io = StringIO.new
73
+ formatter = Gherkin::Formatter::JSONFormatter.new(io)
74
+ parser = Gherkin::Parser::Parser.new(formatter, true)
75
+ parser.parse(input, file, 0)
76
+ formatter.done
77
+ MultiJson.load io.string
78
+ end
79
+
80
+ def scenario_names(input)
81
+ # TODO: scenario outlines with example values inside?
82
+ scenarios = []
83
+ input.each do |features|
84
+ next unless features.key? 'elements'
85
+ elements = features['elements']
86
+ elements.each do |scenario|
87
+ scenarios.push scenario['name'] if scenario['type'] == 'scenario'
88
+ scenarios.push scenario['name'] if scenario['type'] == 'scenario_outline'
89
+ scenarios.push scenario['description'] unless scenario['description'].empty?
90
+ end
91
+ end
92
+ scenarios
93
+ end
94
+
95
+ def sentences(input)
96
+ sentences = []
97
+ background = []
98
+ input.each do |features|
99
+ next unless features.key? 'elements'
100
+ features['elements'].each do |scenario|
101
+ next unless scenario.key? 'steps'
102
+ terms = background.dup
103
+ if scenario['type'] == 'background'
104
+ background.push extract_terms_from_scenario(scenario['steps'], terms)
105
+ next
106
+ end
107
+
108
+ terms.push extract_terms_from_scenario(scenario['steps'], background)
109
+ sentence = terms.join(' ').strip
110
+ if scenario.key? 'examples'
111
+ sentences += extract_examples(scenario['examples'], sentence)
112
+ else
113
+ sentences.push sentence
114
+ end
115
+ end
116
+ end
117
+ sentences
118
+ end
119
+
120
+ def extract_terms_from_scenario(steps, background)
121
+ steps.map do |step|
122
+ keyword = step['keyword']
123
+ keyword = 'and ' unless background.empty? || keyword != 'Given '
124
+ terms = [keyword, step['name']].join
125
+ terms = uncapitalize(terms) unless background.empty?
126
+ background = terms
127
+ terms
128
+ end.flatten
129
+ end
130
+
131
+ def extract_examples(examples, prototype)
132
+ examples.map do |example|
133
+ sentences = []
134
+ sentences.push example['name'] unless example['name'].empty?
135
+ sentences.push example['description'] unless example['description'].empty?
136
+ sentences += expand_outlines(prototype, example)
137
+ sentences
138
+ end.flatten
139
+ end
140
+
141
+ def uncapitalize(term)
142
+ term[0, 1].downcase + term[1..-1]
143
+ end
144
+
145
+ def expand_outlines(sentence, example)
146
+ result = []
147
+ headers = example['rows'][0]['cells']
148
+ example['rows'].slice(1, example['rows'].length).each do |row|
149
+ modified_sentence = sentence.dup
150
+ headers.zip(row['cells']).map { |key, value| modified_sentence.gsub!("<#{key}>", value) }
151
+ result.push modified_sentence
152
+ end
153
+ result
154
+ end
155
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gherkin_readability
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Stefan Rohe
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-10-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: gherkin
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 2.12.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 2.12.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: term-ansicolor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.3.2
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 1.3.2
41
+ - !ruby/object:Gem::Dependency
42
+ name: syllables
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 0.1.4
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 0.1.4
55
+ - !ruby/object:Gem::Dependency
56
+ name: aruba
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 0.6.2
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 0.6.2
69
+ description: Check readability of Gherkin Files
70
+ email:
71
+ executables:
72
+ - gherkin_readability
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".rubocop.yml"
77
+ - ".travis.yml"
78
+ - Dockerfile
79
+ - Gemfile
80
+ - Guardfile
81
+ - LICENSE
82
+ - README.md
83
+ - Rakefile
84
+ - bin/gherkin_readability
85
+ - features/rate.feature
86
+ - features/summary.feature
87
+ - features/support/env.rb
88
+ - gherkin_readability.gemspec
89
+ - lib/gherkin_readability.rb
90
+ homepage: http://github.com/funkwerk/gherkin_readability/
91
+ licenses: []
92
+ metadata: {}
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.2.3
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: Gherkin Readability
113
+ test_files: []