rubocop 0.52.0 → 0.52.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (166) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -5
  3. data/config/default.yml +1 -11
  4. data/config/disabled.yml +5 -0
  5. data/config/enabled.yml +6 -8
  6. data/lib/rubocop.rb +13 -2
  7. data/lib/rubocop/ast/node.rb +23 -15
  8. data/lib/rubocop/cli.rb +25 -2
  9. data/lib/rubocop/config.rb +23 -8
  10. data/lib/rubocop/cop/bundler/duplicated_gem.rb +2 -2
  11. data/lib/rubocop/cop/bundler/ordered_gems.rb +9 -0
  12. data/lib/rubocop/cop/commissioner.rb +1 -1
  13. data/lib/rubocop/cop/correctors/alignment_corrector.rb +121 -0
  14. data/lib/rubocop/cop/correctors/condition_corrector.rb +28 -0
  15. data/lib/rubocop/cop/correctors/empty_line_corrector.rb +26 -0
  16. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +62 -0
  17. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +44 -0
  18. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +31 -0
  19. data/lib/rubocop/cop/correctors/punctuation_corrector.rb +29 -0
  20. data/lib/rubocop/cop/correctors/space_corrector.rb +34 -0
  21. data/lib/rubocop/cop/correctors/string_literal_corrector.rb +25 -0
  22. data/lib/rubocop/cop/correctors/unused_arg_corrector.rb +31 -0
  23. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +2 -2
  24. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +9 -0
  25. data/lib/rubocop/cop/generator.rb +18 -87
  26. data/lib/rubocop/cop/generator/require_file_injector.rb +78 -0
  27. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +5 -1
  28. data/lib/rubocop/cop/layout/align_array.rb +5 -1
  29. data/lib/rubocop/cop/layout/align_hash.rb +1 -1
  30. data/lib/rubocop/cop/layout/align_parameters.rb +5 -1
  31. data/lib/rubocop/cop/layout/case_indentation.rb +1 -1
  32. data/lib/rubocop/cop/layout/class_structure.rb +2 -2
  33. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +5 -1
  34. data/lib/rubocop/cop/layout/comment_indentation.rb +5 -1
  35. data/lib/rubocop/cop/layout/else_alignment.rb +5 -1
  36. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +3 -3
  37. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +17 -19
  38. data/lib/rubocop/cop/layout/empty_lines_around_begin_body.rb +4 -0
  39. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +4 -0
  40. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +4 -0
  41. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +4 -0
  42. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +4 -0
  43. data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +4 -0
  44. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +4 -0
  45. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +4 -0
  46. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +4 -0
  47. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +4 -0
  48. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +6 -2
  49. data/lib/rubocop/cop/layout/indent_array.rb +6 -2
  50. data/lib/rubocop/cop/layout/indent_assignment.rb +6 -2
  51. data/lib/rubocop/cop/layout/indent_hash.rb +5 -1
  52. data/lib/rubocop/cop/layout/indentation_consistency.rb +5 -1
  53. data/lib/rubocop/cop/layout/indentation_width.rb +5 -1
  54. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +4 -0
  55. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +3 -3
  56. data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -2
  57. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +4 -0
  58. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +4 -0
  59. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +6 -2
  60. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +4 -0
  61. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +6 -2
  62. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -1
  63. data/lib/rubocop/cop/layout/space_after_comma.rb +4 -0
  64. data/lib/rubocop/cop/layout/space_after_semicolon.rb +4 -0
  65. data/lib/rubocop/cop/layout/space_before_comma.rb +4 -0
  66. data/lib/rubocop/cop/layout/space_before_semicolon.rb +4 -0
  67. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +3 -2
  68. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +16 -7
  69. data/lib/rubocop/cop/layout/tab.rb +1 -1
  70. data/lib/rubocop/cop/lint/block_alignment.rb +1 -1
  71. data/lib/rubocop/cop/lint/def_end_alignment.rb +2 -2
  72. data/lib/rubocop/cop/lint/end_alignment.rb +3 -1
  73. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
  74. data/lib/rubocop/cop/lint/unused_block_argument.rb +4 -0
  75. data/lib/rubocop/cop/lint/unused_method_argument.rb +6 -0
  76. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -1
  77. data/lib/rubocop/cop/mixin/alignment.rb +70 -0
  78. data/lib/rubocop/cop/mixin/array_hash_indentation.rb +2 -0
  79. data/lib/rubocop/cop/mixin/array_syntax.rb +2 -0
  80. data/lib/rubocop/cop/mixin/code_length.rb +2 -0
  81. data/lib/rubocop/cop/mixin/configurable_max.rb +2 -0
  82. data/lib/rubocop/cop/mixin/def_node.rb +3 -1
  83. data/lib/rubocop/cop/mixin/documentation_comment.rb +2 -2
  84. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +3 -15
  85. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -25
  86. data/lib/rubocop/cop/mixin/enforce_superclass.rb +0 -6
  87. data/lib/rubocop/cop/mixin/first_element_line_break.rb +5 -9
  88. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +2 -2
  89. data/lib/rubocop/cop/mixin/ignored_pattern.rb +2 -0
  90. data/lib/rubocop/cop/mixin/integer_node.rb +2 -0
  91. data/lib/rubocop/cop/mixin/match_range.rb +2 -0
  92. data/lib/rubocop/cop/mixin/min_body_length.rb +2 -0
  93. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -0
  94. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +9 -48
  95. data/lib/rubocop/cop/mixin/negative_conditional.rb +2 -16
  96. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +12 -31
  97. data/lib/rubocop/cop/mixin/parentheses.rb +2 -19
  98. data/lib/rubocop/cop/mixin/percent_literal.rb +3 -3
  99. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +2 -0
  100. data/lib/rubocop/cop/mixin/rescue_node.rb +2 -0
  101. data/lib/rubocop/cop/mixin/safe_assignment.rb +2 -0
  102. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -3
  103. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -3
  104. data/lib/rubocop/cop/mixin/statement_modifier.rb +4 -2
  105. data/lib/rubocop/cop/mixin/string_help.rb +2 -0
  106. data/lib/rubocop/cop/mixin/string_literals_help.rb +2 -13
  107. data/lib/rubocop/cop/mixin/surrounding_space.rb +4 -21
  108. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -10
  109. data/lib/rubocop/cop/mixin/unused_argument.rb +2 -15
  110. data/lib/rubocop/cop/performance/case_when_splat.rb +1 -1
  111. data/lib/rubocop/cop/rails/action_filter.rb +3 -2
  112. data/lib/rubocop/cop/rails/active_support_aliases.rb +3 -2
  113. data/lib/rubocop/cop/rails/application_job.rb +6 -0
  114. data/lib/rubocop/cop/rails/application_record.rb +6 -0
  115. data/lib/rubocop/cop/rails/blank.rb +10 -9
  116. data/lib/rubocop/cop/rails/date.rb +22 -14
  117. data/lib/rubocop/cop/rails/delegate.rb +1 -1
  118. data/lib/rubocop/cop/rails/dynamic_find_by.rb +3 -2
  119. data/lib/rubocop/cop/rails/enum_uniqueness.rb +4 -2
  120. data/lib/rubocop/cop/rails/environment_comparison.rb +2 -2
  121. data/lib/rubocop/cop/rails/file_path.rb +1 -1
  122. data/lib/rubocop/cop/rails/find_by.rb +2 -2
  123. data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +15 -7
  124. data/lib/rubocop/cop/rails/http_positional_arguments.rb +2 -2
  125. data/lib/rubocop/cop/rails/inverse_of.rb +130 -8
  126. data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +3 -3
  127. data/lib/rubocop/cop/rails/pluralization_grammar.rb +3 -2
  128. data/lib/rubocop/cop/rails/presence.rb +31 -18
  129. data/lib/rubocop/cop/rails/present.rb +11 -8
  130. data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +52 -10
  131. data/lib/rubocop/cop/rails/request_referer.rb +2 -3
  132. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +9 -2
  133. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +38 -10
  134. data/lib/rubocop/cop/style/class_and_module_children.rb +76 -0
  135. data/lib/rubocop/cop/style/commented_keyword.rb +1 -1
  136. data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
  137. data/lib/rubocop/cop/style/format_string_token.rb +24 -4
  138. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +46 -0
  139. data/lib/rubocop/cop/style/hash_syntax.rb +4 -3
  140. data/lib/rubocop/cop/style/if_unless_modifier.rb +14 -0
  141. data/lib/rubocop/cop/style/method_def_parentheses.rb +79 -0
  142. data/lib/rubocop/cop/style/mixin_usage.rb +13 -2
  143. data/lib/rubocop/cop/style/multiline_if_modifier.rb +1 -1
  144. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +19 -0
  145. data/lib/rubocop/cop/style/negated_if.rb +1 -1
  146. data/lib/rubocop/cop/style/negated_while.rb +6 -4
  147. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -1
  148. data/lib/rubocop/cop/style/parentheses_around_condition.rb +4 -0
  149. data/lib/rubocop/cop/style/redundant_conditional.rb +1 -1
  150. data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -0
  151. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -1
  152. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  153. data/lib/rubocop/cop/style/string_literals.rb +4 -0
  154. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +4 -0
  155. data/lib/rubocop/cop/style/trailing_body_on_method_definition.rb +1 -1
  156. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -0
  157. data/lib/rubocop/cop/style/trailing_comma_in_literal.rb +4 -0
  158. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -1
  159. data/lib/rubocop/formatter/disabled_config_formatter.rb +33 -24
  160. data/lib/rubocop/options.rb +33 -10
  161. data/lib/rubocop/path_util.rb +7 -0
  162. data/lib/rubocop/token.rb +4 -0
  163. data/lib/rubocop/version.rb +1 -1
  164. metadata +14 -4
  165. data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +0 -149
  166. data/lib/rubocop/cop/style/extend_self.rb +0 -92
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # This class does condition auto-correction
6
+ class ConditionCorrector
7
+ class << self
8
+ def correct_negative_condition(node)
9
+ condition = negated_condition(node)
10
+
11
+ lambda do |corrector|
12
+ corrector.replace(node.loc.keyword, node.inverse_keyword)
13
+ corrector.replace(condition.source_range,
14
+ condition.children.first.source)
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def negated_condition(node)
21
+ condition = node.condition
22
+ condition = condition.children.first while condition.begin_type?
23
+ condition
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # This class does empty line auto-correction
6
+ class EmptyLineCorrector
7
+ class << self
8
+ def correct(node)
9
+ offense_style, range = node
10
+ lambda do |corrector|
11
+ case offense_style
12
+ when :no_empty_lines then
13
+ corrector.remove(range)
14
+ when :empty_lines then
15
+ corrector.insert_before(range, "\n")
16
+ end
17
+ end
18
+ end
19
+
20
+ def insert_before(node)
21
+ ->(corrector) { corrector.insert_before(node.source_range, "\n") }
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # Autocorrection logic for the closing brace of a literal either
6
+ # on the same line as the last contained elements, or a new line.
7
+ class MultilineLiteralBraceCorrector
8
+ extend MultilineLiteralBraceLayout
9
+ extend Util
10
+
11
+ class << self
12
+ attr_reader :processed_source
13
+
14
+ # rubocop:disable Metrics/MethodLength
15
+ def correct(processed_source, node)
16
+ @processed_source = processed_source
17
+ if closing_brace_on_same_line?(node)
18
+ lambda do |corrector|
19
+ corrector.insert_before(node.loc.end, "\n".freeze)
20
+ end
21
+ else
22
+ # When a comment immediately before the closing brace gets in the
23
+ # way of an easy correction, the offense is reported but not auto-
24
+ # corrected. The user must handle the delicate decision of where to
25
+ # put the comment.
26
+ return if new_line_needed_before_closing_brace?(node)
27
+
28
+ lambda do |corrector|
29
+ corrector.remove(range_with_surrounding_space(range: node.loc.end,
30
+ side: :left))
31
+
32
+ corrector.insert_after(
33
+ last_element_range_with_trailing_comma(node),
34
+ node.loc.end.source
35
+ )
36
+ end
37
+ end
38
+ end
39
+ # rubocop:enable Metrics/MethodLength
40
+
41
+ private
42
+
43
+ def last_element_range_with_trailing_comma(node)
44
+ trailing_comma_range = last_element_trailing_comma_range(node)
45
+ if trailing_comma_range
46
+ children(node).last.source_range.join(trailing_comma_range)
47
+ else
48
+ children(node).last.source_range
49
+ end
50
+ end
51
+
52
+ def last_element_trailing_comma_range(node)
53
+ range = range_with_surrounding_space(
54
+ range: children(node).last.source_range,
55
+ side: :right
56
+ ).end.resize(1)
57
+ range.source == ',' ? range : nil
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # This auto-corrects gem dependency order
6
+ class OrderedGemCorrector
7
+ extend OrderedGemNode
8
+
9
+ class << self
10
+ attr_reader :processed_source, :comments_as_separators
11
+
12
+ def correct(processed_source, node,
13
+ previous_declaration, comments_as_separators)
14
+ @processed_source = processed_source
15
+ @comments_as_separators = comments_as_separators
16
+
17
+ current_range = declaration_with_comment(node)
18
+ previous_range = declaration_with_comment(previous_declaration)
19
+
20
+ lambda do |corrector|
21
+ swap_range(corrector, current_range, previous_range)
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def declaration_with_comment(node)
28
+ buffer = processed_source.buffer
29
+ begin_pos = get_source_range(node, comments_as_separators).begin_pos
30
+ end_line = buffer.line_for_position(node.loc.expression.end_pos)
31
+ end_pos = buffer.line_range(end_line).end_pos
32
+ Parser::Source::Range.new(buffer, begin_pos, end_pos)
33
+ end
34
+
35
+ def swap_range(corrector, range1, range2)
36
+ src1 = range1.source
37
+ src2 = range2.source
38
+ corrector.replace(range1, src2)
39
+ corrector.replace(range2, src1)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # This auto-corrects parentheses
6
+ class ParenthesesCorrector
7
+ class << self
8
+ def correct(node)
9
+ lambda do |corrector|
10
+ corrector.remove(node.loc.begin)
11
+ corrector.remove(node.loc.end)
12
+
13
+ if ternary_condition?(node) && next_char_is_question_mark?(node)
14
+ corrector.insert_after(node.loc.end, ' ')
15
+ end
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def ternary_condition?(node)
22
+ node.parent && node.parent.if_type? && node.parent.ternary?
23
+ end
24
+
25
+ def next_char_is_question_mark?(node)
26
+ node.loc.last_column == node.parent.loc.question.column
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # This auto-corrects punctuation
6
+ class PunctuationCorrector
7
+ class << self
8
+ def remove_space(space_before)
9
+ ->(corrector) { corrector.remove(space_before) }
10
+ end
11
+
12
+ def add_space(token)
13
+ ->(corrector) { corrector.replace(token.pos, token.pos.source + ' ') }
14
+ end
15
+
16
+ def swap_comma(range)
17
+ return unless range
18
+
19
+ lambda do |corrector|
20
+ case range.source
21
+ when ',' then corrector.remove(range)
22
+ else corrector.insert_after(range, ',')
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # This auto-corrects whitespace
6
+ class SpaceCorrector
7
+ extend SurroundingSpace
8
+
9
+ class << self
10
+ attr_reader :processed_source
11
+
12
+ def remove_space(processed_source, corrector, left_token, right_token)
13
+ @processed_source = processed_source
14
+ if left_token.space_after?
15
+ range = side_space_range(range: left_token.pos, side: :right)
16
+ corrector.remove(range)
17
+ end
18
+ return unless right_token.space_before?
19
+ range = side_space_range(range: right_token.pos, side: :left)
20
+ corrector.remove(range)
21
+ end
22
+
23
+ def add_space(processed_source, corrector, left_token, right_token)
24
+ @processed_source = processed_source
25
+ unless left_token.space_after?
26
+ corrector.insert_after(left_token.pos, ' ')
27
+ end
28
+ return if right_token.space_before?
29
+ corrector.insert_before(right_token.pos, ' ')
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # This auto-corrects string literals
6
+ class StringLiteralCorrector
7
+ extend Util
8
+
9
+ class << self
10
+ def correct(node, style)
11
+ return if node.dstr_type?
12
+
13
+ lambda do |corrector|
14
+ str = node.str_content
15
+ if style == :single_quotes
16
+ corrector.replace(node.source_range, to_string_literal(str))
17
+ else
18
+ corrector.replace(node.source_range, str.inspect)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # This auto-corrects unused arguments.
6
+ class UnusedArgCorrector
7
+ extend Util
8
+
9
+ class << self
10
+ attr_reader :processed_source
11
+
12
+ def correct(processed_source, node)
13
+ return if %i[kwarg kwoptarg].include?(node.type)
14
+
15
+ @processed_source = processed_source
16
+
17
+ if node.blockarg_type?
18
+ lambda do |corrector|
19
+ range = range_with_surrounding_space(range: node.source_range,
20
+ side: :left)
21
+ range = range_with_surrounding_comma(range, :left)
22
+ corrector.remove(range)
23
+ end
24
+ else
25
+ ->(corrector) { corrector.insert_before(node.loc.name, '_') }
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -60,7 +60,7 @@ module RuboCop
60
60
  register_offense(
61
61
  node,
62
62
  node.method_name,
63
- nodes.first.loc.line
63
+ nodes.first.first_line
64
64
  )
65
65
  end
66
66
  end
@@ -88,7 +88,7 @@ module RuboCop
88
88
  def register_offense(node, assignment, line_of_first_occurrence)
89
89
  line_range = node.loc.column...node.loc.last_column
90
90
  offense_location =
91
- source_range(processed_source.buffer, node.loc.line, line_range)
91
+ source_range(processed_source.buffer, node.first_line, line_range)
92
92
  message = format(
93
93
  MSG,
94
94
  assignment: assignment,
@@ -76,6 +76,15 @@ module RuboCop
76
76
  end
77
77
  end
78
78
 
79
+ def autocorrect(node)
80
+ OrderedGemCorrector.correct(
81
+ processed_source,
82
+ node,
83
+ previous_declaration(node),
84
+ treat_comments_as_separators
85
+ )
86
+ end
87
+
79
88
  private
80
89
 
81
90
  def previous_declaration(node)
@@ -54,7 +54,7 @@ module RuboCop
54
54
  SPEC_TEMPLATE = <<-SPEC.strip_indent
55
55
  # frozen_string_literal: true
56
56
 
57
- describe RuboCop::Cop::%<department>s::%<cop_name>s do
57
+ RSpec.describe RuboCop::Cop::%<department>s::%<cop_name>s do
58
58
  subject(:cop) { described_class.new(config) }
59
59
 
60
60
  let(:config) { RuboCop::Config.new }
@@ -77,9 +77,9 @@ module RuboCop
77
77
  end
78
78
  SPEC
79
79
 
80
- def initialize(name)
80
+ def initialize(name, output: $stdout)
81
81
  @badge = Badge.parse(name)
82
-
82
+ @output = output
83
83
  return if badge.qualified?
84
84
 
85
85
  raise ArgumentError, 'Specify a cop name with Department/Name style'
@@ -93,12 +93,15 @@ module RuboCop
93
93
  write_unless_file_exists(spec_path, generated_spec)
94
94
  end
95
95
 
96
- def inject_require
97
- RequireFileInjector.new(require_path).inject
96
+ def inject_require(root_file_path: 'lib/rubocop.rb')
97
+ RequireFileInjector.new(
98
+ source_path: source_path,
99
+ root_file_path: root_file_path
100
+ ).inject
98
101
  end
99
102
 
100
- def inject_config(path = 'config/enabled.yml')
101
- config = File.readlines(path)
103
+ def inject_config(config_file_path: 'config/enabled.yml')
104
+ config = File.readlines(config_file_path)
102
105
  content = <<-YAML.strip_indent
103
106
  #{badge}:
104
107
  Description: 'TODO: Write a description of the cop.'
@@ -110,19 +113,15 @@ module RuboCop
110
113
  break index - 1 if badge.to_s < line
111
114
  end
112
115
  config.insert(target_line, content)
113
- File.write(path, config.join)
116
+ File.write(config_file_path, config.join)
117
+ output.puts <<-MESSAGE.strip_indent
118
+ [modify] A configuration for the cop is added into #{config_file_path}.
119
+ If you want to disable the cop by default, move the added config to config/disabled.yml
120
+ MESSAGE
114
121
  end
115
122
 
116
123
  def todo
117
124
  <<-TODO.strip_indent
118
- Files created:
119
- - #{source_path}
120
- - #{spec_path}
121
- File modified:
122
- - `require_relative '#{require_path}'` added into lib/rubocop.rb
123
- - A configuration for the cop is added into config/enabled.yml
124
- - If you want to disable the cop by default, move the added config to config/disabled.yml
125
-
126
125
  Do 3 steps:
127
126
  1. Add an entry to the "New features" section in CHANGELOG.md,
128
127
  e.g. "Add new `#{badge}` cop. ([@your_id][])"
@@ -133,7 +132,7 @@ module RuboCop
133
132
 
134
133
  private
135
134
 
136
- attr_reader :badge
135
+ attr_reader :badge, :output
137
136
 
138
137
  def write_unless_file_exists(path, contents)
139
138
  if File.exist?(path)
@@ -145,6 +144,7 @@ module RuboCop
145
144
  FileUtils.mkdir_p(dir) unless File.exist?(dir)
146
145
 
147
146
  File.write(path, contents)
147
+ output.puts "[create] #{path}"
148
148
  end
149
149
 
150
150
  def generated_source
@@ -159,10 +159,6 @@ module RuboCop
159
159
  format(template, department: badge.department, cop_name: badge.cop_name)
160
160
  end
161
161
 
162
- def require_path
163
- source_path.sub('lib/', '').sub('.rb', '')
164
- end
165
-
166
162
  def spec_path
167
163
  File.join(
168
164
  'spec',
@@ -184,77 +180,12 @@ module RuboCop
184
180
  end
185
181
 
186
182
  def snake_case(camel_case_string)
183
+ return 'rspec' if camel_case_string == 'RSpec'
187
184
  camel_case_string
188
185
  .gsub(/([^A-Z])([A-Z]+)/, '\1_\2')
189
186
  .gsub(/([A-Z])([A-Z][^A-Z\d]+)/, '\1_\2')
190
187
  .downcase
191
188
  end
192
-
193
- # A class that injects a require directive into the root RuboCop file.
194
- # It looks for other directives that require files in the same (cop)
195
- # namespace and injects the provided one in alpha
196
- class RequireFileInjector
197
- REQUIRE_PATH = /require_relative ['"](.+)['"]/
198
-
199
- def initialize(require_path)
200
- @require_path = require_path
201
- @require_entries = File.readlines(rubocop_root_file_path)
202
- end
203
-
204
- def inject
205
- return if require_exists? || !target_line
206
-
207
- File.write(rubocop_root_file_path, updated_directives)
208
- end
209
-
210
- private
211
-
212
- attr_reader :require_path, :require_entries
213
-
214
- def rubocop_root_file_path
215
- File.join('lib', 'rubocop.rb')
216
- end
217
-
218
- def require_exists?
219
- require_entries.any? do |entry|
220
- entry == injectable_require_directive
221
- end
222
- end
223
-
224
- def updated_directives
225
- require_entries.insert(target_line,
226
- injectable_require_directive).join
227
- end
228
-
229
- def target_line
230
- @target_line ||= begin
231
- in_the_same_department = false
232
- inject_parts = require_path_fragments(injectable_require_directive)
233
-
234
- require_entries.find.with_index do |entry, index|
235
- current_entry_parts = require_path_fragments(entry)
236
-
237
- if inject_parts[0..-2] == current_entry_parts[0..-2]
238
- in_the_same_department = true
239
-
240
- break index if inject_parts.last < current_entry_parts.last
241
- elsif in_the_same_department
242
- break index
243
- end
244
- end
245
- end
246
- end
247
-
248
- def require_path_fragments(require_directove)
249
- path = require_directove.match(REQUIRE_PATH)
250
-
251
- path ? path.captures.first.split('/') : []
252
- end
253
-
254
- def injectable_require_directive
255
- "require_relative '#{require_path}'\n"
256
- end
257
- end
258
189
  end
259
190
  end
260
191
  end