rubocop 0.34.2 → 0.35.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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +86 -0
  3. data/README.md +103 -31
  4. data/config/default.yml +32 -2
  5. data/config/disabled.yml +24 -0
  6. data/config/enabled.yml +20 -2
  7. data/lib/rubocop.rb +13 -0
  8. data/lib/rubocop/ast_node.rb +48 -0
  9. data/lib/rubocop/cli.rb +9 -0
  10. data/lib/rubocop/config.rb +8 -6
  11. data/lib/rubocop/config_loader.rb +30 -8
  12. data/lib/rubocop/cop/commissioner.rb +1 -1
  13. data/lib/rubocop/cop/cop.rb +19 -6
  14. data/lib/rubocop/cop/lint/circular_argument_reference.rb +33 -2
  15. data/lib/rubocop/cop/lint/debugger.rb +9 -56
  16. data/lib/rubocop/cop/lint/end_alignment.rb +29 -9
  17. data/lib/rubocop/cop/lint/eval.rb +6 -2
  18. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +24 -6
  19. data/lib/rubocop/cop/lint/literal_in_condition.rb +0 -5
  20. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +10 -1
  21. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
  22. data/lib/rubocop/cop/lint/space_before_first_arg.rb +1 -1
  23. data/lib/rubocop/cop/lint/unused_block_argument.rb +6 -0
  24. data/lib/rubocop/cop/lint/unused_method_argument.rb +8 -0
  25. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  26. data/lib/rubocop/cop/mixin/access_modifier_node.rb +1 -1
  27. data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +1 -1
  28. data/lib/rubocop/cop/mixin/autocorrect_unless_changing_ast.rb +26 -3
  29. data/lib/rubocop/cop/mixin/check_assignment.rb +2 -3
  30. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +59 -12
  31. data/lib/rubocop/cop/mixin/configurable_max.rb +1 -1
  32. data/lib/rubocop/cop/mixin/configurable_naming.rb +1 -1
  33. data/lib/rubocop/cop/mixin/first_element_line_break.rb +41 -0
  34. data/lib/rubocop/cop/mixin/negative_conditional.rb +1 -1
  35. data/lib/rubocop/cop/mixin/safe_assignment.rb +3 -14
  36. data/lib/rubocop/cop/mixin/statement_modifier.rb +2 -2
  37. data/lib/rubocop/cop/performance/detect.rb +5 -1
  38. data/lib/rubocop/cop/performance/fixed_size.rb +50 -0
  39. data/lib/rubocop/cop/performance/size.rb +1 -1
  40. data/lib/rubocop/cop/performance/string_replacement.rb +14 -8
  41. data/lib/rubocop/cop/rails/pluralization_grammar.rb +97 -0
  42. data/lib/rubocop/cop/style/align_hash.rb +1 -12
  43. data/lib/rubocop/cop/style/align_parameters.rb +19 -7
  44. data/lib/rubocop/cop/style/and_or.rb +42 -13
  45. data/lib/rubocop/cop/style/block_comments.rb +4 -2
  46. data/lib/rubocop/cop/style/block_delimiters.rb +57 -18
  47. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +1 -1
  48. data/lib/rubocop/cop/style/command_literal.rb +2 -10
  49. data/lib/rubocop/cop/style/copyright.rb +5 -3
  50. data/lib/rubocop/cop/style/documentation.rb +9 -6
  51. data/lib/rubocop/cop/style/dot_position.rb +6 -0
  52. data/lib/rubocop/cop/style/double_negation.rb +4 -15
  53. data/lib/rubocop/cop/style/each_with_object.rb +17 -4
  54. data/lib/rubocop/cop/style/empty_line_between_defs.rb +1 -5
  55. data/lib/rubocop/cop/style/encoding.rb +10 -4
  56. data/lib/rubocop/cop/style/extra_spacing.rb +23 -13
  57. data/lib/rubocop/cop/style/first_array_element_line_break.rb +41 -0
  58. data/lib/rubocop/cop/style/first_hash_element_line_break.rb +35 -0
  59. data/lib/rubocop/cop/style/first_method_argument_line_break.rb +37 -0
  60. data/lib/rubocop/cop/style/first_method_parameter_line_break.rb +42 -0
  61. data/lib/rubocop/cop/style/for.rb +2 -1
  62. data/lib/rubocop/cop/style/if_unless_modifier.rb +31 -0
  63. data/lib/rubocop/cop/style/indent_hash.rb +67 -37
  64. data/lib/rubocop/cop/style/indentation_width.rb +1 -1
  65. data/lib/rubocop/cop/style/leading_comment_space.rb +3 -2
  66. data/lib/rubocop/cop/style/method_call_parentheses.rb +8 -0
  67. data/lib/rubocop/cop/style/method_def_parentheses.rb +10 -7
  68. data/lib/rubocop/cop/style/multiline_operation_indentation.rb +8 -13
  69. data/lib/rubocop/cop/style/nested_modifier.rb +97 -0
  70. data/lib/rubocop/cop/style/next.rb +18 -0
  71. data/lib/rubocop/cop/style/parallel_assignment.rb +57 -15
  72. data/lib/rubocop/cop/style/predicate_name.rb +7 -2
  73. data/lib/rubocop/cop/style/regexp_literal.rb +2 -10
  74. data/lib/rubocop/cop/style/single_line_methods.rb +7 -5
  75. data/lib/rubocop/cop/style/single_space_before_first_arg.rb +1 -1
  76. data/lib/rubocop/cop/style/space_around_operators.rb +2 -0
  77. data/lib/rubocop/cop/style/special_global_vars.rb +4 -2
  78. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +108 -0
  79. data/lib/rubocop/cop/style/trailing_comma.rb +9 -6
  80. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +23 -2
  81. data/lib/rubocop/cop/style/unneeded_percent_q.rb +31 -20
  82. data/lib/rubocop/cop/style/variable_name.rb +5 -0
  83. data/lib/rubocop/cop/style/word_array.rb +2 -1
  84. data/lib/rubocop/cop/team.rb +17 -4
  85. data/lib/rubocop/cop/util.rb +5 -0
  86. data/lib/rubocop/cop/variable_force/locatable.rb +1 -1
  87. data/lib/rubocop/formatter/base_formatter.rb +1 -1
  88. data/lib/rubocop/formatter/disabled_config_formatter.rb +22 -10
  89. data/lib/rubocop/formatter/simple_text_formatter.rb +1 -1
  90. data/lib/rubocop/node_pattern.rb +390 -0
  91. data/lib/rubocop/options.rb +48 -36
  92. data/lib/rubocop/processed_source.rb +3 -1
  93. data/lib/rubocop/rake_task.rb +1 -1
  94. data/lib/rubocop/remote_config.rb +60 -0
  95. data/lib/rubocop/result_cache.rb +4 -2
  96. data/lib/rubocop/runner.rb +33 -10
  97. data/lib/rubocop/token.rb +2 -1
  98. data/lib/rubocop/version.rb +1 -1
  99. data/lib/rubocop/warning.rb +11 -0
  100. data/relnotes/v0.35.0.md +210 -0
  101. data/rubocop.gemspec +2 -2
  102. metadata +20 -6
@@ -22,6 +22,30 @@ Style/InlineComment:
22
22
  Description: 'Avoid inline comments.'
23
23
  Enabled: false
24
24
 
25
+ Style/FirstArrayElementLineBreak:
26
+ Description: >-
27
+ Checks for a line break before the first element in a
28
+ multi-line array.
29
+ Enabled: false
30
+
31
+ Style/FirstHashElementLineBreak:
32
+ Description: >-
33
+ Checks for a line break before the first element in a
34
+ multi-line hash.
35
+ Enabled: false
36
+
37
+ Style/FirstMethodArgumentLineBreak:
38
+ Description: >-
39
+ Checks for a line break before the first argument in a
40
+ multi-line method call.
41
+ Enabled: false
42
+
43
+ Style/FirstMethodParameterLineBreak:
44
+ Description: >-
45
+ Checks for a line break before the first parameter in a
46
+ multi-line method parameter definition.
47
+ Enabled: false
48
+
25
49
  Style/MethodCalledOnDoEndBlock:
26
50
  Description: 'Avoid chaining a method call on a do...end block.'
27
51
  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#single-line-blocks'
@@ -415,6 +415,10 @@ Style/NegatedWhile:
415
415
  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#until-for-negatives'
416
416
  Enabled: true
417
417
 
418
+ Style/NestedModifier:
419
+ Description: 'Avoid using nested modifiers.'
420
+ Enabled: true
421
+
418
422
  Style/NestedTernaryOperator:
419
423
  Description: 'Use one expression per branch in a ternary operator.'
420
424
  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-nested-ternary'
@@ -690,6 +694,11 @@ Style/SpecialGlobalVars:
690
694
  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-cryptic-perlisms'
691
695
  Enabled: true
692
696
 
697
+ Style/StabbyLambdaParentheses:
698
+ Description: 'Check for the usage of parentheses around stabby lambda arguments.'
699
+ StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#stabby-lambda-with-args'
700
+ Enabled: true
701
+
693
702
  Style/StringLiterals:
694
703
  Description: 'Checks if uses of quotes match the configured preference.'
695
704
  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#consistent-string-literals'
@@ -759,6 +768,7 @@ Style/TrailingUnderscoreVariable:
759
768
  Description: >-
760
769
  Checks for the usage of unneeded trailing underscores at the
761
770
  end of parallel variable assignment.
771
+ AllowNamedUnderscoreVariables: true
762
772
  Enabled: true
763
773
 
764
774
  Style/VariableInterpolation:
@@ -857,7 +867,7 @@ Lint/AmbiguousOperator:
857
867
  Lint/AmbiguousRegexpLiteral:
858
868
  Description: >-
859
869
  Checks for ambiguous regexp literals in the first argument of
860
- a method invocation without parenthesis.
870
+ a method invocation without parentheses.
861
871
  Enabled: true
862
872
 
863
873
  Lint/AssignmentInCondition:
@@ -870,7 +880,7 @@ Lint/BlockAlignment:
870
880
  Enabled: true
871
881
 
872
882
  Lint/CircularArgumentReference:
873
- Description: "Don't refer to the keyword argument in the default value."
883
+ Description: "Default values in optional keyword arguments and optional ordinal arguments should not refer back to the name of the argument."
874
884
  Enabled: true
875
885
 
876
886
  Lint/ConditionPosition:
@@ -1079,6 +1089,10 @@ Performance/Detect:
1079
1089
  Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerabledetect-vs-enumerableselectfirst-code'
1080
1090
  Enabled: true
1081
1091
 
1092
+ Performance/FixedSize:
1093
+ Description: 'Do not compute the size of statically sized objects except in constants'
1094
+ Enabled: true
1095
+
1082
1096
  Performance/FlatMap:
1083
1097
  Description: >-
1084
1098
  Use `Enumerable#flat_map`
@@ -1155,6 +1169,10 @@ Rails/Output:
1155
1169
  Description: 'Checks for calls to puts, print, etc.'
1156
1170
  Enabled: true
1157
1171
 
1172
+ Rails/PluralizationGrammar:
1173
+ Description: 'Checks for incorrect grammar when using methods like `3.day.ago`.'
1174
+ Enabled: true
1175
+
1158
1176
  Rails/ReadWriteAttribute:
1159
1177
  Description: >-
1160
1178
  Checks for read_attribute(:attr) and
@@ -15,6 +15,8 @@ require 'rubocop/version'
15
15
 
16
16
  require 'rubocop/path_util'
17
17
  require 'rubocop/string_util'
18
+ require 'rubocop/node_pattern'
19
+ require 'rubocop/ast_node'
18
20
 
19
21
  require 'rubocop/cop/util'
20
22
  require 'rubocop/cop/offense'
@@ -48,6 +50,7 @@ require 'rubocop/cop/mixin/configurable_enforced_style'
48
50
  require 'rubocop/cop/mixin/configurable_naming'
49
51
  require 'rubocop/cop/mixin/empty_lines_around_body'
50
52
  require 'rubocop/cop/mixin/end_keyword_alignment'
53
+ require 'rubocop/cop/mixin/first_element_line_break'
51
54
  require 'rubocop/cop/mixin/if_node'
52
55
  require 'rubocop/cop/mixin/negative_conditional'
53
56
  require 'rubocop/cop/mixin/on_method_def'
@@ -126,6 +129,7 @@ require 'rubocop/cop/metrics/perceived_complexity'
126
129
  require 'rubocop/cop/performance/case_when_splat'
127
130
  require 'rubocop/cop/performance/count'
128
131
  require 'rubocop/cop/performance/detect'
132
+ require 'rubocop/cop/performance/fixed_size'
129
133
  require 'rubocop/cop/performance/flat_map'
130
134
  require 'rubocop/cop/performance/reverse_each'
131
135
  require 'rubocop/cop/performance/sample'
@@ -189,6 +193,10 @@ require 'rubocop/cop/style/end_of_line'
189
193
  require 'rubocop/cop/style/even_odd'
190
194
  require 'rubocop/cop/style/extra_spacing'
191
195
  require 'rubocop/cop/style/file_name'
196
+ require 'rubocop/cop/style/first_array_element_line_break'
197
+ require 'rubocop/cop/style/first_hash_element_line_break'
198
+ require 'rubocop/cop/style/first_method_argument_line_break'
199
+ require 'rubocop/cop/style/first_method_parameter_line_break'
192
200
  require 'rubocop/cop/style/first_parameter_indentation'
193
201
  require 'rubocop/cop/style/flip_flop'
194
202
  require 'rubocop/cop/style/for'
@@ -222,6 +230,7 @@ require 'rubocop/cop/style/multiline_ternary_operator'
222
230
  require 'rubocop/cop/style/mutable_constant'
223
231
  require 'rubocop/cop/style/negated_if'
224
232
  require 'rubocop/cop/style/negated_while'
233
+ require 'rubocop/cop/style/nested_modifier'
225
234
  require 'rubocop/cop/style/nested_ternary_operator'
226
235
  require 'rubocop/cop/style/next'
227
236
  require 'rubocop/cop/style/nil_comparison'
@@ -276,6 +285,7 @@ require 'rubocop/cop/style/space_inside_parens'
276
285
  require 'rubocop/cop/style/space_inside_range_literal'
277
286
  require 'rubocop/cop/style/space_inside_string_interpolation'
278
287
  require 'rubocop/cop/style/special_global_vars'
288
+ require 'rubocop/cop/style/stabby_lambda_parentheses'
279
289
  require 'rubocop/cop/style/string_literals'
280
290
  require 'rubocop/cop/style/string_literals_in_interpolation'
281
291
  require 'rubocop/cop/style/string_methods'
@@ -307,6 +317,7 @@ require 'rubocop/cop/rails/find_by'
307
317
  require 'rubocop/cop/rails/find_each'
308
318
  require 'rubocop/cop/rails/has_and_belongs_to_many'
309
319
  require 'rubocop/cop/rails/output'
320
+ require 'rubocop/cop/rails/pluralization_grammar'
310
321
  require 'rubocop/cop/rails/read_write_attribute'
311
322
  require 'rubocop/cop/rails/scope_args'
312
323
  require 'rubocop/cop/rails/time_zone'
@@ -337,3 +348,5 @@ require 'rubocop/result_cache'
337
348
  require 'rubocop/runner'
338
349
  require 'rubocop/cli'
339
350
  require 'rubocop/options'
351
+ require 'rubocop/warning'
352
+ require 'rubocop/remote_config'
@@ -0,0 +1,48 @@
1
+ # encoding: utf-8
2
+
3
+ require 'astrolabe/node'
4
+
5
+ module Astrolabe
6
+ # RuboCop's extensions to Astrolabe::Node (which extends Parser::AST::Node)
7
+ #
8
+ # Contribute as much of this as possible to the `astrolabe` gem
9
+ # If any of it is accepted, it can be deleted from here
10
+ #
11
+ class Node
12
+ # def_matcher can be used to define a pattern-matching method on Node:
13
+ class << self
14
+ extend RuboCop::NodePattern::Macros
15
+
16
+ # define both Node.method_name(node), and also node.method_name
17
+ def def_matcher(method_name, pattern_str)
18
+ singleton_class.def_node_matcher method_name, pattern_str
19
+ class_eval("def #{method_name}; Node.#{method_name}(self); end")
20
+ end
21
+ end
22
+
23
+ ## Destructuring
24
+
25
+ def_matcher :method_name, '{(send _ $_ ...) (block (send _ $_ ...) ...)}'
26
+ # Note: for masgn, #asgn_rhs will be an array node
27
+ def_matcher :asgn_rhs, '[assignment? (... $_)]'
28
+
29
+ ## Predicates
30
+
31
+ def multiline?
32
+ expr = loc.expression
33
+ expr && (expr.first_line != expr.last_line)
34
+ end
35
+
36
+ def single_line?
37
+ !multiline?
38
+ end
39
+
40
+ def asgn_method_call?
41
+ method_name != :== && method_name.to_s.end_with?('=')
42
+ end
43
+
44
+ def_matcher :equals_asgn?, '{lvasgn ivasgn cvasgn gvasgn casgn masgn}'
45
+ def_matcher :shorthand_asgn?, '{op_asgn or_asgn and_asgn}'
46
+ def_matcher :assignment?, '{equals_asgn? shorthand_asgn? asgn_method_call?}'
47
+ end
48
+ end
@@ -24,6 +24,7 @@ module RuboCop
24
24
  runner = Runner.new(@options, @config_store)
25
25
  trap_interrupt(runner)
26
26
  all_passed = runner.run(paths)
27
+ display_warning_summary(runner.warnings)
27
28
  display_error_summary(runner.errors)
28
29
 
29
30
  all_passed && !runner.aborting? && runner.errors.empty? ? 0 : 1
@@ -100,6 +101,14 @@ module RuboCop
100
101
  end
101
102
  end
102
103
 
104
+ def display_warning_summary(warnings)
105
+ return if warnings.empty?
106
+
107
+ warn Rainbow("\n#{pluralize(warnings.size, 'warning')}:").yellow
108
+
109
+ warnings.each { |warning| warn warning }
110
+ end
111
+
103
112
  def display_error_summary(errors)
104
113
  return if errors.empty?
105
114
 
@@ -14,12 +14,15 @@ module RuboCop
14
14
 
15
15
  class ValidationError < StandardError; end
16
16
 
17
- COMMON_PARAMS = %w(Exclude Include Severity AutoCorrect)
17
+ COMMON_PARAMS = %w(Exclude Include Severity AutoCorrect StyleGuide Details)
18
18
 
19
19
  attr_reader :loaded_path
20
20
 
21
21
  def initialize(hash = {}, loaded_path = nil)
22
22
  @loaded_path = loaded_path
23
+ @for_cop = Hash.new do |h, cop|
24
+ h[cop] = self[Cop::Cop.qualified_cop_name(cop, loaded_path)] || {}
25
+ end
23
26
  super(hash)
24
27
  end
25
28
 
@@ -72,13 +75,11 @@ module RuboCop
72
75
  end
73
76
 
74
77
  def for_cop(cop)
75
- cop = cop.cop_name if cop.respond_to?(:cop_name)
76
- @for_cop ||= {}
77
- @for_cop[cop] ||= self[Cop::Cop.qualified_cop_name(cop, loaded_path)]
78
+ @for_cop[cop.respond_to?(:cop_name) ? cop.cop_name : cop]
78
79
  end
79
80
 
80
81
  def cop_enabled?(cop)
81
- for_cop(cop).nil? || for_cop(cop)['Enabled']
82
+ for_cop(cop).empty? || for_cop(cop)['Enabled']
82
83
  end
83
84
 
84
85
  def warn_unless_valid
@@ -170,7 +171,8 @@ module RuboCop
170
171
  def base_dir_for_path_parameters
171
172
  config_files = [ConfigLoader::DOTFILE, ConfigLoader::AUTO_GENERATED_FILE]
172
173
  @base_dir_for_path_parameters ||=
173
- if config_files.include?(File.basename(loaded_path))
174
+ if config_files.include?(File.basename(loaded_path)) &&
175
+ loaded_path != File.join(Dir.home, ConfigLoader::DOTFILE)
174
176
  File.expand_path(File.dirname(loaded_path))
175
177
  else
176
178
  Dir.pwd
@@ -18,6 +18,7 @@ module RuboCop
18
18
  class << self
19
19
  attr_accessor :debug, :auto_gen_config, :exclude_limit
20
20
  attr_writer :root_level # The upwards search is stopped at this level.
21
+ attr_writer :default_configuration
21
22
 
22
23
  alias_method :debug?, :debug
23
24
  alias_method :auto_gen_config?, :auto_gen_config
@@ -26,6 +27,7 @@ module RuboCop
26
27
  path = File.absolute_path(path)
27
28
  hash = load_yaml_configuration(path)
28
29
 
30
+ resolve_inheritance_from_gems(hash, hash.delete('inherit_gem'))
29
31
  resolve_inheritance(path, hash)
30
32
 
31
33
  Array(hash.delete('require')).each { |r| require(r) }
@@ -57,16 +59,21 @@ module RuboCop
57
59
  end
58
60
 
59
61
  def base_configs(path, inherit_from)
60
- configs = Array(inherit_from).map do |f|
61
- f = File.expand_path(f, File.dirname(path))
62
+ configs = Array(inherit_from).compact.map do |f|
63
+ if f =~ URI.regexp
64
+ f = RemoteConfig.new(f).file
65
+ load_file(f)
66
+ else
67
+ f = File.expand_path(f, File.dirname(path))
62
68
 
63
- if auto_gen_config?
64
- next if f.include?(AUTO_GENERATED_FILE)
65
- old_auto_config_file_warning if f.include?('rubocop-todo.yml')
66
- end
69
+ if auto_gen_config?
70
+ next if f.include?(AUTO_GENERATED_FILE)
71
+ old_auto_config_file_warning if f.include?('rubocop-todo.yml')
72
+ end
67
73
 
68
- print 'Inheriting ' if debug?
69
- load_file(f)
74
+ print 'Inheriting ' if debug?
75
+ load_file(f)
76
+ end
70
77
  end
71
78
 
72
79
  configs.compact
@@ -165,6 +172,21 @@ module RuboCop
165
172
  end
166
173
  end
167
174
 
175
+ def resolve_inheritance_from_gems(hash, gems)
176
+ (gems || {}).each_pair do |gem_name, config_path|
177
+ hash['inherit_from'] = Array(hash['inherit_from'])
178
+ hash['inherit_from'] << gem_config_path(gem_name, config_path)
179
+ end
180
+ end
181
+
182
+ def gem_config_path(gem_name, relative_config_path)
183
+ spec = Gem::Specification.find_by_name(gem_name)
184
+ return File.join(spec.gem_dir, relative_config_path)
185
+ rescue Gem::LoadError => e
186
+ raise Gem::LoadError,
187
+ "Unable to find gem #{gem_name}; is the gem installed? #{e}"
188
+ end
189
+
168
190
  def config_files_in_path(target)
169
191
  possible_config_files = dirs_to_search(target).map do |dir|
170
192
  File.join(dir, DOTFILE)
@@ -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})
@@ -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
@@ -138,6 +139,11 @@ module RuboCop
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)
@@ -179,7 +185,8 @@ module RuboCop
179
185
  end
180
186
 
181
187
  def config_to_allow_offenses
182
- Formatter::DisabledConfigFormatter.config_to_allow_offenses[cop_name]
188
+ Formatter::DisabledConfigFormatter
189
+ .config_to_allow_offenses[cop_name] ||= {}
183
190
  end
184
191
 
185
192
  def config_to_allow_offenses=(hash)
@@ -203,19 +210,25 @@ module RuboCop
203
210
  end
204
211
 
205
212
  def style_guide_url
206
- url = cop_config && cop_config['StyleGuide']
213
+ url = cop_config['StyleGuide']
207
214
  (url.nil? || url.empty?) ? nil : url
208
215
  end
209
216
 
210
217
  def reference_url
211
- url = cop_config && cop_config['Reference']
218
+ url = cop_config['Reference']
212
219
  (url.nil? || url.empty?) ? nil : url
213
220
  end
214
221
 
222
+ def details
223
+ details = cop_config && cop_config['Details']
224
+ (details.nil? || details.empty?) ? nil : details
225
+ end
226
+
215
227
  private
216
228
 
217
229
  def annotate_message(message)
218
230
  message = "#{name}: #{message}" if display_cop_names?
231
+ message += " #{details}" if extra_details?
219
232
  if display_style_guide?
220
233
  links = [style_guide_url, reference_url].compact.join(', ')
221
234
  message = "#{message} (#{links})"
@@ -224,7 +237,7 @@ module RuboCop
224
237
  end
225
238
 
226
239
  def file_name_matches_any?(file, parameter, default_result)
227
- patterns = cop_config && cop_config[parameter]
240
+ patterns = cop_config[parameter]
228
241
  return default_result unless patterns
229
242
  path = nil
230
243
  patterns.any? do |pattern|
@@ -247,7 +260,7 @@ module RuboCop
247
260
  end
248
261
 
249
262
  def custom_severity
250
- severity = cop_config && cop_config['Severity']
263
+ severity = cop_config['Severity']
251
264
  return unless severity
252
265
 
253
266
  if Severity::NAMES.include?(severity.to_sym)
@@ -3,19 +3,50 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # This cop checks for circular argument references in keyword arguments.
6
+ # This cop checks for circular argument references in optional keyword
7
+ # arguments and optional ordinal arguments.
7
8
  #
8
9
  # This cop mirrors a warning produced by MRI since 2.2.
9
10
  #
10
11
  # @example
12
+ # # bad
11
13
  # def bake(pie: pie)
12
14
  # pie.heat_up
13
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
14
36
  class CircularArgumentReference < Cop
15
37
  MSG = 'Circular argument reference - `%s`.'
16
38
 
17
39
  def on_kwoptarg(node)
18
- arg_name, arg_value = *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)
19
50
  case arg_value.type
20
51
  when :send
21
52
  # Ruby 2.0 will have type send every time, and "send nil" if it is