rubocop 0.52.0 → 0.52.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.
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