rubocop 0.37.2 → 0.38.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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -1
  3. data/assets/output.html.erb +3 -0
  4. data/config/default.yml +14 -1
  5. data/config/disabled.yml +0 -4
  6. data/lib/rubocop.rb +0 -1
  7. data/lib/rubocop/ast_node.rb +6 -0
  8. data/lib/rubocop/ast_node/traversal.rb +1 -1
  9. data/lib/rubocop/cached_data.rb +6 -2
  10. data/lib/rubocop/config_loader.rb +7 -3
  11. data/lib/rubocop/cop/cop.rb +1 -1
  12. data/lib/rubocop/cop/lint/block_alignment.rb +91 -17
  13. data/lib/rubocop/cop/lint/else_layout.rb +24 -14
  14. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +6 -12
  15. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +16 -10
  16. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
  17. data/lib/rubocop/cop/lint/unneeded_disable.rb +36 -23
  18. data/lib/rubocop/cop/lint/unused_block_argument.rb +0 -1
  19. data/lib/rubocop/cop/lint/useless_access_modifier.rb +4 -4
  20. data/lib/rubocop/cop/metrics/line_length.rb +25 -18
  21. data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +1 -1
  22. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  23. data/lib/rubocop/cop/mixin/if_node.rb +0 -4
  24. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +5 -1
  25. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +6 -6
  26. data/lib/rubocop/cop/mixin/trailing_comma.rb +26 -24
  27. data/lib/rubocop/cop/mixin/unused_argument.rb +9 -1
  28. data/lib/rubocop/cop/offense.rb +16 -0
  29. data/lib/rubocop/cop/performance/casecmp.rb +15 -10
  30. data/lib/rubocop/cop/performance/count.rb +3 -2
  31. data/lib/rubocop/cop/performance/fixed_size.rb +13 -12
  32. data/lib/rubocop/cop/performance/reverse_each.rb +15 -14
  33. data/lib/rubocop/cop/rails/date.rb +13 -1
  34. data/lib/rubocop/cop/rails/output.rb +2 -1
  35. data/lib/rubocop/cop/rails/pluralization_grammar.rb +1 -1
  36. data/lib/rubocop/cop/rails/read_write_attribute.rb +1 -1
  37. data/lib/rubocop/cop/style/and_or.rb +1 -2
  38. data/lib/rubocop/cop/style/block_delimiters.rb +41 -48
  39. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +4 -2
  40. data/lib/rubocop/cop/style/class_and_module_children.rb +3 -3
  41. data/lib/rubocop/cop/style/comment_annotation.rb +8 -10
  42. data/lib/rubocop/cop/style/conditional_assignment.rb +7 -2
  43. data/lib/rubocop/cop/style/encoding.rb +15 -10
  44. data/lib/rubocop/cop/style/extra_spacing.rb +14 -12
  45. data/lib/rubocop/cop/style/file_name.rb +3 -7
  46. data/lib/rubocop/cop/style/lambda.rb +17 -6
  47. data/lib/rubocop/cop/style/method_call_parentheses.rb +1 -1
  48. data/lib/rubocop/cop/style/method_def_parentheses.rb +0 -4
  49. data/lib/rubocop/cop/style/nested_modifier.rb +7 -1
  50. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +0 -4
  51. data/lib/rubocop/cop/style/not.rb +27 -5
  52. data/lib/rubocop/cop/style/one_line_conditional.rb +21 -0
  53. data/lib/rubocop/cop/style/redundant_parentheses.rb +9 -1
  54. data/lib/rubocop/cop/style/signal_exception.rb +28 -26
  55. data/lib/rubocop/cop/style/space_around_keyword.rb +10 -6
  56. data/lib/rubocop/cop/style/string_literals.rb +1 -0
  57. data/lib/rubocop/cop/style/unless_else.rb +24 -0
  58. data/lib/rubocop/cop/style/unneeded_interpolation.rb +26 -13
  59. data/lib/rubocop/cop/style/zero_length_predicate.rb +5 -3
  60. data/lib/rubocop/cop/team.rb +6 -1
  61. data/lib/rubocop/cop/util.rb +13 -6
  62. data/lib/rubocop/formatter/clang_style_formatter.rb +18 -14
  63. data/lib/rubocop/formatter/html_formatter.rb +9 -10
  64. data/lib/rubocop/rake_task.rb +4 -4
  65. data/lib/rubocop/remote_config.rb +4 -2
  66. data/lib/rubocop/result_cache.rb +14 -8
  67. data/lib/rubocop/runner.rb +9 -0
  68. data/lib/rubocop/version.rb +1 -1
  69. data/spec/support/cop_helper.rb +81 -0
  70. metadata +13 -7
  71. data/lib/rubocop/cop/mixin/autocorrect_unless_changing_ast.rb +0 -57
@@ -12,6 +12,11 @@ module RuboCop
12
12
  Style::SpaceBeforeBlockBraces => [Style::SymbolProc]
13
13
  }.freeze
14
14
 
15
+ DEFAULT_OPTIONS = {
16
+ auto_correct: false,
17
+ debug: false
18
+ }.freeze
19
+
15
20
  attr_reader :errors, :warnings, :updated_source_file
16
21
 
17
22
  alias updated_source_file? updated_source_file
@@ -19,7 +24,7 @@ module RuboCop
19
24
  def initialize(cop_classes, config, options = nil)
20
25
  @cop_classes = cop_classes
21
26
  @config = config
22
- @options = options || { auto_correct: false, debug: false }
27
+ @options = options || DEFAULT_OPTIONS
23
28
  @errors = []
24
29
  @warnings = []
25
30
 
@@ -46,6 +46,10 @@ module RuboCop
46
46
  OPERATOR_METHODS.include?(symbol)
47
47
  end
48
48
 
49
+ def ternary_op?(node)
50
+ node.loc.respond_to?(:question)
51
+ end
52
+
49
53
  def strip_quotes(str)
50
54
  if str[0] == '"' || str[0] == "'"
51
55
  str[0] = ''
@@ -84,6 +88,10 @@ module RuboCop
84
88
  node.loc.end.is?(')'.freeze)
85
89
  end
86
90
 
91
+ def parenthesized_call?(send)
92
+ send.loc.begin && send.loc.begin.is?('(')
93
+ end
94
+
87
95
  def on_node(syms, sexp, excludes = [], &block)
88
96
  return to_enum(:on_node, syms, sexp, excludes) unless block_given?
89
97
 
@@ -104,12 +112,11 @@ module RuboCop
104
112
  column_index = column
105
113
  end
106
114
 
107
- preceding_line_numbers = (1...line_number)
108
-
109
- line_begin_pos = preceding_line_numbers.reduce(0) do |pos, line|
110
- pos + source_buffer.source_line(line).length + 1
111
- end
112
-
115
+ line_begin_pos = if line_number == 0
116
+ 0
117
+ else
118
+ source_buffer.line_range(line_number).begin_pos
119
+ end
113
120
  begin_pos = line_begin_pos + column_index
114
121
  end_pos = begin_pos + length
115
122
 
@@ -7,29 +7,33 @@ module RuboCop
7
7
  # The precise location of the problem is shown together with the
8
8
  # relevant source code.
9
9
  class ClangStyleFormatter < SimpleTextFormatter
10
+ ELLIPSES = Rainbow('...').yellow.freeze
11
+
10
12
  def report_file(file, offenses)
11
13
  offenses.each do |o|
12
14
  output.printf("%s:%d:%d: %s: %s\n",
13
15
  cyan(smart_path(file)), o.line, o.real_column,
14
16
  colored_severity_code(o), message(o))
15
17
 
16
- source_line = o.location.source_line
17
- next if source_line.blank?
18
+ # rubocop:disable Lint/HandleExceptions
19
+ begin
20
+ location = o.location
21
+ source_line = location.source_line
22
+ next if source_line.blank?
18
23
 
19
- output.puts(source_line)
20
- output.puts(highlight_line(o.location))
24
+ if location.first_line == location.last_line
25
+ output.puts(source_line)
26
+ else
27
+ output.puts("#{source_line} #{ELLIPSES}")
28
+ end
29
+ output.puts("#{' ' * o.highlighted_area.begin_pos}" \
30
+ "#{'^' * o.highlighted_area.size}")
31
+ rescue IndexError
32
+ # range is not on a valid line; perhaps the source file is empty
33
+ end
34
+ # rubocop:enable Lint/HandleExceptions
21
35
  end
22
36
  end
23
-
24
- def highlight_line(location)
25
- column_length = if location.begin.line == location.end.line
26
- location.column_range.count
27
- else
28
- location.source_line.length - location.column
29
- end
30
-
31
- ' ' * location.column + '^' * column_length
32
- end
33
37
  end
34
38
  end
35
39
  end
@@ -11,6 +11,7 @@ module RuboCop
11
11
  module Formatter
12
12
  # This formatter saves the output as a html file.
13
13
  class HTMLFormatter < BaseFormatter
14
+ ELLIPSES = '<span class="extra-code">...</span>'.freeze
14
15
  TEMPLATE_PATH =
15
16
  File.expand_path('../../../../assets/output.html.erb', __FILE__)
16
17
 
@@ -95,19 +96,17 @@ module RuboCop
95
96
  def highlighted_source_line(offense)
96
97
  location = offense.location
97
98
 
98
- column_range = if location.begin.line == location.end.line
99
- location.column_range
100
- else
101
- location.column...location.source_line.length
102
- end
99
+ source_line = if location.first_line == location.last_line
100
+ location.source_line
101
+ else
102
+ "#{location.source_line} #{ELLIPSES}"
103
+ end
103
104
 
104
- source_line = location.source_line
105
-
106
- escape(source_line[0...column_range.begin]) +
105
+ escape(source_line[0...offense.highlighted_area.begin_pos]) +
107
106
  "<span class=\"highlight #{offense.severity}\">" +
108
- escape(source_line[column_range]) +
107
+ escape(offense.highlighted_area.source) +
109
108
  '</span>' +
110
- escape(source_line[column_range.end..-1])
109
+ escape(source_line[offense.highlighted_area.end_pos..-1])
111
110
  end
112
111
 
113
112
  def escape(s)
@@ -21,7 +21,7 @@ module RuboCop
21
21
  def initialize(*args, &task_block)
22
22
  setup_ivars(args)
23
23
 
24
- desc 'Run RuboCop' unless ::Rake.application.last_comment
24
+ desc 'Run RuboCop' unless ::Rake.application.last_description
25
25
 
26
26
  task(name, *args) do |_, task_args|
27
27
  RakeFileUtils.send(:verbose, verbose) do
@@ -52,9 +52,9 @@ module RuboCop
52
52
 
53
53
  def full_options
54
54
  [].tap do |result|
55
- result.concat(formatters.flat_map { |f| ['--format', f] })
56
- result.concat(requires.flat_map { |r| ['--require', r] })
57
- result.concat(options)
55
+ result.concat(formatters.map { |f| ['--format', f] }.flatten)
56
+ result.concat(requires.map { |r| ['--require', r] }.flatten)
57
+ result.concat(options.flatten)
58
58
  result.concat(patterns)
59
59
  end
60
60
  end
@@ -2,14 +2,16 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'net/http'
5
+ require 'time'
5
6
 
6
7
  module RuboCop
7
8
  # Common methods and behaviors for dealing with remote config files.
8
9
  class RemoteConfig
9
10
  CACHE_LIFETIME = 24 * 60 * 60
10
11
 
11
- def initialize(url)
12
+ def initialize(url, base_dir)
12
13
  @uri = URI.parse(url)
14
+ @base_dir = base_dir
13
15
  end
14
16
 
15
17
  def file
@@ -36,7 +38,7 @@ module RuboCop
36
38
  private
37
39
 
38
40
  def cache_path
39
- ".rubocop-#{cache_name_from_uri}"
41
+ File.expand_path(".rubocop-#{cache_name_from_uri}", @base_dir)
40
42
  end
41
43
 
42
44
  def cache_path_exists?
@@ -33,14 +33,20 @@ module RuboCop
33
33
  puts "Removing the #{remove_count} oldest files from #{cache_root}"
34
34
  end
35
35
  sorted = files.sort_by { |path| File.mtime(path) }
36
- begin
37
- File.delete(*sorted[0, remove_count])
38
- dirs.each { |dir| Dir.rmdir(dir) if Dir["#{dir}/*"].empty? }
39
- rescue Errno::ENOENT
40
- # This can happen if parallel RuboCop invocations try to remove the
41
- # same files. No problem.
42
- puts $ERROR_INFO if verbose
43
- end
36
+ remove_files(sorted, dirs, remove_count, verbose)
37
+ end
38
+ end
39
+
40
+ class << self
41
+ private
42
+
43
+ def remove_files(files, dirs, remove_count, verbose)
44
+ File.delete(*files[0, remove_count])
45
+ dirs.each { |dir| Dir.rmdir(dir) if Dir["#{dir}/*"].empty? }
46
+ rescue Errno::ENOENT
47
+ # This can happen if parallel RuboCop invocations try to remove the
48
+ # same files. No problem.
49
+ puts $ERROR_INFO if verbose
44
50
  end
45
51
  end
46
52
 
@@ -151,6 +151,11 @@ module RuboCop
151
151
  # infinite loop.
152
152
  @processed_sources = []
153
153
 
154
+ # It is also possible for a cop to keep adding indefinitely to a file,
155
+ # making it bigger and bigger. If the inspection loop runs for an
156
+ # excessively high number of iterations, this is likely happening.
157
+ @iterations = 0
158
+
154
159
  # When running with --auto-correct, we need to inspect the file (which
155
160
  # includes writing a corrected version of it) until no more corrections
156
161
  # are made. This is because automatic corrections can introduce new
@@ -158,6 +163,10 @@ module RuboCop
158
163
  loop do
159
164
  check_for_infinite_loop(processed_source, offenses)
160
165
 
166
+ if (@iterations += 1) > 200
167
+ raise InfiniteCorrectionLoop.new(processed_source.path, offenses)
168
+ end
169
+
161
170
  # The offenses that couldn't be corrected will be found again so we
162
171
  # only keep the corrected ones in order to avoid duplicate reporting.
163
172
  offenses.select!(&:corrected?)
@@ -4,7 +4,7 @@
4
4
  module RuboCop
5
5
  # This module holds the RuboCop version information.
6
6
  module Version
7
- STRING = '0.37.2'.freeze
7
+ STRING = '0.38.0'.freeze
8
8
 
9
9
  MSG = '%s (using Parser %s, running on %s %s %s)'.freeze
10
10
 
@@ -0,0 +1,81 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ require 'tempfile'
5
+
6
+ module CopHelper
7
+ extend RSpec::SharedContext
8
+
9
+ let(:ruby_version) { 2.2 }
10
+
11
+ def inspect_source_file(cop, source)
12
+ Tempfile.open('tmp') { |f| inspect_source(cop, source, f) }
13
+ end
14
+
15
+ def inspect_source(cop, source, file = nil)
16
+ if source.is_a?(Array) && source.size == 1
17
+ raise "Don't use an array for a single line of code: #{source}"
18
+ end
19
+ RuboCop::Formatter::DisabledConfigFormatter.config_to_allow_offenses = {}
20
+ RuboCop::Formatter::DisabledConfigFormatter.detected_styles = {}
21
+ processed_source = parse_source(source, file)
22
+ raise 'Error parsing example code' unless processed_source.valid_syntax?
23
+ _investigate(cop, processed_source)
24
+ end
25
+
26
+ def parse_source(source, file = nil)
27
+ source = source.join($RS) if source.is_a?(Array)
28
+
29
+ if file && file.respond_to?(:write)
30
+ file.write(source)
31
+ file.rewind
32
+ file = file.path
33
+ end
34
+
35
+ RuboCop::ProcessedSource.new(source, ruby_version, file)
36
+ end
37
+
38
+ def autocorrect_source_file(cop, source)
39
+ Tempfile.open('tmp') { |f| autocorrect_source(cop, source, f) }
40
+ end
41
+
42
+ def autocorrect_source(cop, source, file = nil)
43
+ cop.instance_variable_get(:@options)[:auto_correct] = true
44
+ processed_source = parse_source(source, file)
45
+ _investigate(cop, processed_source)
46
+
47
+ corrector =
48
+ RuboCop::Cop::Corrector.new(processed_source.buffer, cop.corrections)
49
+ corrector.rewrite
50
+ end
51
+
52
+ def _investigate(cop, processed_source)
53
+ forces = RuboCop::Cop::Force.all.each_with_object([]) do |klass, instances|
54
+ next unless cop.join_force?(klass)
55
+ instances << klass.new([cop])
56
+ end
57
+
58
+ commissioner =
59
+ RuboCop::Cop::Commissioner.new([cop], forces, raise_error: true)
60
+ commissioner.investigate(processed_source)
61
+ commissioner
62
+ end
63
+ end
64
+
65
+ module RuboCop
66
+ module Cop
67
+ class Cop
68
+ def messages
69
+ offenses.sort.map(&:message)
70
+ end
71
+
72
+ def highlights
73
+ offenses.sort.map { |o| o.location.source }
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ RSpec.configure do |config|
80
+ config.include CopHelper
81
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.37.2
4
+ version: 0.38.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2016-02-11 00:00:00.000000000 Z
13
+ date: 2016-03-09 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rainbow
@@ -38,7 +38,7 @@ dependencies:
38
38
  requirements:
39
39
  - - ">="
40
40
  - !ruby/object:Gem::Version
41
- version: 2.3.0.4
41
+ version: 2.3.0.6
42
42
  - - "<"
43
43
  - !ruby/object:Gem::Version
44
44
  version: '3.0'
@@ -48,7 +48,7 @@ dependencies:
48
48
  requirements:
49
49
  - - ">="
50
50
  - !ruby/object:Gem::Version
51
- version: 2.3.0.4
51
+ version: 2.3.0.6
52
52
  - - "<"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
@@ -86,14 +86,20 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0.3'
89
+ version: '1.0'
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 1.0.1
90
93
  type: :runtime
91
94
  prerelease: false
92
95
  version_requirements: !ruby/object:Gem::Requirement
93
96
  requirements:
94
97
  - - "~>"
95
98
  - !ruby/object:Gem::Version
96
- version: '0.3'
99
+ version: '1.0'
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 1.0.1
97
103
  - !ruby/object:Gem::Dependency
98
104
  name: bundler
99
105
  requirement: !ruby/object:Gem::Requirement
@@ -207,7 +213,6 @@ files:
207
213
  - lib/rubocop/cop/mixin/array_hash_indentation.rb
208
214
  - lib/rubocop/cop/mixin/array_syntax.rb
209
215
  - lib/rubocop/cop/mixin/autocorrect_alignment.rb
210
- - lib/rubocop/cop/mixin/autocorrect_unless_changing_ast.rb
211
216
  - lib/rubocop/cop/mixin/check_assignment.rb
212
217
  - lib/rubocop/cop/mixin/classish_length.rb
213
218
  - lib/rubocop/cop/mixin/code_length.rb
@@ -504,6 +509,7 @@ files:
504
509
  - lib/rubocop/token.rb
505
510
  - lib/rubocop/version.rb
506
511
  - lib/rubocop/warning.rb
512
+ - spec/support/cop_helper.rb
507
513
  homepage: http://github.com/bbatsov/rubocop
508
514
  licenses:
509
515
  - MIT
@@ -1,57 +0,0 @@
1
- # encoding: utf-8
2
- # frozen_string_literal: true
3
-
4
- module RuboCop
5
- module Cop
6
- # This module does auto-correction of nodes that could become grammatically
7
- # different after the correction. If the code change would alter the
8
- # abstract syntax tree, it is not done.
9
- #
10
- # However, if the code change merely introduces extraneous "begin" nodes
11
- # which do not change the meaning of the code, it is still accepted.
12
- #
13
- module AutocorrectUnlessChangingAST
14
- def autocorrect(node)
15
- current_buffer_src = processed_source.buffer.source
16
- replaced_range = node.source_range
17
- pre = current_buffer_src[0...replaced_range.begin_pos]
18
- post = current_buffer_src[replaced_range.end_pos..-1]
19
- new_buffer_src = pre + rewrite_node(node) + post
20
- new_processed_src = parse(new_buffer_src, processed_source.buffer.name)
21
-
22
- # Make the correction only if it doesn't change the AST for the buffer.
23
- return if !new_processed_src.ast ||
24
- (INLINE_BEGIN.process(processed_source.ast) !=
25
- INLINE_BEGIN.process(new_processed_src.ast))
26
-
27
- correction(node)
28
- end
29
-
30
- private
31
-
32
- def rewrite_node(node)
33
- ps = parse(node.source)
34
- c = correction(ps.ast)
35
- Corrector.new(ps.buffer, [c]).rewrite
36
- end
37
-
38
- # 'begin' nodes with a single child can be removed without changing
39
- # the semantics of an AST. Canonicalizing an AST in this way can help
40
- # us determine whether it has really changed in a meaningful way, or
41
- # not. This means we can auto-correct in cases where we would otherwise
42
- # refrain from doing so.
43
- #
44
- # If any other simplifications can be done to an AST without changing
45
- # its meaning, they should be added here (and the class renamed).
46
- # This will make autocorrection more powerful across the board.
47
- #
48
- class InlineBeginNodes < Parser::AST::Processor
49
- def on_begin(node)
50
- node.children.one? ? process(node.children[0]) : super
51
- end
52
- end
53
-
54
- INLINE_BEGIN = InlineBeginNodes.new
55
- end
56
- end
57
- end