rubocop 0.46.0 → 0.47.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rubocop might be problematic. Click here for more details.

Files changed (214) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +77 -2
  4. data/config/default.yml +151 -74
  5. data/config/disabled.yml +9 -0
  6. data/config/enabled.yml +49 -9
  7. data/lib/rubocop.rb +36 -8
  8. data/lib/rubocop/ast/builder.rb +59 -0
  9. data/lib/rubocop/ast/node.rb +607 -0
  10. data/lib/rubocop/ast/node/array_node.rb +45 -0
  11. data/lib/rubocop/ast/node/case_node.rb +63 -0
  12. data/lib/rubocop/ast/node/for_node.rb +53 -0
  13. data/lib/rubocop/ast/node/hash_node.rb +102 -0
  14. data/lib/rubocop/ast/node/if_node.rb +136 -0
  15. data/lib/rubocop/ast/node/keyword_splat_node.rb +45 -0
  16. data/lib/rubocop/ast/node/mixin/conditional_node.rb +45 -0
  17. data/lib/rubocop/ast/node/mixin/hash_element_node.rb +125 -0
  18. data/lib/rubocop/ast/node/mixin/modifier_node.rb +17 -0
  19. data/lib/rubocop/ast/node/pair_node.rb +64 -0
  20. data/lib/rubocop/ast/node/until_node.rb +43 -0
  21. data/lib/rubocop/ast/node/when_node.rb +61 -0
  22. data/lib/rubocop/ast/node/while_node.rb +43 -0
  23. data/lib/rubocop/ast/sexp.rb +16 -0
  24. data/lib/rubocop/{ast_node → ast}/traversal.rb +1 -1
  25. data/lib/rubocop/cli.rb +18 -14
  26. data/lib/rubocop/comment_config.rb +1 -3
  27. data/lib/rubocop/config.rb +93 -35
  28. data/lib/rubocop/config_loader.rb +1 -1
  29. data/lib/rubocop/cop/badge.rb +73 -0
  30. data/lib/rubocop/cop/bundler/duplicated_gem.rb +2 -2
  31. data/lib/rubocop/cop/bundler/ordered_gems.rb +43 -3
  32. data/lib/rubocop/cop/commissioner.rb +17 -6
  33. data/lib/rubocop/cop/cop.rb +25 -112
  34. data/lib/rubocop/cop/lint/ambiguous_operator.rb +9 -4
  35. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +7 -0
  36. data/lib/rubocop/cop/lint/assignment_in_condition.rb +18 -4
  37. data/lib/rubocop/cop/lint/block_alignment.rb +40 -9
  38. data/lib/rubocop/cop/lint/circular_argument_reference.rb +14 -0
  39. data/lib/rubocop/cop/lint/condition_position.rb +14 -16
  40. data/lib/rubocop/cop/lint/debugger.rb +28 -0
  41. data/lib/rubocop/cop/lint/def_end_alignment.rb +21 -1
  42. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +13 -1
  43. data/lib/rubocop/cop/lint/duplicate_case_condition.rb +26 -22
  44. data/lib/rubocop/cop/lint/duplicate_methods.rb +15 -1
  45. data/lib/rubocop/cop/lint/duplicated_key.rb +16 -8
  46. data/lib/rubocop/cop/lint/each_with_object_argument.rb +9 -0
  47. data/lib/rubocop/cop/lint/else_layout.rb +26 -29
  48. data/lib/rubocop/cop/lint/empty_ensure.rb +38 -0
  49. data/lib/rubocop/cop/lint/empty_expression.rb +11 -1
  50. data/lib/rubocop/cop/lint/empty_interpolation.rb +8 -0
  51. data/lib/rubocop/cop/lint/empty_when.rb +14 -16
  52. data/lib/rubocop/cop/lint/end_alignment.rb +48 -28
  53. data/lib/rubocop/cop/lint/end_in_method.rb +23 -0
  54. data/lib/rubocop/cop/lint/ensure_return.rb +21 -0
  55. data/lib/rubocop/cop/lint/float_out_of_range.rb +5 -0
  56. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +29 -4
  57. data/lib/rubocop/cop/lint/handle_exceptions.rb +40 -0
  58. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +7 -2
  59. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +11 -2
  60. data/lib/rubocop/cop/lint/invalid_character_literal.rb +3 -0
  61. data/lib/rubocop/cop/lint/literal_in_condition.rb +34 -36
  62. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +8 -0
  63. data/lib/rubocop/cop/lint/loop.rb +36 -0
  64. data/lib/rubocop/cop/lint/multiple_compare.rb +46 -0
  65. data/lib/rubocop/cop/lint/nested_method_definition.rb +22 -0
  66. data/lib/rubocop/cop/lint/next_without_accumulator.rb +5 -0
  67. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +8 -0
  68. data/lib/rubocop/cop/lint/percent_string_array.rb +27 -13
  69. data/lib/rubocop/cop/lint/percent_symbol_array.rb +14 -4
  70. data/lib/rubocop/cop/lint/rand_one.rb +7 -3
  71. data/lib/rubocop/cop/lint/require_parentheses.rb +20 -19
  72. data/lib/rubocop/cop/lint/rescue_exception.rb +20 -0
  73. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +66 -0
  74. data/lib/rubocop/cop/lint/shadowed_exception.rb +6 -1
  75. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +24 -0
  76. data/lib/rubocop/cop/lint/string_conversion_in_interpolation.rb +8 -0
  77. data/lib/rubocop/cop/lint/underscore_prefixed_variable_name.rb +24 -0
  78. data/lib/rubocop/cop/lint/unified_integer.rb +5 -0
  79. data/lib/rubocop/cop/lint/unneeded_disable.rb +2 -2
  80. data/lib/rubocop/cop/lint/unneeded_splat_expansion.rb +5 -0
  81. data/lib/rubocop/cop/lint/unreachable_code.rb +17 -0
  82. data/lib/rubocop/cop/lint/unused_block_argument.rb +2 -0
  83. data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
  84. data/lib/rubocop/cop/lint/useless_access_modifier.rb +28 -1
  85. data/lib/rubocop/cop/lint/useless_assignment.rb +18 -0
  86. data/lib/rubocop/cop/lint/useless_comparison.rb +3 -1
  87. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +16 -1
  88. data/lib/rubocop/cop/lint/useless_setter_call.rb +16 -4
  89. data/lib/rubocop/cop/lint/void.rb +52 -0
  90. data/lib/rubocop/cop/message_annotator.rb +102 -0
  91. data/lib/rubocop/cop/metrics/block_length.rb +6 -0
  92. data/lib/rubocop/cop/metrics/block_nesting.rb +17 -5
  93. data/lib/rubocop/cop/metrics/line_length.rb +11 -4
  94. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -2
  95. data/lib/rubocop/cop/mixin/array_syntax.rb +2 -11
  96. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +12 -5
  97. data/lib/rubocop/cop/mixin/configurable_formatting.rb +48 -0
  98. data/lib/rubocop/cop/mixin/configurable_max.rb +3 -3
  99. data/lib/rubocop/cop/mixin/configurable_naming.rb +5 -33
  100. data/lib/rubocop/cop/mixin/configurable_numbering.rb +6 -47
  101. data/lib/rubocop/cop/mixin/documentation_comment.rb +7 -1
  102. data/lib/rubocop/cop/mixin/duplication.rb +46 -0
  103. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +2 -2
  104. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +14 -11
  105. data/lib/rubocop/cop/mixin/hash_alignment.rb +114 -0
  106. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +3 -3
  107. data/lib/rubocop/cop/mixin/negative_conditional.rb +21 -7
  108. data/lib/rubocop/cop/mixin/on_method_def.rb +14 -0
  109. data/lib/rubocop/cop/mixin/on_normal_if_unless.rb +1 -24
  110. data/lib/rubocop/cop/mixin/statement_modifier.rb +8 -13
  111. data/lib/rubocop/cop/mixin/target_ruby_version.rb +16 -0
  112. data/lib/rubocop/cop/mixin/trailing_comma.rb +2 -3
  113. data/lib/rubocop/cop/offense.rb +1 -1
  114. data/lib/rubocop/cop/performance/case_when_splat.rb +56 -59
  115. data/lib/rubocop/cop/performance/detect.rb +2 -2
  116. data/lib/rubocop/cop/performance/flat_map.rb +3 -3
  117. data/lib/rubocop/cop/performance/redundant_merge.rb +3 -6
  118. data/lib/rubocop/cop/performance/regexp_match.rb +201 -0
  119. data/lib/rubocop/cop/rails/delegate.rb +2 -2
  120. data/lib/rubocop/cop/rails/delegate_allow_blank.rb +10 -19
  121. data/lib/rubocop/cop/rails/enum_uniqueness.rb +12 -40
  122. data/lib/rubocop/cop/rails/file_path.rb +80 -0
  123. data/lib/rubocop/cop/rails/find_each.rb +5 -14
  124. data/lib/rubocop/cop/rails/http_positional_arguments.rb +30 -24
  125. data/lib/rubocop/cop/rails/not_null_column.rb +23 -0
  126. data/lib/rubocop/cop/rails/reversible_migration.rb +217 -0
  127. data/lib/rubocop/cop/rails/safe_navigation.rb +4 -2
  128. data/lib/rubocop/cop/rails/skips_model_validations.rb +46 -0
  129. data/lib/rubocop/cop/rails/time_zone.rb +1 -1
  130. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +7 -5
  131. data/lib/rubocop/cop/registry.rb +170 -0
  132. data/lib/rubocop/cop/{lint → security}/eval.rb +7 -1
  133. data/lib/rubocop/cop/security/marshal_load.rb +33 -0
  134. data/lib/rubocop/cop/security/yaml_load.rb +37 -0
  135. data/lib/rubocop/cop/style/align_hash.rb +138 -169
  136. data/lib/rubocop/cop/style/and_or.rb +1 -1
  137. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +10 -15
  138. data/lib/rubocop/cop/style/case_indentation.rb +36 -27
  139. data/lib/rubocop/cop/style/conditional_assignment.rb +64 -47
  140. data/lib/rubocop/cop/style/each_with_object.rb +4 -1
  141. data/lib/rubocop/cop/style/else_alignment.rb +14 -20
  142. data/lib/rubocop/cop/style/empty_case_condition.rb +16 -25
  143. data/lib/rubocop/cop/style/empty_else.rb +20 -22
  144. data/lib/rubocop/cop/style/empty_literal.rb +4 -4
  145. data/lib/rubocop/cop/style/empty_method.rb +12 -6
  146. data/lib/rubocop/cop/style/encoding.rb +1 -1
  147. data/lib/rubocop/cop/style/file_name.rb +24 -4
  148. data/lib/rubocop/cop/style/first_method_argument_line_break.rb +1 -1
  149. data/lib/rubocop/cop/style/format_string.rb +17 -48
  150. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +40 -11
  151. data/lib/rubocop/cop/style/guard_clause.rb +11 -17
  152. data/lib/rubocop/cop/style/hash_syntax.rb +24 -42
  153. data/lib/rubocop/cop/style/identical_conditional_branches.rb +40 -28
  154. data/lib/rubocop/cop/style/if_inside_else.rb +6 -9
  155. data/lib/rubocop/cop/style/if_unless_modifier.rb +16 -25
  156. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +3 -9
  157. data/lib/rubocop/cop/style/indent_array.rb +1 -1
  158. data/lib/rubocop/cop/style/indentation_width.rb +29 -60
  159. data/lib/rubocop/cop/style/infinite_loop.rb +21 -22
  160. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +86 -0
  161. data/lib/rubocop/cop/style/{method_call_parentheses.rb → method_call_without_args_parentheses.rb} +8 -1
  162. data/lib/rubocop/cop/style/missing_else.rb +40 -14
  163. data/lib/rubocop/cop/style/multiline_if_modifier.rb +5 -15
  164. data/lib/rubocop/cop/style/multiline_if_then.rb +14 -8
  165. data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +3 -3
  166. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +1 -5
  167. data/lib/rubocop/cop/style/mutable_constant.rb +3 -2
  168. data/lib/rubocop/cop/style/negated_if.rb +3 -19
  169. data/lib/rubocop/cop/style/negated_while.rb +2 -17
  170. data/lib/rubocop/cop/style/nested_modifier.rb +16 -43
  171. data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -5
  172. data/lib/rubocop/cop/style/next.rb +23 -21
  173. data/lib/rubocop/cop/style/non_nil_check.rb +2 -3
  174. data/lib/rubocop/cop/style/not.rb +1 -3
  175. data/lib/rubocop/cop/style/numeric_literals.rb +2 -2
  176. data/lib/rubocop/cop/style/one_line_conditional.rb +12 -22
  177. data/lib/rubocop/cop/style/option_hash.rb +4 -15
  178. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -3
  179. data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -12
  180. data/lib/rubocop/cop/style/percent_q_literals.rb +15 -12
  181. data/lib/rubocop/cop/style/redundant_freeze.rb +3 -2
  182. data/lib/rubocop/cop/style/redundant_parentheses.rb +27 -4
  183. data/lib/rubocop/cop/style/redundant_return.rb +4 -8
  184. data/lib/rubocop/cop/style/safe_navigation.rb +13 -6
  185. data/lib/rubocop/cop/style/space_after_colon.rb +2 -4
  186. data/lib/rubocop/cop/style/space_around_block_parameters.rb +1 -1
  187. data/lib/rubocop/cop/style/space_around_operators.rb +15 -13
  188. data/lib/rubocop/cop/style/string_methods.rb +1 -3
  189. data/lib/rubocop/cop/style/symbol_array.rb +1 -5
  190. data/lib/rubocop/cop/style/ternary_parentheses.rb +5 -6
  191. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +2 -5
  192. data/lib/rubocop/cop/style/trailing_comma_in_literal.rb +1 -1
  193. data/lib/rubocop/cop/style/unless_else.rb +1 -5
  194. data/lib/rubocop/cop/style/when_then.rb +4 -2
  195. data/lib/rubocop/cop/style/while_until_do.rb +9 -13
  196. data/lib/rubocop/cop/style/while_until_modifier.rb +12 -11
  197. data/lib/rubocop/cop/style/word_array.rb +5 -9
  198. data/lib/rubocop/cop/team.rb +16 -15
  199. data/lib/rubocop/cop/util.rb +13 -3
  200. data/lib/rubocop/formatter/clang_style_formatter.rb +2 -2
  201. data/lib/rubocop/formatter/disabled_config_formatter.rb +2 -1
  202. data/lib/rubocop/magic_comment.rb +196 -0
  203. data/lib/rubocop/options.rb +5 -4
  204. data/lib/rubocop/processed_source.rb +1 -1
  205. data/lib/rubocop/rspec/cop_helper.rb +9 -0
  206. data/lib/rubocop/rspec/shared_examples.rb +1 -1
  207. data/lib/rubocop/runner.rb +7 -2
  208. data/lib/rubocop/version.rb +1 -1
  209. metadata +41 -14
  210. data/lib/rubocop/ast_node.rb +0 -624
  211. data/lib/rubocop/ast_node/builder.rb +0 -30
  212. data/lib/rubocop/ast_node/sexp.rb +0 -13
  213. data/lib/rubocop/cop/mixin/hash_node.rb +0 -14
  214. data/lib/rubocop/cop/mixin/if_node.rb +0 -42
@@ -40,51 +40,42 @@ module RuboCop
40
40
  'expression.'.freeze
41
41
 
42
42
  def on_case(case_node)
43
- condition_node = case_node.children.first
43
+ return if case_node.condition
44
44
 
45
- add_offense(case_node, :keyword, MSG) if condition_node.nil?
45
+ add_offense(case_node, :keyword, MSG)
46
46
  end
47
47
 
48
48
  private
49
49
 
50
50
  def autocorrect(case_node)
51
- lambda do |corrector|
52
- _cond_node, *when_nodes, _else_node = *case_node
53
-
54
- correct_case_whens(corrector, case_node, when_nodes)
51
+ when_branches = case_node.when_branches
55
52
 
56
- correct_multiple_alternative_whens(corrector, when_nodes)
53
+ lambda do |corrector|
54
+ correct_case_when(corrector, case_node, when_branches)
55
+ correct_when_conditions(corrector, when_branches)
57
56
  end
58
57
  end
59
58
 
60
- def correct_case_whens(corrector, case_node, when_nodes)
61
- case_to_first_when =
62
- case_node.loc.keyword.join(when_nodes.first.loc.keyword)
59
+ def correct_case_when(corrector, case_node, when_nodes)
60
+ case_range = case_node.loc.keyword.join(when_nodes.shift.loc.keyword)
63
61
 
64
- corrector.replace(case_to_first_when, 'if')
62
+ corrector.replace(case_range, 'if')
65
63
 
66
- when_nodes.drop(1).each do |when_node|
64
+ when_nodes.each do |when_node|
67
65
  corrector.replace(when_node.loc.keyword, 'elsif')
68
66
  end
69
67
  end
70
68
 
71
- # Since an if condition containing commas is not syntactically valid, we
72
- # correct `when x, y` to `if x || y`.
73
- def correct_multiple_alternative_whens(corrector, when_nodes)
69
+ def correct_when_conditions(corrector, when_nodes)
74
70
  when_nodes.each do |when_node|
75
- # In `when a; r` we have two children: [a, r].
76
- # In `when a, b, c; r` we have 4.
77
- # In `when a, b then r` we have 3.
78
- *children, _ = when_node.children
71
+ conditions = when_node.conditions
79
72
 
80
- next unless children.size > 1
73
+ next unless conditions.size > 1
81
74
 
82
- first = children.first
83
- last = children.last
84
- range = range_between(first.loc.expression.begin_pos,
85
- last.loc.expression.end_pos)
75
+ range = range_between(conditions.first.loc.expression.begin_pos,
76
+ conditions.last.loc.expression.end_pos)
86
77
 
87
- corrector.replace(range, children.map(&:source).join(' || '))
78
+ corrector.replace(range, conditions.map(&:source).join(' || '))
88
79
  end
89
80
  end
90
81
  end
@@ -76,38 +76,38 @@ module RuboCop
76
76
  MSG = 'Redundant `else`-clause.'.freeze
77
77
 
78
78
  def on_normal_if_unless(node)
79
- check(node, if_else_clause(node))
79
+ check(node)
80
80
  end
81
81
 
82
82
  def on_case(node)
83
- check(node, case_else_clause(node))
83
+ check(node)
84
84
  end
85
85
 
86
86
  private
87
87
 
88
- def check(node, else_clause)
89
- case style
90
- when :empty
91
- empty_check(node, else_clause)
92
- when :nil
93
- nil_check(node, else_clause)
94
- when :both
95
- both_check(node, else_clause)
96
- end
88
+ def check(node)
89
+ empty_check(node) if empty_style?
90
+ nil_check(node) if nil_style?
91
+ end
92
+
93
+ def nil_style?
94
+ style == :nil || style == :both
97
95
  end
98
96
 
99
- def empty_check(node, else_clause)
100
- add_offense(node, :else, MSG) if node.loc.else && else_clause.nil?
97
+ def empty_style?
98
+ style == :empty || style == :both
101
99
  end
102
100
 
103
- def nil_check(node, else_clause)
104
- return unless else_clause && else_clause.nil_type?
101
+ def empty_check(node)
102
+ return unless node.else? && !node.else_branch
103
+
105
104
  add_offense(node, :else, MSG)
106
105
  end
107
106
 
108
- def both_check(node, else_clause)
109
- empty_check(node, else_clause)
110
- nil_check(node, else_clause)
107
+ def nil_check(node)
108
+ return unless node.else_branch && node.else_branch.nil_type?
109
+
110
+ add_offense(node, :else, MSG)
111
111
  end
112
112
 
113
113
  def autocorrect(node)
@@ -121,13 +121,11 @@ module RuboCop
121
121
  end
122
122
 
123
123
  def base_if_node(node)
124
- parent_node = node
125
- parent_node = parent_node.parent until parent_node.loc.end
126
- parent_node
124
+ node.each_ancestor(:if).find { |parent| parent.loc.end } || node
127
125
  end
128
126
 
129
127
  def autocorrect_forbidden?(type)
130
- [type, 'both'].include? missing_else_style
128
+ [type, 'both'].include?(missing_else_style)
131
129
  end
132
130
 
133
131
  def missing_else_style
@@ -27,7 +27,7 @@ module RuboCop
27
27
  end
28
28
 
29
29
  str_node(node) do
30
- return if frozen_string_literals_enabled?(processed_source)
30
+ return if frozen_string_literals_enabled?
31
31
 
32
32
  add_offense(node, :expression,
33
33
  format(STR_MSG, preferred_string_literal))
@@ -54,7 +54,7 @@ module RuboCop
54
54
  config.for_cop('Style/StringLiterals')
55
55
  end
56
56
 
57
- def first_arg_in_method_call_without_parentheses?(node)
57
+ def first_argument_unparenthesized?(node)
58
58
  return false unless node.parent && node.parent.send_type?
59
59
 
60
60
  _receiver, _method_name, *args = *node.parent
@@ -63,7 +63,7 @@ module RuboCop
63
63
 
64
64
  def replacement_range(node)
65
65
  if hash_node(node) &&
66
- first_arg_in_method_call_without_parentheses?(node)
66
+ first_argument_unparenthesized?(node)
67
67
  # `some_method {}` is not same as `some_method Hash.new`
68
68
  # because the braces are interpreted as a block. We will have
69
69
  # to rewrite the arguments to wrap them in parenthesis.
@@ -83,7 +83,7 @@ module RuboCop
83
83
  elsif str_node(node)
84
84
  preferred_string_literal
85
85
  elsif hash_node(node)
86
- if first_arg_in_method_call_without_parentheses?(node)
86
+ if first_argument_unparenthesized?(node)
87
87
  # `some_method {}` is not same as `some_method Hash.new`
88
88
  # because the braces are interpreted as a block. We will have
89
89
  # to rewrite the arguments to wrap them in parenthesis.
@@ -5,7 +5,7 @@ module RuboCop
5
5
  module Style
6
6
  # This cop checks for the formatting of empty method definitions.
7
7
  # By default it enforces empty method definitions to go on a single
8
- # line (compact style), but it cah be configured to enforce the `end`
8
+ # line (compact style), but it can be configured to enforce the `end`
9
9
  # to go on its own line (expanded style.)
10
10
  #
11
11
  # Note: A method definition is not considered empty if it contains
@@ -18,31 +18,36 @@ module RuboCop
18
18
  # @bad
19
19
  # def foo(bar)
20
20
  # end
21
+ # def self.foo(bar)
22
+ # end
21
23
  #
22
24
  # @good
23
25
  # def foo(bar); end
24
26
  # def foo(bar)
25
27
  # # baz
26
28
  # end
29
+ # def self.foo(bar); end
27
30
  #
28
31
  # EnforcedStyle: expanded
29
32
  #
30
33
  # @bad
31
34
  # def foo(bar); end
35
+ # def self.foo(bar); end
32
36
  #
33
37
  # @good
34
38
  # def foo(bar)
35
39
  # end
40
+ # def self.foo(bar)
41
+ # end
36
42
  class EmptyMethod < Cop
43
+ include OnMethodDef
37
44
  include ConfigurableEnforcedStyle
38
45
 
39
46
  MSG_COMPACT = 'Put empty method definitions on a single line.'.freeze
40
47
  MSG_EXPANDED = 'Put the `end` of empty method definitions on the ' \
41
48
  'next line.'.freeze
42
49
 
43
- def on_def(node)
44
- _method_name, _args, body = *node
45
-
50
+ def on_method_def(node, _method_name, _args, body)
46
51
  return if body || comment_lines?(node)
47
52
  return if compact_style? && compact?(node)
48
53
  return if expanded_style? && expanded?(node)
@@ -63,12 +68,13 @@ module RuboCop
63
68
  end
64
69
 
65
70
  def corrected(node)
66
- method_name, args, _body = *node
71
+ method_name, args, _body, scope = method_def_node_parts(node)
67
72
 
68
73
  arguments = args.source unless args.children.empty?
69
74
  joint = compact_style? ? '; ' : "\n"
75
+ scope = scope ? 'self.' : ''
70
76
 
71
- ["def #{method_name}#{arguments}", 'end'].join(joint)
77
+ ["def #{scope}#{method_name}#{arguments}", 'end'].join(joint)
72
78
  end
73
79
 
74
80
  def comment_lines?(node)
@@ -72,7 +72,7 @@ module RuboCop
72
72
  end
73
73
 
74
74
  def encoding_present?(line)
75
- line =~ ENCODING_PATTERN
75
+ MagicComment.parse(line).encoding
76
76
  end
77
77
 
78
78
  def encoding_omitable?
@@ -34,10 +34,10 @@ module RuboCop
34
34
  return unless expect_matching_definition?
35
35
  return if find_class_or_module(processed_source.ast,
36
36
  to_namespace(file_path))
37
+
37
38
  no_definition_message(basename, file_path)
38
39
  else
39
- return if cop_config['IgnoreExecutableScripts'] &&
40
- shebang?(first_line)
40
+ return if ignore_executable_scripts? && shebang?(first_line)
41
41
  other_message(basename)
42
42
  end
43
43
 
@@ -66,6 +66,10 @@ module RuboCop
66
66
  line && line.start_with?('#!')
67
67
  end
68
68
 
69
+ def ignore_executable_scripts?
70
+ cop_config['IgnoreExecutableScripts']
71
+ end
72
+
69
73
  def expect_matching_definition?
70
74
  cop_config['ExpectMatchingDefinition']
71
75
  end
@@ -74,6 +78,10 @@ module RuboCop
74
78
  cop_config['Regex']
75
79
  end
76
80
 
81
+ def allowed_acronyms
82
+ cop_config['AllowedAcronyms'] || []
83
+ end
84
+
77
85
  def filename_good?(basename)
78
86
  basename = basename.sub(/\.[^\.]+$/, '')
79
87
  basename =~ (regex || SNAKE_CASE)
@@ -87,11 +95,12 @@ module RuboCop
87
95
  next unless (const = child.defined_module)
88
96
 
89
97
  const_namespace, const_name = *const
90
- next unless name == const_name
98
+ next if name != const_name && !match_acronym?(name, const_name)
91
99
 
92
100
  return node if namespace.empty?
93
101
  return node if match_namespace(child, const_namespace, namespace)
94
102
  end
103
+
95
104
  nil
96
105
  end
97
106
 
@@ -115,7 +124,9 @@ module RuboCop
115
124
 
116
125
  namespace, name = *namespace
117
126
 
118
- expected.pop if name == expected.last
127
+ if name == expected.last || match_acronym?(expected.last, name)
128
+ expected.pop
129
+ end
119
130
  end
120
131
 
121
132
  false
@@ -126,6 +137,15 @@ module RuboCop
126
137
  expected.empty? || expected == [:Object]
127
138
  end
128
139
 
140
+ def match_acronym?(expected, name)
141
+ expected = expected.to_s
142
+ name = name.to_s
143
+
144
+ allowed_acronyms.any? do |acronym|
145
+ expected.gsub(acronym.capitalize, acronym) == name
146
+ end
147
+ end
148
+
129
149
  def to_namespace(path)
130
150
  components = Pathname(path).each_filename.to_a
131
151
  # To convert a pathname to a Ruby namespace, we need a starting point
@@ -36,7 +36,7 @@ module RuboCop
36
36
  # ...then each key/value pair is treated as a method 'argument'
37
37
  # when determining where line breaks should appear.
38
38
  if (last_arg = args.last)
39
- if last_arg.hash_type? && !last_arg.loc.begin # no explicit {
39
+ if last_arg.hash_type? && !last_arg.braces?
40
40
  args = args.concat(args.pop.children)
41
41
  end
42
42
  end
@@ -13,62 +13,31 @@ module RuboCop
13
13
  class FormatString < Cop
14
14
  include ConfigurableEnforcedStyle
15
15
 
16
- def on_send(node)
17
- add_offense(node, :selector) if offending_node?(node)
18
- end
16
+ MSG = 'Favor `%s` over `%s`.'.freeze
19
17
 
20
- private
21
-
22
- def offending_node?(node)
23
- case style
24
- when :format
25
- sprintf?(node) || percent?(node)
26
- when :sprintf
27
- format?(node) || percent?(node)
28
- when :percent
29
- format?(node) || sprintf?(node)
30
- end
31
- end
18
+ def_node_matcher :formatter, <<-PATTERN
19
+ {
20
+ (send nil ${:sprintf :format} _ _ ...)
21
+ (send {str dstr} $:% ... )
22
+ (send !nil $:% {array hash})
23
+ }
24
+ PATTERN
32
25
 
33
- def format_method?(name, node)
34
- receiver, method_name, *args = *node
35
-
36
- # commands have no explicit receiver
37
- return false unless !receiver && method_name == name
38
-
39
- # we do an argument count check to reduce false positives
40
- args.size >= 2
41
- end
26
+ def on_send(node)
27
+ return unless (selector = formatter(node))
42
28
 
43
- def format?(node)
44
- format_method?(:format, node)
45
- end
29
+ detected_style = selector == :% ? :percent : selector
30
+ return if detected_style == style
46
31
 
47
- def sprintf?(node)
48
- format_method?(:sprintf, node)
32
+ add_offense(node, :selector, message(detected_style))
49
33
  end
50
34
 
51
- def percent?(node)
52
- receiver_node, method_name, *arg_nodes = *node
53
-
54
- method_name == :% &&
55
- ([:str, :dstr].include?(receiver_node.type) ||
56
- arg_nodes.first.array_type?)
35
+ def message(detected_style)
36
+ format(MSG, method_name(style), method_name(detected_style))
57
37
  end
58
38
 
59
- def message(node)
60
- _receiver_node, method_name, *_arg_nodes = *node
61
-
62
- preferred =
63
- if style == :percent
64
- 'String#%'
65
- else
66
- style
67
- end
68
-
69
- method_name = 'String#%' if method_name == :%
70
-
71
- "Favor `#{preferred}` over `#{method_name}`."
39
+ def method_name(style_name)
40
+ style_name == :percent ? 'String#%' : style_name
72
41
  end
73
42
  end
74
43
  end
@@ -13,32 +13,47 @@ module RuboCop
13
13
  include FrozenStringLiteral
14
14
 
15
15
  MSG = 'Missing frozen string literal comment.'.freeze
16
+ MSG_UNNECESSARY = 'Unnecessary frozen string literal comment.'.freeze
16
17
  SHEBANG = '#!'.freeze
17
18
 
18
19
  def investigate(processed_source)
19
20
  return if style == :when_needed && target_ruby_version < 2.3
20
21
  return if processed_source.tokens.empty?
21
22
 
22
- return if frozen_string_literal_comment_exists?(processed_source)
23
-
24
- offense(processed_source)
23
+ if frozen_string_literal_comment_exists?
24
+ check_for_no_comment(processed_source)
25
+ else
26
+ check_for_comment(processed_source)
27
+ end
25
28
  end
26
29
 
27
- def autocorrect(_node)
30
+ def autocorrect(node)
28
31
  lambda do |corrector|
29
- last_special_comment = last_special_comment(processed_source)
30
- if last_special_comment.nil?
31
- corrector.insert_before(processed_source.tokens[0].pos,
32
- "#{FROZEN_STRING_LITERAL_ENABLED}\n")
32
+ if style == :never
33
+ corrector.remove(range_with_surrounding_space(node.pos, :right))
33
34
  else
34
- corrector.insert_after(last_special_comment.pos,
35
- "\n#{FROZEN_STRING_LITERAL_ENABLED}")
35
+ last_special_comment = last_special_comment(processed_source)
36
+ if last_special_comment.nil?
37
+ corrector.insert_before(processed_source.tokens[0].pos,
38
+ "#{FROZEN_STRING_LITERAL_ENABLED}\n")
39
+ else
40
+ corrector.insert_after(last_special_comment.pos,
41
+ "\n#{FROZEN_STRING_LITERAL_ENABLED}")
42
+ end
36
43
  end
37
44
  end
38
45
  end
39
46
 
40
47
  private
41
48
 
49
+ def check_for_no_comment(processed_source)
50
+ unnecessary_comment_offense(processed_source) if style == :never
51
+ end
52
+
53
+ def check_for_comment(processed_source)
54
+ offense(processed_source) unless style == :never
55
+ end
56
+
42
57
  def last_special_comment(processed_source)
43
58
  token_number = 0
44
59
  if processed_source.tokens[token_number].text.start_with?(SHEBANG)
@@ -54,13 +69,27 @@ module RuboCop
54
69
  token
55
70
  end
56
71
 
72
+ def frozen_string_literal_comment(processed_source)
73
+ processed_source.tokens.find do |token|
74
+ token.text.start_with?(FrozenStringLiteral::FROZEN_STRING_LITERAL)
75
+ end
76
+ end
77
+
57
78
  def offense(processed_source)
58
79
  last_special_comment = last_special_comment(processed_source)
59
- last_special_comment ||= processed_source.tokens[0]
60
80
  range = source_range(processed_source.buffer, 0, 0)
61
81
 
62
82
  add_offense(last_special_comment, range, MSG)
63
83
  end
84
+
85
+ def unnecessary_comment_offense(processed_source)
86
+ frozen_string_literal_comment =
87
+ frozen_string_literal_comment(processed_source)
88
+
89
+ add_offense(frozen_string_literal_comment,
90
+ frozen_string_literal_comment.pos,
91
+ MSG_UNNECESSARY)
92
+ end
64
93
  end
65
94
  end
66
95
  end