rubocop 1.6.1 → 1.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +4 -3
- data/config/default.yml +145 -19
- data/lib/rubocop.rb +16 -1
- data/lib/rubocop/cli/command/auto_genenerate_config.rb +5 -4
- data/lib/rubocop/comment_config.rb +6 -6
- data/lib/rubocop/config.rb +13 -7
- data/lib/rubocop/config_loader.rb +11 -14
- data/lib/rubocop/config_loader_resolver.rb +21 -4
- data/lib/rubocop/config_obsoletion.rb +5 -3
- data/lib/rubocop/config_store.rb +12 -1
- data/lib/rubocop/cop/base.rb +2 -1
- data/lib/rubocop/cop/exclude_limit.rb +26 -0
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +3 -2
- data/lib/rubocop/cop/generator.rb +1 -3
- data/lib/rubocop/cop/internal_affairs.rb +6 -1
- data/lib/rubocop/cop/internal_affairs/empty_line_between_expect_offense_and_correction.rb +68 -0
- data/lib/rubocop/cop/internal_affairs/example_description.rb +89 -0
- data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +61 -0
- data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +64 -0
- data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +145 -0
- data/lib/rubocop/cop/layout/class_structure.rb +7 -2
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +56 -20
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +16 -2
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +14 -0
- data/lib/rubocop/cop/layout/line_length.rb +2 -1
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -2
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -10
- data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +1 -0
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +2 -0
- data/lib/rubocop/cop/layout/space_before_brackets.rb +67 -0
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +13 -10
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -2
- data/lib/rubocop/cop/lint/ambiguous_assignment.rb +59 -0
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +7 -2
- data/lib/rubocop/cop/lint/deprecated_constants.rb +80 -0
- data/lib/rubocop/cop/lint/duplicate_branch.rb +64 -2
- data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +44 -0
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +10 -6
- data/lib/rubocop/cop/lint/number_conversion.rb +41 -6
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +47 -0
- data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +39 -0
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +2 -1
- data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +50 -0
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +50 -17
- data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -11
- data/lib/rubocop/cop/lint/symbol_conversion.rb +103 -0
- data/lib/rubocop/cop/lint/triple_quotes.rb +71 -0
- data/lib/rubocop/cop/lint/unreachable_loop.rb +17 -0
- data/lib/rubocop/cop/message_annotator.rb +4 -1
- data/lib/rubocop/cop/metrics/block_nesting.rb +2 -2
- data/lib/rubocop/cop/metrics/parameter_lists.rb +5 -2
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
- data/lib/rubocop/cop/mixin/allowed_identifiers.rb +18 -0
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +5 -0
- data/lib/rubocop/cop/mixin/code_length.rb +3 -1
- data/lib/rubocop/cop/mixin/comments_help.rb +1 -11
- data/lib/rubocop/cop/mixin/configurable_max.rb +1 -0
- data/lib/rubocop/cop/mixin/first_element_line_break.rb +1 -1
- data/lib/rubocop/cop/mixin/method_complexity.rb +3 -1
- data/lib/rubocop/cop/mixin/uncommunicative_name.rb +5 -1
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +59 -5
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +38 -5
- data/lib/rubocop/cop/naming/variable_name.rb +2 -0
- data/lib/rubocop/cop/naming/variable_number.rb +2 -9
- data/lib/rubocop/cop/registry.rb +10 -0
- data/lib/rubocop/cop/severity.rb +3 -3
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +3 -1
- data/lib/rubocop/cop/style/ascii_comments.rb +1 -1
- data/lib/rubocop/cop/style/collection_methods.rb +14 -1
- data/lib/rubocop/cop/style/commented_keyword.rb +22 -5
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +49 -9
- data/lib/rubocop/cop/style/empty_literal.rb +6 -2
- data/lib/rubocop/cop/style/endless_method.rb +102 -0
- data/lib/rubocop/cop/style/eval_with_location.rb +63 -34
- data/lib/rubocop/cop/style/explicit_block_argument.rb +10 -0
- data/lib/rubocop/cop/style/float_division.rb +3 -0
- data/lib/rubocop/cop/style/for.rb +2 -0
- data/lib/rubocop/cop/style/format_string_token.rb +18 -2
- data/lib/rubocop/cop/style/hash_except.rb +95 -0
- data/lib/rubocop/cop/style/hash_like_case.rb +2 -1
- data/lib/rubocop/cop/style/if_inside_else.rb +22 -10
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +120 -0
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +12 -2
- data/lib/rubocop/cop/style/lambda_call.rb +2 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +16 -6
- data/lib/rubocop/cop/style/method_def_parentheses.rb +7 -0
- data/lib/rubocop/cop/style/multiline_method_signature.rb +26 -1
- data/lib/rubocop/cop/style/multiline_when_then.rb +3 -1
- data/lib/rubocop/cop/style/mutable_constant.rb +13 -3
- data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +4 -0
- data/lib/rubocop/cop/style/nil_comparison.rb +3 -0
- data/lib/rubocop/cop/style/non_nil_check.rb +23 -13
- data/lib/rubocop/cop/style/numeric_literals.rb +6 -9
- data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
- data/lib/rubocop/cop/style/raise_args.rb +5 -2
- data/lib/rubocop/cop/style/redundant_argument.rb +7 -1
- data/lib/rubocop/cop/style/redundant_freeze.rb +8 -4
- data/lib/rubocop/cop/style/redundant_return.rb +1 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +36 -2
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +29 -5
- data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
- data/lib/rubocop/cop/style/symbol_proc.rb +5 -4
- data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/while_until_modifier.rb +2 -4
- data/lib/rubocop/cop/util.rb +3 -1
- data/lib/rubocop/formatter/git_hub_actions_formatter.rb +1 -0
- data/lib/rubocop/formatter/simple_text_formatter.rb +2 -1
- data/lib/rubocop/magic_comment.rb +30 -1
- data/lib/rubocop/options.rb +10 -10
- data/lib/rubocop/rspec/cop_helper.rb +0 -4
- data/lib/rubocop/rspec/expect_offense.rb +37 -22
- data/lib/rubocop/runner.rb +17 -1
- data/lib/rubocop/target_finder.rb +4 -2
- data/lib/rubocop/target_ruby.rb +47 -11
- data/lib/rubocop/util.rb +16 -0
- data/lib/rubocop/version.rb +8 -2
- metadata +27 -7
@@ -9,6 +9,7 @@ module RuboCop
|
|
9
9
|
self.command_name = :auto_gen_config
|
10
10
|
|
11
11
|
AUTO_GENERATED_FILE = '.rubocop_todo.yml'
|
12
|
+
YAML_OPTIONAL_DOC_START = /\A---(\s+#|\s*\z)/.freeze
|
12
13
|
|
13
14
|
PHASE_1 = 'Phase 1 of 2: run Layout/LineLength cop'
|
14
15
|
PHASE_2 = 'Phase 2 of 2: run all cops'
|
@@ -130,10 +131,10 @@ module RuboCop
|
|
130
131
|
end
|
131
132
|
|
132
133
|
def write_config_file(file_name, file_string, rubocop_yml_contents)
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
134
|
+
lines = /\S/.match?(rubocop_yml_contents) ? rubocop_yml_contents.split("\n", -1) : []
|
135
|
+
doc_start_index = lines.index { |line| YAML_OPTIONAL_DOC_START.match?(line) } || -1
|
136
|
+
lines.insert(doc_start_index + 1, "inherit_from:#{file_string}\n")
|
137
|
+
File.open(file_name, 'w') { |f| f.write lines.join("\n") }
|
137
138
|
end
|
138
139
|
end
|
139
140
|
end
|
@@ -47,6 +47,12 @@ module RuboCop
|
|
47
47
|
)
|
48
48
|
end
|
49
49
|
|
50
|
+
def comment_only_line?(line_number)
|
51
|
+
non_comment_token_line_numbers.none? do |non_comment_line_number|
|
52
|
+
non_comment_line_number == line_number
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
50
56
|
private
|
51
57
|
|
52
58
|
def extra_enabled_comments_with_names(extras:, names:)
|
@@ -166,12 +172,6 @@ module RuboCop
|
|
166
172
|
@all_cop_names ||= Cop::Registry.global.names - [REDUNDANT_DISABLE]
|
167
173
|
end
|
168
174
|
|
169
|
-
def comment_only_line?(line_number)
|
170
|
-
non_comment_token_line_numbers.none? do |non_comment_line_number|
|
171
|
-
non_comment_line_number == line_number
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
175
|
def non_comment_token_line_numbers
|
176
176
|
@non_comment_token_line_numbers ||= begin
|
177
177
|
non_comment_tokens = processed_source.tokens.reject(&:comment?)
|
data/lib/rubocop/config.rb
CHANGED
@@ -33,8 +33,11 @@ module RuboCop
|
|
33
33
|
@validator = ConfigValidator.new(self)
|
34
34
|
end
|
35
35
|
|
36
|
-
def self.create(hash, path)
|
37
|
-
new(hash, path)
|
36
|
+
def self.create(hash, path, check: true)
|
37
|
+
config = new(hash, path)
|
38
|
+
config.check if check
|
39
|
+
|
40
|
+
config
|
38
41
|
end
|
39
42
|
|
40
43
|
def loaded_features
|
@@ -50,8 +53,8 @@ module RuboCop
|
|
50
53
|
self
|
51
54
|
end
|
52
55
|
|
53
|
-
def_delegators :@hash, :[], :[]=, :delete, :each, :key?, :keys, :each_key,
|
54
|
-
:fetch, :map, :merge, :to_h, :to_hash, :transform_values
|
56
|
+
def_delegators :@hash, :[], :[]=, :delete, :dig, :each, :key?, :keys, :each_key,
|
57
|
+
:fetch, :map, :merge, :replace, :to_h, :to_hash, :transform_values
|
55
58
|
def_delegators :@validator, :validate, :target_ruby_version
|
56
59
|
|
57
60
|
def to_s
|
@@ -281,6 +284,9 @@ module RuboCop
|
|
281
284
|
end
|
282
285
|
|
283
286
|
def enable_cop?(qualified_cop_name, cop_options)
|
287
|
+
# If the cop is explicitly enabled, the other checks can be skipped.
|
288
|
+
return true if cop_options['Enabled'] == true
|
289
|
+
|
284
290
|
department = department_of(qualified_cop_name)
|
285
291
|
cop_enabled = cop_options.fetch('Enabled') do
|
286
292
|
!for_all_cops['DisabledByDefault']
|
@@ -292,10 +298,10 @@ module RuboCop
|
|
292
298
|
end
|
293
299
|
|
294
300
|
def department_of(qualified_cop_name)
|
295
|
-
cop_department,
|
296
|
-
return nil if
|
301
|
+
*cop_department, _ = qualified_cop_name.split('/')
|
302
|
+
return nil if cop_department.empty?
|
297
303
|
|
298
|
-
self[cop_department]
|
304
|
+
self[cop_department.join('/')]
|
299
305
|
end
|
300
306
|
end
|
301
307
|
end
|
@@ -25,16 +25,18 @@ module RuboCop
|
|
25
25
|
attr_accessor :debug, :ignore_parent_exclusion,
|
26
26
|
:disable_pending_cops, :enable_pending_cops
|
27
27
|
attr_writer :default_configuration, :project_root
|
28
|
+
attr_reader :loaded_features
|
28
29
|
|
29
30
|
alias debug? debug
|
30
31
|
alias ignore_parent_exclusion? ignore_parent_exclusion
|
31
32
|
|
32
33
|
def clear_options
|
33
34
|
@debug = nil
|
35
|
+
@loaded_features = Set.new
|
34
36
|
FileFinder.root_level = nil
|
35
37
|
end
|
36
38
|
|
37
|
-
def load_file(file)
|
39
|
+
def load_file(file, check: true)
|
38
40
|
path = file_path(file)
|
39
41
|
|
40
42
|
hash = load_yaml_configuration(path)
|
@@ -51,7 +53,7 @@ module RuboCop
|
|
51
53
|
|
52
54
|
hash.delete('inherit_from')
|
53
55
|
|
54
|
-
Config.create(hash, path)
|
56
|
+
Config.create(hash, path, check: check)
|
55
57
|
end
|
56
58
|
|
57
59
|
def load_yaml_configuration(absolute_path)
|
@@ -98,10 +100,10 @@ module RuboCop
|
|
98
100
|
find_user_xdg_config || DEFAULT_FILE
|
99
101
|
end
|
100
102
|
|
101
|
-
def configuration_from_file(config_file)
|
103
|
+
def configuration_from_file(config_file, check: true)
|
102
104
|
return default_configuration if config_file == DEFAULT_FILE
|
103
105
|
|
104
|
-
config = load_file(config_file)
|
106
|
+
config = load_file(config_file, check: check)
|
105
107
|
if ignore_parent_exclusion?
|
106
108
|
print 'Ignoring AllCops/Exclude from parent folders' if debug?
|
107
109
|
else
|
@@ -173,8 +175,11 @@ module RuboCop
|
|
173
175
|
resolver.merge_with_default(config, config_file, unset_nil: unset_nil)
|
174
176
|
end
|
175
177
|
|
176
|
-
|
177
|
-
|
178
|
+
# @api private
|
179
|
+
# Used to add features that were required inside a config or from
|
180
|
+
# the CLI using `--require`.
|
181
|
+
def add_loaded_features(loaded_features)
|
182
|
+
@loaded_features.merge(Array(loaded_features))
|
178
183
|
end
|
179
184
|
|
180
185
|
private
|
@@ -183,14 +188,6 @@ module RuboCop
|
|
183
188
|
File.absolute_path(file.is_a?(RemoteConfig) ? file.file : file)
|
184
189
|
end
|
185
190
|
|
186
|
-
def add_loaded_features(loaded_features)
|
187
|
-
if instance_variable_defined?(:@loaded_features)
|
188
|
-
instance_variable_get(:@loaded_features) << loaded_features
|
189
|
-
else
|
190
|
-
instance_variable_set(:@loaded_features, [loaded_features])
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
191
|
def find_project_dotfile(target_dir)
|
195
192
|
find_file_upwards(DOTFILE, target_dir, project_root)
|
196
193
|
end
|
@@ -20,12 +20,13 @@ module RuboCop
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
# rubocop:disable Metrics/MethodLength
|
24
|
-
def resolve_inheritance(path, hash, file, debug)
|
23
|
+
def resolve_inheritance(path, hash, file, debug) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
25
24
|
inherited_files = Array(hash['inherit_from'])
|
26
25
|
base_configs(path, inherited_files, file)
|
27
26
|
.reverse.each_with_index do |base_config, index|
|
28
27
|
override_department_setting_for_cops(base_config, hash)
|
28
|
+
override_enabled_for_disabled_departments(base_config, hash)
|
29
|
+
|
29
30
|
base_config.each do |k, v|
|
30
31
|
next unless v.is_a?(Hash)
|
31
32
|
|
@@ -39,7 +40,6 @@ module RuboCop
|
|
39
40
|
end
|
40
41
|
end
|
41
42
|
end
|
42
|
-
# rubocop:enable Metrics/MethodLength
|
43
43
|
|
44
44
|
def resolve_inheritance_from_gems(hash)
|
45
45
|
gems = hash.delete('inherit_gem')
|
@@ -75,6 +75,7 @@ module RuboCop
|
|
75
75
|
end
|
76
76
|
|
77
77
|
config = handle_disabled_by_default(config, default_configuration) if disabled_by_default
|
78
|
+
override_enabled_for_disabled_departments(default_configuration, config)
|
78
79
|
|
79
80
|
opts = { inherit_mode: config['inherit_mode'] || {},
|
80
81
|
unset_nil: unset_nil }
|
@@ -122,10 +123,26 @@ module RuboCop
|
|
122
123
|
end
|
123
124
|
end
|
124
125
|
|
126
|
+
# If a cop was previously explicitly enabled, but then superseded by the
|
127
|
+
# department being disabled, disable it.
|
128
|
+
def override_enabled_for_disabled_departments(base_hash, derived_hash)
|
129
|
+
cops_to_disable = derived_hash.each_key.with_object([]) do |key, cops|
|
130
|
+
next unless disabled?(derived_hash, key)
|
131
|
+
|
132
|
+
cops.concat(base_hash.keys.grep(Regexp.new("^#{key}/")))
|
133
|
+
end
|
134
|
+
|
135
|
+
cops_to_disable.each do |cop_name|
|
136
|
+
next unless base_hash.dig(cop_name, 'Enabled') == true
|
137
|
+
|
138
|
+
derived_hash.replace(merge({ cop_name => { 'Enabled' => false } }, derived_hash))
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
125
142
|
private
|
126
143
|
|
127
144
|
def disabled?(hash, department)
|
128
|
-
hash[department] && hash[department]['Enabled'] == false
|
145
|
+
hash[department].is_a?(Hash) && hash[department]['Enabled'] == false
|
129
146
|
end
|
130
147
|
|
131
148
|
def duplicate_setting?(base_hash, derived_hash, key, inherited_file)
|
@@ -63,9 +63,11 @@ module RuboCop
|
|
63
63
|
# Cop rules are keyed by the name of the original cop
|
64
64
|
def load_cop_rules(rules)
|
65
65
|
rules.flat_map do |rule_type, data|
|
66
|
-
data.map do |configuration|
|
67
|
-
|
68
|
-
|
66
|
+
data.map do |cop_name, configuration|
|
67
|
+
next unless configuration # allow configurations to be disabled with `CopName: ~`
|
68
|
+
|
69
|
+
COP_RULE_CLASSES[rule_type].new(@config, cop_name, configuration)
|
70
|
+
end.compact
|
69
71
|
end
|
70
72
|
end
|
71
73
|
|
data/lib/rubocop/config_store.rb
CHANGED
@@ -4,6 +4,9 @@ module RuboCop
|
|
4
4
|
# Handles caching of configurations and association of inspected
|
5
5
|
# ruby files to configurations.
|
6
6
|
class ConfigStore
|
7
|
+
attr_reader :validated
|
8
|
+
alias validated? validated
|
9
|
+
|
7
10
|
def initialize
|
8
11
|
# @options_config stores a config that is specified in the command line.
|
9
12
|
# This takes precedence over configs located in any directories
|
@@ -17,6 +20,9 @@ module RuboCop
|
|
17
20
|
# @object_cache maps configuration file paths to
|
18
21
|
# configuration objects so we only need to load them once.
|
19
22
|
@object_cache = {}
|
23
|
+
|
24
|
+
# By default the config is validated before it can be used.
|
25
|
+
@validated = true
|
20
26
|
end
|
21
27
|
|
22
28
|
def options_config=(options_config)
|
@@ -29,6 +35,11 @@ module RuboCop
|
|
29
35
|
@options_config = ConfigLoader.default_configuration
|
30
36
|
end
|
31
37
|
|
38
|
+
def unvalidated
|
39
|
+
@validated = false
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
32
43
|
def for_file(file)
|
33
44
|
for_dir(File.dirname(file))
|
34
45
|
end
|
@@ -55,7 +66,7 @@ module RuboCop
|
|
55
66
|
path = @path_cache[dir]
|
56
67
|
@object_cache[path] ||= begin
|
57
68
|
print "For #{dir}: " if ConfigLoader.debug?
|
58
|
-
ConfigLoader.configuration_from_file(path)
|
69
|
+
ConfigLoader.configuration_from_file(path, check: validated?)
|
59
70
|
end
|
60
71
|
end
|
61
72
|
end
|
data/lib/rubocop/cop/base.rb
CHANGED
@@ -34,6 +34,7 @@ module RuboCop
|
|
34
34
|
class Base # rubocop:disable Metrics/ClassLength
|
35
35
|
extend RuboCop::AST::Sexp
|
36
36
|
extend NodePattern::Macros
|
37
|
+
extend ExcludeLimit
|
37
38
|
include RuboCop::AST::Sexp
|
38
39
|
include Util
|
39
40
|
include IgnoredNode
|
@@ -351,7 +352,7 @@ module RuboCop
|
|
351
352
|
def use_corrector(range, corrector)
|
352
353
|
if autocorrect?
|
353
354
|
attempt_correction(range, corrector)
|
354
|
-
elsif corrector
|
355
|
+
elsif corrector && cop_config.fetch('AutoCorrect', true)
|
355
356
|
:uncorrected
|
356
357
|
else
|
357
358
|
:unsupported
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
# Allows specified configuration options to have an exclude limit
|
5
|
+
# ie. a maximum value tracked that it can be used by `--auto-gen-config`.
|
6
|
+
module ExcludeLimit
|
7
|
+
# Sets up a configuration option to have an exclude limit tracked.
|
8
|
+
# The parameter name given is transformed into a method name (eg. `Max`
|
9
|
+
# becomes `self.max=` and `MinDigits` becomes `self.min_digits=`).
|
10
|
+
def exclude_limit(parameter_name, method_name: transform(parameter_name))
|
11
|
+
define_method("#{method_name}=") do |value|
|
12
|
+
cfg = config_to_allow_offenses
|
13
|
+
cfg[:exclude_limit] ||= {}
|
14
|
+
current_max = cfg[:exclude_limit][parameter_name]
|
15
|
+
value = [current_max, value].max if current_max
|
16
|
+
cfg[:exclude_limit][parameter_name] = value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def transform(parameter_name)
|
23
|
+
parameter_name.gsub(/(?<!\A)(?=[A-Z])/, '_').downcase
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -36,12 +36,13 @@ module RuboCop
|
|
36
36
|
# spec.required_ruby_version = '>= 2.5'
|
37
37
|
# end
|
38
38
|
#
|
39
|
-
# #
|
39
|
+
# # accepted but not recommended
|
40
40
|
# Gem::Specification.new do |spec|
|
41
41
|
# spec.required_ruby_version = ['>= 2.5.0', '< 2.7.0']
|
42
42
|
# end
|
43
43
|
#
|
44
|
-
# #
|
44
|
+
# # accepted but not recommended, since
|
45
|
+
# # Ruby does not really follow semantic versionning
|
45
46
|
# Gem::Specification.new do |spec|
|
46
47
|
# spec.required_ruby_version = '~> 2.5'
|
47
48
|
# end
|
@@ -81,9 +81,7 @@ module RuboCop
|
|
81
81
|
SPEC_TEMPLATE = <<~SPEC
|
82
82
|
# frozen_string_literal: true
|
83
83
|
|
84
|
-
RSpec.describe RuboCop::Cop::%<department>s::%<cop_name>s do
|
85
|
-
subject(:cop) { described_class.new(config) }
|
86
|
-
|
84
|
+
RSpec.describe RuboCop::Cop::%<department>s::%<cop_name>s, :config do
|
87
85
|
let(:config) { RuboCop::Config.new }
|
88
86
|
|
89
87
|
# TODO: Write test code
|
@@ -1,9 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'internal_affairs/empty_line_between_expect_offense_and_correction'
|
4
|
+
require_relative 'internal_affairs/example_description'
|
3
5
|
require_relative 'internal_affairs/method_name_equal'
|
4
6
|
require_relative 'internal_affairs/node_destructuring'
|
5
7
|
require_relative 'internal_affairs/node_type_predicate'
|
6
8
|
require_relative 'internal_affairs/offense_location_keyword'
|
7
|
-
require_relative 'internal_affairs/
|
9
|
+
require_relative 'internal_affairs/redundant_described_class_as_subject'
|
10
|
+
require_relative 'internal_affairs/redundant_let_rubocop_config_new'
|
8
11
|
require_relative 'internal_affairs/redundant_location_argument'
|
12
|
+
require_relative 'internal_affairs/redundant_message_argument'
|
13
|
+
require_relative 'internal_affairs/style_detected_api_use'
|
9
14
|
require_relative 'internal_affairs/useless_message_assertion'
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module InternalAffairs
|
6
|
+
# This cop checks whether `expect_offense` and correction expectation methods
|
7
|
+
# (i.e. `expect_correction` and `expect_no_corrections`) are separated by empty line.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# it 'registers and corrects an offense' do
|
12
|
+
# expect_offense(<<~RUBY)
|
13
|
+
# bad_method
|
14
|
+
# ^^^^^^^^^^ Use `good_method`.
|
15
|
+
# RUBY
|
16
|
+
# expect_correction(<<~RUBY)
|
17
|
+
# good_method
|
18
|
+
# RUBY
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# # good
|
22
|
+
# it 'registers and corrects an offense' do
|
23
|
+
# expect_offense(<<~RUBY)
|
24
|
+
# bad_method
|
25
|
+
# ^^^^^^^^^^ Use `good_method`.
|
26
|
+
# RUBY
|
27
|
+
#
|
28
|
+
# expect_correction(<<~RUBY)
|
29
|
+
# good_method
|
30
|
+
# RUBY
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
class EmptyLineBetweenExpectOffenseAndCorrection < Base
|
34
|
+
extend AutoCorrector
|
35
|
+
|
36
|
+
MSG = 'Add empty line between `expect_offense` and `%<expect_correction>s`.'
|
37
|
+
RESTRICT_ON_SEND = %i[expect_offense].freeze
|
38
|
+
CORRECTION_EXPECTATION_METHODS = %i[expect_correction expect_no_corrections].freeze
|
39
|
+
|
40
|
+
def on_send(node)
|
41
|
+
return unless (next_sibling = node.right_sibling) && next_sibling.send_type?
|
42
|
+
|
43
|
+
method_name = next_sibling.method_name
|
44
|
+
return unless CORRECTION_EXPECTATION_METHODS.include?(method_name)
|
45
|
+
|
46
|
+
range = offense_range(node)
|
47
|
+
return unless range.last_line + 1 == next_sibling.loc.line
|
48
|
+
|
49
|
+
add_offense(range, message: format(MSG, expect_correction: method_name)) do |corrector|
|
50
|
+
corrector.insert_after(range, "\n")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def offense_range(node)
|
57
|
+
first_argument = node.first_argument
|
58
|
+
|
59
|
+
if first_argument.respond_to?(:heredoc?) && first_argument.heredoc?
|
60
|
+
first_argument.loc.heredoc_end
|
61
|
+
else
|
62
|
+
node
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module InternalAffairs
|
6
|
+
# Checks that RSpec examples that use `expects_offense`
|
7
|
+
# or `expects_no_offenses` do not have conflicting
|
8
|
+
# descriptions.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# # bad
|
12
|
+
# it 'does not register an offense' do
|
13
|
+
# expect_offense('...')
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# it 'registers an offense' do
|
17
|
+
# expect_no_offenses('...')
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# it 'registers an offense' do
|
22
|
+
# expect_offense('...')
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# it 'does not register an offense' do
|
26
|
+
# expect_no_offenses('...')
|
27
|
+
# end
|
28
|
+
class ExampleDescription < Base
|
29
|
+
class << self
|
30
|
+
attr_accessor :descriptions
|
31
|
+
end
|
32
|
+
|
33
|
+
MSG = 'Description does not match use of `%<method_name>s`.'
|
34
|
+
|
35
|
+
RESTRICT_ON_SEND = %i[
|
36
|
+
expect_offense
|
37
|
+
expect_no_offenses
|
38
|
+
expect_correction
|
39
|
+
expect_no_corrections
|
40
|
+
].to_set.freeze
|
41
|
+
|
42
|
+
EXPECT_NO_OFFENSES_INCORRECT_DESCRIPTIONS = [
|
43
|
+
/^(adds|registers|reports|finds) (an? )?offense/,
|
44
|
+
/^flags\b/
|
45
|
+
].freeze
|
46
|
+
|
47
|
+
EXPECT_OFFENSE_INCORRECT_DESCRIPTIONS = [
|
48
|
+
/^(does not|doesn't) (register|find|flag|report)/,
|
49
|
+
/^(does not|doesn't) add (a|an|any )?offense/
|
50
|
+
].freeze
|
51
|
+
|
52
|
+
EXPECT_NO_CORRECTIONS_INCORRECT_DESCRIPTIONS = [
|
53
|
+
/^(auto[- ]?)?correct/
|
54
|
+
].freeze
|
55
|
+
|
56
|
+
EXPECT_CORRECTION_INCORRECT_DESCRIPTIONS = [
|
57
|
+
/\b(does not|doesn't) (auto[- ]?)?correct/
|
58
|
+
].freeze
|
59
|
+
|
60
|
+
def_node_matcher :offense_example?, <<~PATTERN
|
61
|
+
(block
|
62
|
+
(send _ {:it :specify} $_description)
|
63
|
+
_args
|
64
|
+
`(send nil? %RESTRICT_ON_SEND ...)
|
65
|
+
)
|
66
|
+
PATTERN
|
67
|
+
|
68
|
+
def on_send(node)
|
69
|
+
parent = node.each_ancestor(:block).first
|
70
|
+
return unless parent && (description = offense_example?(parent))
|
71
|
+
|
72
|
+
method_name = node.method_name
|
73
|
+
message = format(MSG, method_name: method_name)
|
74
|
+
|
75
|
+
regexp_group = self.class.const_get("#{method_name}_incorrect_descriptions".upcase)
|
76
|
+
check_description(description, regexp_group, message)
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def check_description(description, regexps, message)
|
82
|
+
return unless regexps.any? { |regexp| regexp.match?(description.value) }
|
83
|
+
|
84
|
+
add_offense(description, message: message)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|