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.
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