ruby-lint 0.0.1a
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.
- data/.gitignore +5 -0
- data/.rbenv-version +1 -0
- data/.yardopts +10 -0
- data/Gemfile +3 -0
- data/LICENSE +19 -0
- data/MANIFEST +79 -0
- data/README.md +48 -0
- data/Rakefile +14 -0
- data/bin/rlint +6 -0
- data/doc/.gitkeep +0 -0
- data/doc/build/.gitkeep +0 -0
- data/doc/css/.gitkeep +0 -0
- data/doc/css/common.css +68 -0
- data/lib/rlint/analyze/coding_style.rb +407 -0
- data/lib/rlint/analyze/definitions.rb +244 -0
- data/lib/rlint/analyze/method_validation.rb +104 -0
- data/lib/rlint/analyze/shadowing_variables.rb +37 -0
- data/lib/rlint/analyze/undefined_variables.rb +99 -0
- data/lib/rlint/analyze/unused_variables.rb +103 -0
- data/lib/rlint/callback.rb +67 -0
- data/lib/rlint/cli.rb +167 -0
- data/lib/rlint/constant_importer.rb +102 -0
- data/lib/rlint/definition.rb +230 -0
- data/lib/rlint/formatter/text.rb +54 -0
- data/lib/rlint/helper/definition_resolver.rb +143 -0
- data/lib/rlint/helper/scoping.rb +138 -0
- data/lib/rlint/iterator.rb +193 -0
- data/lib/rlint/options.rb +58 -0
- data/lib/rlint/parser.rb +1252 -0
- data/lib/rlint/parser_error.rb +42 -0
- data/lib/rlint/report.rb +98 -0
- data/lib/rlint/token/assignment_token.rb +46 -0
- data/lib/rlint/token/begin_rescue_token.rb +57 -0
- data/lib/rlint/token/block_token.rb +17 -0
- data/lib/rlint/token/case_token.rb +44 -0
- data/lib/rlint/token/class_token.rb +24 -0
- data/lib/rlint/token/method_definition_token.rb +64 -0
- data/lib/rlint/token/method_token.rb +58 -0
- data/lib/rlint/token/parameters_token.rb +99 -0
- data/lib/rlint/token/regexp_token.rb +15 -0
- data/lib/rlint/token/statement_token.rb +69 -0
- data/lib/rlint/token/token.rb +162 -0
- data/lib/rlint/token/variable_token.rb +18 -0
- data/lib/rlint/version.rb +3 -0
- data/lib/rlint.rb +36 -0
- data/ruby-lint.gemspec +23 -0
- data/spec/benchmarks/memory.rb +52 -0
- data/spec/benchmarks/parse_parser.rb +16 -0
- data/spec/helper.rb +4 -0
- data/spec/rlint/analyze/coding_style.rb +224 -0
- data/spec/rlint/analyze/definitions/classes.rb +114 -0
- data/spec/rlint/analyze/definitions/methods.rb +91 -0
- data/spec/rlint/analyze/definitions/modules.rb +207 -0
- data/spec/rlint/analyze/definitions/variables.rb +103 -0
- data/spec/rlint/analyze/method_validation.rb +177 -0
- data/spec/rlint/analyze/shadowing_variables.rb +30 -0
- data/spec/rlint/analyze/undefined_variables.rb +230 -0
- data/spec/rlint/analyze/unused_variables.rb +225 -0
- data/spec/rlint/callback.rb +28 -0
- data/spec/rlint/constant_importer.rb +27 -0
- data/spec/rlint/definition.rb +96 -0
- data/spec/rlint/formatter/text.rb +21 -0
- data/spec/rlint/iterator.rb +452 -0
- data/spec/rlint/parser/arrays.rb +147 -0
- data/spec/rlint/parser/classes.rb +152 -0
- data/spec/rlint/parser/errors.rb +19 -0
- data/spec/rlint/parser/hashes.rb +136 -0
- data/spec/rlint/parser/methods.rb +249 -0
- data/spec/rlint/parser/modules.rb +49 -0
- data/spec/rlint/parser/objects.rb +39 -0
- data/spec/rlint/parser/operators.rb +75 -0
- data/spec/rlint/parser/procs.rb +113 -0
- data/spec/rlint/parser/ranges.rb +49 -0
- data/spec/rlint/parser/regexp.rb +31 -0
- data/spec/rlint/parser/scalars.rb +93 -0
- data/spec/rlint/parser/statements.rb +550 -0
- data/spec/rlint/parser/variables.rb +181 -0
- data/spec/rlint/report.rb +30 -0
- data/task/test.rake +6 -0
- metadata +188 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
# This file runs a simple benchmark to see how fast (or slow) Rlint is.
|
2
|
+
# It benchmarks how long it takes to parse the main parser file
|
3
|
+
# (lib/rlint/parser.rb) itself.
|
4
|
+
require File.expand_path('../../../lib/rlint', __FILE__)
|
5
|
+
require 'benchmark'
|
6
|
+
|
7
|
+
code = File.read(File.expand_path('../../../lib/rlint/parser.rb', __FILE__))
|
8
|
+
amount = ENV['AMOUNT'] ? ENV['AMOUNT'].to_i : 100
|
9
|
+
|
10
|
+
Benchmark.bmbm(40) do |bench|
|
11
|
+
bench.report "Parse parser.rb #{amount} times" do
|
12
|
+
amount.times do
|
13
|
+
Rlint::Parser.new(code).parse
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/spec/helper.rb
ADDED
@@ -0,0 +1,224 @@
|
|
1
|
+
require File.expand_path('../../../helper', __FILE__)
|
2
|
+
|
3
|
+
describe 'Rlint::Analyze::CodingStyle' do
|
4
|
+
it 'Check the casing of method names and variables' do
|
5
|
+
code = <<-CODE
|
6
|
+
def getNumber(theNumber = 10)
|
7
|
+
valid_number = theNumber
|
8
|
+
|
9
|
+
return theNumber
|
10
|
+
end
|
11
|
+
CODE
|
12
|
+
|
13
|
+
tokens = Rlint::Parser.new(code).parse
|
14
|
+
report = Rlint::Report.new
|
15
|
+
iterator = Rlint::Iterator.new(report)
|
16
|
+
|
17
|
+
iterator.bind(Rlint::Analyze::CodingStyle)
|
18
|
+
iterator.run(tokens)
|
19
|
+
|
20
|
+
messages = report.messages[:info]
|
21
|
+
message = 'the use of camelCase for names is discouraged'
|
22
|
+
|
23
|
+
messages.class.should == Array
|
24
|
+
messages.length.should == 4
|
25
|
+
|
26
|
+
messages[0][:message].should == message
|
27
|
+
messages[0][:line].should == 1
|
28
|
+
messages[0][:column].should == 4
|
29
|
+
|
30
|
+
messages[1][:message].should == message
|
31
|
+
messages[1][:line].should == 1
|
32
|
+
messages[1][:column].should == 14
|
33
|
+
|
34
|
+
messages[2][:message].should == message
|
35
|
+
messages[2][:line].should == 2
|
36
|
+
messages[2][:column].should == 17
|
37
|
+
|
38
|
+
messages[3][:message].should == message
|
39
|
+
messages[3][:line].should == 4
|
40
|
+
messages[3][:column].should == 9
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'Check the length of method and variable names' do
|
44
|
+
code = <<-CODE
|
45
|
+
def this_method_name_is_rather_long_dont_you_think
|
46
|
+
this_variable_name_is_also_rather_long = 10
|
47
|
+
end
|
48
|
+
|
49
|
+
this_variable_is_fine = 10
|
50
|
+
|
51
|
+
THIS_CONSTANT_NAME_IS_WAY_TOO_LONG = 10
|
52
|
+
CODE
|
53
|
+
|
54
|
+
tokens = Rlint::Parser.new(code).parse
|
55
|
+
report = Rlint::Report.new
|
56
|
+
iterator = Rlint::Iterator.new(report)
|
57
|
+
|
58
|
+
iterator.bind(Rlint::Analyze::CodingStyle)
|
59
|
+
iterator.run(tokens)
|
60
|
+
|
61
|
+
messages = report.messages[:info]
|
62
|
+
message = "method and variable names should not be longer than " \
|
63
|
+
"#{Rlint::Analyze::CodingStyle::MAXIMUM_NAME_LENGTH} characters"
|
64
|
+
|
65
|
+
messages[0][:message].should == message
|
66
|
+
messages[0][:line].should == 1
|
67
|
+
messages[0][:column].should == 4
|
68
|
+
|
69
|
+
messages[1][:message].should == message
|
70
|
+
messages[1][:line].should == 2
|
71
|
+
messages[1][:column].should == 2
|
72
|
+
|
73
|
+
messages[2][:message].should == message
|
74
|
+
messages[2][:line].should == 7
|
75
|
+
messages[2][:column].should == 0
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'Check for the use of class variables' do
|
79
|
+
tokens = Rlint::Parser.new('@@number = 10').parse
|
80
|
+
report = Rlint::Report.new
|
81
|
+
iterator = Rlint::Iterator.new(report)
|
82
|
+
|
83
|
+
iterator.bind(Rlint::Analyze::CodingStyle)
|
84
|
+
iterator.run(tokens)
|
85
|
+
|
86
|
+
info = report.messages[:info][0]
|
87
|
+
|
88
|
+
info[:message].should == 'the use of class variables is discouraged'
|
89
|
+
info[:line].should == 1
|
90
|
+
info[:column].should == 0
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'Check for the use of parenthesis in various statements' do
|
94
|
+
code = <<-CODE
|
95
|
+
if ( name == 'Ruby' )
|
96
|
+
puts 'This is some weird code'
|
97
|
+
elsif ( name == 'Python')
|
98
|
+
puts 10
|
99
|
+
end
|
100
|
+
|
101
|
+
while ( true )
|
102
|
+
puts 'Infinite loop'
|
103
|
+
end
|
104
|
+
|
105
|
+
case ( number )
|
106
|
+
when ( 10 )
|
107
|
+
puts 'The number is 10'
|
108
|
+
else
|
109
|
+
puts 'Something else'
|
110
|
+
end
|
111
|
+
|
112
|
+
until ( number == 10 )
|
113
|
+
number += 1
|
114
|
+
end
|
115
|
+
|
116
|
+
unless ( foobar )
|
117
|
+
something
|
118
|
+
end
|
119
|
+
CODE
|
120
|
+
|
121
|
+
tokens = Rlint::Parser.new(code).parse
|
122
|
+
report = Rlint::Report.new
|
123
|
+
iterator = Rlint::Iterator.new(report)
|
124
|
+
|
125
|
+
iterator.bind(Rlint::Analyze::CodingStyle)
|
126
|
+
iterator.run(tokens)
|
127
|
+
|
128
|
+
report.messages[:info].class.should == Array
|
129
|
+
report.messages[:info].length.should == 7
|
130
|
+
|
131
|
+
message = 'the use of parenthesis for statements is discouraged'
|
132
|
+
|
133
|
+
[1, 3, 7, 11, 12, 18, 22].each_with_index do |line, index|
|
134
|
+
report.messages[:info][index][:message].should == message
|
135
|
+
report.messages[:info][index][:line].should == line
|
136
|
+
report.messages[:info][index][:column].should == 0
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'Check for correct names for predicate methods' do
|
141
|
+
code = <<-CODE
|
142
|
+
def invalid_name
|
143
|
+
return true
|
144
|
+
end
|
145
|
+
|
146
|
+
def valid_name?
|
147
|
+
return true
|
148
|
+
end
|
149
|
+
CODE
|
150
|
+
|
151
|
+
tokens = Rlint::Parser.new(code).parse
|
152
|
+
report = Rlint::Report.new
|
153
|
+
iterator = Rlint::Iterator.new(report)
|
154
|
+
|
155
|
+
iterator.bind(Rlint::Analyze::CodingStyle)
|
156
|
+
iterator.run(tokens)
|
157
|
+
|
158
|
+
message = 'predicate methods should end with a question mark'
|
159
|
+
|
160
|
+
report.messages[:info].class.should == Array
|
161
|
+
report.messages[:info].length.should == 1
|
162
|
+
|
163
|
+
report.messages[:info][0][:message].should == message
|
164
|
+
report.messages[:info][0][:line].should == 1
|
165
|
+
report.messages[:info][0][:column].should == 4
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'Check for recommending alternative method names' do
|
169
|
+
code = <<-CODE
|
170
|
+
[].collect { |a| }
|
171
|
+
[].map { |a| }
|
172
|
+
CODE
|
173
|
+
|
174
|
+
tokens = Rlint::Parser.new(code).parse
|
175
|
+
report = Rlint::Report.new
|
176
|
+
iterator = Rlint::Iterator.new(report)
|
177
|
+
|
178
|
+
iterator.bind(Rlint::Analyze::CodingStyle)
|
179
|
+
iterator.run(tokens)
|
180
|
+
|
181
|
+
message = 'it is recommended to use the method "map" instead of "collect"'
|
182
|
+
|
183
|
+
report.messages[:info].class.should == Array
|
184
|
+
report.messages[:info].length.should == 1
|
185
|
+
|
186
|
+
report.messages[:info][0][:message].should == message
|
187
|
+
report.messages[:info][0][:line].should == 1
|
188
|
+
report.messages[:info][0][:column].should == 3
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'Add warnings when modifying core Ruby constants' do
|
192
|
+
code = <<-CODE
|
193
|
+
class String
|
194
|
+
def custom_method
|
195
|
+
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def String.class_method
|
200
|
+
|
201
|
+
end
|
202
|
+
CODE
|
203
|
+
|
204
|
+
tokens = Rlint::Parser.new(code).parse
|
205
|
+
report = Rlint::Report.new
|
206
|
+
iterator = Rlint::Iterator.new(report)
|
207
|
+
|
208
|
+
iterator.bind(Rlint::Analyze::CodingStyle)
|
209
|
+
iterator.run(tokens)
|
210
|
+
|
211
|
+
report.messages[:warning].class.should == Array
|
212
|
+
report.messages[:warning].length.should == 2
|
213
|
+
|
214
|
+
warnings = report.messages[:warning]
|
215
|
+
|
216
|
+
warnings[0][:message].should == 'modification of a core Ruby constant'
|
217
|
+
warnings[0][:line].should == 1
|
218
|
+
warnings[0][:column].should == 6
|
219
|
+
|
220
|
+
warnings[1][:message].should == 'modification of a core Ruby constant'
|
221
|
+
warnings[1][:line].should == 7
|
222
|
+
warnings[1][:column].should == 4
|
223
|
+
end
|
224
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require File.expand_path('../../../../helper', __FILE__)
|
2
|
+
|
3
|
+
describe 'Rlint::Analyze::Definitions: classes' do
|
4
|
+
it 'Define a class in the global scope' do
|
5
|
+
code = <<-CODE
|
6
|
+
class Example
|
7
|
+
def example_method
|
8
|
+
|
9
|
+
end
|
10
|
+
end
|
11
|
+
CODE
|
12
|
+
|
13
|
+
tokens = Rlint::Parser.new(code).parse
|
14
|
+
iterator = Rlint::Iterator.new
|
15
|
+
|
16
|
+
iterator.bind(Rlint::Analyze::Definitions)
|
17
|
+
iterator.run(tokens)
|
18
|
+
|
19
|
+
scope = iterator.storage[:scope]
|
20
|
+
const = scope.lookup(:constant, 'Example')
|
21
|
+
|
22
|
+
const.class.should == Rlint::Definition
|
23
|
+
|
24
|
+
const.token.class.should == Rlint::Token::ClassToken
|
25
|
+
const.token.name.should == ['Example']
|
26
|
+
const.token.value.nil?.should == true
|
27
|
+
|
28
|
+
# Check the method that was defined inside the class.
|
29
|
+
scope.lookup(:instance_method, 'example_method').nil?.should == true
|
30
|
+
|
31
|
+
method = const.lookup(:instance_method, 'example_method')
|
32
|
+
|
33
|
+
method.class.should == Rlint::Definition
|
34
|
+
|
35
|
+
method.token.class.should == Rlint::Token::MethodDefinitionToken
|
36
|
+
method.token.name.should == 'example_method'
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'Define a class method inside a class' do
|
40
|
+
code = <<-CODE
|
41
|
+
class Example
|
42
|
+
def self.example_method
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
CODE
|
47
|
+
|
48
|
+
tokens = Rlint::Parser.new(code).parse
|
49
|
+
iterator = Rlint::Iterator.new
|
50
|
+
|
51
|
+
iterator.bind(Rlint::Analyze::Definitions)
|
52
|
+
iterator.run(tokens)
|
53
|
+
|
54
|
+
scope = iterator.storage[:scope]
|
55
|
+
|
56
|
+
scope.lookup(:method, 'example_method').nil?.should == true
|
57
|
+
|
58
|
+
const = scope.lookup(:constant, 'Example')
|
59
|
+
|
60
|
+
const.class.should == Rlint::Definition
|
61
|
+
|
62
|
+
const.lookup(:instance_method, 'example_method').nil?.should == true
|
63
|
+
const.lookup(:method, 'example_method').class.should == Rlint::Definition
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'Inherit methods from a parent class' do
|
67
|
+
code = <<-CODE
|
68
|
+
class A
|
69
|
+
def parent_method
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class B < A
|
75
|
+
|
76
|
+
end
|
77
|
+
CODE
|
78
|
+
|
79
|
+
tokens = Rlint::Parser.new(code).parse
|
80
|
+
iterator = Rlint::Iterator.new
|
81
|
+
|
82
|
+
iterator.bind(Rlint::Analyze::Definitions)
|
83
|
+
iterator.run(tokens)
|
84
|
+
|
85
|
+
scope = iterator.storage[:scope]
|
86
|
+
|
87
|
+
a = scope.lookup(:constant, 'A')
|
88
|
+
b = scope.lookup(:constant, 'B')
|
89
|
+
|
90
|
+
# check class A
|
91
|
+
a.class.should == Rlint::Definition
|
92
|
+
|
93
|
+
a.token.class.should == Rlint::Token::ClassToken
|
94
|
+
a.token.name.should == ['A']
|
95
|
+
a.token.parent.should == ['Object']
|
96
|
+
|
97
|
+
a.lookup(:method, :methods).class.should == Rlint::Definition
|
98
|
+
a.lookup(:instance_method, :methods).class.should == Rlint::Definition
|
99
|
+
|
100
|
+
# check class B
|
101
|
+
b.class.should == Rlint::Definition
|
102
|
+
|
103
|
+
b.token.class.should == Rlint::Token::ClassToken
|
104
|
+
b.token.name.should == ['B']
|
105
|
+
b.token.parent.should == ['A']
|
106
|
+
|
107
|
+
b.lookup(:instance_method, 'parent_method') \
|
108
|
+
.class \
|
109
|
+
.should == Rlint::Definition
|
110
|
+
|
111
|
+
b.lookup(:method, :methods).class.should == Rlint::Definition
|
112
|
+
b.lookup(:instance_method, :methods).class.should == Rlint::Definition
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require File.expand_path('../../../../helper', __FILE__)
|
2
|
+
|
3
|
+
describe 'Rlint::Analyze::Definitions: methods' do
|
4
|
+
it 'Build a list of globally defined methods' do
|
5
|
+
code = <<-CODE
|
6
|
+
def example_method
|
7
|
+
return 10
|
8
|
+
end
|
9
|
+
|
10
|
+
def another_example_method
|
11
|
+
return 20
|
12
|
+
end
|
13
|
+
CODE
|
14
|
+
|
15
|
+
tokens = Rlint::Parser.new(code).parse
|
16
|
+
iterator = Rlint::Iterator.new
|
17
|
+
|
18
|
+
iterator.bind(Rlint::Analyze::Definitions)
|
19
|
+
iterator.run(tokens)
|
20
|
+
|
21
|
+
scope = iterator.storage[:scope]
|
22
|
+
|
23
|
+
scope.class.should == Rlint::Definition
|
24
|
+
|
25
|
+
method_1 = scope.lookup(:instance_method, 'example_method')
|
26
|
+
method_2 = scope.lookup(:instance_method, 'another_example_method')
|
27
|
+
|
28
|
+
method_1.class.should == Rlint::Definition
|
29
|
+
method_1.token.class.should == Rlint::Token::MethodDefinitionToken
|
30
|
+
method_1.token.name.should == 'example_method'
|
31
|
+
|
32
|
+
method_2.class.should == Rlint::Definition
|
33
|
+
method_2.token.class.should == Rlint::Token::MethodDefinitionToken
|
34
|
+
method_2.token.name.should == 'another_example_method'
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'Build a list of globally defined class methods' do
|
38
|
+
code = <<-CODE
|
39
|
+
def self.example_method
|
40
|
+
return 10
|
41
|
+
end
|
42
|
+
CODE
|
43
|
+
|
44
|
+
tokens = Rlint::Parser.new(code).parse
|
45
|
+
iterator = Rlint::Iterator.new
|
46
|
+
|
47
|
+
iterator.bind(Rlint::Analyze::Definitions)
|
48
|
+
iterator.run(tokens)
|
49
|
+
|
50
|
+
scope = iterator.storage[:scope]
|
51
|
+
|
52
|
+
scope.class.should == Rlint::Definition
|
53
|
+
|
54
|
+
method = scope.lookup(:method, 'example_method')
|
55
|
+
|
56
|
+
method.class.should == Rlint::Definition
|
57
|
+
method.token.class.should == Rlint::Token::MethodDefinitionToken
|
58
|
+
method.token.name.should == 'example_method'
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'Define a class method on the String class' do
|
62
|
+
code = <<-CODE
|
63
|
+
def String.example_method
|
64
|
+
return 10
|
65
|
+
end
|
66
|
+
CODE
|
67
|
+
|
68
|
+
tokens = Rlint::Parser.new(code).parse
|
69
|
+
iterator = Rlint::Iterator.new
|
70
|
+
|
71
|
+
iterator.bind(Rlint::Analyze::Definitions)
|
72
|
+
iterator.run(tokens)
|
73
|
+
|
74
|
+
scope = iterator.storage[:scope]
|
75
|
+
|
76
|
+
scope.class.should == Rlint::Definition
|
77
|
+
|
78
|
+
scope.lookup(:instance_method, 'example_method').nil?.should == true
|
79
|
+
scope.lookup(:method, 'example_method').nil?.should == true
|
80
|
+
|
81
|
+
string = scope.lookup(:constant, 'String')
|
82
|
+
|
83
|
+
string.class.should == Rlint::Definition
|
84
|
+
|
85
|
+
method = string.lookup(:method, 'example_method')
|
86
|
+
|
87
|
+
method.class.should == Rlint::Definition
|
88
|
+
method.token.class.should == Rlint::Token::MethodDefinitionToken
|
89
|
+
method.token.name.should == 'example_method'
|
90
|
+
end
|
91
|
+
end
|