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