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,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,4 @@
1
+ require File.expand_path('../../lib/rlint', __FILE__)
2
+ require 'bacon'
3
+
4
+ Bacon.summary_on_exit
@@ -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