rubycop 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +4 -0
  3. data/README.md +3 -0
  4. data/Rakefile +1 -0
  5. data/lib/rubycop.rb +6 -0
  6. data/lib/rubycop/analyzer.rb +6 -0
  7. data/lib/rubycop/analyzer/gray_list.rb +28 -0
  8. data/lib/rubycop/analyzer/node_builder.rb +523 -0
  9. data/lib/rubycop/analyzer/policy.rb +354 -0
  10. data/lib/rubycop/analyzer/ruby.rb +24 -0
  11. data/lib/rubycop/analyzer/ruby/args.rb +28 -0
  12. data/lib/rubycop/analyzer/ruby/array.rb +11 -0
  13. data/lib/rubycop/analyzer/ruby/assignment.rb +45 -0
  14. data/lib/rubycop/analyzer/ruby/assoc.rb +15 -0
  15. data/lib/rubycop/analyzer/ruby/blocks.rb +23 -0
  16. data/lib/rubycop/analyzer/ruby/call.rb +33 -0
  17. data/lib/rubycop/analyzer/ruby/case.rb +24 -0
  18. data/lib/rubycop/analyzer/ruby/constants.rb +49 -0
  19. data/lib/rubycop/analyzer/ruby/definitions.rb +27 -0
  20. data/lib/rubycop/analyzer/ruby/for.rb +17 -0
  21. data/lib/rubycop/analyzer/ruby/hash.rb +13 -0
  22. data/lib/rubycop/analyzer/ruby/if.rb +33 -0
  23. data/lib/rubycop/analyzer/ruby/list.rb +17 -0
  24. data/lib/rubycop/analyzer/ruby/node.rb +11 -0
  25. data/lib/rubycop/analyzer/ruby/operators.rb +54 -0
  26. data/lib/rubycop/analyzer/ruby/params.rb +23 -0
  27. data/lib/rubycop/analyzer/ruby/position.rb +15 -0
  28. data/lib/rubycop/analyzer/ruby/range.rb +17 -0
  29. data/lib/rubycop/analyzer/ruby/statements.rb +34 -0
  30. data/lib/rubycop/analyzer/ruby/string.rb +26 -0
  31. data/lib/rubycop/analyzer/ruby/tokens.rb +46 -0
  32. data/lib/rubycop/analyzer/ruby/variables.rb +26 -0
  33. data/lib/rubycop/analyzer/ruby/while.rb +29 -0
  34. data/lib/rubycop/version.rb +3 -0
  35. data/rubycop.gemspec +25 -0
  36. data/spec/node_builder_spec.rb +374 -0
  37. data/spec/policy_spec.rb +405 -0
  38. metadata +97 -0
@@ -0,0 +1,46 @@
1
+ module Rubycop
2
+ module Analyzer
3
+ module Ruby
4
+ class Token < Node
5
+ def initialize(token, position)
6
+ @token = token
7
+ @position = position
8
+ end
9
+
10
+ attr_reader :token
11
+ attr_reader :position
12
+
13
+ # def inspect
14
+ # "#{@token}<t>"
15
+ # end
16
+ end
17
+
18
+ class Integer < Token
19
+ end
20
+
21
+ class Float < Token
22
+ end
23
+
24
+ class Char < Token
25
+ end
26
+
27
+ class Label < Token
28
+ end
29
+
30
+ class Symbol < Token
31
+ # def inspect
32
+ # ":#{@token.inspect}"
33
+ # end
34
+ end
35
+
36
+ class Keyword < Token
37
+ end
38
+
39
+ class Identifier < Token
40
+ def assignment(rvalue, operator)
41
+ LocalVariableAssignment.new(self, rvalue, operator)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,26 @@
1
+ module Rubycop
2
+ module Analyzer
3
+ module Ruby
4
+ class Variable < Identifier
5
+ end
6
+
7
+ class ClassVariable < Variable
8
+ def assignment(rvalue, operator)
9
+ ClassVariableAssignment.new(self, rvalue, operator)
10
+ end
11
+ end
12
+
13
+ class GlobalVariable < Variable
14
+ def assignment(rvalue, operator)
15
+ GlobalVariableAssignment.new(self, rvalue, operator)
16
+ end
17
+ end
18
+
19
+ class InstanceVariable < Variable
20
+ def assignment(rvalue, operator)
21
+ InstanceVariableAssignment.new(self, rvalue, operator)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,29 @@
1
+ module Rubycop
2
+ module Analyzer
3
+ module Ruby
4
+ class While < Block
5
+ def initialize(expression, statements)
6
+ @expression = expression
7
+ super(statements)
8
+ end
9
+
10
+ attr_reader :expression
11
+ end
12
+
13
+ class WhileMod < Block
14
+ def initialize(expression, statements)
15
+ @expression = expression
16
+ super(statements)
17
+ end
18
+
19
+ attr_reader :expression
20
+ end
21
+
22
+ class Until < While
23
+ end
24
+
25
+ class UntilMod < WhileMod
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,3 @@
1
+ module Rubycop
2
+ VERSION = "0.5.0"
3
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rubycop/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rubycop"
7
+ s.version = Rubycop::VERSION
8
+ s.authors = ["Dray Lacy", "Eric Allam"]
9
+ s.email = ["dray@envylabs.com", "rubymaverick@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{A semantic analyzer for Ruby 1.9}
12
+ s.description = %q{A semantic analyzer for Ruby 1.9}
13
+
14
+ s.rubyforge_project = "rubycop"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ # s.add_development_dependency "rspec"
23
+ # s.add_runtime_dependency "rest-client"
24
+ s.add_development_dependency "rspec"
25
+ end
@@ -0,0 +1,374 @@
1
+ require 'rubycop'
2
+
3
+ describe Rubycop::Analyzer::NodeBuilder do
4
+ subject { described_class }
5
+
6
+ RSpec::Matchers.define(:parse) do |ruby|
7
+ match { |nb| nb.build(ruby).is_a?(Rubycop::Analyzer::Ruby::Node) }
8
+ end
9
+
10
+ context "arrays" do
11
+ it { should parse('[:foo, :bar]') }
12
+ it { should parse('%w(foo bar)') }
13
+ it { should parse('%(foo)') }
14
+ it { should parse("%(\nfoo bar\n)") }
15
+ it { should parse("%( \nfoo bar\n )") }
16
+ it { should parse('%W[foo bar]') }
17
+ it { should parse('%w()') }
18
+ it { should parse('%W()') }
19
+ it { should parse('%w[]') }
20
+ it { should parse('%W[]') }
21
+ it { should parse('%W[#{foo}]') }
22
+ it { should parse('foo[1]') }
23
+ it { should parse('foo[]') }
24
+ it { should parse('foo.bar[]') }
25
+ it { should parse('[ foo[bar] ]') }
26
+ it { should parse('result[0] = :value') }
27
+ it { should parse("\n [type, [row]]\n") }
28
+ end
29
+
30
+ context "assignment" do
31
+ it { should parse('a = b') }
32
+ it { should parse('a ||= b') }
33
+ it { should parse('a, b = c') }
34
+ it { should parse('a, b = c, d') }
35
+ it { should parse('a, *b = c') }
36
+ it { should parse('A::B = 1') }
37
+ end
38
+
39
+ context "blocks" do
40
+ it { should parse("t do\nfoo\nbar\nend") }
41
+ it { should parse('t do ; end') }
42
+ it { should parse("t do ||\nfoo\nend") }
43
+ it { should parse('t do ;; ;foo ; ;;bar; ; end') }
44
+ it { should parse("t do |(a, b), *c|\n foo\n bar\nend") }
45
+ it { should parse('t { |(a, b), *c| }') }
46
+ it { should parse('t do |(a, b), *c| end') }
47
+ it { should parse('t do |*a, &c| end') }
48
+ it { should parse('t { |a, (b)| }') }
49
+ it { should parse("begin\nend") }
50
+ it { should parse('begin ; end') }
51
+ it { should parse('begin foo; end') }
52
+ it { should parse("begin\nfoo\nelse\nbar\nend") }
53
+ it { should parse("begin\nfoo\nrescue\nbar\nend") }
54
+ it { should parse("begin \n rescue A \n end") }
55
+ it { should parse("begin foo\n rescue A => e\n bar\n end") }
56
+ it { should parse("begin foo\n rescue A, B => e\n bar\n end") }
57
+ it { should parse("begin foo\n rescue A, B => e\n bar\nrescue C => e\n bam\nensure\nbaz\n end") }
58
+ it { should parse('begin a; rescue NameError => e then e else :foo end') }
59
+ it { should parse("begin\nrescue A => e\nrescue B\nend") }
60
+ it { should parse("begin\nrescue A\nelse\nend\n") }
61
+ it { should parse('foo rescue bar') }
62
+ it { should parse('foo rescue 0') }
63
+ end
64
+
65
+ context "calls" do
66
+ it { should parse('t') }
67
+ it { should parse('I18n.t') }
68
+ it { should parse('a.b(:foo)') }
69
+ it { should parse('I18n.t()') }
70
+ it { should parse("I18n.t('foo')") }
71
+ it { should parse("I18n.t 'foo'") }
72
+ it { should parse('I18n::t') }
73
+ it { should parse('I18n::t()') }
74
+ it { should parse("I18n::t('foo')") }
75
+ it { should parse('foo.<=>(bar)') }
76
+ it { should parse('foo.<< bar') }
77
+ it { should parse('foo("#{bar}")') }
78
+ it { should parse("t('foo', 'bar')") }
79
+ it { should parse("t('foo', 'bar'); t 'baz'") }
80
+ it { should parse("t 'foo'") }
81
+ it { should parse('t %(foo #{bar}), %(baz)') }
82
+ it { should parse('t()') }
83
+ it { should parse('t(:a, b(:b))') }
84
+ it { should parse('t(:`)') }
85
+ it { should parse("t do |a, b, *c|\nfoo\nend") }
86
+ it { should parse("t do |(a, b), *c|\nfoo\nend") }
87
+ it { should parse('t(:foo, &block)') }
88
+ it { should parse('foo(bar do |a| ; end)') }
89
+ it { should parse('self.b') }
90
+ it { should parse('super') }
91
+ it { should parse('super(:foo)') }
92
+ it { should parse('yield') }
93
+ it { should parse('yield(:foo)') }
94
+ it { should parse('return :foo') }
95
+ it { should parse('next') }
96
+ it { should parse('redo') }
97
+ it { should parse('break') }
98
+ it { should parse('retry') }
99
+ it { should parse('a.b = :c') }
100
+ it { should parse('defined?(A)') }
101
+ it { should parse('BEGIN { foo }') }
102
+ it { should parse('END { foo }') }
103
+ it { should parse('alias eql? ==') }
104
+ it { should parse('alias :foo :bar') }
105
+ it { should parse('alias $ERROR_INFO $!') }
106
+ it { should parse('undef :foo') }
107
+ it { should parse('undef foo, bar, baz') }
108
+ it { should parse('undef =~') }
109
+ end
110
+
111
+ context "case" do
112
+ it { should parse('case a; when 1; 2 end') }
113
+ it { should parse('case (a) when 1; 2 end') }
114
+ it { should parse('case (a;) when 1; 2 end') }
115
+ it { should parse('case (a); when 1; 2 end') }
116
+ it { should parse('case (a;;); when 1; 2 end') }
117
+ it { should parse('case (a;b); when 1; 2 end') }
118
+ it { should parse('case a; when 1; 2 end') }
119
+ it { should parse('case a; when 1, 2; 2 end') }
120
+ it { should parse('case a; when (1; 2), (3; 4;); 2 end') }
121
+ it { should parse('case (true); when 1; false; when 2, 3, 4; nil; else; nil; end') }
122
+ it { should parse("case true\n when 1\n false\n when 2\n nil\n else\n nil\n end") }
123
+ it { should parse("case true\n when 1 then false\n when 2 then nil\n else\n nil\n end") }
124
+ end
125
+
126
+ context "constants" do
127
+ it { should parse('A') }
128
+ it { should parse('module A::B ; end') }
129
+ it { should parse('class A::B < C ; end') }
130
+ it { should parse('self.class::A') }
131
+ it { should parse('class << self; self; end') }
132
+ it { should parse('foo (class << @bar; self; end)') }
133
+ it { should parse("class A ; end\n::B = 3") }
134
+ end
135
+
136
+ context "for" do
137
+ it { should parse('for i in [1]; a; end') }
138
+ it { should parse("for i in [1]\n a\n end") }
139
+ it { should parse("for i in [1] do a\n end") }
140
+ it { should parse("lambda do\n for a in b\n end\nend") }
141
+ it { should parse("\nfor i in 0...1 do\n for j in 0...2 do\n end\nend\n") }
142
+ end
143
+
144
+ context "hash" do
145
+ it { should parse('{ :foo => :bar }') }
146
+ it { should parse('{ :a => { :b => { :b => :c, }, }, }') }
147
+ it { should parse('t(:a => { :b => :b, :c => { :d => :d } })') }
148
+ it { should parse('{ :if => :foo }') }
149
+ it { should parse('{ :a => :a, :b => "#{b 1}" }') }
150
+ it { should parse('{ foo: bar }') }
151
+ it { should parse('t(:a => :a, :b => :b)') }
152
+ it { should parse('foo[:bar] = :baz') }
153
+ end
154
+
155
+ context "heredoc" do
156
+ it { should parse("\n<<-eos\neos\n") }
157
+ it { should parse("<<-eos\nfoo\neos") }
158
+ it { should parse("'string'\n<<-eos\nheredoc\neos\n'string'") }
159
+ it { should parse(":'symbol'\n<<-eos\nheredoc\neos\n:'symbol'") }
160
+ it { should parse("%w(words)\n<<-eoc\n heredoc\neoc\n%w(words)") }
161
+ it { should parse("foo(%w(words))\n<<-eoc\n\neoc") }
162
+ it { should parse("\n<<-end;\nfoo\nend\n") }
163
+ it { should parse("\n<<-'end' ;\n foo\nend\nfoo;") }
164
+ it { should parse("<<-eos\n foo \#{bar} baz\neos") }
165
+ it { should parse("<<-end\n\#{a['b']}\nend") }
166
+ it { should parse("<<-end\n\#{'a'}\nend") }
167
+ it { should parse("foo(<<-eos)\n foo\neos") }
168
+ it { should parse("foo(<<-eos\n foo\neos\n)") }
169
+ it { should parse("foo(<<-eos, __FILE__, __LINE__ + 1)\n foo\neos") }
170
+ it { should parse("foo(<<-eos, __FILE__, line)\n foo\neos") }
171
+ it { should parse("foo(<<-eos, \"\#{bar}\")\n foo\neos") }
172
+ it { should parse("begin <<-src \n\n\nfoo\nsrc\n end") }
173
+ it { should parse("each do\n <<-src \n\nfoo\n\#{bar}\nsrc\n end\n") }
174
+ it { should parse("<<-eos\n \#{\"\n \#{sym}\n \"}\neos") }
175
+ it { should parse("<<-eos\n \t\#{ a\n }\neos") }
176
+ it { should parse("<<-eos\n\#{:'dyna_symbol'}\neos") }
177
+ it { should parse("<<-eos # comment\neos\nfoo\nfoo\n") }
178
+ it { should parse("<<-eos # comment\nstring\neos\n'index'") }
179
+ it { should parse("foo <<-eos if bar\na\neos\nbaz") }
180
+ it { should parse("<<-eos.foo\neos\nbar\n") }
181
+ it { should parse("<<-end\nend\n<<-end\n\nend\n") }
182
+ it { should parse("heredocs = <<-\"foo\", <<-\"bar\"\n I said foo.\nfoo\n I said bar.\nbar\n") }
183
+ it { should parse("a = %w[]\n<<-eos\nfoo\neos") }
184
+ it { should parse("<<-eos\nfoo\n__END__\neos") }
185
+ it { should parse("foo = <<-`foo`\nfoo") }
186
+ end
187
+
188
+ context "identifier" do
189
+ it { should parse('foo') }
190
+ it { should parse('@foo') }
191
+ it { should parse('@@foo') }
192
+ it { should parse('$foo') }
193
+ it { should parse('__FILE__') }
194
+ it { should parse('__LINE__') }
195
+ it { should parse('__ENCODING__') }
196
+ end
197
+
198
+ context "if" do
199
+ it { should parse('if true; false end') }
200
+ it { should parse("if true\n false\n end") }
201
+ it { should parse("if true\n false\n end") }
202
+ it { should parse('if true then false end') }
203
+ it { should parse('if true; false; else; true end') }
204
+ it { should parse("if true\n false\n else\n true end") }
205
+ it { should parse("if true\n false\n elsif false\n true end") }
206
+ it { should parse("if true then false; elsif false then true; else nil end") }
207
+ it { should parse("if a == 1 then b\nelsif b == c then d\ne\nf\nelse e end") }
208
+ it { should parse('foo if true') }
209
+ it { should parse('return if true') }
210
+ it { should parse('foo.bar += bar if bar') }
211
+ it { should parse('foo, bar = *baz if bum') }
212
+ it { should parse('foo *args if bar?') }
213
+ it { should parse('pos[1] if pos') }
214
+ it { should parse('a if (defined? a)') }
215
+ it { should parse('rescued rescue rescuing') }
216
+ it { should parse('rescued = assigned rescue rescuing') }
217
+ end
218
+
219
+ context "literals" do
220
+ it { should parse('1') }
221
+ it { should parse('1.1') }
222
+ it { should parse('nil') }
223
+ it { should parse('true') }
224
+ it { should parse('false') }
225
+ it { should parse('1..2') }
226
+ it { should parse('1...2') }
227
+ it { should parse('?a') }
228
+ end
229
+
230
+ context "methods" do
231
+ it { should parse("def foo(a, b = nil, c = :foo, *d, &block)\n bar\n baz\nend") }
232
+ it { should parse("def foo(a, b = {})\nend") }
233
+ it { should parse("def foo a, b = nil, c = :foo, *d, &block\n bar\n baz\nend") }
234
+ it { should parse("def self.for(options)\nend") }
235
+ it { should parse('def foo(a = 1, b=2); end') }
236
+ it { should parse('def t(a = []) end') }
237
+ it { should parse('def t(*) end') }
238
+ it { should parse('def <<(arg) end') }
239
+ it { should parse('def | ; end') }
240
+ it { should parse('class A < B; def |(foo); end; end') }
241
+ it { should parse('def <<(arg) foo; bar; end') }
242
+ it { should parse("def t\nrescue => e\nend") }
243
+ it { should parse("def a(b, c)\n d\nrescue A\n e\nensure\nb\nend") }
244
+ it { should parse('def foo ; bar { |k, v| k } end') }
245
+ it { should parse("class A\n def class\n end\nend") }
246
+ it { should parse("def end\nend") }
247
+ it { should parse('def def; 234; end') }
248
+ end
249
+
250
+ context "operators" do
251
+ context "unary" do
252
+ it { should parse('+1') }
253
+ it { should parse('-1') }
254
+ it { should parse('!1') }
255
+ it { should parse('not 1') }
256
+ it { should parse('not(1)') }
257
+ it { should parse('~1') }
258
+ it { should parse('(~1)') }
259
+ it { should parse('not (@main or @sub)') }
260
+ end
261
+
262
+ context "binary" do
263
+ context "mathematical" do
264
+ it { should parse('1 + 2') }
265
+ it { should parse('1 - 2') }
266
+ it { should parse('1 * 2') }
267
+ it { should parse('1 / 2') }
268
+ it { should parse('1 ** 2') }
269
+ it { should parse('1 % 2') }
270
+ it { should parse('(1 + 2)') }
271
+ end
272
+ context "logical" do
273
+ it { should parse('1 && 2') }
274
+ it { should parse('1 || 2') }
275
+ it { should parse('1 and 2') }
276
+ it { should parse('1 or 2') }
277
+ it { should parse('(1 and 2)') }
278
+ end
279
+ context "bitwise" do
280
+ it { should parse('1 << 2') }
281
+ it { should parse('1 >> 2') }
282
+ it { should parse('1 & 2') }
283
+ it { should parse('1 | 2') }
284
+ it { should parse('1 ^ 2') }
285
+ end
286
+ context "comparison, equality, matching" do
287
+ it { should parse('1 < 2') }
288
+ it { should parse('1 <= 2') }
289
+ it { should parse('1 > 2') }
290
+ it { should parse('1 >= 2') }
291
+ it { should parse('1 <=> 2') }
292
+ it { should parse('1 == 2') }
293
+ it { should parse('1 != 2') }
294
+ it { should parse('1 === 2') }
295
+ it { should parse('1 =~ 2') }
296
+ it { should parse('1 !~ 2') }
297
+ end
298
+ end
299
+
300
+ context "ternary" do
301
+ it { should parse('1 == 1 ? 2 : 3') }
302
+ it { should parse('((1) ? 2 : (3))') }
303
+ end
304
+ end
305
+
306
+ context "statements" do
307
+ it { should parse('foo') }
308
+ it { should parse(';foo') }
309
+ it { should parse('foo;') }
310
+ it { should parse(';foo;') }
311
+ it { should parse(';foo;;bar;baz;') }
312
+ it { should parse(';foo;;bar;;;;baz;') }
313
+ it { should parse(';;;foo;;bar;baz;;;;') }
314
+ it { should parse('(foo)') }
315
+ it { should parse('(((foo)); (bar))') }
316
+ it { should parse('(((foo)); ((bar); (baz)));') }
317
+ it { should parse("\n foo \n \n") }
318
+ it { should parse("foo\n__END__\nbar") }
319
+ end
320
+
321
+ context "string" do
322
+ it { should parse('""') }
323
+ it { should parse('"foo"') }
324
+ it { should parse("'foo'") }
325
+ it { should parse('%(foo)') }
326
+ it { should parse('%.foo.') }
327
+ it { should parse('%|foo|') }
328
+ it { should parse('"foo#{bar}"') }
329
+ it { should parse('%(foo #{bar})') }
330
+ it { should parse("%w(a)\n%(b)") }
331
+ it { should parse('/foo/') }
332
+ it { should parse('%r(foo)') }
333
+ it { should parse('"#{$1}"') }
334
+ it { should parse('"#$0"') }
335
+ it { should parse("'a' 'b'") }
336
+ it { should parse('`foo`') }
337
+ it { should parse('%x(foo)') }
338
+ end
339
+
340
+ context "symbol" do
341
+ it { should parse(':foo') }
342
+ it { should parse(':!') }
343
+ it { should parse(':-@') }
344
+ it { should parse(':if') }
345
+ it { should parse(':[]') }
346
+ it { should parse(':[]=') }
347
+ it { should parse(':"foo.bar"') }
348
+ it { should parse(":'foo.bar'") }
349
+ it { should parse(':"@#{token}"') }
350
+ end
351
+
352
+ context "unless" do
353
+ it { should parse('unless true; false end') }
354
+ it { should parse("unless true\n false end") }
355
+ it { should parse('unless true then false end') }
356
+ it { should parse('unless true; false; else; true end') }
357
+ it { should parse("unless true\n false\n else\n true end") }
358
+ it { should parse('foo unless true') }
359
+ it { should parse('1 unless false if true') }
360
+ end
361
+
362
+ context "until" do
363
+ it { should parse('until true; false end') }
364
+ it { should parse('until (true); false end') }
365
+ it { should parse('until (true;); false end') }
366
+ it { should parse("until true\n false end") }
367
+ it { should parse("until (true)\n false end") }
368
+ it { should parse('until foo do ; end') }
369
+ it { should parse('begin; false; end until true') }
370
+ it { should parse("begin\n false\n end until true") }
371
+ it { should parse('foo until true') }
372
+ it { should parse('foo until (true)') }
373
+ end
374
+ end