gherkin_language 0.0.2

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