rubocop 0.17.0 → 0.18.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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +65 -42
  3. data/CONTRIBUTING.md +20 -3
  4. data/config/enabled.yml +10 -0
  5. data/lib/rubocop.rb +7 -0
  6. data/lib/rubocop/cop/cop.rb +4 -13
  7. data/lib/rubocop/cop/lint/ambiguous_operator.rb +1 -1
  8. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +1 -1
  9. data/lib/rubocop/cop/lint/loop.rb +1 -1
  10. data/lib/rubocop/cop/lint/require_parentheses.rb +72 -0
  11. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +1 -1
  12. data/lib/rubocop/cop/style/access_modifier_indentation.rb +3 -1
  13. data/lib/rubocop/cop/style/align_array.rb +1 -1
  14. data/lib/rubocop/cop/style/align_hash.rb +1 -1
  15. data/lib/rubocop/cop/style/align_parameters.rb +1 -1
  16. data/lib/rubocop/cop/style/def_parentheses.rb +1 -1
  17. data/lib/rubocop/cop/style/line_end_concatenation.rb +53 -0
  18. data/lib/rubocop/cop/style/nested_ternary_operator.rb +1 -1
  19. data/lib/rubocop/cop/style/proc.rb +6 -0
  20. data/lib/rubocop/cop/style/regexp_literal.rb +1 -1
  21. data/lib/rubocop/cop/style/space_after_method_name.rb +1 -1
  22. data/lib/rubocop/cop/style/trailing_comma.rb +7 -0
  23. data/lib/rubocop/cop/style/word_array.rb +27 -0
  24. data/lib/rubocop/cop/util.rb +1 -0
  25. data/lib/rubocop/formatter/simple_text_formatter.rb +6 -2
  26. data/lib/rubocop/options.rb +1 -1
  27. data/lib/rubocop/path_util.rb +22 -0
  28. data/lib/rubocop/rake_task.rb +17 -3
  29. data/lib/rubocop/version.rb +1 -1
  30. data/rubocop.gemspec +2 -2
  31. data/spec/project_spec.rb +93 -0
  32. data/spec/rubocop/cli_spec.rb +27 -22
  33. data/spec/rubocop/cop/cop_spec.rb +1 -1
  34. data/spec/rubocop/cop/lint/ambiguous_operator_spec.rb +2 -2
  35. data/spec/rubocop/cop/lint/ambiguous_regexp_literal_spec.rb +1 -1
  36. data/spec/rubocop/cop/lint/block_alignment_spec.rb +5 -5
  37. data/spec/rubocop/cop/lint/parentheses_as_grouped_expression_spec.rb +2 -2
  38. data/spec/rubocop/cop/lint/require_parentheses_spec.rb +82 -0
  39. data/spec/rubocop/cop/lint/rescue_exception_spec.rb +1 -1
  40. data/spec/rubocop/cop/lint/shadowing_outer_local_variable_spec.rb +9 -9
  41. data/spec/rubocop/cop/lint/useless_assignment_spec.rb +54 -54
  42. data/spec/rubocop/cop/lint/useless_setter_call_spec.rb +6 -6
  43. data/spec/rubocop/cop/style/access_modifier_indentation_spec.rb +49 -8
  44. data/spec/rubocop/cop/style/align_array_spec.rb +1 -1
  45. data/spec/rubocop/cop/style/align_hash_spec.rb +1 -1
  46. data/spec/rubocop/cop/style/align_parameters_spec.rb +2 -2
  47. data/spec/rubocop/cop/style/blocks_spec.rb +1 -1
  48. data/spec/rubocop/cop/style/case_indentation_spec.rb +1 -1
  49. data/spec/rubocop/cop/style/dot_position_spec.rb +1 -1
  50. data/spec/rubocop/cop/style/favor_unless_over_negated_if_spec.rb +2 -2
  51. data/spec/rubocop/cop/style/if_unless_modifier_spec.rb +3 -3
  52. data/spec/rubocop/cop/style/indentation_consistency_spec.rb +4 -4
  53. data/spec/rubocop/cop/style/indentation_width_spec.rb +3 -3
  54. data/spec/rubocop/cop/style/line_end_concatenation_spec.rb +27 -0
  55. data/spec/rubocop/cop/style/multiline_block_chain_spec.rb +1 -1
  56. data/spec/rubocop/cop/style/proc_spec.rb +5 -0
  57. data/spec/rubocop/cop/style/regexp_literal_spec.rb +4 -4
  58. data/spec/rubocop/cop/style/string_literals_spec.rb +7 -7
  59. data/spec/rubocop/cop/style/trailing_comma_spec.rb +27 -6
  60. data/spec/rubocop/cop/style/unless_else_spec.rb +1 -1
  61. data/spec/rubocop/cop/style/variable_interpolation_spec.rb +2 -2
  62. data/spec/rubocop/cop/style/word_array_spec.rb +10 -0
  63. data/spec/rubocop/cop/variable_inspector/variable_table_spec.rb +4 -4
  64. data/spec/rubocop/formatter/disabled_config_formatter_spec.rb +1 -1
  65. data/spec/rubocop/formatter/formatter_set_spec.rb +1 -1
  66. data/spec/rubocop/path_util_spec.rb +42 -0
  67. data/spec/spec_helper.rb +3 -1
  68. metadata +29 -8
@@ -39,7 +39,7 @@ module Rubocop
39
39
  def alternative_style
40
40
  a = cop_config['SupportedStyles'].map(&:to_sym)
41
41
  if a.size != 2
42
- fail 'alternative_style can only be used when there are exactly ' +
42
+ fail 'alternative_style can only be used when there are exactly ' \
43
43
  '2 SupportedStyles'
44
44
  end
45
45
  style == a.first ? a.last : a.first
@@ -7,6 +7,7 @@ module Rubocop
7
7
  # Modifiers should be indented as deeps are method definitions and
8
8
  # surrounded by blank lines.
9
9
  class AccessModifierIndentation < Cop
10
+ include AutocorrectAlignment
10
11
  include ConfigurableEnforcedStyle
11
12
 
12
13
  MSG = '%s access modifiers like %s.'
@@ -47,7 +48,8 @@ module Rubocop
47
48
  access_modifier_start_col = send_node.loc.expression.column
48
49
  offset = access_modifier_start_col - class_start_col
49
50
 
50
- if offset == expected_indent_offset
51
+ @column_delta = expected_indent_offset - offset
52
+ if @column_delta == 0
51
53
  correct_style_detected
52
54
  else
53
55
  add_offence(send_node, :expression) do
@@ -8,7 +8,7 @@ module Rubocop
8
8
  class AlignArray < Cop
9
9
  include AutocorrectAlignment
10
10
 
11
- MSG = 'Align the elements of an array literal if they span more ' +
11
+ MSG = 'Align the elements of an array literal if they span more ' \
12
12
  'than one line.'
13
13
 
14
14
  def on_array(node)
@@ -141,7 +141,7 @@ module Rubocop
141
141
  end
142
142
  end
143
143
 
144
- MSG = 'Align the elements of a hash literal if they span more than ' +
144
+ MSG = 'Align the elements of a hash literal if they span more than ' \
145
145
  'one line.'
146
146
 
147
147
  def on_hash(node)
@@ -8,7 +8,7 @@ module Rubocop
8
8
  class AlignParameters < Cop
9
9
  include AutocorrectAlignment
10
10
 
11
- MSG = 'Align the parameters of a method call if they span ' +
11
+ MSG = 'Align the parameters of a method call if they span ' \
12
12
  'more than one line.'
13
13
 
14
14
  def on_send(node)
@@ -9,7 +9,7 @@ module Rubocop
9
9
  class DefWithParentheses < Cop
10
10
  include CheckMethods
11
11
 
12
- MSG = "Omit the parentheses in defs when the method doesn't accept " +
12
+ MSG = "Omit the parentheses in defs when the method doesn't accept " \
13
13
  'any arguments.'
14
14
 
15
15
  def check(node, _method_name, args, _body)
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for string literal concatenation at
7
+ # the end of a line.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # some_str = 'ala' +
13
+ # 'bala'
14
+ #
15
+ # # good
16
+ # some_str = 'ala' \
17
+ # 'bala'
18
+ #
19
+ class LineEndConcatenation < Cop
20
+ MSG = 'Use \\ instead of + to concatenate those strings.'
21
+
22
+ def on_send(node)
23
+ add_offence(node, :selector) if offending_node?(node)
24
+ end
25
+
26
+ def autocorrect(node)
27
+ @corrections << lambda do |corrector|
28
+ # replace + with \
29
+ corrector.replace(node.loc.selector, '\\')
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def offending_node?(node)
36
+ receiver, method, arg = *node
37
+
38
+ # TODO: Report Emacs bug.
39
+ return false unless :+ == method
40
+
41
+ return false unless receiver.type == :str
42
+
43
+ return false unless arg.type == :str
44
+
45
+ receiver_line = receiver.loc.expression.line
46
+ arg_line = arg.loc.expression.line
47
+
48
+ receiver_line != arg_line
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -5,7 +5,7 @@ module Rubocop
5
5
  module Style
6
6
  # This cop checks for nested ternary op expressions.
7
7
  class NestedTernaryOperator < Cop
8
- MSG = 'Ternary operators must not be nested. Prefer if/else ' +
8
+ MSG = 'Ternary operators must not be nested. Prefer if/else ' \
9
9
  'constructs instead.'
10
10
 
11
11
  def on_if(node)
@@ -20,6 +20,12 @@ module Rubocop
20
20
 
21
21
  add_offence(block_method, :expression) if block_method == TARGET
22
22
  end
23
+
24
+ def autocorrect(node)
25
+ @corrections << lambda do |corrector|
26
+ corrector.replace(node.loc.expression, 'proc')
27
+ end
28
+ end
23
29
  end
24
30
  end
25
31
  end
@@ -39,7 +39,7 @@ module Rubocop
39
39
  end
40
40
 
41
41
  def error_message(word)
42
- sprintf('Use %%r %sfor regular expressions matching more ' +
42
+ sprintf('Use %%r %sfor regular expressions matching more ' \
43
43
  "than %d '/' character%s.",
44
44
  word,
45
45
  max_slashes,
@@ -7,7 +7,7 @@ module Rubocop
7
7
  class SpaceAfterMethodName < Cop
8
8
  include CheckMethods
9
9
 
10
- MSG = 'Never put a space between a method name and the opening ' +
10
+ MSG = 'Never put a space between a method name and the opening ' \
11
11
  'parenthesis.'
12
12
 
13
13
  def check(_node, _method_name, args, body)
@@ -48,6 +48,9 @@ module Rubocop
48
48
  def check(node, items, kind, begin_pos, end_pos)
49
49
  sb = items.first.loc.expression.source_buffer
50
50
  after_last_item = Parser::Source::Range.new(sb, begin_pos, end_pos)
51
+
52
+ return if heredoc?(after_last_item.source)
53
+
51
54
  comma_offset = after_last_item.source =~ /,/
52
55
  should_have_comma = style == :comma && multiline?(node)
53
56
  if comma_offset
@@ -60,6 +63,10 @@ module Rubocop
60
63
  end
61
64
  end
62
65
 
66
+ def heredoc?(source_after_last_item)
67
+ source_after_last_item =~ /\w/
68
+ end
69
+
63
70
  # Returns true if the node has round/square/curly brackets.
64
71
  def brackets?(node)
65
72
  !node.loc.end.nil?
@@ -53,6 +53,33 @@ module Rubocop
53
53
  def min_size
54
54
  cop_config['MinSize']
55
55
  end
56
+
57
+ def autocorrect(node)
58
+ sb = node.loc.expression.source_buffer
59
+ interpolated = false
60
+
61
+ contents = node.children.map do |n|
62
+ if character_literal?(n)
63
+ interpolated = true
64
+ begin_pos = n.loc.expression.begin_pos + '?'.length
65
+ end_pos = n.loc.expression.end_pos
66
+ else
67
+ begin_pos = n.loc.begin.end_pos
68
+ end_pos = n.loc.end.begin_pos
69
+ end
70
+ Parser::Source::Range.new(sb, begin_pos, end_pos).source
71
+ end.join(' ')
72
+
73
+ char = interpolated ? 'W' : 'w'
74
+
75
+ @corrections << lambda do |corrector|
76
+ corrector.replace(node.loc.expression, "%#{char}(#{contents})")
77
+ end
78
+ end
79
+
80
+ def character_literal?(node)
81
+ node.loc.end.nil?
82
+ end
56
83
  end
57
84
  end
58
85
  end
@@ -4,6 +4,7 @@ module Rubocop
4
4
  module Cop
5
5
  # This module contains a collection of useful utility methods.
6
6
  module Util
7
+ include PathUtil
7
8
  extend AST::Sexp
8
9
 
9
10
  PROC_NEW_NODE = s(:send, s(:const, nil, :Proc), :new)
@@ -9,6 +9,7 @@ module Rubocop
9
9
  # location of the problem and the associated message.
10
10
  class SimpleTextFormatter < BaseFormatter
11
11
  include Colorizable
12
+ include PathUtil
12
13
 
13
14
  COLOR_FOR_SEVERITY = {
14
15
  refactor: :yellow,
@@ -73,8 +74,11 @@ module Rubocop
73
74
  end
74
75
 
75
76
  def smart_path(path)
76
- if path.start_with?(Dir.pwd)
77
- Pathname.new(path).relative_path_from(Pathname.getwd).to_s
77
+ # Ideally, we calculate this relative to the project root.
78
+ base_dir = Dir.pwd
79
+
80
+ if path.start_with? base_dir
81
+ relative_path(path, base_dir)
78
82
  else
79
83
  path
80
84
  end
@@ -123,7 +123,7 @@ module Rubocop
123
123
  # since those are mostly used by external tools.
124
124
  rejected = args.reject! { |a| %w(-s --silent).include?(a) }
125
125
  if rejected
126
- warn '-s/--silent options is dropped. ' +
126
+ warn '-s/--silent options is dropped. ' \
127
127
  '`emacs` and `files` formatters no longer display summary.'
128
128
  end
129
129
  end
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ # Common methods and behaviors for dealing with paths.
5
+ module PathUtil
6
+ module_function
7
+
8
+ def relative_path(path, base_dir = Dir.pwd)
9
+ Pathname.new(path).relative_path_from(Pathname.new(base_dir)).to_s
10
+ end
11
+
12
+ def match_path?(pattern, path)
13
+ case pattern
14
+ when String
15
+ basename = File.basename(path)
16
+ path == pattern || basename == pattern || File.fnmatch(pattern, path)
17
+ when Regexp
18
+ path =~ pattern
19
+ end
20
+ end
21
+ end
22
+ end
@@ -3,8 +3,6 @@
3
3
  require 'rake'
4
4
  require 'rake/tasklib'
5
5
 
6
- require 'rubocop/options'
7
-
8
6
  module Rubocop
9
7
  # Provides a custom rake task.
10
8
  #
@@ -16,6 +14,8 @@ module Rubocop
16
14
  attr_accessor :fail_on_error
17
15
  attr_accessor :patterns
18
16
  attr_accessor :formatters
17
+ attr_accessor :requires
18
+ attr_accessor :options
19
19
 
20
20
  def initialize(*args, &task_block)
21
21
  setup_ivars(args)
@@ -39,17 +39,31 @@ module Rubocop
39
39
 
40
40
  cli = CLI.new
41
41
  puts 'Running RuboCop...' if verbose
42
- result = cli.run([formatters.map { |f| ['-f', f] }, patterns])
42
+ result = cli.run(full_options)
43
43
  abort('RuboCop failed!') if fail_on_error unless result == 0
44
44
  end
45
45
 
46
46
  private
47
47
 
48
+ def full_options
49
+ [].tap do |result|
50
+ result.concat(formatters.map { |f| ['--format', f] }.flatten)
51
+ result.concat(requires.map { |r| ['--require', r] }.flatten)
52
+ result.concat(options)
53
+ result.concat(patterns)
54
+ end
55
+ end
56
+
48
57
  def setup_ivars(args)
58
+ # More lazy-loading to keep load time down.
59
+ require 'rubocop/options'
60
+
49
61
  @name = args.shift || :rubocop
50
62
  @verbose = true
51
63
  @fail_on_error = true
52
64
  @patterns = []
65
+ @requires = []
66
+ @options = []
53
67
  @formatters = [Rubocop::Options::DEFAULT_FORMATTER]
54
68
  end
55
69
  end
@@ -3,7 +3,7 @@
3
3
  module Rubocop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '0.17.0'
6
+ STRING = '0.18.0'
7
7
 
8
8
  MSG = '%s (using Parser %s, running on %s %s %s)'
9
9
 
@@ -26,10 +26,10 @@ Gem::Specification.new do |s|
26
26
  s.rubygems_version = '1.8.23'
27
27
  s.summary = 'Automatic Ruby code style checking tool.'
28
28
 
29
- s.add_runtime_dependency('rainbow', '~> 1.99.1')
29
+ s.add_runtime_dependency('rainbow', '>= 1.99.1', '< 3.0')
30
30
  s.add_runtime_dependency('parser', '~> 2.1.3')
31
31
  s.add_runtime_dependency('powerpack', '~> 0.0.6')
32
- s.add_runtime_dependency('json', '~> 1.8')
32
+ s.add_runtime_dependency('json', '>= 1.7.7', '< 2')
33
33
  s.add_development_dependency('rake', '~> 10.1')
34
34
  s.add_development_dependency('rspec', '~> 2.14')
35
35
  s.add_development_dependency('yard', '~> 0.8')
@@ -22,4 +22,97 @@ describe 'RuboCop Project' do
22
22
  end
23
23
  end
24
24
  end
25
+
26
+ describe 'changelog' do
27
+ subject(:changelog) do
28
+ path = File.join(File.dirname(__FILE__), '..', 'CHANGELOG.md')
29
+ File.read(path)
30
+ end
31
+
32
+ it 'has link definitions for all implicit links' do
33
+ implicit_link_names = changelog.scan(/\[([^\]]+)\]\[\]/).flatten.uniq
34
+ implicit_link_names.each do |name|
35
+ expect(changelog).to include("[#{name}]: http")
36
+ end
37
+ end
38
+
39
+ describe 'entry' do
40
+ subject(:entries) { lines.grep(/^\*/).map(&:chomp) }
41
+ let(:lines) { changelog.each_line }
42
+
43
+ it 'has a whitespace between the * and the body' do
44
+ entries.each do |entry|
45
+ expect(entry).to match(/^\* \S/)
46
+ end
47
+ end
48
+
49
+ context 'after version 0.14.0' do
50
+ let(:lines) do
51
+ changelog.each_line.take_while do |line|
52
+ !line.start_with?('## 0.14.0')
53
+ end
54
+ end
55
+
56
+ it 'has a link to the contributors at the end' do
57
+ entries.each do |entry|
58
+ expect(entry).to match(/\(\[@\S+\]\[\](?:, \[@\S+\]\[\])*\)$/)
59
+ end
60
+ end
61
+ end
62
+
63
+ describe 'link to related issue' do
64
+ let(:issues) do
65
+ entries.map do |entry|
66
+ entry.match(/\[(?<number>[#\d]+)\]\((?<url>[^\)]+)\)/)
67
+ end.compact
68
+ end
69
+
70
+ it 'has an issue number prefixed with #' do
71
+ issues.each do |issue|
72
+ expect(issue[:number]).to match(/^#\d+$/)
73
+ end
74
+ end
75
+
76
+ it 'has a valid URL' do
77
+ issues.each do |issue|
78
+ number = issue[:number].gsub(/\D/, '')
79
+ pattern = %r{^https://github\.com/bbatsov/rubocop/(?:issues|pull)/#{number}$} # rubocop:disable LineLength
80
+ expect(issue[:url]).to match(pattern)
81
+ end
82
+ end
83
+
84
+ it 'has a colon and a whitespace at the end' do
85
+ entries_including_issue_link = entries.select do |entry|
86
+ entry.match(/^\*\s*\[/)
87
+ end
88
+
89
+ entries_including_issue_link.each do |entry|
90
+ expect(entry).to include('): ')
91
+ end
92
+ end
93
+ end
94
+
95
+ describe 'body' do
96
+ let(:bodies) do
97
+ entries.map do |entry|
98
+ entry
99
+ .sub(/^\*\s*(?:\[.+?\):\s*)?/, '')
100
+ .sub(/\s*\([^\)]+\)$/, '')
101
+ end
102
+ end
103
+
104
+ it 'does not start with a lower case' do
105
+ bodies.each do |body|
106
+ expect(body).not_to match(/^[a-z]/)
107
+ end
108
+ end
109
+
110
+ it 'ends with a punctuation' do
111
+ bodies.each do |body|
112
+ expect(body).to match(/[\.\!]$/)
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
25
118
  end