gherkin_language 0.0.2

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: 6e36578ba3f6c90fdc22f8ddde30d96a0ac9c955
4
+ data.tar.gz: 96d5cfa9266ad79f3c287c7101b27669cf47e009
5
+ SHA512:
6
+ metadata.gz: 550d087efcbff10a081dda79bab4d26060c6c84df5777a1ae24112dbafbd61ca11775685bf43f7b1b8a84d8e23670a307d907467863be3fc9181ecad4b60804b
7
+ data.tar.gz: 951757d91180b2cdb0720ecb1e325aab15779e34e86a532b3222b63a30effe5a1ee7987c5070fccd510da2adb6b3321de3564498627532a85a31e84b4b237dda
data/.rubocop.yml ADDED
@@ -0,0 +1,38 @@
1
+ # This configuration was generated by `rubocop --auto-gen-config`
2
+ # on 2015-07-02 21:10:32 +0200 using RuboCop version 0.31.0.
3
+ # The point is for the user to remove these configuration records
4
+ # one by one as the offenses are removed from the code base.
5
+ # Note that changes in the inspected code, or installation of new
6
+ # versions of RuboCop, may require this file to be generated again.
7
+
8
+ # Offense count: 5
9
+ Metrics/AbcSize:
10
+ Max: 47
11
+
12
+ # Offense count: 2
13
+ # Configuration parameters: CountComments.
14
+ Metrics/ClassLength:
15
+ Max: 159
16
+
17
+ # Offense count: 2
18
+ Metrics/CyclomaticComplexity:
19
+ Max: 11
20
+
21
+ # Offense count: 17
22
+ # Configuration parameters: AllowURI, URISchemes.
23
+ Metrics/LineLength:
24
+ Max: 121
25
+
26
+ # Offense count: 8
27
+ # Configuration parameters: CountComments.
28
+ Metrics/MethodLength:
29
+ Max: 36
30
+
31
+ # Offense count: 1
32
+ # Configuration parameters: CountKeywordArgs.
33
+ Metrics/ParameterLists:
34
+ Max: 8
35
+
36
+ # Offense count: 2
37
+ Metrics/PerceivedComplexity:
38
+ Max: 12
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.0
4
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+ gem 'rubocop'
3
+ gem 'gherkin'
4
+ gem 'rake'
5
+ gem 'aruba'
6
+ gem 'term-ansicolor'
data/Guardfile ADDED
@@ -0,0 +1,3 @@
1
+ guard 'rake', task: :default do
2
+ watch(%r{^src/.*$})
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,29 @@
1
+ Check Language of Gherkin Files
2
+ ===============================
3
+
4
+ [![Build Status](https://travis-ci.org/funkwerk/gherkin_language.svg)](https://travis-ci.org/funkwerk/gherkin_language)
5
+
6
+ This tool analyzes the language of gherkin files and report language errors.
7
+ Currently just English is supported.
8
+
9
+ Usage
10
+ -----
11
+
12
+ run `gherkin_language` on a list of files
13
+
14
+ gherkin_language FEATURE_FILES
15
+
16
+ `gherkin_language` caches valid sentences. If all sentences are valid, it just needs some time to hash them.
17
+
18
+ To disable usage of cache, start it with `--no-cache`.
19
+
20
+ To just extract the sentences, start it with `--sentences`. This could be helpful for using these sentences in another tool. It should not be used for formatting issues. For formatting `gherkin_format --template ...` could be used.
21
+
22
+ To tag all words used, start it with `--tag`. This allows to build up a glossary based on the feature files provided.
23
+
24
+
25
+ Glossary
26
+ --------
27
+
28
+ It happens that there are words which are unknown to the dictionary.
29
+ Once this happens think about if could use another word, that is more common. If there is no such word, add it to the directory-located glossary.
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ require 'rake/testtask'
2
+
3
+ task default: :build
4
+
5
+ desc 'Builds the Gem.'
6
+ task build: :test do
7
+ sh 'gem build gherkin_language.gemspec'
8
+ end
9
+
10
+ Rake::TestTask.new do |t|
11
+ t.libs << 'test'
12
+ end
13
+
14
+ task test: :rubocop
15
+ task test: :cucumber
16
+
17
+ desc 'Publishes the Gem'
18
+ task :push do
19
+ sh 'gem push gherkin_language-0.0.2.gem'
20
+ end
21
+
22
+ desc 'Checks ruby style'
23
+ task :rubocop do
24
+ sh 'rubocop'
25
+ end
26
+
27
+ task :cucumber do
28
+ sh 'cucumber'
29
+ end
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+ require 'gherkin_language'
3
+ require 'optparse'
4
+
5
+ options = {}
6
+ OptionParser.new do |opts|
7
+ opts.banner = 'Usage: gherkin_language [files]'
8
+ opts.on('-v', '--[no-]verbose', 'Run verbosely') do |verbose|
9
+ options[:verbose] = verbose
10
+ end
11
+ opts.on('--sentences', 'extract relevant sentences') do |sentences|
12
+ options[:sentences] = sentences
13
+ end
14
+ opts.on('--tag', 'tag words') do |tag|
15
+ options[:tag] = tag
16
+ end
17
+ opts.on('--no-cache', 'do not use cache') do |no_cache|
18
+ options[:no_cache] = no_cache
19
+ end
20
+ end.parse!
21
+
22
+ language = GherkinLanguage.new(options.key? :no_cache)
23
+
24
+ if options.key? :sentences
25
+ ARGV.each { |file| puts language.extract_sentences language.parse file }
26
+ exit
27
+ end
28
+ if options.key? :tag
29
+ puts language.tag ARGV
30
+ exit
31
+ end
32
+
33
+ ARGV.each { |file| language.analyze file }
34
+ exit language.report
@@ -0,0 +1,58 @@
1
+ Feature: Report
2
+ As a Business Analyst
3
+ I want to get a report for language mistakes within my feature files
4
+ so that I am able to fix them
5
+
6
+ Background:
7
+ Given a file named "report.rb" with:
8
+ """
9
+ $LOAD_PATH << '../../lib'
10
+ require 'gherkin_language'
11
+
12
+ no_cache = true
13
+ language = GherkinLanguage.new no_cache
14
+ language.analyze 'test.feature'
15
+ exit language.report
16
+
17
+ """
18
+
19
+ Scenario: Broken Sentence
20
+ Given a file named "test.feature" with:
21
+ """
22
+ Feature: Test
23
+ Scenario: Tag
24
+ Given an test
25
+ When execute
26
+ Then pass
27
+ """
28
+ When I run `ruby report.rb`
29
+ Then it should fail with exactly:
30
+ """
31
+ [misspelling] EN_A_VS_AN
32
+ Use 'a' instead of 'an' if the following word doesn't start with a vowel sound, e.g. 'a sentence', 'a university'
33
+ Context: Given an test when execute then pass
34
+ Replacements: a
35
+ References: test.feature
36
+
37
+ """
38
+
39
+ Scenario: Unknown Words
40
+ Given a file named "test.feature" with:
41
+ """
42
+ Feature: Test
43
+ Scenario: Tag
44
+ Given a test
45
+ When exicute
46
+ Then pass
47
+ """
48
+ When I run `ruby report.rb`
49
+ Then it should fail with exactly:
50
+ """
51
+ [misspelling] MORFOLOGIK_RULE_EN_US
52
+ Possible spelling mistake found
53
+ Context: Given a test when exicute then pass
54
+ Replacements: execute
55
+ References: test.feature
56
+ 1 unknown words: exicute
57
+
58
+ """
@@ -0,0 +1,127 @@
1
+ Feature: Sentences
2
+ As a Business Analyst
3
+ I want to extract all sentences out of my feature files
4
+ so that I could do further analysis on them
5
+
6
+ Background:
7
+ Given a file named "extract_sentences.rb" with:
8
+ """
9
+ $LOAD_PATH << '../../lib'
10
+ require 'gherkin_language'
11
+
12
+ language = GherkinLanguage.new false
13
+ puts language.extract_sentences language.parse 'foo.feature'
14
+
15
+ """
16
+
17
+ Scenario: Extract Sentences
18
+ Given a file named "foo.feature" with:
19
+ """
20
+ Feature: Foo
21
+ Scenario: Bar
22
+ Given a foo
23
+ When I bar
24
+ Then I baz
25
+ """
26
+ When I run `ruby extract_sentences.rb`
27
+ Then it should pass with:
28
+ """
29
+ Foo
30
+ Bar
31
+ Given a foo when I bar then I baz
32
+ """
33
+
34
+ Scenario: Extract Sentences with background
35
+ Given a file named "foo.feature" with:
36
+ """
37
+ Feature: Foo
38
+ Background:
39
+ Given something
40
+
41
+ Scenario: Bar
42
+ Given a foo
43
+ When I bar
44
+ Then I baz
45
+ """
46
+ When I run `ruby extract_sentences.rb`
47
+ Then it should pass with:
48
+ """
49
+ Foo
50
+ Bar
51
+ Given something and a foo when I bar then I baz
52
+ """
53
+
54
+ Scenario: Extract Sentences from outlines
55
+ Given a file named "foo.feature" with:
56
+ """
57
+ Feature: Foo
58
+ Scenario Outline: Bar
59
+ Given a <foo>
60
+ When I <bar>
61
+ Then I <baz>
62
+
63
+ Examples: table
64
+ | foo | bar | baz |
65
+ | FOO | BAR | BAZ |
66
+ | oof | rab | zab |
67
+ """
68
+ When I run `ruby extract_sentences.rb`
69
+ Then it should pass with:
70
+ """
71
+ Foo
72
+ Bar
73
+ table
74
+ Given a FOO when I BAR then I BAZ
75
+ Given a oof when I rab then I zab
76
+ """
77
+
78
+ Scenario: Extract Sentences considers feature description
79
+ Given a file named "foo.feature" with:
80
+ """
81
+ Feature: Foo
82
+ As a user,
83
+ I want something
84
+ so that I have that
85
+
86
+ Scenario: Bar
87
+ Given a foo
88
+ When I bar
89
+ Then I baz
90
+ """
91
+ When I run `ruby extract_sentences.rb`
92
+ Then it should pass with:
93
+ """
94
+ Foo
95
+ As a user,
96
+ I want something
97
+ so that I have that
98
+ Bar
99
+ Given a foo when I bar then I baz
100
+ """
101
+
102
+ Scenario: Extract Sentences considers scenario description
103
+ Given a file named "foo.feature" with:
104
+ """
105
+ Feature: Foo
106
+ As a user,
107
+ I want something
108
+ so that I have that
109
+
110
+ Scenario: Bar
111
+ This is a sentence description
112
+
113
+ Given a foo
114
+ When I bar
115
+ Then I baz
116
+ """
117
+ When I run `ruby extract_sentences.rb`
118
+ Then it should pass with:
119
+ """
120
+ Foo
121
+ As a user,
122
+ I want something
123
+ so that I have that
124
+ Bar
125
+ This is a sentence description
126
+ Given a foo when I bar then I baz
127
+ """
@@ -0,0 +1,5 @@
1
+ require 'aruba/cucumber'
2
+
3
+ Before do
4
+ @aruba_timeout_seconds = 1000 # external java process, give it some time
5
+ end
@@ -0,0 +1,53 @@
1
+ Feature: Tag
2
+ As a Business Analyst
3
+ I want to tag all words from my features files
4
+ so that I can build up a glossary or check against forbidden words
5
+
6
+ Background: Prepare Testee
7
+ Given a file named "tag.rb" with:
8
+ """
9
+ $LOAD_PATH << '../../lib'
10
+ require 'gherkin_language'
11
+
12
+ no_cache = true
13
+ language = GherkinLanguage.new no_cache
14
+ puts language.tag ['tag.feature']
15
+
16
+ """
17
+
18
+ Scenario: Tag words
19
+ Given a file named "tag.feature" with:
20
+ """
21
+ Feature: Test
22
+ Scenario: Tag
23
+ Given a test
24
+ When execute
25
+ Then pass
26
+ """
27
+ When I run `ruby tag.rb`
28
+ Then it should pass with exactly:
29
+ """
30
+ <S>
31
+ [[[/null]
32
+ "["/``]
33
+ Test[Test/NNP]
34
+ "["/'']
35
+ ,[,/,,O]
36
+ "["/``,O]
37
+ Tag[tag/NN:UN,tag/VB,tag/VBP]
38
+ "["/'']
39
+ ,[,/,,O]
40
+ "["/``,O]
41
+ Given[Given/NNP,B-VP]
42
+ a[a/DT,B-NP-singular]
43
+ test[test/JJ,test/NN,test/VB,test/VBP,E-NP-singular]
44
+ when[when/WRB,B-ADVP]
45
+ execute[execute/VB,execute/VBP,B-VP]
46
+ then[then/JJ,then/NN,then/RB,I-VP]
47
+ pass[pass/JJ,pass/NN,pass/VB,pass/VBP,I-VP]
48
+ "["/'',B-ADVP]
49
+ ]
50
+ [</S>,O]
51
+
52
+
53
+ """
@@ -0,0 +1,14 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'gherkin_language'
3
+ s.version = '0.0.2'
4
+ s.date = '2015-07-02'
5
+ s.summary = 'Gherkin Language'
6
+ s.description = 'Check language of Gherkin Files'
7
+ s.authors = ['Stefan Rohe']
8
+ s.homepage = 'http://github.com/funkwerk/gherkin_language/'
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_development_dependency 'aruba', ['>= 0.6.2']
14
+ end
@@ -0,0 +1,333 @@
1
+ require 'gherkin/formatter/json_formatter'
2
+ require 'gherkin/parser/parser'
3
+ require 'rexml/document'
4
+ require 'stringio'
5
+ require 'multi_json'
6
+ require 'term/ansicolor'
7
+ include Term::ANSIColor
8
+ require 'tmpdir'
9
+ require 'fileutils'
10
+ require 'yaml'
11
+ require 'set'
12
+ require 'digest'
13
+
14
+ # gherkin utilities
15
+ class GherkinLanguage
16
+ # This service class provides access to language tool process.
17
+ class LanguageToolProcess
18
+ attr_accessor :errors, :unknown_words
19
+
20
+ VERSION = 'LanguageTool-3.0'
21
+ URL = "https://www.languagetool.org/download/#{VERSION}.zip"
22
+
23
+ # This value entity class represents a language error
24
+ class Error
25
+ attr_accessor :category, :context, :issuetype, :message, :replacements, :rule, :from_y, :to_y
26
+
27
+ def initialize(category, context, issuetype, message, replacements, rule, from_y, to_y)
28
+ @category = category
29
+ @context = context
30
+ @issuetype = issuetype
31
+ @message = message
32
+ @replacements = replacements
33
+ @rule = rule
34
+ @from_y = from_y
35
+ @to_y = to_y
36
+ end
37
+
38
+ def str(references)
39
+ (red("[#{@issuetype}] #{@rule}\n") +
40
+ " #{@message}\n Context: #{@context}\n Replacements: #{@replacements}\n References: #{references * ', '}\n")
41
+ end
42
+ end
43
+
44
+ def initialize
45
+ path = Dir.tmpdir
46
+ download path unless File.exist? "#{path}/#{VERSION}/languagetool-commandline.jar"
47
+ @path = path
48
+ @p = nil
49
+ @reference_line = 0
50
+ @errors = []
51
+ @unknown_words = []
52
+ use_user_glossary "#{path}/#{VERSION}" if File.exist? '.glossary'
53
+ end
54
+
55
+ def use_user_glossary(path)
56
+ resource_path = "#{path}/org/languagetool/resource/en"
57
+ system "cp #{resource_path}/added.txt #{resource_path}/added.copy && cp .glossary #{resource_path}/added.txt"
58
+ at_exit do
59
+ system "cp #{resource_path}/added.copy #{resource_path}/added.txt"
60
+ end
61
+ end
62
+
63
+ def download(path)
64
+ system "wget --quiet #{URL} -O /var/tmp/languagetool.zip"
65
+ FileUtils.mkdir_p path
66
+ system "unzip -qq -u /var/tmp/languagetool.zip -d #{path}"
67
+ end
68
+
69
+ def start!
70
+ @errors = []
71
+ @unknown_words = []
72
+ @reference_line = 0
73
+ Dir.chdir("#{@path}/#{VERSION}/") do
74
+ @p = IO.popen('java -jar languagetool-commandline.jar --list-unknown --api --language en-US -', 'r+')
75
+ end
76
+ end
77
+
78
+ def tag(sentences)
79
+ output = ''
80
+ Dir.chdir("#{@path}/#{VERSION}/") do
81
+ p = IO.popen('java -jar languagetool-commandline.jar --taggeronly --api --language en-US -', 'r+')
82
+ sentences.each { |sentence| p.write sentence }
83
+ p.close_write
84
+ line = p.readline
85
+ loop do
86
+ break if line == "<!--\n"
87
+ output << line
88
+ line = p.readline
89
+ end
90
+ p.close
91
+ end
92
+ output.gsub!(' ', "\n")
93
+ output.gsub!(']', "]\n")
94
+ output.gsub!("\n\n", "\n")
95
+ output
96
+ end
97
+
98
+ def check_paragraph(paragraph)
99
+ start_line = @reference_line
100
+ send paragraph
101
+ end_line = @reference_line
102
+ send "\n\n"
103
+ Range.new(start_line, end_line)
104
+ end
105
+
106
+ def send(sentence)
107
+ @reference_line += sentence.count "\n"
108
+ @p.write sentence
109
+ end
110
+
111
+ def parse_errors(result)
112
+ doc = REXML::Document.new result
113
+ errors = []
114
+ doc.elements.each '//error' do |error|
115
+ errors.push Error.new(
116
+ error.attributes['category'],
117
+ error.attributes['context'],
118
+ error.attributes['locqualityissuetype'],
119
+ error.attributes['msg'],
120
+ error.attributes['replacements'],
121
+ error.attributes['ruleId'],
122
+ error.attributes['fromy'].to_i,
123
+ error.attributes['toy'].to_i)
124
+ end
125
+ errors
126
+ end
127
+
128
+ def parse_unknown_words(result)
129
+ doc = REXML::Document.new result
130
+ errors = []
131
+ doc.elements.each '//unknown_words/word' do |error|
132
+ errors.push error.text
133
+ end
134
+ errors
135
+ end
136
+
137
+ def stop!
138
+ @p.close_write
139
+ errors = ''
140
+ line = @p.readline
141
+ loop do
142
+ break if line == "<!--\n"
143
+ errors << line
144
+ line = @p.readline
145
+ end
146
+ @errors = parse_errors errors
147
+ @unknown_words = parse_unknown_words errors
148
+ @p.close
149
+ end
150
+ end
151
+
152
+ def initialize(no_cache = false)
153
+ path = "~/.gherkin_language/#{LanguageToolProcess::VERSION}/accepted_paragraphs.yml"
154
+ @settings_path = File.expand_path path
155
+ @accepted_paragraphs = {}
156
+ begin
157
+ @accepted_paragraphs = YAML.load_file @settings_path unless no_cache
158
+ rescue
159
+ puts 'could not read settings'
160
+ end
161
+ @references = {}
162
+ @line_to_reference = {}
163
+ end
164
+
165
+ def analyze(file)
166
+ sentences = extract_sentences parse file
167
+ sentences.select! { |sentence| !accepted? sentence }
168
+ return if sentences.empty?
169
+ sentences.each do |sentence|
170
+ stripped = sentence.strip
171
+ @references[stripped] = [] unless @references.include? stripped
172
+ @references[stripped].push file
173
+ end
174
+ end
175
+
176
+ def accepted?(sentence)
177
+ return false if @accepted_paragraphs.nil?
178
+ key = :without_glossary
179
+ key = hash(File.read '.glossary') if File.exist? '.glossary'
180
+
181
+ return false unless @accepted_paragraphs.key? key
182
+ @accepted_paragraphs[key].include? hash sentence
183
+ end
184
+
185
+ def hash(value)
186
+ Digest::MD5.digest value.strip
187
+ end
188
+
189
+ def parse(file)
190
+ content = File.read file
191
+ to_json(content, file)
192
+ end
193
+
194
+ def extract_sentences(parsed)
195
+ feature_names = lambda do |input|
196
+ input.map { |feature| feature['name'] unless feature['name'] == '' }
197
+ end
198
+
199
+ descriptions = lambda do |input|
200
+ input.map { |feature| feature['description'] unless feature['description'] == '' }
201
+ end
202
+
203
+ sentences = feature_names.call(parsed) + descriptions.call(parsed) + scenario_names(parsed) + sentences(parsed)
204
+ sentences.select! { |sentence| sentence }
205
+ sentences.map { |sentence| sentence.gsub(/ «.+»/, '') }
206
+ end
207
+
208
+ def tag(files)
209
+ sentences = files.map { |file| extract_sentences parse file }
210
+ language = LanguageToolProcess.new
211
+ language.tag sentences
212
+ end
213
+
214
+ def report
215
+ return if @references.keys.empty?
216
+ language = LanguageToolProcess.new
217
+ language.start!
218
+
219
+ @references.keys.each do |sentence|
220
+ location = language.check_paragraph sentence
221
+ location.map { |line| @line_to_reference[line] = sentence }
222
+ end
223
+ language.stop!
224
+ errors = language.errors
225
+ unknown_words = language.unknown_words
226
+
227
+ used_refs = Set.new []
228
+ errors.each do |error|
229
+ used_refs.add @line_to_reference[error.from_y]
230
+ local_refs = @references[@line_to_reference[error.from_y]]
231
+ puts error.str local_refs
232
+ end
233
+ # TODO: list references for unknown words
234
+ puts red "#{unknown_words.count} unknown words: #{unknown_words * ', '}" unless unknown_words.empty?
235
+ return -1 unless unknown_words.empty?
236
+
237
+ @references.each do |sentence, _refs|
238
+ next if used_refs.include? sentence
239
+ key = :without_glossary
240
+ key = hash(File.read '.glossary') if File.exist? '.glossary'
241
+
242
+ @accepted_paragraphs[key] = Set.new [] unless @accepted_paragraphs.key? key
243
+ @accepted_paragraphs[key].add hash sentence
244
+ end
245
+
246
+ FileUtils.mkdir_p File.dirname @settings_path
247
+ File.open(@settings_path, 'w') do |settings_file|
248
+ settings_file.write @accepted_paragraphs.to_yaml
249
+ end
250
+ return -1 unless errors.empty?
251
+ 0
252
+ end
253
+
254
+ def to_json(input, file = 'generated.feature')
255
+ io = StringIO.new
256
+ formatter = Gherkin::Formatter::JSONFormatter.new(io)
257
+ parser = Gherkin::Parser::Parser.new(formatter, true)
258
+ parser.parse(input, file, 0)
259
+ formatter.done
260
+ MultiJson.load io.string
261
+ end
262
+
263
+ def scenario_names(input)
264
+ # TODO: scenario outlines with example values inside?
265
+ scenarios = []
266
+ input.each do |features|
267
+ next unless features.key? 'elements'
268
+ elements = features['elements']
269
+ elements.each do |scenario|
270
+ scenarios.push scenario['name'] if scenario['type'] == 'scenario'
271
+ scenarios.push scenario['name'] if scenario['type'] == 'scenario_outline'
272
+ scenarios.push scenario['description'] unless scenario['description'].empty?
273
+ end
274
+ end
275
+ scenarios
276
+ end
277
+
278
+ def sentences(input)
279
+ sentences = []
280
+ background = []
281
+ input.each do |features|
282
+ next unless features.key? 'elements'
283
+ elements = features['elements']
284
+ elements.each do |scenario|
285
+ next unless scenario.key? 'steps'
286
+ terms = background.dup
287
+ if scenario['type'] == 'background'
288
+ scenario['steps'].each do |step|
289
+ new_terms = [step['keyword'], step['name']].join
290
+ new_terms = uncapitalize(new_terms) unless terms.empty?
291
+ background.push new_terms
292
+ end
293
+ next
294
+ end
295
+
296
+ scenario['steps'].each do |step|
297
+ keyword = step['keyword']
298
+ keyword = 'and ' unless background.empty? || keyword != 'Given '
299
+ new_terms = [keyword, step['name']].join
300
+ new_terms = uncapitalize(new_terms) unless terms.empty?
301
+ terms.push new_terms
302
+ end
303
+ sentence = terms.join ' '
304
+ if scenario.key? 'examples'
305
+ # TODO: support for multiple examples?
306
+ scenario['examples'].each do |example|
307
+ sentences.push example['name'] unless example['name'].empty?
308
+ sentences.push example['description'] unless example['description'].empty?
309
+ expand_outlines(sentence.strip, example).map { |expanded| sentences.push expanded }
310
+ end
311
+ else
312
+ sentences.push sentence.strip
313
+ end
314
+ end
315
+ end
316
+ sentences
317
+ end
318
+
319
+ def uncapitalize(term)
320
+ term[0, 1].downcase + term[1..-1]
321
+ end
322
+
323
+ def expand_outlines(sentence, example)
324
+ result = []
325
+ headers = example['rows'][0]['cells']
326
+ example['rows'].slice(1, example['rows'].length).each do |row|
327
+ modified_sentence = sentence.dup
328
+ headers.zip(row['cells']).map { |key, value| modified_sentence.gsub!("<#{key}>", value) }
329
+ result.push modified_sentence
330
+ end
331
+ result
332
+ end
333
+ end
@@ -0,0 +1,61 @@
1
+ require 'minitest/autorun'
2
+ require 'gherkin_language'
3
+
4
+ # gherkin language test
5
+ class GherkinLanguageTest < Minitest::Unit::TestCase
6
+ def setup
7
+ @gherkin = GherkinLanguage.new
8
+ end
9
+
10
+ def test_to_json
11
+ # setup
12
+ feature = %(Feature: Foo
13
+ Scenario: Bar
14
+ )
15
+ expected = MultiJson.load %(
16
+ [
17
+ {
18
+ "keyword": "Feature",
19
+ "name": "Foo",
20
+ "line": 1,
21
+ "description": "",
22
+ "id": "foo",
23
+ "uri": "generated.feature",
24
+ "elements":
25
+ [
26
+ {
27
+ "keyword": "Scenario", "name": "Bar",
28
+ "line": 2, "description": "",
29
+ "id": "foo;bar", "type": "scenario"
30
+ }
31
+ ]
32
+ }
33
+ ]
34
+ )
35
+
36
+ # exercise
37
+ actual = @gherkin.to_json feature
38
+
39
+ # verify
40
+ assert_equal expected, actual
41
+ end
42
+
43
+ def test_sentences
44
+ # setup
45
+ feature = %(Feature: Foo
46
+ Scenario: Bar
47
+ Given a Foo
48
+ And another Foo
49
+ But no Bar
50
+ When a Bar
51
+ Then a Baz
52
+ )
53
+ expected = ['Given a Foo and another Foo but no Bar when a Bar then a Baz']
54
+
55
+ # exercise
56
+ actual = @gherkin.sentences @gherkin.to_json feature
57
+
58
+ # verify
59
+ assert_equal expected, actual
60
+ end
61
+ end
@@ -0,0 +1,40 @@
1
+ require 'minitest/autorun'
2
+ require 'gherkin_language'
3
+
4
+ # checks language
5
+ class LanguageTest < Minitest::Unit::TestCase
6
+ def setup
7
+ @language = GherkinLanguage::LanguageToolProcess.new
8
+ @language.start!
9
+ end
10
+
11
+ def test_check_valid_paragraph
12
+ # setup
13
+ feature = 'This is good English'
14
+
15
+ # exercise
16
+ @language.check_paragraph feature
17
+ @language.stop!
18
+ actual = @language.errors
19
+ unknown_words = @language.unknown_words
20
+
21
+ # verify
22
+ assert_empty actual
23
+ assert_empty unknown_words
24
+ end
25
+
26
+ def test_check_invalid_paragraph
27
+ # setup
28
+ feature = 'This are no English good'
29
+
30
+ # exercise
31
+ @language.check_paragraph feature
32
+ @language.stop!
33
+ actual = @language.errors
34
+ unknown_words = @language.unknown_words
35
+
36
+ # verify
37
+ refute_empty actual
38
+ assert_empty unknown_words
39
+ end
40
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gherkin_language
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Stefan Rohe
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-07-02 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: aruba
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 0.6.2
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 0.6.2
55
+ description: Check language of Gherkin Files
56
+ email:
57
+ executables:
58
+ - gherkin_language
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".rubocop.yml"
63
+ - ".travis.yml"
64
+ - Gemfile
65
+ - Guardfile
66
+ - LICENSE
67
+ - README.md
68
+ - Rakefile
69
+ - bin/gherkin_language
70
+ - features/report.feature
71
+ - features/sentences.feature
72
+ - features/support/env.rb
73
+ - features/tag.feature
74
+ - gherkin_language.gemspec
75
+ - lib/gherkin_language.rb
76
+ - test/test_gherkin_language.rb
77
+ - test/test_gherkin_language_tool.rb
78
+ homepage: http://github.com/funkwerk/gherkin_language/
79
+ licenses: []
80
+ metadata: {}
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ requirements: []
96
+ rubyforge_project:
97
+ rubygems_version: 2.2.3
98
+ signing_key:
99
+ specification_version: 4
100
+ summary: Gherkin Language
101
+ test_files: []