cuke_linter 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|