cuke_linter 1.0.0 → 1.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 +4 -4
- data/CHANGELOG.md +7 -1
- data/README.md +8 -4
- data/cuke_linter.gemspec +23 -19
- data/exe/cuke_linter +3 -1
- data/lib/cuke_linter.rb +119 -182
- data/lib/cuke_linter/configuration.rb +45 -0
- data/lib/cuke_linter/default_linters.rb +32 -0
- data/lib/cuke_linter/formatters/pretty_formatter.rb +63 -35
- data/lib/cuke_linter/gherkin.rb +10 -0
- data/lib/cuke_linter/linter_registration.rb +32 -0
- data/lib/cuke_linter/linters/background_does_more_than_setup_linter.rb +1 -1
- data/lib/cuke_linter/linters/element_with_common_tags_linter.rb +23 -14
- data/lib/cuke_linter/linters/element_with_duplicate_tags_linter.rb +18 -13
- data/lib/cuke_linter/linters/element_with_too_many_tags_linter.rb +17 -11
- data/lib/cuke_linter/linters/feature_with_too_many_different_tags_linter.rb +1 -3
- data/lib/cuke_linter/linters/feature_without_description_linter.rb +1 -1
- data/lib/cuke_linter/linters/linter.rb +17 -13
- data/lib/cuke_linter/linters/step_with_too_many_characters_linter.rb +2 -2
- data/lib/cuke_linter/linters/test_should_use_background_linter.rb +23 -15
- data/lib/cuke_linter/linters/test_with_bad_name_linter.rb +4 -4
- data/lib/cuke_linter/linters/test_with_setup_step_as_final_step_linter.rb +1 -1
- data/lib/cuke_linter/version.rb +1 -1
- metadata +85 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cda526ecd0ab5cab7e5a1a588c5052cc9b15ca0779239289b043b5b0aa7160fa
|
4
|
+
data.tar.gz: 2a1b1eb4ad68db07f1b8deee8bee8614e1b5fb1048971ae6580e08d544c88424
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be54da9ed9d7571302954de93506194b13b605790bcd140c421f00f70af02070b01e6c9af4cf1d51ceaa3b699b967ad60327fb06c85c6bf6cd2b993a26400381
|
7
|
+
data.tar.gz: b004e3c98632a9d510b828a238de24460c76201dc659ef780e98606225749b9feeb1568546ed1e9eda218a63e17873594bef8c2301cfa2886b03ddf733e6e855
|
data/CHANGELOG.md
CHANGED
@@ -8,6 +8,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
8
8
|
|
9
9
|
Nothing yet...
|
10
10
|
|
11
|
+
## [1.0.1] - 2020-05-06
|
12
|
+
|
13
|
+
### Fixed
|
14
|
+
- Replaced some code that was not valid with earlier versions of Ruby 2.x, with which this gem is specified as being compatible.
|
15
|
+
|
11
16
|
|
12
17
|
## [1.0.0] - 2020-03-09
|
13
18
|
|
@@ -154,7 +159,8 @@ Nothing yet...
|
|
154
159
|
- Custom linters, formatters, and command line usability
|
155
160
|
|
156
161
|
|
157
|
-
[Unreleased]: https://github.com/enkessler/cuke_linter/compare/v1.0.
|
162
|
+
[Unreleased]: https://github.com/enkessler/cuke_linter/compare/v1.0.1...HEAD
|
163
|
+
[1.0.1]: https://github.com/enkessler/cuke_linter/compare/v1.0.0...v1.0.1
|
158
164
|
[1.0.0]: https://github.com/enkessler/cuke_linter/compare/v0.13.0...v1.0.0
|
159
165
|
[0.13.0]: https://github.com/enkessler/cuke_linter/compare/v0.12.1...v0.13.0
|
160
166
|
[0.12.1]: https://github.com/enkessler/cuke_linter/compare/v0.12.0...v0.12.1
|
data/README.md
CHANGED
@@ -104,7 +104,8 @@ class MyCustomLinter
|
|
104
104
|
return nil unless model.is_a?(CukeModeler::Scenario)
|
105
105
|
|
106
106
|
if model.name.empty?
|
107
|
-
{ problem: 'Scenario has no name',
|
107
|
+
{ problem: 'Scenario has no name',
|
108
|
+
location: "#{model.get_ancestor(:feature_file).path}:#{model.source_line}" }
|
108
109
|
else
|
109
110
|
nil
|
110
111
|
end
|
@@ -134,13 +135,16 @@ output_path = "#{__dir__}/my_report.txt"
|
|
134
135
|
model_tree_root = CukeModeler::Directory.new(Dir.pwd)
|
135
136
|
additional_file_path = 'path/to/some.feature'
|
136
137
|
|
137
|
-
# Providing the formatter twice so that
|
138
|
-
CukeLinter.lint(linters: [linter],
|
138
|
+
# Providing the formatter twice so that output also is printed to the console
|
139
|
+
CukeLinter.lint(linters: [linter],
|
140
|
+
formatters: [[formatter], [formatter, output_path]],
|
141
|
+
model_trees: [model_tree_root],
|
142
|
+
file_paths: [additional_file_path])
|
139
143
|
```
|
140
144
|
|
141
145
|
### Configuration
|
142
146
|
|
143
|
-
Rather than using the default linters or providing a custom set of of modified linters every time linting occurs, which linters to use and any linter specific modifications can be configured in a more static manner via a configuration file or setting the configuration directly in code. See [documentation](#documentation) for specifics.
|
147
|
+
Rather than using the default linters or providing a custom set of of modified linters every time linting occurs, which linters to use and any linter specific modifications (such as choosing a non-default dialect) can be configured in a more static manner via a configuration file or setting the configuration directly in code. See [documentation](#documentation) for specifics.
|
144
148
|
|
145
149
|
|
146
150
|
### <a id="documentation"></a>Everything Else
|
data/cuke_linter.gemspec
CHANGED
@@ -1,40 +1,44 @@
|
|
1
|
-
|
2
|
-
lib = File.expand_path("../lib", __FILE__)
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
3
|
+
require 'cuke_linter/version'
|
5
4
|
|
6
5
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
6
|
+
spec.name = 'cuke_linter'
|
8
7
|
spec.version = CukeLinter::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
8
|
+
spec.authors = ['Eric Kessler']
|
9
|
+
spec.email = ['morrow748@gmail.com']
|
11
10
|
|
12
|
-
spec.summary =
|
11
|
+
spec.summary = 'Lints feature files used by Cucumber and other similar frameworks.'
|
13
12
|
spec.homepage = 'https://github.com/enkessler/cuke_linter'
|
14
|
-
spec.license =
|
13
|
+
spec.license = 'MIT'
|
15
14
|
|
16
15
|
|
17
16
|
# Specify which files should be added to the gem when it is released.
|
18
17
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
19
|
-
spec.files
|
18
|
+
spec.files = Dir.chdir(File.expand_path('', __dir__)) do
|
20
19
|
source_controlled_files = `git ls-files -z`.split("\x0")
|
21
|
-
source_controlled_files.keep_if { |file| file =~ %r{^(lib|exe|testing/cucumber/features)} }
|
20
|
+
source_controlled_files.keep_if { |file| file =~ %r{^(lib|exe|testing/cucumber/features)} }
|
21
|
+
source_controlled_files + ['README.md', 'LICENSE.txt', 'CHANGELOG.md', 'cuke_linter.gemspec']
|
22
22
|
end
|
23
|
-
spec.bindir =
|
23
|
+
spec.bindir = 'exe'
|
24
24
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
25
|
-
spec.require_paths = [
|
25
|
+
spec.require_paths = ['lib']
|
26
26
|
|
27
27
|
spec.required_ruby_version = '~> 2.0'
|
28
28
|
|
29
29
|
spec.add_runtime_dependency 'cuke_modeler', '>= 1.5', '< 3.0'
|
30
30
|
|
31
|
-
spec.add_development_dependency
|
32
|
-
spec.add_development_dependency
|
33
|
-
spec.add_development_dependency "racatt", "~> 1.0"
|
34
|
-
spec.add_development_dependency "rake", "~> 12.0"
|
35
|
-
spec.add_development_dependency "require_all", "~> 2.0"
|
36
|
-
spec.add_development_dependency "rspec", "~> 3.0"
|
37
|
-
spec.add_development_dependency 'simplecov', '< 1.0.0'
|
31
|
+
spec.add_development_dependency 'bundler', '< 3.0'
|
32
|
+
spec.add_development_dependency 'childprocess', '~> 3.0'
|
38
33
|
spec.add_development_dependency 'coveralls', '< 1.0.0'
|
34
|
+
spec.add_development_dependency 'cucumber', '~> 3.0'
|
35
|
+
spec.add_development_dependency 'cuke_slicer', '>= 2.0.2', '< 3.0'
|
36
|
+
spec.add_development_dependency 'ffi', '~> 1.0'
|
37
|
+
spec.add_development_dependency 'parallel', '~> 1.0'
|
39
38
|
spec.add_development_dependency 'rainbow', '< 4.0.0'
|
39
|
+
spec.add_development_dependency 'rake', '~> 12.0'
|
40
|
+
spec.add_development_dependency 'require_all', '~> 2.0'
|
41
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
42
|
+
spec.add_development_dependency 'rubocop', '< 1.0.0'
|
43
|
+
spec.add_development_dependency 'simplecov', '< 1.0.0'
|
40
44
|
end
|
data/exe/cuke_linter
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require
|
3
|
+
require 'cuke_linter'
|
4
4
|
require 'optparse'
|
5
5
|
|
6
6
|
params = {}
|
@@ -9,6 +9,7 @@ params[:formatters] = []
|
|
9
9
|
params[:outs] = []
|
10
10
|
params[:requires] = []
|
11
11
|
|
12
|
+
# rubocop:disable Metrics/BlockLength
|
12
13
|
parser = OptionParser.new do |options|
|
13
14
|
|
14
15
|
options.set_summary_width(30)
|
@@ -68,6 +69,7 @@ parser = OptionParser.new do |options|
|
|
68
69
|
end
|
69
70
|
|
70
71
|
end
|
72
|
+
# rubocop:enable Metrics/BlockLength
|
71
73
|
|
72
74
|
begin
|
73
75
|
parser.parse!
|
data/lib/cuke_linter.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'cuke_modeler'
|
3
3
|
|
4
|
-
require
|
4
|
+
require 'cuke_linter/version'
|
5
5
|
require 'cuke_linter/formatters/pretty_formatter'
|
6
6
|
require 'cuke_linter/linters/linter'
|
7
7
|
require 'cuke_linter/linters/background_does_more_than_setup_linter'
|
@@ -29,233 +29,170 @@ require 'cuke_linter/linters/test_with_setup_step_after_action_step_linter'
|
|
29
29
|
require 'cuke_linter/linters/test_with_setup_step_after_verification_step_linter'
|
30
30
|
require 'cuke_linter/linters/test_with_setup_step_as_final_step_linter'
|
31
31
|
require 'cuke_linter/linters/test_with_too_many_steps_linter'
|
32
|
+
require 'cuke_linter/configuration'
|
33
|
+
require 'cuke_linter/default_linters'
|
34
|
+
require 'cuke_linter/gherkin'
|
35
|
+
require 'cuke_linter/linter_registration'
|
32
36
|
|
33
37
|
|
34
38
|
# The top level namespace used by this gem
|
35
|
-
|
36
39
|
module CukeLinter
|
37
40
|
|
38
|
-
|
39
|
-
|
40
|
-
# The default keyword that is considered a 'When' keyword
|
41
|
-
DEFAULT_WHEN_KEYWORD = 'When'.freeze
|
42
|
-
# The default keyword that is considered a 'Then' keyword
|
43
|
-
DEFAULT_THEN_KEYWORD = 'Then'.freeze
|
44
|
-
|
45
|
-
@original_linters = { 'BackgroundDoesMoreThanSetupLinter' => BackgroundDoesMoreThanSetupLinter.new,
|
46
|
-
'ElementWithCommonTagsLinter' => ElementWithCommonTagsLinter.new,
|
47
|
-
'ElementWithDuplicateTagsLinter' => ElementWithDuplicateTagsLinter.new,
|
48
|
-
'ElementWithTooManyTagsLinter' => ElementWithTooManyTagsLinter.new,
|
49
|
-
'ExampleWithoutNameLinter' => ExampleWithoutNameLinter.new,
|
50
|
-
'FeatureFileWithInvalidNameLinter' => FeatureFileWithInvalidNameLinter.new,
|
51
|
-
'FeatureFileWithMismatchedNameLinter' => FeatureFileWithMismatchedNameLinter.new,
|
52
|
-
'FeatureWithTooManyDifferentTagsLinter' => FeatureWithTooManyDifferentTagsLinter.new,
|
53
|
-
'FeatureWithoutDescriptionLinter' => FeatureWithoutDescriptionLinter.new,
|
54
|
-
'FeatureWithoutNameLinter' => FeatureWithoutNameLinter.new,
|
55
|
-
'FeatureWithoutScenariosLinter' => FeatureWithoutScenariosLinter.new,
|
56
|
-
'OutlineWithSingleExampleRowLinter' => OutlineWithSingleExampleRowLinter.new,
|
57
|
-
'SingleTestBackgroundLinter' => SingleTestBackgroundLinter.new,
|
58
|
-
'StepWithEndPeriodLinter' => StepWithEndPeriodLinter.new,
|
59
|
-
'StepWithTooManyCharactersLinter' => StepWithTooManyCharactersLinter.new,
|
60
|
-
'TestShouldUseBackgroundLinter' => TestShouldUseBackgroundLinter.new,
|
61
|
-
'TestWithActionStepAsFinalStepLinter' => TestWithActionStepAsFinalStepLinter.new,
|
62
|
-
'TestWithBadNameLinter' => TestWithBadNameLinter.new,
|
63
|
-
'TestWithNoActionStepLinter' => TestWithNoActionStepLinter.new,
|
64
|
-
'TestWithNoNameLinter' => TestWithNoNameLinter.new,
|
65
|
-
'TestWithNoVerificationStepLinter' => TestWithNoVerificationStepLinter.new,
|
66
|
-
'TestWithSetupStepAfterActionStepLinter' => TestWithSetupStepAfterActionStepLinter.new,
|
67
|
-
'TestWithSetupStepAfterVerificationStepLinter' => TestWithSetupStepAfterVerificationStepLinter.new,
|
68
|
-
'TestWithSetupStepAsFinalStepLinter' => TestWithSetupStepAsFinalStepLinter.new,
|
69
|
-
'TestWithTooManyStepsLinter' => TestWithTooManyStepsLinter.new }
|
70
|
-
|
71
|
-
|
72
|
-
# Configures linters based on the given options
|
73
|
-
def self.load_configuration(config_file_path: nil, config: nil)
|
74
|
-
# TODO: define what happens if both a configuration file and a configuration are provided. Merge them or have direct config take precedence? Both?
|
75
|
-
|
76
|
-
unless config || config_file_path
|
77
|
-
config_file_path = "#{Dir.pwd}/.cuke_linter"
|
78
|
-
raise 'No configuration or configuration file given and no .cuke_linter file found' unless File.exist?(config_file_path)
|
79
|
-
end
|
80
|
-
|
81
|
-
config = config || YAML.load_file(config_file_path)
|
41
|
+
extend CukeLinter::Configuration
|
42
|
+
extend CukeLinter::LinterRegistration
|
82
43
|
|
83
|
-
|
84
|
-
to_delete = []
|
44
|
+
class << self
|
85
45
|
|
86
|
-
|
87
|
-
|
88
|
-
|
46
|
+
# Lints the given model trees and file paths using the given linting objects and formatting
|
47
|
+
# the results with the given formatters and their respective output locations
|
48
|
+
def lint(file_paths: [], model_trees: [], linters: registered_linters.values, formatters: [[CukeLinter::PrettyFormatter.new]]) # rubocop:disable Metrics/LineLength
|
49
|
+
# TODO: Test this?
|
50
|
+
# Because directive memoization is based on a model's `#object_id` and Ruby reuses object IDs over the
|
51
|
+
# life of a program as objects are garbage collected, it is not safe to remember the IDs forever. However,
|
52
|
+
# models shouldn't get GC'd in the middle of the linting process and so the start of the linting process is
|
53
|
+
# a good time to reset things
|
54
|
+
@directives_for_feature_file = {}
|
89
55
|
|
90
|
-
|
56
|
+
model_trees = [CukeModeler::Directory.new(Dir.pwd)] if model_trees.empty? && file_paths.empty?
|
57
|
+
file_path_models = collect_file_path_models(file_paths)
|
58
|
+
model_sets = model_trees + file_path_models
|
91
59
|
|
92
|
-
|
93
|
-
|
60
|
+
linting_data = lint_models(model_sets, linters)
|
61
|
+
format_data(formatters, linting_data)
|
94
62
|
|
95
|
-
|
63
|
+
linting_data
|
96
64
|
end
|
97
65
|
|
98
|
-
to_delete.each { |linter_name| unregister_linter(linter_name) }
|
99
|
-
end
|
100
|
-
|
101
|
-
# Returns the registered linters to their default state
|
102
|
-
def self.reset_linters
|
103
|
-
@registered_linters = nil
|
104
|
-
end
|
105
|
-
|
106
|
-
# Registers for linting use the given linter object, tracked by the given name
|
107
|
-
def self.register_linter(linter:, name:)
|
108
|
-
self.registered_linters[name] = linter
|
109
|
-
end
|
110
|
-
|
111
|
-
# Unregisters the linter object tracked by the given name so that it is not used for linting
|
112
|
-
def self.unregister_linter(name)
|
113
|
-
self.registered_linters.delete(name)
|
114
|
-
end
|
115
66
|
|
116
|
-
|
117
|
-
def self.registered_linters
|
118
|
-
@registered_linters ||= Marshal.load(Marshal.dump(@original_linters))
|
119
|
-
end
|
67
|
+
private
|
120
68
|
|
121
|
-
# Unregisters all currently registered linting objects
|
122
|
-
def self.clear_registered_linters
|
123
|
-
self.registered_linters.clear
|
124
|
-
end
|
125
69
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
# Because directive memoization is based on a model's `#object_id` and Ruby reuses object IDs over the
|
131
|
-
# life of a program as objects are garbage collected, it is not safe to remember the IDs forever. However,
|
132
|
-
# models shouldn't get GC'd in the middle of the linting process and so the start of the linting process is
|
133
|
-
# a good time to reset things
|
134
|
-
@directives_for_feature_file = {}
|
135
|
-
|
136
|
-
model_trees = [CukeModeler::Directory.new(Dir.pwd)] if model_trees.empty? && file_paths.empty?
|
137
|
-
file_path_models = file_paths.collect do |file_path|
|
138
|
-
# TODO: raise exception unless path exists?
|
139
|
-
case
|
140
|
-
when File.directory?(file_path)
|
70
|
+
def collect_file_path_models(file_paths)
|
71
|
+
file_paths.collect do |file_path|
|
72
|
+
# TODO: raise exception unless path exists?
|
73
|
+
if File.directory?(file_path)
|
141
74
|
CukeModeler::Directory.new(file_path)
|
142
|
-
|
75
|
+
elsif File.file?(file_path) && File.extname(file_path) == '.feature'
|
143
76
|
CukeModeler::FeatureFile.new(file_path)
|
144
|
-
else
|
145
|
-
# Non-feature files are not modeled
|
146
|
-
end
|
147
|
-
end.compact # Compacting in order to get rid of any `nil` values left over from non-feature files
|
148
|
-
|
149
|
-
linting_data = []
|
150
|
-
model_sets = model_trees + file_path_models
|
151
|
-
|
152
|
-
model_sets.each do |model_tree|
|
153
|
-
model_tree.each_model do |model|
|
154
|
-
applicable_linters = relevant_linters_for_model(linters, model)
|
155
|
-
applicable_linters.each do |linter|
|
156
|
-
# TODO: have linters lint only certain types of models?
|
157
|
-
# linting_data.concat(linter.lint(model)) if relevant_model?(linter, model)
|
158
|
-
|
159
|
-
result = linter.lint(model)
|
160
|
-
|
161
|
-
if result
|
162
|
-
result[:linter] = linter.name
|
163
|
-
linting_data << result
|
164
|
-
end
|
165
77
|
end
|
166
|
-
end
|
78
|
+
end.compact # Compacting in order to get rid of any `nil` values left over from non-feature files
|
167
79
|
end
|
168
80
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
81
|
+
def lint_models(model_sets, linters)
|
82
|
+
[].tap do |linting_data|
|
83
|
+
model_sets.each do |model_tree|
|
84
|
+
model_tree.each_model do |model|
|
85
|
+
applicable_linters = relevant_linters_for_model(linters, model)
|
86
|
+
applicable_linters.each do |linter|
|
87
|
+
# TODO: have linters lint only certain types of models?
|
88
|
+
# linting_data.concat(linter.lint(model)) if relevant_model?(linter, model)
|
89
|
+
|
90
|
+
result = linter.lint(model)
|
91
|
+
|
92
|
+
if result
|
93
|
+
result[:linter] = linter.name
|
94
|
+
linting_data << result
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
179
99
|
end
|
180
100
|
end
|
181
101
|
|
182
|
-
|
183
|
-
|
102
|
+
def relevant_linters_for_model(base_linters, model)
|
103
|
+
feature_file_model = model.get_ancestor(:feature_file)
|
184
104
|
|
105
|
+
# Linter directives are not applicable for directory and feature file models. Every other
|
106
|
+
# model type should have a feature file ancestor from which to grab linter directive comments.
|
107
|
+
return base_linters if feature_file_model.nil?
|
185
108
|
|
186
|
-
|
187
|
-
feature_file_model = model.get_ancestor(:feature_file)
|
109
|
+
linter_modifications_for_model = {}
|
188
110
|
|
189
|
-
|
190
|
-
|
111
|
+
linter_directives_for_feature_file(feature_file_model).each do |directive|
|
112
|
+
# Assuming that the directives are in the same order that they appear in the file
|
113
|
+
break if directive[:source_line] > model.source_line
|
191
114
|
|
192
|
-
|
115
|
+
linter_modifications_for_model[directive[:linter_class]] = directive[:enabled_status]
|
116
|
+
end
|
193
117
|
|
194
|
-
|
195
|
-
|
196
|
-
break if directive[:source_line] > model.source_line
|
118
|
+
disabled_linter_classes = linter_modifications_for_model.reject { |_name, status| status }.keys
|
119
|
+
enabled_linter_classes = linter_modifications_for_model.select { |_name, status| status }.keys
|
197
120
|
|
198
|
-
|
121
|
+
determine_final_linters(base_linters, disabled_linter_classes, enabled_linter_classes)
|
199
122
|
end
|
200
123
|
|
201
|
-
|
202
|
-
|
124
|
+
def determine_final_linters(base_linters, disabled_linter_classes, enabled_linter_classes)
|
125
|
+
final_linters = base_linters.reject { |linter| disabled_linter_classes.include?(linter.class) }
|
203
126
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
end
|
208
|
-
|
209
|
-
final_linters
|
210
|
-
end
|
127
|
+
enabled_linter_classes.each do |clazz|
|
128
|
+
final_linters << dynamic_linters[clazz] unless final_linters.map(&:class).include?(clazz)
|
129
|
+
end
|
211
130
|
|
212
|
-
|
131
|
+
final_linters
|
132
|
+
end
|
213
133
|
|
134
|
+
def linter_directives_for_feature_file(feature_file_model)
|
135
|
+
# IMPORTANT ASSUMPTION: Models never change during the life of a linting, so data only has to be gathered once
|
136
|
+
existing_directives = @directives_for_feature_file[feature_file_model.object_id]
|
214
137
|
|
215
|
-
|
216
|
-
# IMPORTANT ASSUMPTION: Models never change during the life of a linting, so data only has to be gathered once
|
217
|
-
return @directives_for_feature_file[feature_file_model.object_id] if @directives_for_feature_file[feature_file_model.object_id]
|
138
|
+
return existing_directives if existing_directives
|
218
139
|
|
140
|
+
directives = gather_directives_in_feature(feature_file_model)
|
219
141
|
|
220
|
-
|
142
|
+
# Make sure that the directives are in the same order as they appear in the source file
|
143
|
+
directives = directives.sort_by { |a| a[:source_line] }
|
221
144
|
|
222
|
-
|
223
|
-
|
224
|
-
next unless pieces # Skipping non-directive file comments
|
145
|
+
@directives_for_feature_file[feature_file_model.object_id] = directives
|
146
|
+
end
|
225
147
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
148
|
+
def gather_directives_in_feature(feature_file_model)
|
149
|
+
[].tap do |directives|
|
150
|
+
feature_file_model.comments.each do |comment|
|
151
|
+
pieces = comment.text.match(/#\s*cuke_linter:(disable|enable)\s+(.*)/)
|
152
|
+
next unless pieces # Skipping non-directive file comments
|
153
|
+
|
154
|
+
linter_classes = pieces[2].tr(',', ' ').split(' ')
|
155
|
+
linter_classes.each do |clazz|
|
156
|
+
directives << { linter_class: Kernel.const_get(clazz),
|
157
|
+
enabled_status: pieces[1] != 'disable',
|
158
|
+
source_line: comment.source_line }
|
159
|
+
end
|
160
|
+
end
|
231
161
|
end
|
232
162
|
end
|
233
163
|
|
234
|
-
|
235
|
-
|
164
|
+
def dynamic_linters
|
165
|
+
# No need to keep making new ones over and over...
|
166
|
+
@dynamic_linters ||= Hash.new { |hash, key| hash[key] = key.new }
|
167
|
+
# return @dynamic_linters if @dynamic_linters
|
168
|
+
#
|
169
|
+
# @dynamic_linters = {}
|
170
|
+
end
|
236
171
|
|
172
|
+
def format_data(formatters, linting_data)
|
173
|
+
formatters.each do |formatter_output_pair|
|
174
|
+
formatter = formatter_output_pair[0]
|
175
|
+
location = formatter_output_pair[1]
|
237
176
|
|
238
|
-
|
239
|
-
end
|
177
|
+
formatted_data = formatter.format(linting_data)
|
240
178
|
|
241
|
-
|
179
|
+
if location
|
180
|
+
File.write(location, formatted_data)
|
181
|
+
else
|
182
|
+
puts formatted_data
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
242
186
|
|
243
|
-
|
244
|
-
#
|
245
|
-
|
246
|
-
#
|
187
|
+
# Not linting unused code
|
188
|
+
# rubocop:disable Metrics/LineLength
|
189
|
+
# def self.relevant_model?(linter, model)
|
190
|
+
# model_classes = linter.class.target_model_types.map { |type| CukeModeler.const_get(type.to_s.capitalize.chop) }
|
191
|
+
# model_classes.any? { |clazz| model.is_a?(clazz) }
|
192
|
+
# end
|
247
193
|
#
|
248
|
-
#
|
249
|
-
|
250
|
-
|
251
|
-
private_class_method(:dynamic_linters)
|
252
|
-
|
253
|
-
|
254
|
-
# # def self.relevant_model?(linter, model)
|
255
|
-
# # model_classes = linter.class.target_model_types.map { |type| CukeModeler.const_get(type.to_s.capitalize.chop) }
|
256
|
-
# # model_classes.any? { |clazz| model.is_a?(clazz) }
|
257
|
-
# # end
|
258
|
-
# #
|
259
|
-
# # private_class_method(:relevant_model?)
|
194
|
+
# private_class_method(:relevant_model?)
|
195
|
+
# rubocop:enable Metrics/LineLength
|
260
196
|
|
197
|
+
end
|
261
198
|
end
|