ruby-lint 0.0.1a

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/.gitignore +5 -0
  2. data/.rbenv-version +1 -0
  3. data/.yardopts +10 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE +19 -0
  6. data/MANIFEST +79 -0
  7. data/README.md +48 -0
  8. data/Rakefile +14 -0
  9. data/bin/rlint +6 -0
  10. data/doc/.gitkeep +0 -0
  11. data/doc/build/.gitkeep +0 -0
  12. data/doc/css/.gitkeep +0 -0
  13. data/doc/css/common.css +68 -0
  14. data/lib/rlint/analyze/coding_style.rb +407 -0
  15. data/lib/rlint/analyze/definitions.rb +244 -0
  16. data/lib/rlint/analyze/method_validation.rb +104 -0
  17. data/lib/rlint/analyze/shadowing_variables.rb +37 -0
  18. data/lib/rlint/analyze/undefined_variables.rb +99 -0
  19. data/lib/rlint/analyze/unused_variables.rb +103 -0
  20. data/lib/rlint/callback.rb +67 -0
  21. data/lib/rlint/cli.rb +167 -0
  22. data/lib/rlint/constant_importer.rb +102 -0
  23. data/lib/rlint/definition.rb +230 -0
  24. data/lib/rlint/formatter/text.rb +54 -0
  25. data/lib/rlint/helper/definition_resolver.rb +143 -0
  26. data/lib/rlint/helper/scoping.rb +138 -0
  27. data/lib/rlint/iterator.rb +193 -0
  28. data/lib/rlint/options.rb +58 -0
  29. data/lib/rlint/parser.rb +1252 -0
  30. data/lib/rlint/parser_error.rb +42 -0
  31. data/lib/rlint/report.rb +98 -0
  32. data/lib/rlint/token/assignment_token.rb +46 -0
  33. data/lib/rlint/token/begin_rescue_token.rb +57 -0
  34. data/lib/rlint/token/block_token.rb +17 -0
  35. data/lib/rlint/token/case_token.rb +44 -0
  36. data/lib/rlint/token/class_token.rb +24 -0
  37. data/lib/rlint/token/method_definition_token.rb +64 -0
  38. data/lib/rlint/token/method_token.rb +58 -0
  39. data/lib/rlint/token/parameters_token.rb +99 -0
  40. data/lib/rlint/token/regexp_token.rb +15 -0
  41. data/lib/rlint/token/statement_token.rb +69 -0
  42. data/lib/rlint/token/token.rb +162 -0
  43. data/lib/rlint/token/variable_token.rb +18 -0
  44. data/lib/rlint/version.rb +3 -0
  45. data/lib/rlint.rb +36 -0
  46. data/ruby-lint.gemspec +23 -0
  47. data/spec/benchmarks/memory.rb +52 -0
  48. data/spec/benchmarks/parse_parser.rb +16 -0
  49. data/spec/helper.rb +4 -0
  50. data/spec/rlint/analyze/coding_style.rb +224 -0
  51. data/spec/rlint/analyze/definitions/classes.rb +114 -0
  52. data/spec/rlint/analyze/definitions/methods.rb +91 -0
  53. data/spec/rlint/analyze/definitions/modules.rb +207 -0
  54. data/spec/rlint/analyze/definitions/variables.rb +103 -0
  55. data/spec/rlint/analyze/method_validation.rb +177 -0
  56. data/spec/rlint/analyze/shadowing_variables.rb +30 -0
  57. data/spec/rlint/analyze/undefined_variables.rb +230 -0
  58. data/spec/rlint/analyze/unused_variables.rb +225 -0
  59. data/spec/rlint/callback.rb +28 -0
  60. data/spec/rlint/constant_importer.rb +27 -0
  61. data/spec/rlint/definition.rb +96 -0
  62. data/spec/rlint/formatter/text.rb +21 -0
  63. data/spec/rlint/iterator.rb +452 -0
  64. data/spec/rlint/parser/arrays.rb +147 -0
  65. data/spec/rlint/parser/classes.rb +152 -0
  66. data/spec/rlint/parser/errors.rb +19 -0
  67. data/spec/rlint/parser/hashes.rb +136 -0
  68. data/spec/rlint/parser/methods.rb +249 -0
  69. data/spec/rlint/parser/modules.rb +49 -0
  70. data/spec/rlint/parser/objects.rb +39 -0
  71. data/spec/rlint/parser/operators.rb +75 -0
  72. data/spec/rlint/parser/procs.rb +113 -0
  73. data/spec/rlint/parser/ranges.rb +49 -0
  74. data/spec/rlint/parser/regexp.rb +31 -0
  75. data/spec/rlint/parser/scalars.rb +93 -0
  76. data/spec/rlint/parser/statements.rb +550 -0
  77. data/spec/rlint/parser/variables.rb +181 -0
  78. data/spec/rlint/report.rb +30 -0
  79. data/task/test.rake +6 -0
  80. metadata +188 -0
@@ -0,0 +1,30 @@
1
+ require File.expand_path('../../../helper', __FILE__)
2
+
3
+ describe 'Rlint::Analyze::ShadowingVariables' do
4
+ it 'Warn for shadowing outer variables' do
5
+ code = <<-CODE
6
+ number = 10
7
+
8
+ [10, 20].each do |number|
9
+ puts number
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::Definitions)
18
+ iterator.bind(Rlint::Analyze::ShadowingVariables)
19
+ iterator.run(tokens)
20
+
21
+ report.messages[:warning].class.should == Array
22
+ report.messages[:warning].length.should == 1
23
+
24
+ warning = report.messages[:warning][0]
25
+
26
+ warning[:message].should == 'shadowing outer local variable number'
27
+ warning[:line].should == 3
28
+ warning[:column].should == 18
29
+ end
30
+ end
@@ -0,0 +1,230 @@
1
+ require File.expand_path('../../../helper', __FILE__)
2
+
3
+ describe 'Rlint::Analyze::UndefinedVariables' do
4
+ it 'Use of undefined variables' do
5
+ code = <<-CODE
6
+ number = 10
7
+
8
+ puts numberx
9
+ puts @number
10
+ puts @@number
11
+ puts $number
12
+ puts NUMBER
13
+
14
+ # The code below should not add any errors.
15
+ numberx = 10
16
+ @number = 10
17
+ @@number = 10
18
+ $number = 10
19
+ NUMBER = 10
20
+
21
+ puts numberx
22
+ puts @number
23
+ puts @@number
24
+ puts $number
25
+ puts NUMBER
26
+ CODE
27
+
28
+ tokens = Rlint::Parser.new(code).parse
29
+ report = Rlint::Report.new
30
+ iterator = Rlint::Iterator.new(report)
31
+
32
+ iterator.bind(Rlint::Analyze::Definitions)
33
+ iterator.bind(Rlint::Analyze::UndefinedVariables)
34
+ iterator.run(tokens)
35
+
36
+ report.messages[:error].class.should == Array
37
+ report.messages[:error].length.should == 5
38
+
39
+ errors = report.messages[:error]
40
+
41
+ errors[0][:message].should == 'undefined local variable or method numberx'
42
+ errors[0][:line].should == 3
43
+ errors[0][:column].should == 5
44
+
45
+ errors[1][:message].should == 'undefined instance variable @number'
46
+ errors[1][:line].should == 4
47
+ errors[1][:column].should == 5
48
+
49
+ errors[2][:message].should == 'undefined class variable @@number'
50
+ errors[2][:line].should == 5
51
+ errors[2][:column].should == 5
52
+
53
+ errors[3][:message].should == 'undefined global variable $number'
54
+ errors[3][:line].should == 6
55
+ errors[3][:column].should == 5
56
+
57
+ errors[4][:message].should == 'undefined constant NUMBER'
58
+ errors[4][:line].should == 7
59
+ errors[4][:column].should == 5
60
+ end
61
+
62
+ it 'Default global variables should not trigger errors' do
63
+ code = Kernel.global_variables.join("\n")
64
+ tokens = Rlint::Parser.new(code).parse
65
+ report = Rlint::Report.new
66
+ iterator = Rlint::Iterator.new(report)
67
+
68
+ iterator.bind(Rlint::Analyze::Definitions)
69
+ iterator.bind(Rlint::Analyze::UndefinedVariables)
70
+ iterator.run(tokens)
71
+
72
+ report.messages[:error].nil?.should == true
73
+ end
74
+
75
+ it 'Use of undefined variables using a method scope' do
76
+ code = <<-CODE
77
+ a = 10
78
+ @a = 10
79
+
80
+ def number
81
+ b = 10
82
+
83
+ puts @a # @a should be available as it's an instance method
84
+ puts a # a is defined outside of this scope
85
+ puts c # c simply doesn't exist
86
+ end
87
+
88
+ puts a
89
+ puts b # b was defined inside the method and isn't available outside it
90
+ CODE
91
+
92
+ tokens = Rlint::Parser.new(code).parse
93
+ report = Rlint::Report.new
94
+ iterator = Rlint::Iterator.new(report)
95
+
96
+ iterator.bind(Rlint::Analyze::Definitions)
97
+ iterator.bind(Rlint::Analyze::UndefinedVariables)
98
+ iterator.run(tokens)
99
+
100
+ report.messages[:error].class.should == Array
101
+ report.messages[:error].length.should == 3
102
+
103
+ errors = report.messages[:error]
104
+
105
+ errors[0][:message].should == 'undefined local variable or method a'
106
+ errors[0][:line].should == 8
107
+ errors[0][:column].should == 7
108
+
109
+ errors[1][:message].should == 'undefined local variable or method c'
110
+ errors[1][:line].should == 9
111
+ errors[1][:column].should == 7
112
+
113
+ errors[2][:message].should == 'undefined local variable or method b'
114
+ errors[2][:line].should == 13
115
+ errors[2][:column].should == 5
116
+ end
117
+
118
+ it 'Instance variables should be available outside a method' do
119
+ code = <<-CODE
120
+ def number
121
+ @number = 10
122
+ end
123
+
124
+ puts @number
125
+ CODE
126
+
127
+ tokens = Rlint::Parser.new(code).parse
128
+ report = Rlint::Report.new
129
+ iterator = Rlint::Iterator.new(report)
130
+
131
+ iterator.bind(Rlint::Analyze::Definitions)
132
+ iterator.bind(Rlint::Analyze::UndefinedVariables)
133
+ iterator.run(tokens)
134
+
135
+ report.messages[:error].nil?.should == true
136
+ end
137
+
138
+ it 'Instance variables should be available across a class\' methods' do
139
+ code = <<-CODE
140
+ class Person
141
+ def initialize
142
+ @name = 'Ruby'
143
+ end
144
+
145
+ def some_method
146
+ @name.upcase
147
+ @namex.upcase
148
+ end
149
+ end
150
+ CODE
151
+
152
+ tokens = Rlint::Parser.new(code).parse
153
+ report = Rlint::Report.new
154
+ iterator = Rlint::Iterator.new(report)
155
+
156
+ iterator.bind(Rlint::Analyze::Definitions)
157
+ iterator.bind(Rlint::Analyze::UndefinedVariables)
158
+ iterator.run(tokens)
159
+
160
+ report.messages[:error].class.should == Array
161
+ report.messages[:error].length.should == 1
162
+
163
+ error = report.messages[:error][0]
164
+
165
+ error[:message].should == 'undefined instance variable @namex'
166
+ error[:line].should == 8
167
+ error[:column].should == 4
168
+ end
169
+
170
+ it 'Add errors for non existing constant paths' do
171
+ code = <<-CODE
172
+ A::B = 10
173
+
174
+ module A
175
+
176
+ end
177
+
178
+ puts A::B
179
+ CODE
180
+
181
+ tokens = Rlint::Parser.new(code).parse
182
+ report = Rlint::Report.new
183
+ iterator = Rlint::Iterator.new(report)
184
+
185
+ iterator.bind(Rlint::Analyze::Definitions)
186
+ iterator.bind(Rlint::Analyze::UndefinedVariables)
187
+ iterator.run(tokens)
188
+
189
+ report.messages[:error].class.should == Array
190
+ report.messages[:error].length.should == 2
191
+
192
+ errors = report.messages[:error]
193
+
194
+ errors[0][:message].should == 'undefined constant A'
195
+ errors[0][:line].should == 1
196
+ errors[0][:column].should == 0
197
+
198
+ errors[1][:message].should == 'undefined constant A::B'
199
+ errors[1][:line].should == 7
200
+ errors[1][:column].should == 5
201
+ end
202
+
203
+ it 'Look up a constant using an implicit constant path' do
204
+ code = <<-CODE
205
+ module Rlint
206
+ module Derp
207
+ Foobar.name
208
+ ConstantImporter.name
209
+ end
210
+ end
211
+ CODE
212
+
213
+ tokens = Rlint::Parser.new(code).parse
214
+ report = Rlint::Report.new
215
+ iterator = Rlint::Iterator.new(report)
216
+
217
+ iterator.bind(Rlint::Analyze::Definitions)
218
+ iterator.bind(Rlint::Analyze::UndefinedVariables)
219
+ iterator.run(tokens)
220
+
221
+ report.messages[:error].class.should == Array
222
+ report.messages[:error].length.should == 1
223
+
224
+ error = report.messages[:error][0]
225
+
226
+ error[:message].should == 'undefined constant Foobar'
227
+ error[:line].should == 3
228
+ error[:column].should == 4
229
+ end
230
+ end
@@ -0,0 +1,225 @@
1
+ require File.expand_path('../../../helper', __FILE__)
2
+
3
+ describe 'Rlint::Analyze::UnusedVariables' do
4
+ it 'Add warnings for unused variables in the global scope' do
5
+ code = <<-CODE
6
+ number = 10
7
+ @number = 10
8
+ @@number = 10
9
+ $number = 10
10
+
11
+ number_2 = 10
12
+ @number_2 = 10
13
+ @@number_2 = 10
14
+ $number_2 = 10
15
+
16
+ puts number_2
17
+ puts @number_2
18
+ puts @@number_2
19
+ puts $number_2
20
+ CODE
21
+
22
+ tokens = Rlint::Parser.new(code).parse
23
+ report = Rlint::Report.new
24
+ iterator = Rlint::Iterator.new(report)
25
+
26
+ iterator.bind(Rlint::Analyze::Definitions)
27
+ iterator.bind(Rlint::Analyze::UnusedVariables)
28
+ iterator.run(tokens)
29
+
30
+ report.messages[:warning].class.should == Array
31
+ report.messages[:warning].length.should == 4
32
+
33
+ warnings = report.messages[:warning]
34
+
35
+ warnings[0][:message].should == 'assigned but unused local variable number'
36
+ warnings[0][:line].should == 1
37
+ warnings[0][:column].should == 0
38
+
39
+ warnings[1][:message].should == 'assigned but unused instance ' \
40
+ 'variable @number'
41
+
42
+ warnings[1][:line].should == 2
43
+ warnings[1][:column].should == 0
44
+
45
+ warnings[2][:message].should == 'assigned but unused class ' \
46
+ 'variable @@number'
47
+
48
+ warnings[2][:line].should == 3
49
+ warnings[2][:column].should == 0
50
+
51
+ warnings[3][:message].should == 'assigned but unused global ' \
52
+ 'variable $number'
53
+
54
+ warnings[3][:line].should == 4
55
+ warnings[3][:column].should == 0
56
+ end
57
+
58
+ it 'Add warnings for unused variables in a method definition scope' do
59
+ code = <<-CODE
60
+ def example
61
+ number = 10
62
+ @number = 10
63
+ @@number = 10
64
+ $number = 10
65
+
66
+ number_2 = 10
67
+ @number_2 = 10
68
+ @@number_2 = 10
69
+ $number_2 = 10
70
+
71
+ puts number_2
72
+ puts @number_2
73
+ puts @@number_2
74
+ puts $number_2
75
+ end
76
+ CODE
77
+
78
+ tokens = Rlint::Parser.new(code).parse
79
+ report = Rlint::Report.new
80
+ iterator = Rlint::Iterator.new(report)
81
+
82
+ iterator.bind(Rlint::Analyze::Definitions)
83
+ iterator.bind(Rlint::Analyze::UnusedVariables)
84
+ iterator.run(tokens)
85
+
86
+ report.messages[:warning].class.should == Array
87
+ report.messages[:warning].length.should == 4
88
+
89
+ warnings = report.messages[:warning]
90
+
91
+ warnings[0][:message].should == 'assigned but unused local variable number'
92
+ warnings[0][:line].should == 2
93
+ warnings[0][:column].should == 2
94
+
95
+ warnings[1][:message].should == 'assigned but unused instance ' \
96
+ 'variable @number'
97
+
98
+ warnings[1][:line].should == 3
99
+ warnings[1][:column].should == 2
100
+
101
+ warnings[2][:message].should == 'assigned but unused class ' \
102
+ 'variable @@number'
103
+
104
+ warnings[2][:line].should == 4
105
+ warnings[2][:column].should == 2
106
+
107
+ warnings[3][:message].should == 'assigned but unused global ' \
108
+ 'variable $number'
109
+
110
+ warnings[3][:line].should == 5
111
+ warnings[3][:column].should == 2
112
+ end
113
+
114
+ it 'Add warnings for unused variables in a class definition scope' do
115
+ code = <<-CODE
116
+ class Example
117
+ number = 10
118
+ @number = 10
119
+ @@number = 10
120
+ $number = 10
121
+
122
+ number_2 = 10
123
+ @number_2 = 10
124
+ @@number_2 = 10
125
+ $number_2 = 10
126
+
127
+ puts number_2
128
+ puts @number_2
129
+ puts @@number_2
130
+ puts $number_2
131
+ end
132
+ CODE
133
+
134
+ tokens = Rlint::Parser.new(code).parse
135
+ report = Rlint::Report.new
136
+ iterator = Rlint::Iterator.new(report)
137
+
138
+ iterator.bind(Rlint::Analyze::Definitions)
139
+ iterator.bind(Rlint::Analyze::UnusedVariables)
140
+ iterator.run(tokens)
141
+
142
+ report.messages[:warning].class.should == Array
143
+ report.messages[:warning].length.should == 4
144
+
145
+ warnings = report.messages[:warning]
146
+
147
+ warnings[0][:message].should == 'assigned but unused local variable number'
148
+ warnings[0][:line].should == 2
149
+ warnings[0][:column].should == 2
150
+
151
+ warnings[1][:message].should == 'assigned but unused instance ' \
152
+ 'variable @number'
153
+
154
+ warnings[1][:line].should == 3
155
+ warnings[1][:column].should == 2
156
+
157
+ warnings[2][:message].should == 'assigned but unused class ' \
158
+ 'variable @@number'
159
+
160
+ warnings[2][:line].should == 4
161
+ warnings[2][:column].should == 2
162
+
163
+ warnings[3][:message].should == 'assigned but unused global ' \
164
+ 'variable $number'
165
+
166
+ warnings[3][:line].should == 5
167
+ warnings[3][:column].should == 2
168
+ end
169
+
170
+ it 'Add warnings for unused variables in a module definition scope' do
171
+ code = <<-CODE
172
+ module Example
173
+ number = 10
174
+ @number = 10
175
+ @@number = 10
176
+ $number = 10
177
+
178
+ number_2 = 10
179
+ @number_2 = 10
180
+ @@number_2 = 10
181
+ $number_2 = 10
182
+
183
+ puts number_2
184
+ puts @number_2
185
+ puts @@number_2
186
+ puts $number_2
187
+ end
188
+ CODE
189
+
190
+ tokens = Rlint::Parser.new(code).parse
191
+ report = Rlint::Report.new
192
+ iterator = Rlint::Iterator.new(report)
193
+
194
+ iterator.bind(Rlint::Analyze::Definitions)
195
+ iterator.bind(Rlint::Analyze::UnusedVariables)
196
+ iterator.run(tokens)
197
+
198
+ report.messages[:warning].class.should == Array
199
+ report.messages[:warning].length.should == 4
200
+
201
+ warnings = report.messages[:warning]
202
+
203
+ warnings[0][:message].should == 'assigned but unused local variable number'
204
+ warnings[0][:line].should == 2
205
+ warnings[0][:column].should == 2
206
+
207
+ warnings[1][:message].should == 'assigned but unused instance ' \
208
+ 'variable @number'
209
+
210
+ warnings[1][:line].should == 3
211
+ warnings[1][:column].should == 2
212
+
213
+ warnings[2][:message].should == 'assigned but unused class ' \
214
+ 'variable @@number'
215
+
216
+ warnings[2][:line].should == 4
217
+ warnings[2][:column].should == 2
218
+
219
+ warnings[3][:message].should == 'assigned but unused global ' \
220
+ 'variable $number'
221
+
222
+ warnings[3][:line].should == 5
223
+ warnings[3][:column].should == 2
224
+ end
225
+ end