rubycop 0.5.1 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/.gitignore +2 -0
  2. data/Gemfile +1 -1
  3. data/README.md +43 -2
  4. data/Rakefile +3 -1
  5. data/lib/ruby_cop.rb +10 -0
  6. data/lib/ruby_cop/gray_list.rb +26 -0
  7. data/lib/ruby_cop/node_builder.rb +521 -0
  8. data/lib/ruby_cop/policy.rb +354 -0
  9. data/lib/ruby_cop/ruby.rb +23 -0
  10. data/lib/ruby_cop/ruby/args.rb +26 -0
  11. data/lib/ruby_cop/ruby/array.rb +13 -0
  12. data/lib/ruby_cop/ruby/assignment.rb +43 -0
  13. data/lib/ruby_cop/ruby/assoc.rb +13 -0
  14. data/lib/ruby_cop/ruby/blocks.rb +21 -0
  15. data/lib/ruby_cop/ruby/call.rb +31 -0
  16. data/lib/ruby_cop/ruby/case.rb +22 -0
  17. data/lib/ruby_cop/ruby/constants.rb +47 -0
  18. data/lib/ruby_cop/ruby/definitions.rb +25 -0
  19. data/lib/ruby_cop/ruby/for.rb +15 -0
  20. data/lib/ruby_cop/ruby/hash.rb +11 -0
  21. data/lib/ruby_cop/ruby/if.rb +31 -0
  22. data/lib/ruby_cop/ruby/list.rb +15 -0
  23. data/lib/ruby_cop/ruby/node.rb +9 -0
  24. data/lib/ruby_cop/ruby/operators.rb +52 -0
  25. data/lib/ruby_cop/ruby/params.rb +21 -0
  26. data/lib/ruby_cop/ruby/position.rb +13 -0
  27. data/lib/ruby_cop/ruby/range.rb +15 -0
  28. data/lib/ruby_cop/ruby/statements.rb +32 -0
  29. data/lib/ruby_cop/ruby/string.rb +24 -0
  30. data/lib/ruby_cop/ruby/tokens.rb +44 -0
  31. data/lib/ruby_cop/ruby/variables.rb +24 -0
  32. data/lib/ruby_cop/ruby/while.rb +27 -0
  33. data/lib/ruby_cop/version.rb +3 -0
  34. data/ruby_cop.gemspec +25 -0
  35. data/spec/{node_builder_spec.rb → analyzer/node_builder_spec.rb} +3 -3
  36. data/spec/{policy_spec.rb → analyzer/policy_spec.rb} +6 -8
  37. data/spec/spec_helper.rb +13 -0
  38. data/tasks/rspec.rake +8 -0
  39. data/tasks/yard.rake +2 -0
  40. metadata +69 -44
  41. data/lib/rubycop.rb +0 -6
  42. data/lib/rubycop/analyzer.rb +0 -6
  43. data/lib/rubycop/analyzer/gray_list.rb +0 -28
  44. data/lib/rubycop/analyzer/node_builder.rb +0 -523
  45. data/lib/rubycop/analyzer/policy.rb +0 -356
  46. data/lib/rubycop/analyzer/ruby.rb +0 -24
  47. data/lib/rubycop/analyzer/ruby/args.rb +0 -28
  48. data/lib/rubycop/analyzer/ruby/array.rb +0 -11
  49. data/lib/rubycop/analyzer/ruby/assignment.rb +0 -45
  50. data/lib/rubycop/analyzer/ruby/assoc.rb +0 -15
  51. data/lib/rubycop/analyzer/ruby/blocks.rb +0 -23
  52. data/lib/rubycop/analyzer/ruby/call.rb +0 -33
  53. data/lib/rubycop/analyzer/ruby/case.rb +0 -24
  54. data/lib/rubycop/analyzer/ruby/constants.rb +0 -49
  55. data/lib/rubycop/analyzer/ruby/definitions.rb +0 -27
  56. data/lib/rubycop/analyzer/ruby/for.rb +0 -17
  57. data/lib/rubycop/analyzer/ruby/hash.rb +0 -13
  58. data/lib/rubycop/analyzer/ruby/if.rb +0 -33
  59. data/lib/rubycop/analyzer/ruby/list.rb +0 -17
  60. data/lib/rubycop/analyzer/ruby/node.rb +0 -11
  61. data/lib/rubycop/analyzer/ruby/operators.rb +0 -54
  62. data/lib/rubycop/analyzer/ruby/params.rb +0 -23
  63. data/lib/rubycop/analyzer/ruby/position.rb +0 -15
  64. data/lib/rubycop/analyzer/ruby/range.rb +0 -17
  65. data/lib/rubycop/analyzer/ruby/statements.rb +0 -34
  66. data/lib/rubycop/analyzer/ruby/string.rb +0 -26
  67. data/lib/rubycop/analyzer/ruby/tokens.rb +0 -46
  68. data/lib/rubycop/analyzer/ruby/variables.rb +0 -26
  69. data/lib/rubycop/analyzer/ruby/while.rb +0 -29
  70. data/lib/rubycop/version.rb +0 -3
  71. data/rubycop.gemspec +0 -25
data/.gitignore CHANGED
@@ -1,4 +1,6 @@
1
1
  *.gem
2
2
  .bundle
3
+ .rvmrc
3
4
  Gemfile.lock
5
+ doc
4
6
  pkg/*
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- # Specify your gem's dependencies in rubycop.gemspec
3
+ # Specify your gem's dependencies in ruby_cop.gemspec
4
4
  gemspec
data/README.md CHANGED
@@ -1,3 +1,44 @@
1
- Rubycop is a semantic analyzer for ruby.
1
+ RubyCop
2
+ =======
2
3
 
3
- TODO: fill out this README
4
+ RubyCop scans Ruby code and tells you whether it's safe or not. We use
5
+ it at [CodeSchool][1] to check user-submitted code before we eval it on
6
+ the server.
7
+
8
+ RubyCop is made up of two pieces: NodeBuilder and Policy. NodeBuilder is
9
+ responsible for parsing Ruby code (using Ripper) and building an AST
10
+ (Abstract Syntax Tree). Policy then scans the AST and tells you whether
11
+ the code is safe or not.
12
+
13
+ ## Requirements
14
+
15
+ RubyCop requires Ruby 1.9, though it should work under 1.8 if you
16
+ include the "ripper" gem.
17
+
18
+ ## Usage
19
+
20
+ Here's a quick example of building the AST, and evaluating it with the
21
+ Policy:
22
+
23
+ >> require "ruby_cop"
24
+ => true
25
+ >> policy = RubyCop::Policy.new
26
+ >> ast = RubyCop::NodeBuilder.build("x = 1 + 2")
27
+ >> ast.accept(policy)
28
+ => true
29
+
30
+ And if you pass in some unsafe code:
31
+
32
+ >> ast = RubyCop::NodeBuilder.build("x = `ls -la`")
33
+ >> ast.accept(policy)
34
+ => false
35
+
36
+ ## Drawbacks
37
+
38
+ Ruby is a very dynamic language, so this kind of static analysis will
39
+ only get you so far. RubyCop blocks obvious things like backticks and
40
+ unsafe Kernel methods (#eval, #exec, #fork, etc.), but has to err on the
41
+ side of safety in other places. For instance, #send is considered
42
+ unsafe.
43
+
44
+ [1]: http://www.codeschool.com/
data/Rakefile CHANGED
@@ -1 +1,3 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+ Dir['tasks/*.rake'].each { |file| load(file) }
@@ -0,0 +1,10 @@
1
+ module RubyCop
2
+ # Your code goes here...
3
+ end
4
+
5
+ require 'ripper'
6
+
7
+ require 'ruby_cop/ruby'
8
+ require 'ruby_cop/node_builder'
9
+ require 'ruby_cop/gray_list'
10
+ require 'ruby_cop/policy'
@@ -0,0 +1,26 @@
1
+ require 'set'
2
+
3
+ module RubyCop
4
+ # Combination blacklist and whitelist.
5
+ class GrayList
6
+ def initialize
7
+ @blacklist = Set.new
8
+ @whitelist = Set.new
9
+ end
10
+
11
+ # An item is allowed if it's whitelisted, or if it's not blacklisted.
12
+ def allow?(item)
13
+ @whitelist.include?(item) || !@blacklist.include?(item)
14
+ end
15
+
16
+ def blacklist(item)
17
+ @whitelist.delete(item)
18
+ @blacklist.add(item)
19
+ end
20
+
21
+ def whitelist(item)
22
+ @blacklist.delete(item)
23
+ @whitelist.add(item)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,521 @@
1
+ module RubyCop
2
+ class NodeBuilder < Ripper::SexpBuilder
3
+ def initialize(src, filename=nil, lineno=nil)
4
+ @src = src ||= filename && File.read(filename) || ''
5
+ @filename = filename
6
+ super
7
+ end
8
+
9
+ class << self
10
+ def build(src, filename=nil)
11
+ new(src, filename).parse
12
+ end
13
+ end
14
+
15
+ def on_alias(new_name, old_name)
16
+ Ruby::Alias.new(to_ident(new_name), to_ident(old_name))
17
+ end
18
+
19
+ def on_aref(target, args)
20
+ Ruby::Call.new(target, ident(:[]), args)
21
+ end
22
+
23
+ def on_aref_field(target, args)
24
+ Ruby::Call.new(target, ident(:[]), args)
25
+ end
26
+
27
+ def on_arg_paren(args)
28
+ args
29
+ end
30
+
31
+ def on_args_add(args, arg)
32
+ args.add(arg); args
33
+ end
34
+
35
+ def on_args_add_block(args, block)
36
+ args.add_block(block) if block; args
37
+ end
38
+
39
+ def on_args_new
40
+ Ruby::Args.new
41
+ end
42
+
43
+ def on_array(args)
44
+ args ? args.to_array : Ruby::Array.new
45
+ end
46
+
47
+ def on_assign(lvalue, rvalue)
48
+ lvalue.assignment(rvalue, ident(:'='))
49
+ end
50
+
51
+ def on_assoc_new(key, value)
52
+ Ruby::Assoc.new(key, value)
53
+ end
54
+
55
+ def on_assoclist_from_args(args)
56
+ args
57
+ end
58
+
59
+ def on_bare_assoc_hash(assocs)
60
+ Ruby::Hash.new(assocs)
61
+ end
62
+
63
+ def on_BEGIN(statements)
64
+ Ruby::Call.new(nil, ident(:BEGIN), nil, statements)
65
+ end
66
+
67
+ def on_begin(body)
68
+ body.is_a?(Ruby::ChainedBlock) ? body : body.to_chained_block
69
+ end
70
+
71
+ def on_binary(lvalue, operator, rvalue)
72
+ Ruby::Binary.new(lvalue, rvalue, operator)
73
+ end
74
+
75
+ def on_blockarg(arg)
76
+ arg
77
+ end
78
+
79
+ def on_block_var(params, something)
80
+ params
81
+ end
82
+
83
+ def on_bodystmt(body, rescue_block, else_block, ensure_block)
84
+ statements = [rescue_block, else_block, ensure_block].compact
85
+ statements.empty? ? body : body.to_chained_block(statements)
86
+ end
87
+
88
+ def on_brace_block(params, statements)
89
+ statements.to_block(params)
90
+ end
91
+
92
+ def on_break(args)
93
+ Ruby::Call.new(nil, ident(:break), args)
94
+ end
95
+
96
+ def on_call(target, separator, identifier)
97
+ Ruby::Call.new(target, identifier)
98
+ end
99
+
100
+ def on_case(args, when_block)
101
+ Ruby::Case.new(args, when_block)
102
+ end
103
+
104
+ def on_CHAR(token)
105
+ Ruby::Char.new(token, position)
106
+ end
107
+
108
+ def on_class(const, superclass, body)
109
+ Ruby::Class.new(const, superclass, body)
110
+ end
111
+
112
+ def on_class_name_error(ident)
113
+ raise SyntaxError, 'class/module name must be CONSTANT'
114
+ end
115
+
116
+ def on_command(identifier, args)
117
+ Ruby::Call.new(nil, identifier, args)
118
+ end
119
+
120
+ def on_command_call(target, separator, identifier, args)
121
+ Ruby::Call.new(target, identifier, args)
122
+ end
123
+
124
+ def on_const(token)
125
+ Ruby::Constant.new(token, position)
126
+ end
127
+
128
+ def on_const_path_field(namespace, const)
129
+ const.namespace = namespace; const
130
+ end
131
+
132
+ def on_const_path_ref(namespace, const)
133
+ const.namespace = namespace; const
134
+ end
135
+
136
+ def on_const_ref(const)
137
+ const
138
+ end
139
+
140
+ def on_cvar(token)
141
+ Ruby::ClassVariable.new(token, position)
142
+ end
143
+
144
+ def on_def(identifier, params, body)
145
+ Ruby::Method.new(nil, identifier, params, body)
146
+ end
147
+
148
+ def on_defs(target, separator, identifier, params, body)
149
+ Ruby::Method.new(target, identifier, params, body)
150
+ end
151
+
152
+ def on_defined(ref)
153
+ Ruby::Defined.new(ref)
154
+ end
155
+
156
+ def on_do_block(params, statements)
157
+ statements.to_block(params)
158
+ end
159
+
160
+ def on_dot2(min, max)
161
+ Ruby::Range.new(min, max, false)
162
+ end
163
+
164
+ def on_dot3(min, max)
165
+ Ruby::Range.new(min, max, true)
166
+ end
167
+
168
+ def on_dyna_symbol(symbol)
169
+ symbol.to_dyna_symbol
170
+ end
171
+
172
+ def on_else(statements)
173
+ Ruby::Else.new(statements)
174
+ end
175
+
176
+ def on_END(statements)
177
+ Ruby::Call.new(nil, ident(:END), nil, statements)
178
+ end
179
+
180
+ def on_ensure(statements)
181
+ statements
182
+ end
183
+
184
+ def on_if(expression, statements, else_block)
185
+ Ruby::If.new(expression, statements, else_block)
186
+ end
187
+ alias_method :on_elsif, :on_if
188
+
189
+ def on_ifop(condition, then_part, else_part)
190
+ Ruby::IfOp.new(condition, then_part, else_part)
191
+ end
192
+
193
+ def on_if_mod(expression, statement)
194
+ Ruby::IfMod.new(expression, statement)
195
+ end
196
+
197
+ def on_fcall(identifier)
198
+ Ruby::Call.new(nil, identifier)
199
+ end
200
+
201
+ def on_field(target, separator, identifier)
202
+ Ruby::Call.new(target, identifier)
203
+ end
204
+
205
+ def on_float(token)
206
+ Ruby::Float.new(token, position)
207
+ end
208
+
209
+ def on_for(variable, range, statements)
210
+ Ruby::For.new(variable, range, statements)
211
+ end
212
+
213
+ def on_gvar(token)
214
+ Ruby::GlobalVariable.new(token, position)
215
+ end
216
+
217
+ def on_hash(assocs)
218
+ Ruby::Hash.new(assocs)
219
+ end
220
+
221
+ def on_ident(token)
222
+ ident(token)
223
+ end
224
+
225
+ def on_int(token)
226
+ Ruby::Integer.new(token, position)
227
+ end
228
+
229
+ def on_ivar(token)
230
+ Ruby::InstanceVariable.new(token, position)
231
+ end
232
+
233
+ def on_kw(token)
234
+ Ruby::Keyword.new(token, position)
235
+ end
236
+
237
+ def on_label(token)
238
+ Ruby::Label.new(token, position)
239
+ end
240
+
241
+ def on_lambda(params, statements)
242
+ Ruby::Block.new(statements, params)
243
+ end
244
+
245
+ def on_massign(lvalue, rvalue)
246
+ lvalue.assignment(rvalue, ident(:'='))
247
+ end
248
+
249
+ def on_method_add_arg(call, args)
250
+ call.arguments = args; call
251
+ end
252
+
253
+ def on_method_add_block(call, block)
254
+ call.block = block; call
255
+ end
256
+
257
+ def on_mlhs_add(assignment, ref)
258
+ assignment.add(ref); assignment
259
+ end
260
+
261
+ def on_mlhs_add_star(assignment, ref)
262
+ assignment.add(Ruby::SplatArg.new(ref)); assignment
263
+ end
264
+
265
+ def on_mlhs_new
266
+ Ruby::MultiAssignmentList.new
267
+ end
268
+
269
+ def on_module(const, body)
270
+ Ruby::Module.new(const, body)
271
+ end
272
+
273
+ def on_mrhs_add(assignment, ref)
274
+ assignment.add(ref); assignment
275
+ end
276
+
277
+ def on_mrhs_new_from_args(args)
278
+ Ruby::MultiAssignmentList.new(args.elements)
279
+ end
280
+
281
+ def on_next(args)
282
+ Ruby::Call.new(nil, ident(:next), args)
283
+ end
284
+
285
+ def on_op(operator)
286
+ operator.intern
287
+ end
288
+
289
+ def on_opassign(lvalue, operator, rvalue)
290
+ lvalue.assignment(rvalue, operator)
291
+ end
292
+
293
+ def on_params(params, optionals, rest, something, block)
294
+ Ruby::Params.new(params, optionals, rest, block)
295
+ end
296
+
297
+ def on_paren(node)
298
+ node
299
+ end
300
+
301
+ def on_parse_error(message)
302
+ raise SyntaxError, message
303
+ end
304
+
305
+ def on_program(statements)
306
+ statements.to_program(@src, @filename)
307
+ end
308
+
309
+ def on_qwords_add(array, word)
310
+ array.add(Ruby::String.new(word)); array
311
+ end
312
+
313
+ def on_qwords_new
314
+ Ruby::Array.new
315
+ end
316
+
317
+ def on_redo
318
+ Ruby::Call.new(nil, ident(:redo))
319
+ end
320
+
321
+ def on_regexp_add(regexp, content)
322
+ regexp.add(content); regexp
323
+ end
324
+
325
+ def on_regexp_literal(regexp, rdelim)
326
+ regexp
327
+ end
328
+
329
+ def on_regexp_new
330
+ Ruby::Regexp.new
331
+ end
332
+
333
+ def on_rescue(types, var, statements, block)
334
+ statements.to_chained_block(block, Ruby::RescueParams.new(types, var))
335
+ end
336
+
337
+ def on_rescue_mod(expression, statements)
338
+ Ruby::RescueMod.new(expression, statements)
339
+ end
340
+
341
+ def on_rest_param(param)
342
+ param
343
+ end
344
+
345
+ def on_retry
346
+ Ruby::Call.new(nil, ident(:retry))
347
+ end
348
+
349
+ def on_return(args)
350
+ Ruby::Call.new(nil, ident(:return), args)
351
+ end
352
+
353
+ def on_sclass(superclass, body)
354
+ Ruby::SingletonClass.new(superclass, body)
355
+ end
356
+
357
+ def on_stmts_add(target, statement)
358
+ target.add(statement) if statement; target
359
+ end
360
+
361
+ def on_stmts_new
362
+ Ruby::Statements.new
363
+ end
364
+
365
+ def on_string_add(string, content)
366
+ string.add(content); string
367
+ end
368
+
369
+ def on_string_concat(*strings)
370
+ Ruby::StringConcat.new(strings)
371
+ end
372
+
373
+ def on_string_content
374
+ Ruby::String.new
375
+ end
376
+
377
+ # weird string syntax that I didn't know existed until writing this lib.
378
+ # ex. "safe level is #$SAFE" => "safe level is 0"
379
+ def on_string_dvar(variable)
380
+ variable
381
+ end
382
+
383
+ def on_string_embexpr(expression)
384
+ expression
385
+ end
386
+
387
+ def on_string_literal(string)
388
+ string
389
+ end
390
+
391
+ def on_super(args)
392
+ Ruby::Call.new(nil, ident(:super), args)
393
+ end
394
+
395
+ def on_symbol(token)
396
+ Ruby::Symbol.new(token, position)
397
+ end
398
+
399
+ def on_symbol_literal(symbol)
400
+ symbol
401
+ end
402
+
403
+ def on_top_const_field(field)
404
+ field
405
+ end
406
+
407
+ def on_top_const_ref(const)
408
+ const
409
+ end
410
+
411
+ def on_tstring_content(token)
412
+ token
413
+ end
414
+
415
+ def on_unary(operator, operand)
416
+ Ruby::Unary.new(operator, operand)
417
+ end
418
+
419
+ def on_undef(args)
420
+ Ruby::Call.new(nil, ident(:undef), Ruby::Args.new(args.collect { |e| to_ident(e) }))
421
+ end
422
+
423
+ def on_unless(expression, statements, else_block)
424
+ Ruby::Unless.new(expression, statements, else_block)
425
+ end
426
+
427
+ def on_unless_mod(expression, statement)
428
+ Ruby::UnlessMod.new(expression, statement)
429
+ end
430
+
431
+ def on_until(expression, statements)
432
+ Ruby::Until.new(expression, statements)
433
+ end
434
+
435
+ def on_until_mod(expression, statement)
436
+ Ruby::UntilMod.new(expression, statement)
437
+ end
438
+
439
+ def on_var_alias(new_name, old_name)
440
+ Ruby::Alias.new(to_ident(new_name), to_ident(old_name))
441
+ end
442
+
443
+ def on_var_field(field)
444
+ field
445
+ end
446
+
447
+ def on_var_ref(ref)
448
+ ref
449
+ end
450
+
451
+ def on_void_stmt
452
+ nil
453
+ end
454
+
455
+ def on_when(expression, statements, next_block)
456
+ Ruby::When.new(expression, statements, next_block)
457
+ end
458
+
459
+ def on_while(expression, statements)
460
+ Ruby::While.new(expression, statements)
461
+ end
462
+
463
+ def on_while_mod(expression, statement)
464
+ Ruby::WhileMod.new(expression, statement)
465
+ end
466
+
467
+ def on_word_add(string, word)
468
+ string.add(word); string
469
+ end
470
+
471
+ def on_words_add(array, word)
472
+ array.add(word); array
473
+ end
474
+
475
+ def on_word_new
476
+ Ruby::String.new
477
+ end
478
+
479
+ def on_words_new
480
+ Ruby::Array.new
481
+ end
482
+
483
+ def on_xstring_add(string, content)
484
+ on_string_add(string, content)
485
+ end
486
+
487
+ def on_xstring_new
488
+ Ruby::ExecutableString.new
489
+ end
490
+
491
+ def on_xstring_literal(string)
492
+ string
493
+ end
494
+
495
+ def on_yield(args)
496
+ Ruby::Call.new(nil, ident(:yield), args)
497
+ end
498
+
499
+ def on_yield0
500
+ Ruby::Call.new(nil, ident(:yield))
501
+ end
502
+
503
+ def on_zsuper(*)
504
+ Ruby::Call.new(nil, ident(:super))
505
+ end
506
+
507
+ private
508
+
509
+ def ident(ident)
510
+ Ruby::Identifier.new(ident, position)
511
+ end
512
+
513
+ def to_ident(ident_or_sym)
514
+ ident_or_sym.is_a?(Ruby::Identifier) ? ident_or_sym : ident(ident_or_sym)
515
+ end
516
+
517
+ def position
518
+ Ruby::Position.new(lineno, column)
519
+ end
520
+ end
521
+ end