rubocop 0.31.0 → 0.35.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 (177) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +315 -0
  3. data/README.md +199 -38
  4. data/config/default.yml +91 -12
  5. data/config/disabled.yml +45 -4
  6. data/config/enabled.yml +107 -9
  7. data/lib/rubocop/ast_node.rb +48 -0
  8. data/lib/rubocop/cli.rb +11 -1
  9. data/lib/rubocop/comment_config.rb +4 -1
  10. data/lib/rubocop/config.rb +26 -17
  11. data/lib/rubocop/config_loader.rb +61 -14
  12. data/lib/rubocop/cop/commissioner.rb +7 -12
  13. data/lib/rubocop/cop/cop.rb +43 -20
  14. data/lib/rubocop/cop/lint/block_alignment.rb +1 -1
  15. data/lib/rubocop/cop/lint/circular_argument_reference.rb +69 -0
  16. data/lib/rubocop/cop/lint/debugger.rb +9 -48
  17. data/lib/rubocop/cop/lint/def_end_alignment.rb +8 -4
  18. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +42 -23
  19. data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -2
  20. data/lib/rubocop/cop/lint/duplicated_key.rb +37 -0
  21. data/lib/rubocop/cop/lint/end_alignment.rb +33 -13
  22. data/lib/rubocop/cop/lint/eval.rb +6 -2
  23. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +175 -0
  24. data/lib/rubocop/cop/lint/literal_in_condition.rb +0 -5
  25. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +10 -0
  26. data/lib/rubocop/cop/lint/nested_method_definition.rb +31 -0
  27. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +19 -1
  28. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
  29. data/lib/rubocop/cop/lint/space_before_first_arg.rb +1 -1
  30. data/lib/rubocop/cop/lint/unneeded_disable.rb +72 -0
  31. data/lib/rubocop/cop/lint/unused_block_argument.rb +6 -0
  32. data/lib/rubocop/cop/lint/unused_method_argument.rb +8 -0
  33. data/lib/rubocop/cop/metrics/abc_size.rb +17 -6
  34. data/lib/rubocop/cop/metrics/class_length.rb +1 -1
  35. data/lib/rubocop/cop/metrics/method_length.rb +1 -3
  36. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  37. data/lib/rubocop/cop/metrics/parameter_lists.rb +1 -1
  38. data/lib/rubocop/cop/mixin/access_modifier_node.rb +1 -1
  39. data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -2
  40. data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +28 -4
  41. data/lib/rubocop/cop/mixin/autocorrect_unless_changing_ast.rb +26 -3
  42. data/lib/rubocop/cop/mixin/check_assignment.rb +2 -3
  43. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +59 -12
  44. data/lib/rubocop/cop/mixin/configurable_max.rb +1 -1
  45. data/lib/rubocop/cop/mixin/configurable_naming.rb +14 -3
  46. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -3
  47. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +10 -1
  48. data/lib/rubocop/cop/mixin/first_element_line_break.rb +41 -0
  49. data/lib/rubocop/cop/mixin/if_node.rb +10 -0
  50. data/lib/rubocop/cop/mixin/method_preference.rb +28 -0
  51. data/lib/rubocop/cop/mixin/negative_conditional.rb +1 -1
  52. data/lib/rubocop/cop/mixin/on_method_def.rb +4 -5
  53. data/lib/rubocop/cop/mixin/safe_assignment.rb +3 -14
  54. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +8 -1
  55. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +8 -1
  56. data/lib/rubocop/cop/mixin/statement_modifier.rb +4 -7
  57. data/lib/rubocop/cop/mixin/string_help.rb +1 -1
  58. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
  59. data/lib/rubocop/cop/mixin/surrounding_space.rb +5 -4
  60. data/lib/rubocop/cop/offense.rb +16 -3
  61. data/lib/rubocop/cop/performance/case_when_splat.rb +160 -0
  62. data/lib/rubocop/cop/performance/count.rb +35 -30
  63. data/lib/rubocop/cop/performance/detect.rb +16 -3
  64. data/lib/rubocop/cop/performance/fixed_size.rb +50 -0
  65. data/lib/rubocop/cop/performance/flat_map.rb +3 -3
  66. data/lib/rubocop/cop/performance/sample.rb +103 -59
  67. data/lib/rubocop/cop/performance/size.rb +2 -1
  68. data/lib/rubocop/cop/performance/string_replacement.rb +187 -0
  69. data/lib/rubocop/cop/rails/action_filter.rb +31 -5
  70. data/lib/rubocop/cop/rails/date.rb +15 -14
  71. data/lib/rubocop/cop/rails/pluralization_grammar.rb +97 -0
  72. data/lib/rubocop/cop/rails/read_write_attribute.rb +1 -1
  73. data/lib/rubocop/cop/rails/time_zone.rb +46 -18
  74. data/lib/rubocop/cop/style/alias.rb +1 -0
  75. data/lib/rubocop/cop/style/align_hash.rb +8 -15
  76. data/lib/rubocop/cop/style/align_parameters.rb +19 -7
  77. data/lib/rubocop/cop/style/and_or.rb +42 -13
  78. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +2 -1
  79. data/lib/rubocop/cop/style/block_comments.rb +4 -2
  80. data/lib/rubocop/cop/style/block_delimiters.rb +69 -24
  81. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +40 -12
  82. data/lib/rubocop/cop/style/case_indentation.rb +18 -4
  83. data/lib/rubocop/cop/style/collection_methods.rb +2 -20
  84. data/lib/rubocop/cop/style/command_literal.rb +2 -10
  85. data/lib/rubocop/cop/style/comment_annotation.rb +29 -8
  86. data/lib/rubocop/cop/style/copyright.rb +5 -3
  87. data/lib/rubocop/cop/style/documentation.rb +21 -12
  88. data/lib/rubocop/cop/style/dot_position.rb +6 -0
  89. data/lib/rubocop/cop/style/double_negation.rb +4 -15
  90. data/lib/rubocop/cop/style/each_with_object.rb +17 -4
  91. data/lib/rubocop/cop/style/else_alignment.rb +2 -1
  92. data/lib/rubocop/cop/style/empty_else.rb +25 -0
  93. data/lib/rubocop/cop/style/empty_line_between_defs.rb +39 -14
  94. data/lib/rubocop/cop/style/encoding.rb +10 -4
  95. data/lib/rubocop/cop/style/extra_spacing.rb +126 -5
  96. data/lib/rubocop/cop/style/first_array_element_line_break.rb +41 -0
  97. data/lib/rubocop/cop/style/first_hash_element_line_break.rb +35 -0
  98. data/lib/rubocop/cop/style/first_method_argument_line_break.rb +37 -0
  99. data/lib/rubocop/cop/style/first_method_parameter_line_break.rb +42 -0
  100. data/lib/rubocop/cop/style/first_parameter_indentation.rb +5 -3
  101. data/lib/rubocop/cop/style/for.rb +2 -1
  102. data/lib/rubocop/cop/style/hash_syntax.rb +5 -0
  103. data/lib/rubocop/cop/style/if_unless_modifier.rb +32 -5
  104. data/lib/rubocop/cop/style/indent_hash.rb +67 -37
  105. data/lib/rubocop/cop/style/indentation_width.rb +36 -10
  106. data/lib/rubocop/cop/style/initial_indentation.rb +37 -0
  107. data/lib/rubocop/cop/style/leading_comment_space.rb +3 -2
  108. data/lib/rubocop/cop/style/method_call_parentheses.rb +28 -1
  109. data/lib/rubocop/cop/style/method_def_parentheses.rb +10 -7
  110. data/lib/rubocop/cop/style/multiline_operation_indentation.rb +21 -24
  111. data/lib/rubocop/cop/style/mutable_constant.rb +35 -0
  112. data/lib/rubocop/cop/style/nested_modifier.rb +97 -0
  113. data/lib/rubocop/cop/style/next.rb +50 -15
  114. data/lib/rubocop/cop/style/non_nil_check.rb +12 -8
  115. data/lib/rubocop/cop/style/one_line_conditional.rb +8 -4
  116. data/lib/rubocop/cop/style/option_hash.rb +64 -0
  117. data/lib/rubocop/cop/style/optional_arguments.rb +49 -0
  118. data/lib/rubocop/cop/style/parallel_assignment.rb +218 -0
  119. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +3 -66
  120. data/lib/rubocop/cop/style/predicate_name.rb +7 -2
  121. data/lib/rubocop/cop/style/redundant_begin.rb +2 -13
  122. data/lib/rubocop/cop/style/redundant_freeze.rb +37 -0
  123. data/lib/rubocop/cop/style/redundant_return.rb +32 -3
  124. data/lib/rubocop/cop/style/regexp_literal.rb +2 -10
  125. data/lib/rubocop/cop/style/rescue_ensure_alignment.rb +81 -0
  126. data/lib/rubocop/cop/style/rescue_modifier.rb +30 -22
  127. data/lib/rubocop/cop/style/send.rb +18 -0
  128. data/lib/rubocop/cop/style/signal_exception.rb +24 -11
  129. data/lib/rubocop/cop/style/single_line_methods.rb +8 -9
  130. data/lib/rubocop/cop/style/single_space_before_first_arg.rb +1 -1
  131. data/lib/rubocop/cop/style/space_around_operators.rb +2 -0
  132. data/lib/rubocop/cop/style/space_inside_string_interpolation.rb +61 -0
  133. data/lib/rubocop/cop/style/special_global_vars.rb +4 -2
  134. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +108 -0
  135. data/lib/rubocop/cop/style/string_methods.rb +32 -0
  136. data/lib/rubocop/cop/style/struct_inheritance.rb +11 -10
  137. data/lib/rubocop/cop/style/symbol_literal.rb +1 -1
  138. data/lib/rubocop/cop/style/symbol_proc.rb +62 -13
  139. data/lib/rubocop/cop/style/trailing_blank_lines.rb +9 -1
  140. data/lib/rubocop/cop/style/trailing_comma.rb +17 -7
  141. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +23 -2
  142. data/lib/rubocop/cop/style/trivial_accessors.rb +10 -1
  143. data/lib/rubocop/cop/style/unneeded_percent_q.rb +31 -20
  144. data/lib/rubocop/cop/style/variable_name.rb +5 -0
  145. data/lib/rubocop/cop/style/while_until_do.rb +1 -1
  146. data/lib/rubocop/cop/style/word_array.rb +15 -2
  147. data/lib/rubocop/cop/team.rb +25 -5
  148. data/lib/rubocop/cop/util.rb +7 -2
  149. data/lib/rubocop/cop/variable_force/locatable.rb +6 -6
  150. data/lib/rubocop/cop/variable_force.rb +10 -10
  151. data/lib/rubocop/formatter/base_formatter.rb +1 -1
  152. data/lib/rubocop/formatter/disabled_config_formatter.rb +70 -8
  153. data/lib/rubocop/formatter/formatter_set.rb +27 -1
  154. data/lib/rubocop/formatter/progress_formatter.rb +10 -2
  155. data/lib/rubocop/formatter/simple_text_formatter.rb +1 -1
  156. data/lib/rubocop/node_pattern.rb +390 -0
  157. data/lib/rubocop/options.rb +148 -81
  158. data/lib/rubocop/processed_source.rb +7 -2
  159. data/lib/rubocop/rake_task.rb +1 -1
  160. data/lib/rubocop/remote_config.rb +60 -0
  161. data/lib/rubocop/result_cache.rb +123 -0
  162. data/lib/rubocop/runner.rb +85 -22
  163. data/lib/rubocop/target_finder.rb +4 -4
  164. data/lib/rubocop/token.rb +2 -1
  165. data/lib/rubocop/version.rb +1 -1
  166. data/lib/rubocop/warning.rb +11 -0
  167. data/lib/rubocop.rb +32 -3
  168. data/relnotes/v0.32.0.md +139 -0
  169. data/relnotes/v0.32.1.md +122 -0
  170. data/relnotes/v0.33.0.md +157 -0
  171. data/relnotes/v0.34.0.md +182 -0
  172. data/relnotes/v0.34.1.md +129 -0
  173. data/relnotes/v0.34.2.md +139 -0
  174. data/relnotes/v0.35.0.md +210 -0
  175. data/rubocop.gemspec +4 -4
  176. metadata +50 -12
  177. data/lib/rubocop/cop/performance/parallel_assignment.rb +0 -79
@@ -30,7 +30,7 @@ module RuboCop
30
30
  end
31
31
 
32
32
  callback_methods.each do |callback|
33
- class_eval <<-EOS
33
+ class_eval <<-EOS, __FILE__, __LINE__
34
34
  def #{callback}(node)
35
35
  @cops.each do |cop|
36
36
  next unless cop.respond_to?(:#{callback})
@@ -46,15 +46,12 @@ module RuboCop
46
46
 
47
47
  def investigate(processed_source)
48
48
  reset_errors
49
+ remove_irrelevant_cops(processed_source.buffer.name)
49
50
  prepare(processed_source)
50
51
  invoke_custom_processing(@cops, processed_source)
51
52
  invoke_custom_processing(@forces, processed_source)
52
53
  process(processed_source.ast) if processed_source.ast
53
- @cops.each_with_object([]) do |cop, offenses|
54
- filename = processed_source.buffer.name
55
- # ignore files that are of no interest to the cop in question
56
- offenses.concat(cop.offenses) if cop.relevant_file?(filename)
57
- end
54
+ @cops.flat_map(&:offenses)
58
55
  end
59
56
 
60
57
  private
@@ -63,6 +60,10 @@ module RuboCop
63
60
  @errors = Hash.new { |hash, k| hash[k] = [] }
64
61
  end
65
62
 
63
+ def remove_irrelevant_cops(filename)
64
+ @cops.reject! { |cop| cop.excluded_file?(filename) }
65
+ end
66
+
66
67
  # TODO: Bad design.
67
68
  def prepare(processed_source)
68
69
  @cops.each { |cop| cop.processed_source = processed_source }
@@ -76,12 +77,6 @@ module RuboCop
76
77
  cops_or_forces.each do |cop|
77
78
  next unless cop.respond_to?(:investigate)
78
79
 
79
- if cop.respond_to?(:relevant_file?)
80
- # ignore files that are of no interest to the cop in question
81
- filename = processed_source.buffer.name
82
- next unless cop.relevant_file?(filename)
83
- end
84
-
85
80
  with_cop_error_handling(cop) do
86
81
  cop.investigate(processed_source)
87
82
  end
@@ -49,7 +49,7 @@ module RuboCop
49
49
  #
50
50
  # The Cop class is meant to be extended.
51
51
  #
52
- # Cops track offenses and can autocorrect them of the fly.
52
+ # Cops track offenses and can autocorrect them on the fly.
53
53
  #
54
54
  # A commissioner object is responsible for traversing the AST and invoking
55
55
  # the specific callbacks on each cop.
@@ -66,6 +66,7 @@ module RuboCop
66
66
  # end
67
67
  class Cop
68
68
  extend AST::Sexp
69
+ extend NodePattern::Macros
69
70
  include Util
70
71
  include IgnoredNode
71
72
  include AutocorrectLogic
@@ -133,11 +134,16 @@ module RuboCop
133
134
  end
134
135
 
135
136
  def display_style_guide?
136
- style_guide_url &&
137
+ (style_guide_url || reference_url) &&
137
138
  (@options[:display_style_guide] ||
138
139
  config['AllCops'] && config['AllCops']['DisplayStyleGuide'])
139
140
  end
140
141
 
142
+ def extra_details?
143
+ @options[:extra_details] ||
144
+ config['AllCops'] && config['AllCops']['ExtraDetails']
145
+ end
146
+
141
147
  # Returns true if the cop name or the cop namespace matches any of the
142
148
  # given names.
143
149
  def self.match?(given_names)
@@ -154,34 +160,33 @@ module RuboCop
154
160
  def add_offense(node, loc, message = nil, severity = nil)
155
161
  location = loc.is_a?(Symbol) ? node.loc.send(loc) : loc
156
162
 
157
- return unless enabled_line?(location.line)
158
-
159
163
  # Don't include the same location twice for one cop.
160
- return if @offenses.find { |o| o.location == location }
164
+ return if @offenses.any? { |o| o.location == location }
161
165
 
162
166
  severity = custom_severity || severity || default_severity
163
167
 
164
168
  message ||= message(node)
165
169
  message = annotate_message(message)
166
170
 
167
- corrected = correct(node)
171
+ status = enabled_line?(location.line) ? correct(node) : :disabled
168
172
 
169
- @offenses << Offense.new(severity, location, message, name, corrected)
170
- yield if block_given?
173
+ @offenses << Offense.new(severity, location, message, name, status)
174
+ yield if block_given? && status != :disabled
171
175
  end
172
176
 
173
177
  def correct(node)
174
- return nil unless support_autocorrect?
175
- return false unless autocorrect?
178
+ return :unsupported unless support_autocorrect?
179
+ return :uncorrected unless autocorrect?
176
180
 
177
181
  correction = autocorrect(node)
178
- return false unless correction
182
+ return :uncorrected unless correction
179
183
  @corrections << correction
180
- true
184
+ :corrected
181
185
  end
182
186
 
183
187
  def config_to_allow_offenses
184
- Formatter::DisabledConfigFormatter.config_to_allow_offenses[cop_name]
188
+ Formatter::DisabledConfigFormatter
189
+ .config_to_allow_offenses[cop_name] ||= {}
185
190
  end
186
191
 
187
192
  def config_to_allow_offenses=(hash)
@@ -200,21 +205,39 @@ module RuboCop
200
205
  !file_name_matches_any?(file, 'Exclude', false)
201
206
  end
202
207
 
208
+ def excluded_file?(file)
209
+ !relevant_file?(file)
210
+ end
211
+
203
212
  def style_guide_url
204
- url = cop_config && cop_config['StyleGuide']
213
+ url = cop_config['StyleGuide']
205
214
  (url.nil? || url.empty?) ? nil : url
206
215
  end
207
216
 
217
+ def reference_url
218
+ url = cop_config['Reference']
219
+ (url.nil? || url.empty?) ? nil : url
220
+ end
221
+
222
+ def details
223
+ details = cop_config && cop_config['Details']
224
+ (details.nil? || details.empty?) ? nil : details
225
+ end
226
+
208
227
  private
209
228
 
210
229
  def annotate_message(message)
211
230
  message = "#{name}: #{message}" if display_cop_names?
212
- message = "#{message} (#{style_guide_url})" if display_style_guide?
231
+ message += " #{details}" if extra_details?
232
+ if display_style_guide?
233
+ links = [style_guide_url, reference_url].compact.join(', ')
234
+ message = "#{message} (#{links})"
235
+ end
213
236
  message
214
237
  end
215
238
 
216
239
  def file_name_matches_any?(file, parameter, default_result)
217
- patterns = cop_config && cop_config[parameter]
240
+ patterns = cop_config[parameter]
218
241
  return default_result unless patterns
219
242
  path = nil
220
243
  patterns.any? do |pattern|
@@ -237,15 +260,15 @@ module RuboCop
237
260
  end
238
261
 
239
262
  def custom_severity
240
- severity = cop_config && cop_config['Severity']
263
+ severity = cop_config['Severity']
241
264
  return unless severity
242
265
 
243
266
  if Severity::NAMES.include?(severity.to_sym)
244
267
  severity.to_sym
245
268
  else
246
- warn("Warning: Invalid severity '#{severity}'. " +
247
- "Valid severities are #{Severity::NAMES.join(', ')}."
248
- .color(:red))
269
+ message = "Warning: Invalid severity '#{severity}'. " \
270
+ "Valid severities are #{Severity::NAMES.join(', ')}."
271
+ warn(Rainbow(message).red)
249
272
  end
250
273
  end
251
274
  end
@@ -14,7 +14,7 @@ module RuboCop
14
14
  class BlockAlignment < Cop
15
15
  include CheckAssignment
16
16
 
17
- MSG = '`end` at %d, %d is not aligned with `%s` at %d, %d%s'
17
+ MSG = '`end` at %d, %d is not aligned with `%s` at %d, %d%s.'
18
18
 
19
19
  def on_block(node)
20
20
  return if ignored_node?(node)
@@ -0,0 +1,69 @@
1
+ # encoding: utf-8
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop checks for circular argument references in optional keyword
7
+ # arguments and optional ordinal arguments.
8
+ #
9
+ # This cop mirrors a warning produced by MRI since 2.2.
10
+ #
11
+ # @example
12
+ # # bad
13
+ # def bake(pie: pie)
14
+ # pie.heat_up
15
+ # end
16
+ #
17
+ # # good
18
+ # def bake(pie:)
19
+ # pie.refrigerate
20
+ # end
21
+ #
22
+ # # good
23
+ # def bake(pie: self.pie)
24
+ # pie.feed_to(user)
25
+ # end
26
+ #
27
+ # # bad
28
+ # def cook(dry_ingredients = dry_ingredients)
29
+ # dry_ingredients.reduce(&:+)
30
+ # end
31
+ #
32
+ # # good
33
+ # def cook(dry_ingredients = self.dry_ingredients)
34
+ # dry_ingredients.combine
35
+ # end
36
+ class CircularArgumentReference < Cop
37
+ MSG = 'Circular argument reference - `%s`.'
38
+
39
+ def on_kwoptarg(node)
40
+ check_for_circular_argument_references(*node)
41
+ end
42
+
43
+ def on_optarg(node)
44
+ check_for_circular_argument_references(*node)
45
+ end
46
+
47
+ private
48
+
49
+ def check_for_circular_argument_references(arg_name, arg_value)
50
+ case arg_value.type
51
+ when :send
52
+ # Ruby 2.0 will have type send every time, and "send nil" if it is
53
+ # calling itself with a specified "self" receiver
54
+ receiver, name = *arg_value
55
+ return unless name == arg_name && receiver.nil?
56
+ when :lvar
57
+ # Ruby 2.2.2 will have type lvar if it is calling its own method
58
+ # without a specified "self"
59
+ return unless arg_value.to_a == [arg_name]
60
+ else
61
+ return
62
+ end
63
+
64
+ add_offense(arg_value, :expression, format(MSG, arg_name))
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -7,56 +7,17 @@ module RuboCop
7
7
  class Debugger < Cop
8
8
  MSG = 'Remove debugger entry point `%s`.'
9
9
 
10
- # debugger call node
11
- #
12
- # (send nil :debugger)
13
- DEBUGGER_NODE = s(:send, nil, :debugger)
14
-
15
- # byebug call node
16
- #
17
- # (send nil :byebug)
18
- BYEBUG_NODE = s(:send, nil, :byebug)
19
-
20
- # binding.pry node
21
- #
22
- # (send
23
- # (send nil :binding) :pry)
24
- PRY_NODE = s(:send, s(:send, nil, :binding), :pry)
25
-
26
- # binding.remote_pry node
27
- #
28
- # (send
29
- # (send nil :binding) :remote_pry)
30
- REMOTE_PRY_NODE = s(:send, s(:send, nil, :binding), :remote_pry)
31
-
32
- # binding.pry_remote node
33
- #
34
- # (send
35
- # (send nil :binding) :pry_remote)
36
- PRY_REMOTE_NODE = s(:send, s(:send, nil, :binding), :pry_remote)
37
-
38
- # save_and_open_page
39
- #
40
- # (send nil :save_and_open_page)
41
- CAPYBARA_SAVE_PAGE = s(:send, nil, :save_and_open_page)
42
-
43
- # save_and_open_screenshot
44
- #
45
- # (send nil :save_and_open_screenshot)
46
- CAPYBARA_SAVE_SCREENSHOT = s(:send, nil, :save_and_open_screenshot)
47
-
48
- DEBUGGER_NODES = [
49
- DEBUGGER_NODE,
50
- BYEBUG_NODE,
51
- PRY_NODE,
52
- REMOTE_PRY_NODE,
53
- PRY_REMOTE_NODE,
54
- CAPYBARA_SAVE_PAGE,
55
- CAPYBARA_SAVE_SCREENSHOT
56
- ]
10
+ def_node_matcher :debugger_call?,
11
+ '{(send nil {:debugger :byebug} ...)
12
+ (send (send nil :binding)
13
+ {:pry :remote_pry :pry_remote} ...)
14
+ (send (const nil :Pry) :rescue ...)
15
+ (send nil {:save_and_open_page
16
+ :save_and_open_screenshot
17
+ :save_screenshot} ...)}'
57
18
 
58
19
  def on_send(node)
59
- return unless DEBUGGER_NODES.include?(node)
20
+ return unless debugger_call?(node)
60
21
  add_offense(node,
61
22
  :expression,
62
23
  format(MSG, node.loc.expression.source))
@@ -20,7 +20,7 @@ module RuboCop
20
20
  include OnMethodDef
21
21
  include EndKeywordAlignment
22
22
 
23
- MSG = '`end` at %d, %d is not aligned with `%s` at %d, %d'
23
+ MSG = '`end` at %d, %d is not aligned with `%s` at %d, %d.'
24
24
 
25
25
  def on_method_def(node, _method_name, _args, _body)
26
26
  check_offset_of_node(node)
@@ -28,8 +28,8 @@ module RuboCop
28
28
 
29
29
  def on_send(node)
30
30
  receiver, method_name, *args = *node
31
- return unless visibility_and_def_on_same_line?(receiver, method_name,
32
- args)
31
+ return unless modifier_and_def_on_same_line?(receiver, method_name,
32
+ args)
33
33
 
34
34
  method_def = args.first
35
35
  if style == :start_of_line
@@ -49,7 +49,11 @@ module RuboCop
49
49
  private
50
50
 
51
51
  def autocorrect(node)
52
- align(node, style == :start_of_line ? node.ancestors.first : node)
52
+ if style == :start_of_line && node.parent && node.parent.send_type?
53
+ align(node, node.parent)
54
+ else
55
+ align(node, node)
56
+ end
53
57
  end
54
58
  end
55
59
  end
@@ -5,22 +5,36 @@ module RuboCop
5
5
  module Lint
6
6
  # This cop checks for uses of the deprecated class method usages.
7
7
  class DeprecatedClassMethods < Cop
8
- include AST::Sexp
8
+ # Inner class to DeprecatedClassMethods.
9
+ # This class exists to add abstraction and clean naming to the
10
+ # objects that are going to be operated on.
11
+ class DeprecatedClassMethod
12
+ include AST::Sexp
9
13
 
10
- MSG = '`%s` is deprecated in favor of `%s`.'
14
+ attr_reader :class_constant, :deprecated_method, :replacement_method
11
15
 
12
- DEPRECATED_METHODS = [
13
- [:File, :exists?, :exist?],
14
- [:Dir, :exists?, :exist?]
15
- ]
16
+ def initialize(class_constant, deprecated_method, replacement_method)
17
+ @class_constant = class_constant
18
+ @deprecated_method = deprecated_method
19
+ @replacement_method = replacement_method
20
+ end
16
21
 
17
- def on_send(node)
18
- receiver, method_name, *_args = *node
22
+ def class_nodes
23
+ @class_nodes ||= [
24
+ s(:const, nil, class_constant),
25
+ s(:const, s(:cbase), class_constant)
26
+ ]
27
+ end
28
+ end
19
29
 
20
- DEPRECATED_METHODS.each do |data|
21
- next unless class_nodes(data).include?(receiver)
22
- next unless method_name == data[1]
30
+ MSG = '`%s` is deprecated in favor of `%s`.'
31
+ DEPRECATED_METHODS_OBJECT = [
32
+ DeprecatedClassMethod.new(:File, :exists?, :exist?),
33
+ DeprecatedClassMethod.new(:Dir, :exists?, :exist?)
34
+ ]
23
35
 
36
+ def on_send(node)
37
+ check(node) do |data|
24
38
  add_offense(node, :selector,
25
39
  format(MSG,
26
40
  deprecated_method(data),
@@ -30,31 +44,36 @@ module RuboCop
30
44
 
31
45
  def autocorrect(node)
32
46
  lambda do |corrector|
33
- receiver, method_name, *_args = *node
34
-
35
- DEPRECATED_METHODS.each do |data|
36
- next unless class_nodes(data).include?(receiver)
37
- next unless method_name == data[1]
38
-
47
+ check(node) do |data|
39
48
  corrector.replace(node.loc.selector,
40
- data[2].to_s)
49
+ data.replacement_method.to_s)
41
50
  end
42
51
  end
43
52
  end
44
53
 
45
54
  private
46
55
 
47
- def class_nodes(data)
48
- [s(:const, nil, data[0]),
49
- s(:const, s(:cbase), data[0])]
56
+ def check(node, &block)
57
+ receiver, method_name, *_args = *node
58
+
59
+ DEPRECATED_METHODS_OBJECT.each do |data|
60
+ next unless data.class_nodes.include?(receiver)
61
+ next unless method_name == data.deprecated_method
62
+
63
+ block.call(data)
64
+ end
50
65
  end
51
66
 
52
67
  def deprecated_method(data)
53
- format('%s.%s', data[0], data[1])
68
+ method_call(data.class_constant, data.deprecated_method)
54
69
  end
55
70
 
56
71
  def replacement_method(data)
57
- format('%s.%s', data[0], data[2])
72
+ method_call(data.class_constant, data.replacement_method)
73
+ end
74
+
75
+ def method_call(class_constant, method)
76
+ format('%s.%s', class_constant, method)
58
77
  end
59
78
  end
60
79
  end
@@ -65,7 +65,7 @@ module RuboCop
65
65
 
66
66
  def method_names(body)
67
67
  body.child_nodes.map do |node|
68
- _receiver, node, body = *node if node.send_type?
68
+ _receiver, node, body = *node if node.send_type?
69
69
 
70
70
  if node.is_a? Symbol
71
71
  next if body.nil?
@@ -76,7 +76,7 @@ module RuboCop
76
76
  method, _args, _body = *node
77
77
  elsif node.defs_type?
78
78
  _receiver, method = *node
79
- method = "self.#{ method }"
79
+ method = "self.#{method}"
80
80
  end
81
81
 
82
82
  method ? [method, node] : nil
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop checks for duplicated keys in hash literals.
7
+ #
8
+ # This cop mirrors a warning in Ruby 2.2.
9
+ #
10
+ # @example
11
+ # hash = { food: 'apple', food: 'orange' }
12
+ class DuplicatedKey < Cop
13
+ MSG = 'Duplicated key in hash literal.'
14
+
15
+ LITERALS = [:sym, :str, :float, :int]
16
+
17
+ def on_hash(node)
18
+ keys = []
19
+
20
+ hash_pairs = *node
21
+ hash_pairs.each do |pair|
22
+ key, _value = *pair
23
+ if keys.include?(key) && LITERALS.include?(key.type)
24
+ add_offense(key, :expression)
25
+ elsif keys.include?(key) && key.type == :array
26
+ key.children.each do |child|
27
+ return false unless LITERALS.include?(child.type)
28
+ end
29
+ add_offense(key, :expression)
30
+ end
31
+ keys << key
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -40,6 +40,14 @@ module RuboCop
40
40
  check_offset_of_node(node)
41
41
  end
42
42
 
43
+ def on_case(node)
44
+ if argument_case?(node)
45
+ return check_alignment(node.ancestors.first, node)
46
+ end
47
+
48
+ check_offset_of_node(node)
49
+ end
50
+
43
51
  private
44
52
 
45
53
  def check_assignment(node, rhs)
@@ -50,31 +58,43 @@ module RuboCop
50
58
 
51
59
  return unless rhs
52
60
 
53
- return unless [:if, :while, :until].include?(rhs.type)
61
+ return unless [:if, :while, :until, :case].include?(rhs.type)
54
62
  return if ternary_op?(rhs)
55
63
 
56
- expr = node.loc.expression
57
- if style == :variable && !line_break_before_keyword?(expr, rhs)
64
+ check_alignment(node, rhs)
65
+ end
66
+
67
+ def check_alignment(outer_node, inner_node)
68
+ expr = outer_node.loc.expression
69
+ if variable_alignment?(expr, inner_node, style)
58
70
  range = Parser::Source::Range.new(expr.source_buffer,
59
71
  expr.begin_pos,
60
- rhs.loc.keyword.end_pos)
61
- offset = rhs.loc.keyword.column - node.loc.expression.column
72
+ inner_node.loc.keyword.end_pos)
73
+ offset =
74
+ inner_node.loc.keyword.column - outer_node.loc.expression.column
62
75
  else
63
- range = rhs.loc.keyword
76
+ range = inner_node.loc.keyword
64
77
  offset = 0
65
78
  end
66
79
 
67
- check_offset(rhs, range.source, offset)
68
- ignore_node(rhs) # Don't check again.
80
+ check_offset(inner_node, range.source, offset)
81
+ ignore_node(inner_node) # Don't check again.
69
82
  end
70
83
 
71
- def line_break_before_keyword?(whole_expression, rhs)
72
- rhs.loc.keyword.line > whole_expression.line
84
+ def autocorrect(node)
85
+ align(node, alignment_node(node))
73
86
  end
74
87
 
75
- def autocorrect(node)
76
- align(node,
77
- style == :variable ? node.each_ancestor(:lvasgn).first : node)
88
+ def alignment_node(node)
89
+ return node unless style == :variable
90
+ return node.ancestors.first if argument_case?(node)
91
+
92
+ node.each_ancestor(:lvasgn).first
93
+ end
94
+
95
+ def argument_case?(node)
96
+ node.case_type? && !node.ancestors.empty? &&
97
+ node.ancestors.first.send_type?
78
98
  end
79
99
  end
80
100
  end
@@ -8,9 +8,13 @@ module RuboCop
8
8
  MSG = 'The use of `eval` is a serious security risk.'
9
9
 
10
10
  def on_send(node)
11
- receiver, method_name, = *node
11
+ receiver, method_name, *args = *node
12
12
 
13
- add_offense(node, :selector) if receiver.nil? && method_name == :eval
13
+ return unless receiver.nil? &&
14
+ method_name == :eval &&
15
+ !args.empty? &&
16
+ args.first.type != :str
17
+ add_offense(node, :selector)
14
18
  end
15
19
  end
16
20
  end