rubocop 1.22.3 → 1.26.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -3
  4. data/config/default.yml +110 -19
  5. data/lib/rubocop/cli/command/auto_genenerate_config.rb +1 -1
  6. data/lib/rubocop/cli/command/init_dotfile.rb +1 -1
  7. data/lib/rubocop/cli/command/show_docs_url.rb +48 -0
  8. data/lib/rubocop/cli/command/suggest_extensions.rb +1 -1
  9. data/lib/rubocop/cli.rb +2 -1
  10. data/lib/rubocop/config_loader_resolver.rb +1 -1
  11. data/lib/rubocop/cop/badge.rb +7 -1
  12. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
  13. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +1 -1
  14. data/lib/rubocop/cop/correctors/if_then_corrector.rb +55 -0
  15. data/lib/rubocop/cop/documentation.rb +19 -2
  16. data/lib/rubocop/cop/gemspec/date_assignment.rb +2 -10
  17. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +1 -10
  18. data/lib/rubocop/cop/gemspec/require_mfa.rb +145 -0
  19. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +10 -3
  20. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -10
  21. data/lib/rubocop/cop/generator.rb +7 -11
  22. data/lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb +46 -0
  23. data/lib/rubocop/cop/internal_affairs/redundant_method_dispatch_node.rb +47 -0
  24. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +3 -1
  25. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  26. data/lib/rubocop/cop/layout/argument_alignment.rb +36 -9
  27. data/lib/rubocop/cop/layout/case_indentation.rb +1 -1
  28. data/lib/rubocop/cop/layout/comment_indentation.rb +31 -2
  29. data/lib/rubocop/cop/layout/dot_position.rb +4 -0
  30. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +22 -1
  31. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +5 -1
  32. data/lib/rubocop/cop/layout/hash_alignment.rb +7 -2
  33. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +7 -8
  34. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
  35. data/lib/rubocop/cop/layout/space_after_colon.rb +1 -1
  36. data/lib/rubocop/cop/layout/space_before_first_arg.rb +4 -0
  37. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +11 -5
  38. data/lib/rubocop/cop/lint/ambiguous_range.rb +2 -2
  39. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +5 -1
  40. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +1 -1
  41. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +16 -4
  42. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +6 -0
  43. data/lib/rubocop/cop/lint/each_with_object_argument.rb +1 -1
  44. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +10 -5
  45. data/lib/rubocop/cop/lint/inherit_exception.rb +19 -28
  46. data/lib/rubocop/cop/lint/number_conversion.rb +5 -2
  47. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +10 -6
  48. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +5 -0
  49. data/lib/rubocop/cop/lint/symbol_conversion.rb +3 -2
  50. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +117 -0
  51. data/lib/rubocop/cop/lint/useless_times.rb +13 -9
  52. data/lib/rubocop/cop/metrics/block_length.rb +1 -0
  53. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +0 -9
  54. data/lib/rubocop/cop/metrics/method_length.rb +1 -0
  55. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  56. data/lib/rubocop/cop/metrics/parameter_lists.rb +1 -1
  57. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  58. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +1 -1
  59. data/lib/rubocop/cop/mixin/enforce_superclass.rb +5 -0
  60. data/lib/rubocop/cop/mixin/gemspec_help.rb +30 -0
  61. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +4 -3
  62. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +82 -0
  63. data/lib/rubocop/cop/mixin/line_length_help.rb +17 -6
  64. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +3 -1
  65. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -5
  66. data/lib/rubocop/cop/naming/block_forwarding.rb +121 -0
  67. data/lib/rubocop/cop/naming/file_name.rb +37 -4
  68. data/lib/rubocop/cop/naming/method_parameter_name.rb +1 -1
  69. data/lib/rubocop/cop/security/open.rb +11 -1
  70. data/lib/rubocop/cop/security/yaml_load.rb +9 -3
  71. data/lib/rubocop/cop/style/character_literal.rb +8 -1
  72. data/lib/rubocop/cop/style/collection_compact.rb +31 -13
  73. data/lib/rubocop/cop/style/combinable_loops.rb +2 -2
  74. data/lib/rubocop/cop/style/def_with_parentheses.rb +16 -11
  75. data/lib/rubocop/cop/style/documentation.rb +1 -1
  76. data/lib/rubocop/cop/style/empty_case_condition.rb +10 -0
  77. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  78. data/lib/rubocop/cop/style/file_read.rb +112 -0
  79. data/lib/rubocop/cop/style/file_write.rb +124 -0
  80. data/lib/rubocop/cop/style/for.rb +4 -0
  81. data/lib/rubocop/cop/style/format_string_token.rb +2 -1
  82. data/lib/rubocop/cop/style/hash_conversion.rb +2 -1
  83. data/lib/rubocop/cop/style/hash_syntax.rb +36 -0
  84. data/lib/rubocop/cop/style/hash_transform_keys.rb +6 -6
  85. data/lib/rubocop/cop/style/hash_transform_values.rb +6 -6
  86. data/lib/rubocop/cop/style/if_inside_else.rb +15 -0
  87. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -1
  88. data/lib/rubocop/cop/style/lambda_call.rb +12 -20
  89. data/lib/rubocop/cop/style/map_to_hash.rb +68 -0
  90. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +20 -0
  91. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +3 -1
  92. data/lib/rubocop/cop/style/method_def_parentheses.rb +17 -13
  93. data/lib/rubocop/cop/style/nested_file_dirname.rb +66 -0
  94. data/lib/rubocop/cop/style/numeric_literals.rb +10 -1
  95. data/lib/rubocop/cop/style/one_line_conditional.rb +18 -39
  96. data/lib/rubocop/cop/style/open_struct_use.rb +69 -0
  97. data/lib/rubocop/cop/style/optional_boolean_parameter.rb +3 -2
  98. data/lib/rubocop/cop/style/parentheses_around_condition.rb +12 -2
  99. data/lib/rubocop/cop/style/quoted_symbols.rb +11 -1
  100. data/lib/rubocop/cop/style/redundant_begin.rb +2 -6
  101. data/lib/rubocop/cop/style/redundant_interpolation.rb +17 -3
  102. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +5 -1
  103. data/lib/rubocop/cop/style/redundant_self.rb +1 -1
  104. data/lib/rubocop/cop/style/safe_navigation.rb +1 -5
  105. data/lib/rubocop/cop/style/sample.rb +5 -3
  106. data/lib/rubocop/cop/style/select_by_regexp.rb +6 -1
  107. data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
  108. data/lib/rubocop/cop/style/sole_nested_conditional.rb +53 -13
  109. data/lib/rubocop/cop/style/string_concatenation.rb +7 -1
  110. data/lib/rubocop/cop/style/swap_values.rb +2 -0
  111. data/lib/rubocop/cop/style/ternary_parentheses.rb +16 -2
  112. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +1 -1
  113. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +1 -1
  114. data/lib/rubocop/cop/style/unless_else.rb +4 -0
  115. data/lib/rubocop/cop/team.rb +1 -1
  116. data/lib/rubocop/cop/util.rb +9 -1
  117. data/lib/rubocop/cop/variable_force.rb +1 -5
  118. data/lib/rubocop/cops_documentation_generator.rb +2 -2
  119. data/lib/rubocop/formatter/disabled_config_formatter.rb +16 -2
  120. data/lib/rubocop/formatter/html_formatter.rb +5 -2
  121. data/lib/rubocop/formatter/json_formatter.rb +4 -1
  122. data/lib/rubocop/options.rb +14 -3
  123. data/lib/rubocop/remote_config.rb +2 -4
  124. data/lib/rubocop/result_cache.rb +1 -1
  125. data/lib/rubocop/rspec/shared_contexts.rb +4 -0
  126. data/lib/rubocop/runner.rb +1 -1
  127. data/lib/rubocop/target_ruby.rb +1 -1
  128. data/lib/rubocop/version.rb +1 -1
  129. data/lib/rubocop/yaml_duplication_checker.rb +1 -1
  130. data/lib/rubocop.rb +12 -0
  131. metadata +22 -7
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Gemspec
6
+ # Requires a gemspec to have `rubygems_mfa_required` metadata set.
7
+ #
8
+ # This setting tells RubyGems that MFA (Multi-Factor Authentication) is
9
+ # required for accounts to be able perform privileged operations, such as
10
+ # (see RubyGems' documentation for the full list of privileged
11
+ # operations):
12
+ #
13
+ # * `gem push`
14
+ # * `gem yank`
15
+ # * `gem owner --add/remove`
16
+ # * adding or removing owners using gem ownership page
17
+ #
18
+ # This helps make your gem more secure, as users can be more
19
+ # confident that gem updates were pushed by maintainers.
20
+ #
21
+ # @example
22
+ # # bad
23
+ # Gem::Specification.new do |spec|
24
+ # # no `rubygems_mfa_required` metadata specified
25
+ # end
26
+ #
27
+ # # good
28
+ # Gem::Specification.new do |spec|
29
+ # spec.metadata = {
30
+ # 'rubygems_mfa_required' => 'true'
31
+ # }
32
+ # end
33
+ #
34
+ # # good
35
+ # Gem::Specification.new do |spec|
36
+ # spec.metadata['rubygems_mfa_required'] = 'true'
37
+ # end
38
+ #
39
+ # # bad
40
+ # Gem::Specification.new do |spec|
41
+ # spec.metadata = {
42
+ # 'rubygems_mfa_required' => 'false'
43
+ # }
44
+ # end
45
+ #
46
+ # # good
47
+ # Gem::Specification.new do |spec|
48
+ # spec.metadata = {
49
+ # 'rubygems_mfa_required' => 'true'
50
+ # }
51
+ # end
52
+ #
53
+ # # bad
54
+ # Gem::Specification.new do |spec|
55
+ # spec.metadata['rubygems_mfa_required'] = 'false'
56
+ # end
57
+ #
58
+ # # good
59
+ # Gem::Specification.new do |spec|
60
+ # spec.metadata['rubygems_mfa_required'] = 'true'
61
+ # end
62
+ #
63
+ class RequireMFA < Base
64
+ include GemspecHelp
65
+ extend AutoCorrector
66
+
67
+ MSG = "`metadata['rubygems_mfa_required']` must be set to `'true'`."
68
+
69
+ # @!method metadata(node)
70
+ def_node_matcher :metadata, <<~PATTERN
71
+ `{
72
+ (send _ :metadata= $_)
73
+ (send (send _ :metadata) :[]= (str "rubygems_mfa_required") $_)
74
+ }
75
+ PATTERN
76
+
77
+ # @!method rubygems_mfa_required(node)
78
+ def_node_search :rubygems_mfa_required, <<~PATTERN
79
+ (pair (str "rubygems_mfa_required") $_)
80
+ PATTERN
81
+
82
+ # @!method true_string?(node)
83
+ def_node_matcher :true_string?, <<~PATTERN
84
+ (str "true")
85
+ PATTERN
86
+
87
+ def on_block(node) # rubocop:disable Metrics/MethodLength
88
+ gem_specification(node) do |block_var|
89
+ metadata_value = metadata(node)
90
+ mfa_value = mfa_value(metadata_value)
91
+
92
+ if mfa_value
93
+ unless true_string?(mfa_value)
94
+ add_offense(mfa_value) do |corrector|
95
+ change_value(corrector, mfa_value)
96
+ end
97
+ end
98
+ else
99
+ add_offense(node) do |corrector|
100
+ autocorrect(corrector, node, block_var, metadata_value)
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ private
107
+
108
+ def mfa_value(metadata_value)
109
+ return unless metadata_value
110
+ return metadata_value if metadata_value.str_type?
111
+
112
+ rubygems_mfa_required(metadata_value).first
113
+ end
114
+
115
+ def autocorrect(corrector, node, block_var, metadata)
116
+ if metadata
117
+ return unless metadata.hash_type?
118
+
119
+ correct_metadata(corrector, metadata)
120
+ else
121
+ insert_mfa_required(corrector, node, block_var)
122
+ end
123
+ end
124
+
125
+ def correct_metadata(corrector, metadata)
126
+ if metadata.pairs.any?
127
+ corrector.insert_after(metadata.pairs.last, ",\n'rubygems_mfa_required' => 'true'")
128
+ else
129
+ corrector.insert_before(metadata.loc.end, "'rubygems_mfa_required' => 'true'")
130
+ end
131
+ end
132
+
133
+ def insert_mfa_required(corrector, node, block_var)
134
+ corrector.insert_before(node.loc.end, <<~RUBY)
135
+ #{block_var}.metadata['rubygems_mfa_required'] = 'true'
136
+ RUBY
137
+ end
138
+
139
+ def change_value(corrector, value)
140
+ corrector.replace(value, "'true'")
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
@@ -68,8 +68,11 @@ module RuboCop
68
68
 
69
69
  # @!method defined_ruby_version(node)
70
70
  def_node_matcher :defined_ruby_version, <<~PATTERN
71
- {$(str _) $(array (str _) (str _))
72
- (send (const (const nil? :Gem) :Requirement) :new $(str _))}
71
+ {
72
+ $(str _)
73
+ $(array (str _) (str _))
74
+ (send (const (const nil? :Gem) :Requirement) :new $str+)
75
+ }
73
76
  PATTERN
74
77
 
75
78
  def on_new_investigation
@@ -97,7 +100,11 @@ module RuboCop
97
100
  def extract_ruby_version(required_ruby_version)
98
101
  return unless required_ruby_version
99
102
 
100
- if required_ruby_version.array_type?
103
+ if required_ruby_version.is_a?(Array)
104
+ required_ruby_version = required_ruby_version.detect do |v|
105
+ /[>=]/.match?(v.str_content)
106
+ end
107
+ elsif required_ruby_version.array_type?
101
108
  required_ruby_version = required_ruby_version.children.detect do |v|
102
109
  /[>=]/.match?(v.str_content)
103
110
  end
@@ -26,20 +26,13 @@ module RuboCop
26
26
  # end
27
27
  #
28
28
  class RubyVersionGlobalsUsage < Base
29
+ include GemspecHelp
30
+
29
31
  MSG = 'Do not use `RUBY_VERSION` in gemspec file.'
30
32
 
31
33
  # @!method ruby_version?(node)
32
34
  def_node_matcher :ruby_version?, '(const {cbase nil?} :RUBY_VERSION)'
33
35
 
34
- # @!method gem_specification?(node)
35
- def_node_search :gem_specification?, <<~PATTERN
36
- (block
37
- (send
38
- (const
39
- (const {cbase nil?} :Gem) :Specification) :new)
40
- ...)
41
- PATTERN
42
-
43
36
  def on_const(node)
44
37
  return unless gem_spec_with_ruby_version?(node)
45
38
 
@@ -49,7 +42,7 @@ module RuboCop
49
42
  private
50
43
 
51
44
  def gem_spec_with_ruby_version?(node)
52
- gem_specification?(processed_source.ast) && ruby_version?(node)
45
+ gem_specification(processed_source.ast) && ruby_version?(node)
53
46
  end
54
47
  end
55
48
  end
@@ -8,13 +8,7 @@ module RuboCop
8
8
  # and spec file when given a valid qualified cop name.
9
9
  # @api private
10
10
  class Generator
11
- # NOTE: RDoc 5.1.0 or lower has the following issue.
12
- # https://github.com/rubocop/rubocop/issues/7043
13
- #
14
- # The following `String#gsub` can be replaced with
15
- # squiggly heredoc when RuboCop supports Ruby 2.5 or higher
16
- # (RDoc 6.0 or higher).
17
- SOURCE_TEMPLATE = <<-RUBY.gsub(/^ {8}/, '')
11
+ SOURCE_TEMPLATE = <<~RUBY
18
12
  # frozen_string_literal: true
19
13
 
20
14
  module RuboCop
@@ -68,6 +62,7 @@ module RuboCop
68
62
  # For example
69
63
  MSG = 'Use `#good_method` instead of `#bad_method`.'
70
64
 
65
+ # @!method bad_method?(node)
71
66
  def_node_matcher :bad_method?, <<~PATTERN
72
67
  (send nil? :bad_method ...)
73
68
  PATTERN
@@ -150,7 +145,7 @@ module RuboCop
150
145
  1. Modify the description of #{badge} in config/default.yml
151
146
  2. Implement your new cop in the generated file!
152
147
  3. Commit your new cop with a message such as
153
- e.g. "Add new `#{badge}` cop."
148
+ e.g. "Add new `#{badge}` cop"
154
149
  4. Run `bundle exec rake changelog:new` to generate a changelog entry
155
150
  for your new cop.
156
151
  TODO
@@ -182,7 +177,8 @@ module RuboCop
182
177
  end
183
178
 
184
179
  def generate(template)
185
- format(template, department: badge.department, cop_name: badge.cop_name)
180
+ format(template, department: badge.department.to_s.gsub('/', '::'),
181
+ cop_name: badge.cop_name)
186
182
  end
187
183
 
188
184
  def spec_path
@@ -209,8 +205,8 @@ module RuboCop
209
205
  return 'rspec' if camel_case_string == 'RSpec'
210
206
 
211
207
  camel_case_string
212
- .gsub(/([^A-Z])([A-Z]+)/, '\1_\2')
213
- .gsub(/([A-Z])([A-Z][^A-Z\d]+)/, '\1_\2')
208
+ .gsub(%r{([^A-Z/])([A-Z]+)}, '\1_\2')
209
+ .gsub(%r{([A-Z])([A-Z][^A-Z\d/]+)}, '\1_\2')
214
210
  .downcase
215
211
  end
216
212
  end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # Checks for redundant `:config` parameter in the `context` arguments.
7
+ #
8
+ # @example
9
+ #
10
+ # # bad
11
+ # context 'foo', :config do
12
+ # end
13
+ #
14
+ # # good
15
+ # context 'foo' do
16
+ # end
17
+ #
18
+ class RedundantContextConfigParameter < Base
19
+ include RangeHelp
20
+ extend AutoCorrector
21
+
22
+ MSG = 'Remove the redundant `:config` parameter.'
23
+ RESTRICT_ON_SEND = %i[context].freeze
24
+
25
+ def on_send(node)
26
+ arguments = node.arguments
27
+ config_node = arguments.detect { |argument| argument.source == ':config' }
28
+ return unless config_node
29
+
30
+ add_offense(config_node) do |corrector|
31
+ dup_arguments = arguments.dup
32
+ dup_arguments.delete(config_node)
33
+
34
+ corrector.replace(offense_range(arguments), dup_arguments.map(&:source).join(', '))
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def offense_range(arguments)
41
+ range_between(arguments.first.source_range.begin_pos, arguments.last.source_range.end_pos)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # Checks for redundant `send_node` method dispatch node.
7
+ #
8
+ # @example
9
+ #
10
+ # # bad
11
+ # node.send_node.method_name
12
+ #
13
+ # # good
14
+ # node.method_name
15
+ #
16
+ # # bad
17
+ # node.send_node.receiver
18
+ #
19
+ # # good
20
+ # node.receiver
21
+ #
22
+ class RedundantMethodDispatchNode < Base
23
+ include RangeHelp
24
+ extend AutoCorrector
25
+
26
+ MSG = 'Remove the redundant `send_node`.'
27
+ RESTRICT_ON_SEND = %i[method_name receiver].freeze
28
+
29
+ # @!method dispatch_method(node)
30
+ def_node_matcher :dispatch_method, <<~PATTERN
31
+ (send $(send _ :send_node) _)
32
+ PATTERN
33
+
34
+ def on_send(node)
35
+ return unless (dispatch_node = dispatch_method(node))
36
+ return unless (dot = dispatch_node.loc.dot)
37
+
38
+ range = range_between(dot.begin_pos, dispatch_node.loc.selector.end_pos)
39
+
40
+ add_offense(range) do |corrector|
41
+ corrector.remove(range)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -14,7 +14,9 @@ module RuboCop
14
14
 
15
15
  # @!method cop_class_def(node)
16
16
  def_node_search :cop_class_def, <<~PATTERN
17
- (class _ (const _ {:Base :Cop}) ...)
17
+ (class _
18
+ (const {nil? (const nil? :Cop) (const (const {cbase nil?} :RuboCop) :Cop)}
19
+ {:Base :Cop}) ...)
18
20
  PATTERN
19
21
 
20
22
  # @!method cop_config_accessor?(node)
@@ -9,10 +9,12 @@ require_relative 'internal_affairs/node_destructuring'
9
9
  require_relative 'internal_affairs/node_matcher_directive'
10
10
  require_relative 'internal_affairs/node_type_predicate'
11
11
  require_relative 'internal_affairs/offense_location_keyword'
12
+ require_relative 'internal_affairs/redundant_context_config_parameter'
12
13
  require_relative 'internal_affairs/redundant_described_class_as_subject'
13
14
  require_relative 'internal_affairs/redundant_let_rubocop_config_new'
14
15
  require_relative 'internal_affairs/redundant_location_argument'
15
16
  require_relative 'internal_affairs/redundant_message_argument'
17
+ require_relative 'internal_affairs/redundant_method_dispatch_node'
16
18
  require_relative 'internal_affairs/style_detected_api_use'
17
19
  require_relative 'internal_affairs/undefined_config'
18
20
  require_relative 'internal_affairs/useless_message_assertion'
@@ -53,23 +53,50 @@ module RuboCop
53
53
  'following the first line of a multi-line method call.'
54
54
 
55
55
  def on_send(node)
56
- first_arg = node.first_argument
57
- return if !multiple_arguments?(node, first_arg) || (node.send_type? && node.method?(:[]=))
56
+ return if !multiple_arguments?(node) || (node.send_type? && node.method?(:[]=))
58
57
 
59
- if first_arg.hash_type? && !first_arg.braces?
60
- pairs = first_arg.pairs
61
- check_alignment(pairs, base_column(node, pairs.first))
62
- else
63
- check_alignment(node.arguments, base_column(node, first_arg))
64
- end
58
+ items = flattened_arguments(node)
59
+
60
+ check_alignment(items, base_column(node, items.first))
65
61
  end
62
+
66
63
  alias on_csend on_send
67
64
 
68
65
  private
69
66
 
70
- def multiple_arguments?(node, first_argument)
67
+ def flattened_arguments(node)
68
+ if fixed_indentation?
69
+ arguments_with_last_arg_pairs(node)
70
+ else
71
+ arguments_or_first_arg_pairs(node)
72
+ end
73
+ end
74
+
75
+ def arguments_with_last_arg_pairs(node)
76
+ items = node.arguments[0..-2]
77
+ last_arg = node.arguments.last
78
+
79
+ if last_arg.hash_type? && !last_arg.braces?
80
+ items += last_arg.pairs
81
+ else
82
+ items << last_arg
83
+ end
84
+ items
85
+ end
86
+
87
+ def arguments_or_first_arg_pairs(node)
88
+ first_arg = node.first_argument
89
+ if first_arg.hash_type? && !first_arg.braces?
90
+ first_arg.pairs
91
+ else
92
+ node.arguments
93
+ end
94
+ end
95
+
96
+ def multiple_arguments?(node)
71
97
  return true if node.arguments.size >= 2
72
98
 
99
+ first_argument = node.first_argument
73
100
  first_argument&.hash_type? && first_argument.pairs.count >= 2
74
101
  end
75
102
 
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Layout
6
- # This cop checks how the `when` and `in`s of a `case` expression
6
+ # This cop checks how the `when` and ``in``s of a `case` expression
7
7
  # are indented in relation to its `case` or `end` keyword.
8
8
  #
9
9
  # It will register a separate offense for each misaligned `when` and `in`.
@@ -32,6 +32,19 @@ module RuboCop
32
32
  # true
33
33
  # end
34
34
  #
35
+ # @example AllowForAlignment: false (default)
36
+ # # bad
37
+ # a = 1 # A really long comment
38
+ # # spanning two lines.
39
+ #
40
+ # # good
41
+ # # A really long comment spanning one line.
42
+ # a = 1
43
+ #
44
+ # @example AllowForAlignment: true
45
+ # # good
46
+ # a = 1 # A really long comment
47
+ # # spanning two lines.
35
48
  class CommentIndentation < Base
36
49
  include Alignment
37
50
  extend AutoCorrector
@@ -40,7 +53,7 @@ module RuboCop
40
53
  'instead of %<correct_comment_indentation>d).'
41
54
 
42
55
  def on_new_investigation
43
- processed_source.comments.each { |comment| check(comment) }
56
+ processed_source.comments.each_with_index { |comment, ix| check(comment, ix) }
44
57
  end
45
58
 
46
59
  private
@@ -76,7 +89,7 @@ module RuboCop
76
89
  AlignmentCorrector.correct(corrector, processed_source, comment, @column_delta)
77
90
  end
78
91
 
79
- def check(comment)
92
+ def check(comment, comment_index)
80
93
  return unless own_line_comment?(comment)
81
94
 
82
95
  next_line = line_after_comment(comment)
@@ -94,11 +107,27 @@ module RuboCop
94
107
  return if column == correct_comment_indentation
95
108
  end
96
109
 
110
+ return if correctly_aligned_with_preceding_comment?(comment_index, column)
111
+
97
112
  add_offense(comment, message: message(column, correct_comment_indentation)) do |corrector|
98
113
  autocorrect(corrector, comment)
99
114
  end
100
115
  end
101
116
 
117
+ # Returns true if:
118
+ # a) the cop is configured to allow extra indentation for alignment, and
119
+ # b) the currently inspected comment is aligned with the nearest preceding end-of-line
120
+ # comment.
121
+ def correctly_aligned_with_preceding_comment?(comment_index, column)
122
+ return false unless cop_config['AllowForAlignment']
123
+
124
+ processed_source.comments[0...comment_index].reverse_each do |other_comment|
125
+ return other_comment.loc.column == column unless own_line_comment?(other_comment)
126
+ end
127
+
128
+ false
129
+ end
130
+
102
131
  def message(column, correct_comment_indentation)
103
132
  format(MSG, column: column, correct_comment_indentation: correct_comment_indentation)
104
133
  end
@@ -27,6 +27,10 @@ module RuboCop
27
27
  include RangeHelp
28
28
  extend AutoCorrector
29
29
 
30
+ def self.autocorrect_incompatible_with
31
+ [Style::RedundantSelf]
32
+ end
33
+
30
34
  def on_send(node)
31
35
  return unless node.dot? || ampersand_dot?(node)
32
36
 
@@ -77,13 +77,34 @@ module RuboCop
77
77
  # def b
78
78
  # end
79
79
  #
80
- # @example AllowAdjacentOneLineDefs: true
80
+ # @example AllowAdjacentOneLineDefs: true (default)
81
81
  #
82
82
  # # good
83
83
  # class ErrorA < BaseError; end
84
84
  # class ErrorB < BaseError; end
85
85
  # class ErrorC < BaseError; end
86
86
  #
87
+ # # good
88
+ # class ErrorA < BaseError; end
89
+ #
90
+ # class ErrorB < BaseError; end
91
+ #
92
+ # class ErrorC < BaseError; end
93
+ #
94
+ # @example AllowAdjacentOneLineDefs: false
95
+ #
96
+ # # bad
97
+ # class ErrorA < BaseError; end
98
+ # class ErrorB < BaseError; end
99
+ # class ErrorC < BaseError; end
100
+ #
101
+ # # good
102
+ # class ErrorA < BaseError; end
103
+ #
104
+ # class ErrorB < BaseError; end
105
+ #
106
+ # class ErrorC < BaseError; end
107
+ #
87
108
  class EmptyLineBetweenDefs < Base
88
109
  include RangeHelp
89
110
  extend AutoCorrector
@@ -81,7 +81,7 @@ module RuboCop
81
81
 
82
82
  locations.each do |loc|
83
83
  line = loc.line
84
- next if line == line_of_def_or_kwbegin
84
+ next if line == line_of_def_or_kwbegin || last_rescue_and_end_on_same_line(body)
85
85
 
86
86
  keyword = loc.source
87
87
  # below the keyword
@@ -91,6 +91,10 @@ module RuboCop
91
91
  end
92
92
  end
93
93
 
94
+ def last_rescue_and_end_on_same_line(body)
95
+ body.rescue_type? && body.resbody_branches.last.loc.line == body.parent.loc.end.line
96
+ end
97
+
94
98
  def message(location, keyword)
95
99
  format(MSG, location: location, keyword: keyword)
96
100
  end
@@ -222,11 +222,16 @@ module RuboCop
222
222
  node.pairs.any? &&
223
223
  node.parent&.call_type?
224
224
 
225
+ left_sibling = argument_before_hash(node)
225
226
  parent_loc = node.parent.loc
226
- selector = parent_loc.selector || parent_loc.expression
227
+ selector = left_sibling || parent_loc.selector || parent_loc.expression
227
228
  same_line?(selector, node.pairs.first)
228
229
  end
229
230
 
231
+ def argument_before_hash(hash_node)
232
+ hash_node.left_sibling.respond_to?(:loc) ? hash_node.left_sibling : nil
233
+ end
234
+
230
235
  def reset!
231
236
  self.offenses_by = {}
232
237
  self.column_deltas = Hash.new { |hash, key| hash[key] = {} }
@@ -313,7 +318,7 @@ module RuboCop
313
318
  # just give each lambda the same reference and they would all get the
314
319
  # last value of each. A local variable fixes the problem.
315
320
 
316
- if node.value
321
+ if node.value && node.respond_to?(:value_omission?) && !node.value_omission?
317
322
  correct_key_value(corrector, delta, node.key.source_range,
318
323
  node.value.source_range,
319
324
  node.loc.operator)
@@ -3,27 +3,26 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Layout
6
- # This cop checks the indentation of the right hand side operand in
7
- # binary operations that span more than one line.
6
+ # This cop checks the indentation of the right hand side operand in binary operations that
7
+ # span more than one line.
8
8
  #
9
- # The `aligned` style checks that operators are aligned if they are part
10
- # of an `if` or `while` condition, a `return` statement, etc. In other
11
- # contexts, the second operand should be indented regardless of enforced
12
- # style.
9
+ # The `aligned` style checks that operators are aligned if they are part of an `if` or `while`
10
+ # condition, an explicit `return` statement, etc. In other contexts, the second operand should
11
+ # be indented regardless of enforced style.
13
12
  #
14
13
  # @example EnforcedStyle: aligned (default)
15
14
  # # bad
16
15
  # if a +
17
16
  # b
18
17
  # something &&
19
- # something_else
18
+ # something_else
20
19
  # end
21
20
  #
22
21
  # # good
23
22
  # if a +
24
23
  # b
25
24
  # something &&
26
- # something_else
25
+ # something_else
27
26
  # end
28
27
  #
29
28
  # @example EnforcedStyle: indented
@@ -143,7 +143,7 @@ module RuboCop
143
143
  return true
144
144
  end
145
145
 
146
- do_keyword_line == selector.line && rescue_keyword_column == selector.column
146
+ do_keyword_line == selector&.line && rescue_keyword_column == selector.column
147
147
  end
148
148
 
149
149
  def aligned_with_leading_dot?(do_keyword_line, send_node_loc, rescue_keyword_column)
@@ -19,7 +19,7 @@ module RuboCop
19
19
  MSG = 'Space missing after colon.'
20
20
 
21
21
  def on_pair(node)
22
- return unless node.colon?
22
+ return if !node.colon? || node.value_omission?
23
23
 
24
24
  colon = node.loc.operator
25
25
 
@@ -28,6 +28,10 @@ module RuboCop
28
28
 
29
29
  MSG = 'Put one space between the method name and the first argument.'
30
30
 
31
+ def self.autocorrect_incompatible_with
32
+ [Style::MethodCallWithArgsParentheses]
33
+ end
34
+
31
35
  def on_send(node)
32
36
  return unless regular_method_call_with_arguments?(node)
33
37