rubocop 1.6.1 → 1.9.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/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
|