rubocop 0.3.0 → 0.3.1
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.
- data/.rubocop.yml +13 -0
- data/VERSION +1 -1
- data/lib/rubocop.rb +1 -0
- data/lib/rubocop/cli.rb +2 -1
- data/lib/rubocop/cop/end_of_line.rb +1 -3
- data/lib/rubocop/cop/favor_modifier.rb +82 -0
- data/lib/rubocop/cop/line_length.rb +7 -3
- data/lib/rubocop/cop/tab.rb +1 -3
- data/rubocop.gemspec +4 -2
- data/spec/rubocop/cli_spec.rb +29 -0
- data/spec/rubocop/cops/favor_modifier_spec.rb +112 -0
- metadata +5 -3
data/.rubocop.yml
CHANGED
@@ -6,6 +6,7 @@ Encoding:
|
|
6
6
|
|
7
7
|
LineLength:
|
8
8
|
Enabled: true
|
9
|
+
Max: 79
|
9
10
|
|
10
11
|
Tab:
|
11
12
|
Enabled: true
|
@@ -87,3 +88,15 @@ NestedTernaryOperator:
|
|
87
88
|
|
88
89
|
UnlessElse:
|
89
90
|
Enabled: true
|
91
|
+
|
92
|
+
AmpersandsPipesVsAndOr:
|
93
|
+
Enabled: true
|
94
|
+
|
95
|
+
WhenThen:
|
96
|
+
Enabled: true
|
97
|
+
|
98
|
+
IfUnlessModifier:
|
99
|
+
Enabled: true
|
100
|
+
|
101
|
+
WhileUntilModifier:
|
102
|
+
Enabled: true
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.1
|
data/lib/rubocop.rb
CHANGED
@@ -25,6 +25,7 @@ require 'rubocop/cop/ternary_operator'
|
|
25
25
|
require 'rubocop/cop/unless_else'
|
26
26
|
require 'rubocop/cop/ampersands_pipes_vs_and_or'
|
27
27
|
require 'rubocop/cop/when_then'
|
28
|
+
require 'rubocop/cop/favor_modifier'
|
28
29
|
|
29
30
|
require 'rubocop/report/report'
|
30
31
|
require 'rubocop/report/plain_text'
|
data/lib/rubocop/cli.rb
CHANGED
@@ -44,11 +44,12 @@ module Rubocop
|
|
44
44
|
end
|
45
45
|
|
46
46
|
tokens, sexp, correlations = CLI.rip_source(source)
|
47
|
+
config = $options[:config] || config_from_dotfile(File.dirname(file))
|
47
48
|
|
48
49
|
cops.each do |cop_klass|
|
49
|
-
config = $options[:config] || config_from_dotfile(File.dirname(file))
|
50
50
|
cop_config = config[cop_klass.name.split('::').last] if config
|
51
51
|
if cop_config.nil? || cop_config['Enabled']
|
52
|
+
cop_klass.config = cop_config
|
52
53
|
cop = cop_klass.new
|
53
54
|
cop.correlations = correlations
|
54
55
|
cop.inspect(file, source, tokens, sexp)
|
@@ -7,9 +7,7 @@ module Rubocop
|
|
7
7
|
|
8
8
|
def inspect(file, source, tokens, sexp)
|
9
9
|
source.each_with_index do |line, index|
|
10
|
-
if line =~ /\r$/
|
11
|
-
add_offence(:convention, index + 1, ERROR_MESSAGE)
|
12
|
-
end
|
10
|
+
add_offence(:convention, index + 1, ERROR_MESSAGE) if line =~ /\r$/
|
13
11
|
end
|
14
12
|
end
|
15
13
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
module FavorModifier
|
6
|
+
def check(kind, tokens, sexp)
|
7
|
+
token_positions = tokens.map(&:pos)
|
8
|
+
token_texts = tokens.map(&:text)
|
9
|
+
each(kind, sexp) do |s|
|
10
|
+
# If it contains an else, it can't be written as a modifier.
|
11
|
+
next if s[3] && s[3][0] == :else
|
12
|
+
|
13
|
+
sexp_positions = all_positions(s)
|
14
|
+
ix = token_positions.index(sexp_positions.first)
|
15
|
+
if_ix = token_texts[0..ix].rindex(kind.to_s) # index of if/unless/...
|
16
|
+
ix = token_positions.index(sexp_positions.last)
|
17
|
+
end_ix = ix + token_texts[ix..-1].index('end')
|
18
|
+
|
19
|
+
# If there's a comment anywhere between
|
20
|
+
# if/unless/while/until and end, we don't report. It's
|
21
|
+
# possible that the comment will be less clear if put above
|
22
|
+
# a one liner rather than inside.
|
23
|
+
next if tokens[if_ix...end_ix].map(&:type).include?(:on_comment)
|
24
|
+
|
25
|
+
if token_positions[end_ix].lineno - token_positions[if_ix].lineno > 2
|
26
|
+
next # not a single-line body
|
27
|
+
end
|
28
|
+
# The start ix is the index of the leftmost token on the
|
29
|
+
# line of the if/unless, i.e. the index of if/unless itself,
|
30
|
+
# or of the indentation space.
|
31
|
+
start_ix = if_ix.downto(0).find do |ix|
|
32
|
+
ix == 0 || tokens[ix - 1].text =~ /\n/
|
33
|
+
end
|
34
|
+
# The stop index is the index of the token just before
|
35
|
+
# 'end', not counting whitespace tokens.
|
36
|
+
stop_ix = (end_ix - 1).downto(0).find do |ix|
|
37
|
+
tokens[ix].text !~ /\s/
|
38
|
+
end
|
39
|
+
if length(tokens, start_ix, stop_ix) <= LineLength.max
|
40
|
+
add_offence(:convention, token_positions[if_ix].lineno,
|
41
|
+
error_message)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def length(tokens, start_ix, stop_ix)
|
47
|
+
(start_ix..stop_ix).inject(0) do |acc, ix|
|
48
|
+
acc + if ix > start_ix && tokens[ix - 1].text =~ /\n/
|
49
|
+
0
|
50
|
+
else
|
51
|
+
tokens[ix].text.length
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class IfUnlessModifier < Cop
|
58
|
+
include FavorModifier
|
59
|
+
|
60
|
+
def error_message
|
61
|
+
'Favor modifier if/unless usage when you have a single-line body. ' +
|
62
|
+
'Another good alternative is the usage of control flow and/or.'
|
63
|
+
end
|
64
|
+
|
65
|
+
def inspect(file, source, tokens, sexp)
|
66
|
+
[:if, :unless].each { |kind| check(kind, tokens, sexp) }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class WhileUntilModifier < Cop
|
71
|
+
include FavorModifier
|
72
|
+
|
73
|
+
def error_message
|
74
|
+
'Favor modifier while/until usage when you have a single-line body.'
|
75
|
+
end
|
76
|
+
|
77
|
+
def inspect(file, source, tokens, sexp)
|
78
|
+
[:while, :until].each { |kind| check(kind, tokens, sexp) }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -4,16 +4,20 @@ module Rubocop
|
|
4
4
|
module Cop
|
5
5
|
class LineLength < Cop
|
6
6
|
ERROR_MESSAGE = 'Line is too long. [%d/%d]'
|
7
|
-
MAX_LINE_LENGTH = 79
|
8
7
|
|
9
8
|
def inspect(file, source, tokens, sexp)
|
10
9
|
source.each_with_index do |line, index|
|
11
|
-
|
12
|
-
|
10
|
+
max = LineLength.max
|
11
|
+
if line.length > max
|
12
|
+
message = sprintf(ERROR_MESSAGE, line.length, max)
|
13
13
|
add_offence(:convention, index + 1, message)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
17
|
+
|
18
|
+
def self.max
|
19
|
+
LineLength.config ? LineLength.config['Max'] || 79 : 79
|
20
|
+
end
|
17
21
|
end
|
18
22
|
end
|
19
23
|
end
|
data/lib/rubocop/cop/tab.rb
CHANGED
@@ -7,9 +7,7 @@ module Rubocop
|
|
7
7
|
|
8
8
|
def inspect(file, source, tokens, sexp)
|
9
9
|
source.each_with_index do |line, index|
|
10
|
-
if line =~ /^ *\t/
|
11
|
-
add_offence(:convention, index + 1, ERROR_MESSAGE)
|
12
|
-
end
|
10
|
+
add_offence(:convention, index + 1, ERROR_MESSAGE) if line =~ /^ *\t/
|
13
11
|
end
|
14
12
|
end
|
15
13
|
end
|
data/rubocop.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "rubocop"
|
8
|
-
s.version = "0.3.
|
8
|
+
s.version = "0.3.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Bozhidar Batsov"]
|
12
|
-
s.date = "2013-02-
|
12
|
+
s.date = "2013-02-28"
|
13
13
|
s.description = "Automatic Ruby code style checking tool. Aims to enforce the community-driven Ruby Style Guide."
|
14
14
|
s.email = "bozhidar@batsov.com"
|
15
15
|
s.executables = ["rubocop"]
|
@@ -45,6 +45,7 @@ Gem::Specification.new do |s|
|
|
45
45
|
"lib/rubocop/cop/empty_lines.rb",
|
46
46
|
"lib/rubocop/cop/encoding.rb",
|
47
47
|
"lib/rubocop/cop/end_of_line.rb",
|
48
|
+
"lib/rubocop/cop/favor_modifier.rb",
|
48
49
|
"lib/rubocop/cop/grammar.rb",
|
49
50
|
"lib/rubocop/cop/hash_syntax.rb",
|
50
51
|
"lib/rubocop/cop/if_then_else.rb",
|
@@ -75,6 +76,7 @@ Gem::Specification.new do |s|
|
|
75
76
|
"spec/rubocop/cops/empty_lines_spec.rb",
|
76
77
|
"spec/rubocop/cops/encoding_spec.rb",
|
77
78
|
"spec/rubocop/cops/end_of_line_spec.rb",
|
79
|
+
"spec/rubocop/cops/favor_modifier_spec.rb",
|
78
80
|
"spec/rubocop/cops/grammar_spec.rb",
|
79
81
|
"spec/rubocop/cops/hash_syntax_spec.rb",
|
80
82
|
"spec/rubocop/cops/if_with_semicolon_spec.rb",
|
data/spec/rubocop/cli_spec.rb
CHANGED
@@ -137,6 +137,28 @@ module Rubocop
|
|
137
137
|
end
|
138
138
|
end
|
139
139
|
|
140
|
+
it 'can use an alternative max line length from a config file' do
|
141
|
+
FileUtils.mkdir 'example_src'
|
142
|
+
File.open('example_src/example1.rb', 'w') { |f| f.puts '#' * 90 }
|
143
|
+
File.open('example_src/.rubocop.yml', 'w') do |f|
|
144
|
+
f.puts('LineLength:',
|
145
|
+
' Enabled: true',
|
146
|
+
' Max: 100')
|
147
|
+
end
|
148
|
+
begin
|
149
|
+
return_code = cli.run(['example_src/example1.rb'])
|
150
|
+
$stdout.string.should ==
|
151
|
+
['== example_src/example1.rb ==',
|
152
|
+
'C: 1: Missing encoding comment.',
|
153
|
+
'',
|
154
|
+
'1 files inspected, 1 offences detected',
|
155
|
+
''].join("\n")
|
156
|
+
return_code.should == 1
|
157
|
+
ensure
|
158
|
+
FileUtils.rm_rf 'example_src'
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
140
162
|
it 'finds no violations when checking the rubocop source code' do
|
141
163
|
cli.run
|
142
164
|
$stdout.string.should =~ /files inspected, 0 offences detected\n/
|
@@ -153,6 +175,13 @@ module Rubocop
|
|
153
175
|
File.delete 'example.rb'
|
154
176
|
end
|
155
177
|
end
|
178
|
+
|
179
|
+
it 'has configuration for all cops in .rubocop.yml' do
|
180
|
+
cop_names = Cop::Cop.all.map do |cop_class|
|
181
|
+
cop_class.name.split('::').last
|
182
|
+
end
|
183
|
+
YAML.load_file('.rubocop.yml').keys.sort.should == cop_names.sort
|
184
|
+
end
|
156
185
|
end
|
157
186
|
end
|
158
187
|
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
module Rubocop
|
6
|
+
module Cop
|
7
|
+
describe FavorModifier do
|
8
|
+
let (:if_until) { IfUnlessModifier.new }
|
9
|
+
let (:while_until) { WhileUntilModifier.new }
|
10
|
+
|
11
|
+
it 'registers an offence for multiline if that fits on one line' do
|
12
|
+
# This if statement fits exactly on one line if written as a modifier.
|
13
|
+
inspect_source(if_until, 'file.rb',
|
14
|
+
['if a_condition_that_is_just_short_enough',
|
15
|
+
' some_long_metod_name(followed_by_args)',
|
16
|
+
'end'])
|
17
|
+
if_until.offences.map(&:message).should ==
|
18
|
+
['Favor modifier if/unless usage when you have a single-line body.' +
|
19
|
+
' Another good alternative is the usage of control flow and/or.']
|
20
|
+
end
|
21
|
+
|
22
|
+
it "accepts multiline if that doesn't fit on one line" do
|
23
|
+
check_too_long(if_until, 'if')
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'accepts multiline if whose body is more than one line' do
|
27
|
+
check_short_multiline(if_until, 'if')
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'registers an offence for multiline unless that fits on one line' do
|
31
|
+
inspect_source(if_until, 'file.rb', ['unless a',
|
32
|
+
' b',
|
33
|
+
'end'])
|
34
|
+
if_until.offences.map(&:message).should ==
|
35
|
+
['Favor modifier if/unless usage when you have a single-line body.' +
|
36
|
+
' Another good alternative is the usage of control flow and/or.']
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'accepts code with EOL comment since user might want to keep it' do
|
40
|
+
inspect_source(if_until, 'file.rb', ['unless a',
|
41
|
+
' b # A comment',
|
42
|
+
'end'])
|
43
|
+
if_until.offences.map(&:message).should == []
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'accepts if-else-end' do
|
47
|
+
inspect_source(if_until, 'file.rb',
|
48
|
+
['if args.last.is_a? Hash then args.pop else ' +
|
49
|
+
'Hash.new end'])
|
50
|
+
if_until.offences.map(&:message).should == []
|
51
|
+
end
|
52
|
+
|
53
|
+
it "accepts multiline unless that doesn't fit on one line" do
|
54
|
+
check_too_long(while_until, 'unless')
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'accepts multiline unless whose body is more than one line' do
|
58
|
+
check_short_multiline(while_until, 'unless')
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'registers an offence for multiline while that fits on one line' do
|
62
|
+
check_really_short(while_until, 'while')
|
63
|
+
end
|
64
|
+
|
65
|
+
it "accepts multiline while that doesn't fit on one line" do
|
66
|
+
check_too_long(while_until, 'while')
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'accepts multiline while whose body is more than one line' do
|
70
|
+
check_short_multiline(while_until, 'while')
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'registers an offence for multiline until that fits on one line' do
|
74
|
+
check_really_short(while_until, 'until')
|
75
|
+
end
|
76
|
+
|
77
|
+
it "accepts multiline until that doesn't fit on one line" do
|
78
|
+
check_too_long(while_until, 'until')
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'accepts multiline until whose body is more than one line' do
|
82
|
+
check_short_multiline(while_until, 'until')
|
83
|
+
end
|
84
|
+
|
85
|
+
def check_really_short(cop, keyword)
|
86
|
+
inspect_source(cop, 'file.rb', ["#{keyword} a",
|
87
|
+
' b',
|
88
|
+
'end'])
|
89
|
+
cop.offences.map(&:message).should ==
|
90
|
+
['Favor modifier while/until usage when you have a single-line ' +
|
91
|
+
'body.']
|
92
|
+
end
|
93
|
+
|
94
|
+
def check_too_long(cop, keyword)
|
95
|
+
inspect_source(cop, 'file.rb',
|
96
|
+
[" #{keyword} a_lengthy_condition_that_goes_on_and_on",
|
97
|
+
' some_long_metod_name(followed_by_args)',
|
98
|
+
' end'])
|
99
|
+
cop.offences.map(&:message).should == []
|
100
|
+
end
|
101
|
+
|
102
|
+
def check_short_multiline(cop, keyword)
|
103
|
+
inspect_source(cop, 'file.rb',
|
104
|
+
["#{keyword} ENV['COVERAGE']",
|
105
|
+
" require 'simplecov'",
|
106
|
+
' SimpleCov.start',
|
107
|
+
'end'])
|
108
|
+
cop.offences.map(&:message).should == []
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
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.3.
|
4
|
+
version: 0.3.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-02-
|
12
|
+
date: 2013-02-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -144,6 +144,7 @@ files:
|
|
144
144
|
- lib/rubocop/cop/empty_lines.rb
|
145
145
|
- lib/rubocop/cop/encoding.rb
|
146
146
|
- lib/rubocop/cop/end_of_line.rb
|
147
|
+
- lib/rubocop/cop/favor_modifier.rb
|
147
148
|
- lib/rubocop/cop/grammar.rb
|
148
149
|
- lib/rubocop/cop/hash_syntax.rb
|
149
150
|
- lib/rubocop/cop/if_then_else.rb
|
@@ -174,6 +175,7 @@ files:
|
|
174
175
|
- spec/rubocop/cops/empty_lines_spec.rb
|
175
176
|
- spec/rubocop/cops/encoding_spec.rb
|
176
177
|
- spec/rubocop/cops/end_of_line_spec.rb
|
178
|
+
- spec/rubocop/cops/favor_modifier_spec.rb
|
177
179
|
- spec/rubocop/cops/grammar_spec.rb
|
178
180
|
- spec/rubocop/cops/hash_syntax_spec.rb
|
179
181
|
- spec/rubocop/cops/if_with_semicolon_spec.rb
|
@@ -217,7 +219,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
217
219
|
version: '0'
|
218
220
|
segments:
|
219
221
|
- 0
|
220
|
-
hash:
|
222
|
+
hash: -1525847250123006446
|
221
223
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
222
224
|
none: false
|
223
225
|
requirements:
|