rubocop 0.48.1 → 0.49.0

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 (184) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -3
  3. data/config/default.yml +397 -357
  4. data/config/disabled.yml +29 -29
  5. data/config/enabled.yml +366 -326
  6. data/lib/rubocop.rb +85 -70
  7. data/lib/rubocop/ast/builder.rb +4 -1
  8. data/lib/rubocop/ast/node.rb +2 -2
  9. data/lib/rubocop/ast/node/and_node.rb +1 -1
  10. data/lib/rubocop/ast/node/args_node.rb +24 -0
  11. data/lib/rubocop/ast/node/block_node.rb +107 -0
  12. data/lib/rubocop/ast/node/case_node.rb +1 -1
  13. data/lib/rubocop/ast/node/ensure_node.rb +1 -1
  14. data/lib/rubocop/ast/node/for_node.rb +1 -1
  15. data/lib/rubocop/ast/node/if_node.rb +1 -1
  16. data/lib/rubocop/ast/node/mixin/parameterized_node.rb +74 -0
  17. data/lib/rubocop/ast/node/or_node.rb +1 -1
  18. data/lib/rubocop/ast/node/pair_node.rb +1 -1
  19. data/lib/rubocop/ast/node/resbody_node.rb +1 -1
  20. data/lib/rubocop/ast/node/send_node.rb +36 -57
  21. data/lib/rubocop/ast/node/super_node.rb +42 -0
  22. data/lib/rubocop/ast/node/until_node.rb +1 -1
  23. data/lib/rubocop/ast/node/when_node.rb +1 -1
  24. data/lib/rubocop/ast/node/while_node.rb +1 -1
  25. data/lib/rubocop/cli.rb +10 -0
  26. data/lib/rubocop/config.rb +23 -7
  27. data/lib/rubocop/config_loader.rb +19 -3
  28. data/lib/rubocop/cop/badge.rb +1 -1
  29. data/lib/rubocop/cop/bundler/duplicated_gem.rb +2 -2
  30. data/lib/rubocop/cop/commissioner.rb +1 -1
  31. data/lib/rubocop/cop/cop.rb +10 -0
  32. data/lib/rubocop/cop/{style → layout}/access_modifier_indentation.rb +33 -3
  33. data/lib/rubocop/cop/{style → layout}/align_array.rb +16 -1
  34. data/lib/rubocop/cop/{style → layout}/align_hash.rb +1 -1
  35. data/lib/rubocop/cop/{style → layout}/align_parameters.rb +29 -1
  36. data/lib/rubocop/cop/{style → layout}/block_end_newline.rb +10 -5
  37. data/lib/rubocop/cop/{style → layout}/case_indentation.rb +64 -1
  38. data/lib/rubocop/cop/{style → layout}/closing_parenthesis_indentation.rb +2 -2
  39. data/lib/rubocop/cop/{style → layout}/comment_indentation.rb +1 -1
  40. data/lib/rubocop/cop/{style → layout}/dot_position.rb +1 -1
  41. data/lib/rubocop/cop/{style → layout}/else_alignment.rb +1 -1
  42. data/lib/rubocop/cop/{style → layout}/empty_line_after_magic_comment.rb +1 -1
  43. data/lib/rubocop/cop/{style → layout}/empty_line_between_defs.rb +1 -1
  44. data/lib/rubocop/cop/{style → layout}/empty_lines.rb +1 -1
  45. data/lib/rubocop/cop/{style → layout}/empty_lines_around_access_modifier.rb +2 -7
  46. data/lib/rubocop/cop/{style → layout}/empty_lines_around_begin_body.rb +1 -1
  47. data/lib/rubocop/cop/{style → layout}/empty_lines_around_block_body.rb +2 -4
  48. data/lib/rubocop/cop/{style → layout}/empty_lines_around_class_body.rb +1 -1
  49. data/lib/rubocop/cop/{style → layout}/empty_lines_around_exception_handling_keywords.rb +1 -1
  50. data/lib/rubocop/cop/{style → layout}/empty_lines_around_method_body.rb +1 -1
  51. data/lib/rubocop/cop/{style → layout}/empty_lines_around_module_body.rb +1 -1
  52. data/lib/rubocop/cop/{style → layout}/end_of_line.rb +1 -1
  53. data/lib/rubocop/cop/{style → layout}/extra_spacing.rb +1 -1
  54. data/lib/rubocop/cop/{style → layout}/first_array_element_line_break.rb +1 -1
  55. data/lib/rubocop/cop/{style → layout}/first_hash_element_line_break.rb +1 -1
  56. data/lib/rubocop/cop/{style → layout}/first_method_argument_line_break.rb +1 -1
  57. data/lib/rubocop/cop/{style → layout}/first_method_parameter_line_break.rb +1 -1
  58. data/lib/rubocop/cop/{style → layout}/first_parameter_indentation.rb +1 -1
  59. data/lib/rubocop/cop/{style → layout}/indent_array.rb +1 -1
  60. data/lib/rubocop/cop/{style → layout}/indent_assignment.rb +1 -1
  61. data/lib/rubocop/cop/{style → layout}/indent_hash.rb +2 -2
  62. data/lib/rubocop/cop/{style → layout}/indent_heredoc.rb +3 -3
  63. data/lib/rubocop/cop/{style → layout}/indentation_consistency.rb +1 -1
  64. data/lib/rubocop/cop/{style → layout}/indentation_width.rb +10 -12
  65. data/lib/rubocop/cop/{style → layout}/initial_indentation.rb +1 -1
  66. data/lib/rubocop/cop/{style → layout}/leading_comment_space.rb +1 -1
  67. data/lib/rubocop/cop/{style → layout}/multiline_array_brace_layout.rb +1 -1
  68. data/lib/rubocop/cop/{style → layout}/multiline_assignment_layout.rb +1 -1
  69. data/lib/rubocop/cop/{style → layout}/multiline_block_layout.rb +21 -36
  70. data/lib/rubocop/cop/{style → layout}/multiline_hash_brace_layout.rb +5 -1
  71. data/lib/rubocop/cop/{style → layout}/multiline_method_call_brace_layout.rb +1 -1
  72. data/lib/rubocop/cop/{style → layout}/multiline_method_call_indentation.rb +3 -3
  73. data/lib/rubocop/cop/{style → layout}/multiline_method_definition_brace_layout.rb +1 -1
  74. data/lib/rubocop/cop/{style → layout}/multiline_operation_indentation.rb +6 -5
  75. data/lib/rubocop/cop/{style → layout}/rescue_ensure_alignment.rb +1 -1
  76. data/lib/rubocop/cop/{style → layout}/space_after_colon.rb +2 -2
  77. data/lib/rubocop/cop/{style → layout}/space_after_comma.rb +2 -2
  78. data/lib/rubocop/cop/{style → layout}/space_after_method_name.rb +1 -1
  79. data/lib/rubocop/cop/{style → layout}/space_after_not.rb +1 -1
  80. data/lib/rubocop/cop/{style → layout}/space_after_semicolon.rb +2 -2
  81. data/lib/rubocop/cop/{style → layout}/space_around_block_parameters.rb +7 -5
  82. data/lib/rubocop/cop/{style → layout}/space_around_equals_in_parameter_default.rb +1 -1
  83. data/lib/rubocop/cop/{style → layout}/space_around_keyword.rb +1 -1
  84. data/lib/rubocop/cop/{style → layout}/space_around_operators.rb +6 -2
  85. data/lib/rubocop/cop/{style → layout}/space_before_block_braces.rb +6 -2
  86. data/lib/rubocop/cop/{style → layout}/space_before_comma.rb +1 -1
  87. data/lib/rubocop/cop/{style → layout}/space_before_comment.rb +1 -1
  88. data/lib/rubocop/cop/{style → layout}/space_before_first_arg.rb +4 -2
  89. data/lib/rubocop/cop/{style → layout}/space_before_semicolon.rb +1 -1
  90. data/lib/rubocop/cop/{style → layout}/space_in_lambda_literal.rb +1 -1
  91. data/lib/rubocop/cop/{style → layout}/space_inside_array_percent_literal.rb +1 -1
  92. data/lib/rubocop/cop/{style → layout}/space_inside_block_braces.rb +3 -4
  93. data/lib/rubocop/cop/{style → layout}/space_inside_brackets.rb +1 -1
  94. data/lib/rubocop/cop/{style → layout}/space_inside_hash_literal_braces.rb +1 -1
  95. data/lib/rubocop/cop/{style → layout}/space_inside_parens.rb +1 -1
  96. data/lib/rubocop/cop/{style → layout}/space_inside_percent_literal_delimiters.rb +8 -7
  97. data/lib/rubocop/cop/{style → layout}/space_inside_range_literal.rb +1 -1
  98. data/lib/rubocop/cop/{style → layout}/space_inside_string_interpolation.rb +1 -1
  99. data/lib/rubocop/cop/{style → layout}/tab.rb +1 -1
  100. data/lib/rubocop/cop/{style → layout}/trailing_blank_lines.rb +1 -1
  101. data/lib/rubocop/cop/{style → layout}/trailing_whitespace.rb +2 -2
  102. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  103. data/lib/rubocop/cop/lint/ambiguous_operator.rb +4 -4
  104. data/lib/rubocop/cop/lint/debugger.rb +0 -15
  105. data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -1
  106. data/lib/rubocop/cop/lint/rescue_type.rb +81 -0
  107. data/lib/rubocop/cop/lint/script_permission.rb +42 -0
  108. data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -1
  109. data/lib/rubocop/cop/message_annotator.rb +23 -13
  110. data/lib/rubocop/cop/metrics/block_length.rb +1 -1
  111. data/lib/rubocop/cop/mixin/array_min_size.rb +59 -0
  112. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +10 -11
  113. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  114. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
  115. data/lib/rubocop/cop/mixin/enforce_superclass.rb +36 -0
  116. data/lib/rubocop/cop/mixin/hash_alignment.rb +1 -1
  117. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +7 -3
  118. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  119. data/lib/rubocop/cop/performance/caller.rb +41 -0
  120. data/lib/rubocop/cop/performance/compare_with_block.rb +60 -14
  121. data/lib/rubocop/cop/performance/double_start_end_with.rb +2 -2
  122. data/lib/rubocop/cop/performance/redundant_merge.rb +2 -0
  123. data/lib/rubocop/cop/rails/action_filter.rb +1 -3
  124. data/lib/rubocop/cop/rails/application_job.rb +32 -0
  125. data/lib/rubocop/cop/rails/application_record.rb +32 -0
  126. data/lib/rubocop/cop/rails/blank.rb +9 -3
  127. data/lib/rubocop/cop/rails/output_safety.rb +59 -15
  128. data/lib/rubocop/cop/rails/present.rb +9 -3
  129. data/lib/rubocop/cop/rails/relative_date_constant.rb +35 -4
  130. data/lib/rubocop/cop/rails/reversible_migration.rb +82 -18
  131. data/lib/rubocop/cop/rails/save_bang.rb +7 -2
  132. data/lib/rubocop/cop/rails/skips_model_validations.rb +7 -0
  133. data/lib/rubocop/cop/registry.rb +4 -3
  134. data/lib/rubocop/cop/security/eval.rb +9 -3
  135. data/lib/rubocop/cop/style/and_or.rb +1 -1
  136. data/lib/rubocop/cop/style/block_delimiters.rb +11 -17
  137. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +1 -1
  138. data/lib/rubocop/cop/style/collection_methods.rb +1 -3
  139. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
  140. data/lib/rubocop/cop/style/copyright.rb +2 -2
  141. data/lib/rubocop/cop/style/documentation_method.rb +1 -1
  142. data/lib/rubocop/cop/style/each_for_simple_loop.rb +2 -1
  143. data/lib/rubocop/cop/style/each_with_object.rb +10 -6
  144. data/lib/rubocop/cop/style/empty_case_condition.rb +2 -2
  145. data/lib/rubocop/cop/style/for.rb +4 -5
  146. data/lib/rubocop/cop/style/format_string.rb +49 -0
  147. data/lib/rubocop/cop/style/format_string_token.rb +141 -0
  148. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  149. data/lib/rubocop/cop/style/identical_conditional_branches.rb +2 -2
  150. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +1 -1
  151. data/lib/rubocop/cop/style/inverse_methods.rb +10 -1
  152. data/lib/rubocop/cop/style/lambda.rb +9 -9
  153. data/lib/rubocop/cop/style/line_end_concatenation.rb +4 -0
  154. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +3 -3
  155. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +1 -2
  156. data/lib/rubocop/cop/style/method_name.rb +8 -2
  157. data/lib/rubocop/cop/style/mixin_grouping.rb +41 -3
  158. data/lib/rubocop/cop/style/multiline_block_chain.rb +7 -11
  159. data/lib/rubocop/cop/style/multiple_comparison.rb +77 -0
  160. data/lib/rubocop/cop/style/next.rb +11 -22
  161. data/lib/rubocop/cop/style/parallel_assignment.rb +10 -19
  162. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -2
  163. data/lib/rubocop/cop/style/self_assignment.rb +4 -0
  164. data/lib/rubocop/cop/style/single_line_block_params.rb +23 -17
  165. data/lib/rubocop/cop/style/symbol_array.rb +24 -13
  166. data/lib/rubocop/cop/style/symbol_proc.rb +4 -0
  167. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  168. data/lib/rubocop/cop/style/unneeded_interpolation.rb +4 -0
  169. data/lib/rubocop/cop/style/word_array.rb +33 -53
  170. data/lib/rubocop/cop/style/yoda_condition.rb +78 -0
  171. data/lib/rubocop/cop/team.rb +1 -14
  172. data/lib/rubocop/cop/util.rb +16 -0
  173. data/lib/rubocop/formatter/simple_text_formatter.rb +0 -11
  174. data/lib/rubocop/node_pattern.rb +52 -52
  175. data/lib/rubocop/options.rb +25 -0
  176. data/lib/rubocop/path_util.rb +17 -1
  177. data/lib/rubocop/result_cache.rb +8 -7
  178. data/lib/rubocop/rspec/expect_offense.rb +167 -0
  179. data/lib/rubocop/rspec/shared_examples.rb +0 -8
  180. data/lib/rubocop/rspec/support.rb +1 -0
  181. data/lib/rubocop/runner.rb +12 -2
  182. data/lib/rubocop/target_finder.rb +5 -0
  183. data/lib/rubocop/version.rb +1 -1
  184. metadata +101 -72
@@ -107,11 +107,16 @@ module RuboCop
107
107
 
108
108
  def persisted_referenced?(assignment)
109
109
  return unless assignment.referenced?
110
+
110
111
  assignment.variable.references.any? do |reference|
111
- reference.node.parent.method?(:persisted?)
112
+ call_to_persisted?(reference.node.parent)
112
113
  end
113
114
  end
114
115
 
116
+ def call_to_persisted?(node)
117
+ node.send_type? && node.method?(:persisted?)
118
+ end
119
+
115
120
  def check_used_in_conditional(node)
116
121
  return false unless conditional?(node)
117
122
 
@@ -130,7 +135,7 @@ module RuboCop
130
135
  end
131
136
 
132
137
  def last_call_of_method?(node)
133
- node.parent && node.parent.children.count == node.sibling_index + 1
138
+ node.parent && node.parent.children.size == node.sibling_index + 1
134
139
  end
135
140
 
136
141
  # Ignore simple assignment or if condition
@@ -22,6 +22,7 @@ module RuboCop
22
22
  #
23
23
  # # good
24
24
  # user.update_attributes(website: 'example.com')
25
+ # FileUtils.touch('file')
25
26
  class SkipsModelValidations < Cop
26
27
  MSG = 'Avoid using `%s` because it skips validations.'.freeze
27
28
 
@@ -36,6 +37,10 @@ module RuboCop
36
37
  update_columns
37
38
  update_counters].freeze
38
39
 
40
+ def_node_matcher :good_touch?, <<-PATTERN
41
+ (send (const nil :FileUtils) :touch ...)
42
+ PATTERN
43
+
39
44
  def on_send(node)
40
45
  return unless blacklist.include?(node.method_name.to_s)
41
46
 
@@ -45,6 +50,8 @@ module RuboCop
45
50
  return
46
51
  end
47
52
 
53
+ return if good_touch?(node)
54
+
48
55
  add_offense(node, :selector)
49
56
  end
50
57
 
@@ -62,17 +62,18 @@ module RuboCop
62
62
  # @example gives back a correctly qualified cop name
63
63
  #
64
64
  # cops = RuboCop::Cop::Cop.all
65
- # cops.qualified_cop_name('Style/IndentArray') # => 'Style/IndentArray'
65
+ # cops.
66
+ # qualified_cop_name('Layout/IndentArray') # => 'Layout/IndentArray'
66
67
  #
67
68
  # @example fixes incorrect namespaces
68
69
  #
69
70
  # cops = RuboCop::Cop::Cop.all
70
- # cops.qualified_cop_name('Lint/IndentArray') # => 'Style/IndentArray'
71
+ # cops.qualified_cop_name('Lint/IndentArray') # => 'Layout/IndentArray'
71
72
  #
72
73
  # @example namespaces bare cop identifiers
73
74
  #
74
75
  # cops = RuboCop::Cop::Cop.all
75
- # cops.qualified_cop_name('IndentArray') # => 'Style/IndentArray'
76
+ # cops.qualified_cop_name('IndentArray') # => 'Layout/IndentArray'
76
77
  #
77
78
  # @example passes back unrecognized cop names
78
79
  #
@@ -3,20 +3,26 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Security
6
- # This cop checks for the use of *Kernel#eval*.
6
+ # This cop checks for the use of `Kernel#eval` and `Binding#eval`.
7
7
  #
8
8
  # @example
9
9
  #
10
10
  # # bad
11
11
  #
12
12
  # eval(something)
13
+ # binding.eval(something)
13
14
  class Eval < Cop
14
15
  MSG = 'The use of `eval` is a serious security risk.'.freeze
15
16
 
16
- def_node_matcher :eval?, '(send nil :eval $!str ...)'
17
+ def_node_matcher :eval?, <<-END
18
+ (send {nil (send nil :binding)} :eval $!str ...)
19
+ END
17
20
 
18
21
  def on_send(node)
19
- eval?(node) { add_offense(node, :selector) }
22
+ eval?(node) do |code|
23
+ return if code.dstr_type? && code.recursive_literal?
24
+ add_offense(node, :selector)
25
+ end
20
26
  end
21
27
  end
22
28
  end
@@ -108,7 +108,7 @@ module RuboCop
108
108
  end
109
109
 
110
110
  def correctable_send?(node)
111
- !node.parenthesized? && node.arguments?
111
+ !node.parenthesized? && !node.method?(:[]) && node.arguments?
112
112
  end
113
113
 
114
114
  def whitespace_before_arg(node)
@@ -71,7 +71,7 @@ module RuboCop
71
71
  def autocorrect(node)
72
72
  return if correction_would_break_code?(node)
73
73
 
74
- if node.loc.begin.is?('{')
74
+ if node.braces?
75
75
  replace_braces_with_do_end(node.loc)
76
76
  else
77
77
  replace_do_end_with_braces(node.loc)
@@ -97,17 +97,18 @@ module RuboCop
97
97
 
98
98
  lambda do |corrector|
99
99
  corrector.insert_after(b, ' ') unless whitespace_after?(b, 2)
100
+
100
101
  corrector.replace(b, '{')
101
102
  corrector.replace(e, '}')
102
103
  end
103
104
  end
104
105
 
105
- def whitespace_before?(node)
106
- node.source_buffer.source[node.begin_pos - 1, 1] =~ /\s/
106
+ def whitespace_before?(range)
107
+ range.source_buffer.source[range.begin_pos - 1, 1] =~ /\s/
107
108
  end
108
109
 
109
- def whitespace_after?(node, length = 1)
110
- node.source_buffer.source[node.begin_pos + length, 1] =~ /\s/
110
+ def whitespace_after?(range, length = 1)
111
+ range.source_buffer.source[range.begin_pos + length, 1] =~ /\s/
111
112
  end
112
113
 
113
114
  def get_blocks(node, &block)
@@ -120,7 +121,7 @@ module RuboCop
120
121
  # A hash which is passed as method argument may have no braces
121
122
  # In that case, one of the K/V pairs could contain a block node
122
123
  # which could change in meaning if do...end replaced {...}
123
- return if node.loc.begin
124
+ return if node.braces?
124
125
  node.each_child_node { |child| get_blocks(child, &block) }
125
126
  when :pair
126
127
  node.each_child_node { |child| get_blocks(child, &block) }
@@ -139,16 +140,13 @@ module RuboCop
139
140
  end
140
141
 
141
142
  def line_count_based_block_style?(node)
142
- block_begin = node.loc.begin.source
143
-
144
- (block_length(node) > 0) ^ (block_begin == '{')
143
+ node.multiline? ^ node.braces?
145
144
  end
146
145
 
147
146
  def semantic_block_style?(node)
148
147
  method_name = node.method_name
149
- block_begin = node.loc.begin.source
150
148
 
151
- if block_begin == '{'
149
+ if node.braces?
152
150
  functional_method?(method_name) || functional_block?(node)
153
151
  else
154
152
  procedural_method?(method_name) || !return_value_used?(node)
@@ -171,13 +169,9 @@ module RuboCop
171
169
  end
172
170
 
173
171
  def correction_would_break_code?(node)
174
- return unless node.loc.begin.is?('do')
175
-
176
- # Converting `obj.method arg do |x| end` to use `{}` would cause
177
- # a syntax error.
178
- send = node.children.first
172
+ return unless node.keywords?
179
173
 
180
- send.arguments? && !send.parenthesized?
174
+ node.send_node.arguments? && !node.send_node.parenthesized?
181
175
  end
182
176
 
183
177
  def ignored_method?(method_name)
@@ -45,7 +45,7 @@ module RuboCop
45
45
  MSG = '%s curly braces around a hash parameter.'.freeze
46
46
 
47
47
  def on_send(node)
48
- return if node.asgn_method_call? || node.operator_method?
48
+ return if node.assignment_method? || node.operator_method?
49
49
 
50
50
  return unless node.arguments? && node.last_argument.hash_type? &&
51
51
  !node.last_argument.empty?
@@ -15,9 +15,7 @@ module RuboCop
15
15
  MSG = 'Prefer `%s` over `%s`.'.freeze
16
16
 
17
17
  def on_block(node)
18
- method, _args, _body = *node
19
-
20
- check_method_node(method)
18
+ check_method_node(node.send_node)
21
19
  end
22
20
 
23
21
  def on_send(node)
@@ -209,7 +209,7 @@ module RuboCop
209
209
  ASSIGNMENT_TYPES = VARIABLE_ASSIGNMENT_TYPES +
210
210
  %i[and_asgn or_asgn op_asgn masgn].freeze
211
211
  LINE_LENGTH = 'Metrics/LineLength'.freeze
212
- INDENTATION_WIDTH = 'Style/IndentationWidth'.freeze
212
+ INDENTATION_WIDTH = 'Layout/IndentationWidth'.freeze
213
213
  ENABLED = 'Enabled'.freeze
214
214
  MAX = 'Max'.freeze
215
215
  SINGLE_LINE_CONDITIONS_ONLY = 'SingleLineConditionsOnly'.freeze
@@ -8,8 +8,8 @@ module RuboCop
8
8
  # The default regexp for an acceptable copyright notice can be found in
9
9
  # config/default.yml. The default can be changed as follows:
10
10
  #
11
- # Style/Copyright:
12
- # Notice: '^Copyright (\(c\) )?2\d{3} Acme Inc'
11
+ # Style/Copyright:
12
+ # Notice: '^Copyright (\(c\) )?2\d{3} Acme Inc'
13
13
  #
14
14
  # This regex string is treated as an unanchored regex. For each file
15
15
  # that RuboCop scans, a comment that matches this regex must be found or
@@ -43,7 +43,7 @@ module RuboCop
43
43
  # end
44
44
  # end
45
45
  #
46
- # # Documenation
46
+ # # Documentation
47
47
  # def foo.bar
48
48
  # puts baz
49
49
  # end
@@ -29,7 +29,8 @@ module RuboCop
29
29
  def on_block(node)
30
30
  return unless offending_each_range(node)
31
31
 
32
- send_node, = *node
32
+ send_node = node.send_node
33
+
33
34
  range = send_node.receiver.source_range.join(send_node.loc.selector)
34
35
 
35
36
  add_offense(node, range)
@@ -38,20 +38,24 @@ module RuboCop
38
38
  end
39
39
  end
40
40
 
41
+ private
42
+
43
+ # rubocop:disable Metrics/AbcSize
41
44
  def autocorrect(node)
42
45
  lambda do |corrector|
43
- method, args, body = *node
44
- corrector.replace(method.loc.selector, 'each_with_object')
45
- first_arg, second_arg = *args
46
+ corrector.replace(node.send_node.loc.selector, 'each_with_object')
47
+
48
+ first_arg, second_arg = *node.arguments
49
+
46
50
  corrector.replace(first_arg.loc.expression, second_arg.source)
47
51
  corrector.replace(second_arg.loc.expression, first_arg.source)
48
52
 
49
- return_value = return_value(body)
53
+ return_value = return_value(node.body)
54
+
50
55
  corrector.remove(return_value.loc.expression)
51
56
  end
52
57
  end
53
-
54
- private
58
+ # rubocop:endable Metrics/AbcSize
55
59
 
56
60
  def simple_method_arg?(method_arg)
57
61
  method_arg && method_arg.basic_literal?
@@ -57,11 +57,11 @@ module RuboCop
57
57
  end
58
58
 
59
59
  def correct_case_when(corrector, case_node, when_nodes)
60
- case_range = case_node.loc.keyword.join(when_nodes.shift.loc.keyword)
60
+ case_range = case_node.loc.keyword.join(when_nodes.first.loc.keyword)
61
61
 
62
62
  corrector.replace(case_range, 'if')
63
63
 
64
- when_nodes.each do |when_node|
64
+ when_nodes[1..-1].each do |when_node|
65
65
  corrector.replace(when_node.loc.keyword, 'elsif')
66
66
  end
67
67
  end
@@ -22,14 +22,13 @@ module RuboCop
22
22
  end
23
23
 
24
24
  def on_block(node)
25
- return if block_length(node).zero?
25
+ return if node.single_line?
26
26
 
27
- method, _args, _body = *node
28
- return unless method.send_type? && method.method?(:each) &&
29
- !method.arguments?
27
+ return unless node.send_node.method?(:each) &&
28
+ !node.send_node.arguments?
30
29
 
31
30
  if style == :for
32
- incorrect_style_detected(method)
31
+ incorrect_style_detected(node.send_node)
33
32
  else
34
33
  correct_style_detected
35
34
  end
@@ -40,6 +40,55 @@ module RuboCop
40
40
  def method_name(style_name)
41
41
  style_name == :percent ? 'String#%' : style_name
42
42
  end
43
+
44
+ def autocorrect(node)
45
+ lambda do |corrector|
46
+ _receiver, detected_method = *node
47
+
48
+ case detected_method
49
+ when :%
50
+ autocorrect_from_percent(corrector, node)
51
+ when :format, :sprintf
52
+ case style
53
+ when :percent
54
+ autocorrect_to_percent(corrector, node)
55
+ when :format, :sprintf
56
+ corrector.replace(node.loc.selector, style.to_s)
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def autocorrect_from_percent(corrector, node)
65
+ receiver, _method, args = *node
66
+ format = receiver.source
67
+ args = if args.array_type? || args.hash_type?
68
+ args.children.map(&:source).join(', ')
69
+ else
70
+ args.source
71
+ end
72
+ corrected = "#{style}(#{format}, #{args})"
73
+ corrector.replace(node.loc.expression, corrected)
74
+ end
75
+
76
+ def autocorrect_to_percent(corrector, node)
77
+ _nil, _method, format, *args = *node
78
+ format = format.source
79
+ args = if args.one?
80
+ arg = args.first
81
+ if arg.hash_type?
82
+ "{ #{arg.source} }"
83
+ else
84
+ arg.source
85
+ end
86
+ else
87
+ "[#{args.map(&:source).join(', ')}]"
88
+ end
89
+ corrected = "#{format} % #{args}"
90
+ corrector.replace(node.loc.expression, corrected)
91
+ end
43
92
  end
44
93
  end
45
94
  end
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Use a consistent style for named format string tokens.
7
+ #
8
+ # @example
9
+ #
10
+ # EnforcedStyle: annotated
11
+ #
12
+ # # bad
13
+ #
14
+ # format('%{greeting}', greeting: 'Hello')
15
+ # format('%s', 'Hello')
16
+ #
17
+ # # good
18
+ #
19
+ # format('%<greeting>s', greeting: 'Hello')
20
+ #
21
+ # @example
22
+ #
23
+ # EnforcedStyle: template
24
+ #
25
+ # # bad
26
+ #
27
+ # format('%<greeting>s', greeting: 'Hello')
28
+ # format('%s', 'Hello')
29
+ #
30
+ # # good
31
+ #
32
+ # format('%{greeting}', greeting: 'Hello')
33
+ class FormatStringToken < Cop
34
+ include ConfigurableEnforcedStyle
35
+
36
+ FIELD_CHARACTERS = Regexp.union(%w[A B E G X a b c d e f g i o p s u x])
37
+
38
+ STYLE_PATTERNS = {
39
+ annotated: /(?<token>%<[^>]+>#{FIELD_CHARACTERS})/,
40
+ template: /(?<token>%\{[^\}]+\})/
41
+ }.freeze
42
+
43
+ TOKEN_PATTERN = Regexp.union(STYLE_PATTERNS.values)
44
+
45
+ def on_str(node)
46
+ return if node.each_ancestor(:xstr).any?
47
+
48
+ tokens(node) do |detected_style, token_range|
49
+ if detected_style == style
50
+ correct_style_detected
51
+ else
52
+ style_detected(detected_style)
53
+ add_offense(node, token_range, message(detected_style))
54
+ end
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def message(detected_style)
61
+ "Prefer #{message_text(style)} over #{message_text(detected_style)}."
62
+ end
63
+
64
+ # rubocop:disable FormatStringToken
65
+ def message_text(style)
66
+ case style
67
+ when :annotated then 'annotated tokens (like `%<foo>s`)'
68
+ when :template then 'template tokens (like `%{foo}`)'
69
+ end
70
+ end
71
+ # rubocop:enable FormatStringToken
72
+
73
+ def tokens(str_node, &block)
74
+ return if str_node.source == '__FILE__'
75
+
76
+ token_ranges(str_contents(str_node.loc), &block)
77
+ end
78
+
79
+ def str_contents(source_map)
80
+ if source_map.is_a?(Parser::Source::Map::Heredoc)
81
+ source_map.heredoc_body
82
+ elsif source_map.begin
83
+ slice_source(
84
+ source_map.expression,
85
+ source_map.expression.begin_pos + 1,
86
+ source_map.expression.end_pos - 1
87
+ )
88
+ else
89
+ source_map.expression
90
+ end
91
+ end
92
+
93
+ def token_ranges(contents)
94
+ while (offending_match = match_token(contents))
95
+ detected_style, *range = *offending_match
96
+ token, contents = split_token(contents, *range)
97
+ yield(detected_style, token)
98
+ end
99
+ end
100
+
101
+ def match_token(source_range)
102
+ supported_styles.each do |style_name|
103
+ pattern = STYLE_PATTERNS.fetch(style_name)
104
+ match = source_range.source.match(pattern)
105
+ next unless match
106
+
107
+ return [style_name, match.begin(:token), match.end(:token)]
108
+ end
109
+
110
+ nil
111
+ end
112
+
113
+ def split_token(source_range, match_begin, match_end)
114
+ token =
115
+ slice_source(
116
+ source_range,
117
+ source_range.begin_pos + match_begin,
118
+ source_range.begin_pos + match_end
119
+ )
120
+
121
+ remainder =
122
+ slice_source(
123
+ source_range,
124
+ source_range.begin_pos + match_end,
125
+ source_range.end_pos
126
+ )
127
+
128
+ [token, remainder]
129
+ end
130
+
131
+ def slice_source(source_range, new_begin, new_end)
132
+ Parser::Source::Range.new(
133
+ source_range.source_buffer,
134
+ new_begin,
135
+ new_end
136
+ )
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end