gherkin_readability 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: 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: []