gherkin_checker 1.2.0 → 1.3.0
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 +4 -4
- data/exe/gherkin_checker +0 -1
- data/lib/gherkin_checker/config.rb +25 -0
- data/lib/gherkin_checker/parser.rb +52 -0
- data/lib/gherkin_checker/validator.rb +45 -0
- data/lib/gherkin_checker/version.rb +1 -1
- data/lib/gherkin_checker.rb +57 -189
- metadata +62 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 842d35c08788f9b36bab530ea6278e57ab3e3b073a1685bcfab5aeec07de3079
|
|
4
|
+
data.tar.gz: 38b86c8550dc83042c76d3903d8a51e25f23ee65749fb3b54da62b2e6658b6d7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b80cfb47d90b9e6e48b1789661862c8246a03738a14e4d2cf68cc13e430d178bb4380588a675f469a12fb3dbf2ed20310c9d87e211c1be1dfe86ca2a48159cc2
|
|
7
|
+
data.tar.gz: c166eff07a845109578d9561546cf7d016a0d25a47dff9e40cd2693ecd1d4ab0bb249cd42ee11ec09a3fa0e6feb21a382a3fc2a3029dd0cad772a7b85fc72580
|
data/exe/gherkin_checker
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "yaml"
|
|
4
|
+
|
|
5
|
+
module GherkinChecker
|
|
6
|
+
# Config class to handle configuration loading
|
|
7
|
+
class Config
|
|
8
|
+
attr_reader :feature_files_path, :one_of_tags, :must_be_tags
|
|
9
|
+
|
|
10
|
+
def initialize(config_file = "gherkin_checker.yml")
|
|
11
|
+
@config = load_config(config_file)
|
|
12
|
+
@feature_files_path = @config.fetch("feature_files_path", "./features")
|
|
13
|
+
@one_of_tags = @config.dig("mandatory_tags", "one_of")
|
|
14
|
+
@must_be_tags = @config.dig("mandatory_tags", "must_be")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def load_config(file)
|
|
20
|
+
return {} unless File.exist?(file)
|
|
21
|
+
|
|
22
|
+
YAML.load_file(file) || {}
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "gherkin/parser"
|
|
4
|
+
require "gherkin/errors"
|
|
5
|
+
|
|
6
|
+
module GherkinChecker
|
|
7
|
+
# Parser class to handle Gherkin file parsing
|
|
8
|
+
class Parser
|
|
9
|
+
def initialize
|
|
10
|
+
@parser = Gherkin::Parser.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def parse(file_path)
|
|
14
|
+
content = File.read(file_path)
|
|
15
|
+
document = @parser.parse(content)
|
|
16
|
+
feature = document.feature
|
|
17
|
+
|
|
18
|
+
return [] unless feature
|
|
19
|
+
|
|
20
|
+
feature_name = feature.name
|
|
21
|
+
feature_tags = feature.tags.map(&:name).map { |tag| tag.delete_prefix("@") }
|
|
22
|
+
|
|
23
|
+
feature.children.map do |child|
|
|
24
|
+
process_child(child, feature_name, feature_tags)
|
|
25
|
+
end.compact
|
|
26
|
+
rescue Gherkin::CompositeParserException => e
|
|
27
|
+
e.errors.map do |error|
|
|
28
|
+
{ error: error.message, type: :syntax_error }
|
|
29
|
+
end
|
|
30
|
+
rescue Gherkin::ParserError => e
|
|
31
|
+
[{ error: e.message, type: :syntax_error }]
|
|
32
|
+
rescue StandardError => e
|
|
33
|
+
[{ error: e.message, type: :unknown_error }]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def process_child(child, feature_name, feature_tags)
|
|
39
|
+
return unless child.respond_to?(:scenario) && child.scenario
|
|
40
|
+
|
|
41
|
+
scenario = child.scenario
|
|
42
|
+
{
|
|
43
|
+
feature_name: feature_name,
|
|
44
|
+
feature_tags: feature_tags,
|
|
45
|
+
line: scenario.location.line,
|
|
46
|
+
column: scenario.location.column,
|
|
47
|
+
name: scenario.name,
|
|
48
|
+
tags: scenario.tags.map(&:name).map { |tag| tag.delete_prefix("@") }
|
|
49
|
+
}
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GherkinChecker
|
|
4
|
+
# Validator class to check tags against rules
|
|
5
|
+
class Validator
|
|
6
|
+
def initialize(config)
|
|
7
|
+
@config = config
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def validate(scenario_data)
|
|
11
|
+
errors = []
|
|
12
|
+
return errors if scenario_data[:error]
|
|
13
|
+
|
|
14
|
+
errors << check_one_of_tags(scenario_data)
|
|
15
|
+
errors << check_must_be_tags(scenario_data)
|
|
16
|
+
errors.compact
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def check_one_of_tags(data)
|
|
22
|
+
return nil unless @config.one_of_tags
|
|
23
|
+
return nil if @config.one_of_tags.any? { |tag| data[:tags].include?(tag) }
|
|
24
|
+
|
|
25
|
+
format_error(:one_of_tags, @config.one_of_tags, data)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def check_must_be_tags(data)
|
|
29
|
+
return nil unless @config.must_be_tags
|
|
30
|
+
return nil if @config.must_be_tags.all? { |tag| data[:tags].include?(tag) }
|
|
31
|
+
|
|
32
|
+
format_error(:must_be_tags, @config.must_be_tags, data)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def format_error(type, expected, data)
|
|
36
|
+
{
|
|
37
|
+
check: type,
|
|
38
|
+
file_line: data[:line], # We will need to prepend file path in runner
|
|
39
|
+
scenario_name: data[:name],
|
|
40
|
+
scenario_tags: data[:tags],
|
|
41
|
+
expected: expected
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
data/lib/gherkin_checker.rb
CHANGED
|
@@ -1,44 +1,38 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "find"
|
|
4
|
-
require "yaml"
|
|
5
|
-
require "gherkin/parser"
|
|
6
|
-
|
|
7
4
|
require_relative "gherkin_checker/version"
|
|
5
|
+
require_relative "gherkin_checker/config"
|
|
6
|
+
require_relative "gherkin_checker/parser"
|
|
7
|
+
require_relative "gherkin_checker/validator"
|
|
8
8
|
|
|
9
9
|
module GherkinChecker
|
|
10
|
-
# Checker class
|
|
10
|
+
# Checker class - The main runner
|
|
11
11
|
class Checker
|
|
12
12
|
def initialize(config_file = "gherkin_checker.yml")
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
@config = YAML.load_file(config_file)
|
|
19
|
-
if @config
|
|
20
|
-
@skip_check = false
|
|
21
|
-
else
|
|
22
|
-
log_message("Warning: The gherkin_checker.yml not define", level: :warn)
|
|
23
|
-
@skip_check = true
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
@feature_files_path = @config&.key?("feature_files_path") ? @config.fetch("feature_files_path") : "./features"
|
|
27
|
-
@one_of_tags = @config.dig("mandatory_tags", "one_of") if @config
|
|
28
|
-
@must_be_tags = @config.dig("mandatory_tags", "must_be") if @config
|
|
29
|
-
|
|
30
|
-
# Flags to ensure warnings are only printed once
|
|
31
|
-
@one_of_tags_warning_shown = false
|
|
32
|
-
@must_be_tags_warning_shown = false
|
|
13
|
+
@config = Config.new(config_file)
|
|
14
|
+
@parser = Parser.new
|
|
15
|
+
@validator = Validator.new(@config)
|
|
33
16
|
end
|
|
34
17
|
|
|
35
18
|
def check_feature_files
|
|
19
|
+
return log_skip_message if skip_check?
|
|
20
|
+
|
|
36
21
|
errors = []
|
|
37
|
-
Find.find(@feature_files_path) do |file|
|
|
22
|
+
Find.find(@config.feature_files_path) do |file|
|
|
38
23
|
next unless File.extname(file) == ".feature"
|
|
39
24
|
|
|
40
|
-
|
|
41
|
-
|
|
25
|
+
scenarios = @parser.parse(file)
|
|
26
|
+
scenarios.each do |scenario|
|
|
27
|
+
if scenario[:error]
|
|
28
|
+
errors << scenario
|
|
29
|
+
else
|
|
30
|
+
validation_errors = @validator.validate(scenario)
|
|
31
|
+
# Prepend file path to the error
|
|
32
|
+
validation_errors.each { |err| err[:file_line] = "#{file}:#{err[:file_line]}:#{scenario[:column]}" }
|
|
33
|
+
errors += validation_errors
|
|
34
|
+
end
|
|
35
|
+
end
|
|
42
36
|
end
|
|
43
37
|
|
|
44
38
|
report_errors(errors)
|
|
@@ -46,188 +40,62 @@ module GherkinChecker
|
|
|
46
40
|
|
|
47
41
|
private
|
|
48
42
|
|
|
49
|
-
def
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
tags = data[:scenario_tags]
|
|
56
|
-
file_line = data[:file_line]
|
|
57
|
-
scenario = data[:scenario_name]
|
|
58
|
-
error = data[:error]
|
|
59
|
-
|
|
60
|
-
if is_tags_nil
|
|
61
|
-
errors << {
|
|
62
|
-
check: :one_of_tags,
|
|
63
|
-
file_line: file_line,
|
|
64
|
-
scenario_name: scenario,
|
|
65
|
-
scenario_tags: tags,
|
|
66
|
-
error: error
|
|
67
|
-
}
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
next if is_tags_nil
|
|
71
|
-
|
|
72
|
-
next if @one_of_tags.any? { |tag| tags.include?(tag) }
|
|
73
|
-
|
|
74
|
-
errors << {
|
|
75
|
-
check: :one_of_tags,
|
|
76
|
-
file_line: file_line,
|
|
77
|
-
scenario_name: scenario,
|
|
78
|
-
scenario_tags: tags,
|
|
79
|
-
error: error
|
|
80
|
-
}
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
errors
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def check_must_be_tags(file)
|
|
87
|
-
return log_must_be_tags_warning if @must_be_tags.nil?
|
|
88
|
-
|
|
89
|
-
errors = []
|
|
90
|
-
extract_scenario_data(file).each do |data|
|
|
91
|
-
is_tags_nil = data[:scenario_tags].nil?
|
|
92
|
-
tags = data[:scenario_tags]
|
|
93
|
-
file_line = data[:file_line]
|
|
94
|
-
scenario = data[:scenario_name]
|
|
95
|
-
error = data[:error]
|
|
96
|
-
|
|
97
|
-
if is_tags_nil
|
|
98
|
-
errors << {
|
|
99
|
-
check: :must_be_tags,
|
|
100
|
-
file_line: file_line,
|
|
101
|
-
scenario_name: scenario,
|
|
102
|
-
scenario_tags: tags,
|
|
103
|
-
error: error
|
|
104
|
-
}
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
next if is_tags_nil
|
|
108
|
-
|
|
109
|
-
next if @must_be_tags.all? { |item| tags.include?(item) }
|
|
110
|
-
|
|
111
|
-
errors << {
|
|
112
|
-
check: :must_be_tags,
|
|
113
|
-
file_line: file_line,
|
|
114
|
-
scenario_name: scenario,
|
|
115
|
-
scenario_tags: tags,
|
|
116
|
-
error: error
|
|
117
|
-
}
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
errors
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def log_one_of_tags_warning
|
|
124
|
-
return [] if @one_of_tags_warning_shown
|
|
125
|
-
|
|
126
|
-
log_message("Warning: Optional tags not set in 'gherkin_checker.yml'.", level: :warn) unless @skip_check
|
|
127
|
-
@one_of_tags_warning_shown = true
|
|
128
|
-
[] # Return an empty array to maintain consistency
|
|
43
|
+
def skip_check?
|
|
44
|
+
# If no config was loaded (meaning no file found or empty), we might want to warn
|
|
45
|
+
# But based on original logic, if config is missing, we warn and skip.
|
|
46
|
+
# Config class handles loading. If attributes are nil, it means load failed or empty.
|
|
47
|
+
# Let's check if critical config is present.
|
|
48
|
+
@config.one_of_tags.nil? && @config.must_be_tags.nil?
|
|
129
49
|
end
|
|
130
50
|
|
|
131
|
-
def
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
log_message("Warning: Mandatory tags not set in 'gherkin_checker.yml'.", level: :warn) unless @skip_check
|
|
135
|
-
@must_be_tags_warning_shown = true
|
|
136
|
-
[] # Return an empty array to maintain consistency
|
|
51
|
+
def log_skip_message
|
|
52
|
+
log_message("Warning: The gherkin_checker.yml not define or no tags configured", level: :warn)
|
|
53
|
+
log_message("Skip gherkin checking", level: :warn)
|
|
137
54
|
end
|
|
138
55
|
|
|
139
56
|
def report_errors(errors)
|
|
140
57
|
if errors.empty?
|
|
141
|
-
|
|
142
|
-
log_message("Skip gherkin checking", level: :warn)
|
|
143
|
-
else
|
|
144
|
-
log_message("All scenarios have the required tags.")
|
|
145
|
-
end
|
|
58
|
+
log_message("All scenarios have the required tags.")
|
|
146
59
|
else
|
|
147
60
|
log_message("Gherkin Checker found Error:", level: :error)
|
|
148
61
|
errors.each do |error|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
scenario_tags = error[:scenario_tags]
|
|
152
|
-
tags = scenario_tags
|
|
153
|
-
tags = scenario_tags.nil? ? "Tagging not set" : "Just found '#{tags}'"
|
|
154
|
-
|
|
155
|
-
message = case error[:check]
|
|
156
|
-
when :one_of_tags
|
|
157
|
-
"one_of_tags '#{@one_of_tags}' not found!, #{tags}"
|
|
158
|
-
when :must_be_tags
|
|
159
|
-
"must_be_tags '#{@must_be_tags}' not found!, #{tags}"
|
|
160
|
-
else
|
|
161
|
-
"error undefined"
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
log_message("#{error[:file_line]}: #{error[:scenario_name]} - #{message}", level: :error)
|
|
62
|
+
if error[:error]
|
|
63
|
+
log_syntax_error(error)
|
|
165
64
|
else
|
|
166
|
-
|
|
65
|
+
log_validation_error(error)
|
|
167
66
|
end
|
|
168
67
|
end
|
|
169
68
|
end
|
|
170
69
|
end
|
|
171
70
|
|
|
172
|
-
|
|
71
|
+
def log_syntax_error(error)
|
|
72
|
+
type = error[:type] == :syntax_error ? "Syntax Error" : "Error"
|
|
73
|
+
log_message("#{type}: #{error[:error]}", level: :error)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def log_validation_error(error)
|
|
77
|
+
tags_str = if error[:scenario_tags].nil? || error[:scenario_tags].empty?
|
|
78
|
+
"Tagging not set"
|
|
79
|
+
else
|
|
80
|
+
"Just found '#{error[:scenario_tags]}'"
|
|
81
|
+
end
|
|
82
|
+
check_type = error[:check] == :one_of_tags ? "one_of_tags" : "must_be_tags"
|
|
83
|
+
|
|
84
|
+
message = "#{check_type} '#{error[:expected]}' not found!, #{tags_str}"
|
|
85
|
+
log_message("#{error[:file_line]}: #{error[:scenario_name]} - #{message}", level: :error)
|
|
86
|
+
end
|
|
87
|
+
|
|
173
88
|
def log_message(message, level: :info)
|
|
174
|
-
# Define color codes
|
|
175
89
|
colors = {
|
|
176
|
-
debug: "\e[36m",
|
|
177
|
-
info: "\e[32m",
|
|
178
|
-
warn: "\e[33m",
|
|
179
|
-
error: "\e[31m",
|
|
180
|
-
fatal: "\e[35m",
|
|
181
|
-
reset: "\e[0m"
|
|
90
|
+
debug: "\e[36m",
|
|
91
|
+
info: "\e[32m",
|
|
92
|
+
warn: "\e[33m",
|
|
93
|
+
error: "\e[31m",
|
|
94
|
+
fatal: "\e[35m",
|
|
95
|
+
reset: "\e[0m"
|
|
182
96
|
}
|
|
183
|
-
|
|
184
97
|
color = colors[level] || colors[:reset]
|
|
185
|
-
|
|
186
98
|
puts "#{color}#{message}#{colors[:reset]}"
|
|
187
99
|
end
|
|
188
|
-
|
|
189
|
-
def extract_scenario_data(file)
|
|
190
|
-
gherkin_parser = Gherkin::Parser.new
|
|
191
|
-
scenario_data = []
|
|
192
|
-
|
|
193
|
-
begin
|
|
194
|
-
content = File.read(file)
|
|
195
|
-
document = gherkin_parser.parse(content)
|
|
196
|
-
feature = document.feature
|
|
197
|
-
feature_name = feature.name
|
|
198
|
-
feature_tags = feature.tags.map(&:name)
|
|
199
|
-
|
|
200
|
-
feature.children.each do |child|
|
|
201
|
-
raise "Error: read scenario data" unless child.respond_to?(:scenario) && child.scenario
|
|
202
|
-
|
|
203
|
-
scenario = child.scenario
|
|
204
|
-
scenario_name = scenario.name
|
|
205
|
-
scenario_tags = scenario.tags.map(&:name)
|
|
206
|
-
scenario_tags = scenario_tags.map { |tag| tag.delete_prefix("@") }
|
|
207
|
-
location_line = scenario.location.line
|
|
208
|
-
location_column = scenario.location.column
|
|
209
|
-
|
|
210
|
-
scenario_data << {
|
|
211
|
-
feature_name: feature_name,
|
|
212
|
-
feature_tags: feature_tags,
|
|
213
|
-
file_line: "#{file}:#{location_line}:#{location_column}",
|
|
214
|
-
scenario_name: scenario_name,
|
|
215
|
-
scenario_tags: scenario_tags,
|
|
216
|
-
error: nil
|
|
217
|
-
}
|
|
218
|
-
end
|
|
219
|
-
rescue StandardError => e
|
|
220
|
-
scenario_data << {
|
|
221
|
-
feature_name: nil,
|
|
222
|
-
feature_tags: nil,
|
|
223
|
-
file_line: nil,
|
|
224
|
-
scenario_name: nil,
|
|
225
|
-
scenario_tags: nil,
|
|
226
|
-
error: e.message
|
|
227
|
-
}
|
|
228
|
-
end
|
|
229
|
-
|
|
230
|
-
scenario_data
|
|
231
|
-
end
|
|
232
100
|
end
|
|
233
101
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,70 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gherkin_checker
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dikakoko
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
-
dependencies:
|
|
10
|
+
date: 2026-01-12 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: cucumber-gherkin
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '33.0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '33.0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: rake
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '13.0'
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '13.0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: rspec
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '3.0'
|
|
47
|
+
type: :development
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '3.0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: rubocop
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '1.21'
|
|
61
|
+
type: :development
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '1.21'
|
|
12
68
|
description: Checking .feature files
|
|
13
69
|
email:
|
|
14
70
|
- dikakoko@icloud.com
|
|
@@ -20,6 +76,9 @@ files:
|
|
|
20
76
|
- README.md
|
|
21
77
|
- exe/gherkin_checker
|
|
22
78
|
- lib/gherkin_checker.rb
|
|
79
|
+
- lib/gherkin_checker/config.rb
|
|
80
|
+
- lib/gherkin_checker/parser.rb
|
|
81
|
+
- lib/gherkin_checker/validator.rb
|
|
23
82
|
- lib/gherkin_checker/version.rb
|
|
24
83
|
homepage: https://github.com/dikako/gherkin_checker
|
|
25
84
|
licenses:
|