rubycop 0.5.1 → 1.0.1

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 (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
@@ -0,0 +1,354 @@
1
+ require 'set'
2
+
3
+ module RubyCop
4
+ # Visitor class for Ruby::Node subclasses. Determines whether the node is
5
+ # safe according to our rules.
6
+ class Policy
7
+ def initialize
8
+ @const_list = GrayList.new
9
+ initialize_const_blacklist
10
+ end
11
+
12
+ def inspect
13
+ '#<%s:0x%x>' % [self.class.name, object_id]
14
+ end
15
+
16
+ def blacklist_const(const)
17
+ @const_list.blacklist(const)
18
+ end
19
+
20
+ def const_allowed?(const)
21
+ @const_list.allow?(const)
22
+ end
23
+
24
+ def whitelist_const(const)
25
+ @const_list.whitelist(const)
26
+ end
27
+
28
+ def visit(node)
29
+ klass = node.class.ancestors.detect do |ancestor|
30
+ respond_to?("visit_#{ancestor.name.split('::').last}")
31
+ end
32
+ if klass
33
+ send("visit_#{klass.name.split('::').last}", node)
34
+ else
35
+ warn "unhandled node type: #{node.inspect}:#{node.class.name}"
36
+ true
37
+ end
38
+ end
39
+
40
+ def visit_Alias(node)
41
+ false # never allowed
42
+ end
43
+
44
+ def visit_Args(node)
45
+ node.elements.all? { |e| visit(e) }
46
+ end
47
+
48
+ def visit_Array(node)
49
+ node.elements.all? { |e| visit(e) }
50
+ end
51
+
52
+ def visit_Assoc(node)
53
+ visit(node.key) && visit(node.value)
54
+ end
55
+
56
+ def visit_Binary(node)
57
+ visit(node.lvalue) && visit(node.rvalue)
58
+ end
59
+
60
+ def visit_Block(node)
61
+ (node.params.nil? || visit(node.params)) && node.elements.all? { |e| visit(e) }
62
+ end
63
+
64
+ CALL_BLACKLIST = %w[
65
+ abort
66
+ alias_method
67
+ at_exit
68
+ autoload
69
+ binding
70
+ callcc
71
+ caller
72
+ class_eval
73
+ const_get
74
+ const_set
75
+ eval
76
+ exec
77
+ exit
78
+ fail
79
+ fork
80
+ gets
81
+ global_variables
82
+ instance_eval
83
+ load
84
+ loop
85
+ method
86
+ module_eval
87
+ open
88
+ readline
89
+ readlines
90
+ redo
91
+ remove_const
92
+ require
93
+ send
94
+ set_trace_func
95
+ sleep
96
+ spawn
97
+ srand
98
+ syscall
99
+ system
100
+ trap
101
+ undef
102
+ __callee__
103
+ __method__
104
+ ].to_set.freeze
105
+
106
+ def visit_Call(node)
107
+ !CALL_BLACKLIST.include?(node.identifier.token.to_s) && [node.target, node.arguments, node.block].compact.all? { |e| visit(e) }
108
+ end
109
+
110
+ def visit_Case(node)
111
+ visit(node.expression) && visit(node.block)
112
+ end
113
+
114
+ def visit_ChainedBlock(node)
115
+ node.elements.all? { |e| visit(e) } && node.blocks.all? { |e| visit(e) } && (node.params.nil? || visit(node.params))
116
+ end
117
+
118
+ def visit_Class(node)
119
+ visit(node.const) && (node.superclass.nil? || visit(node.superclass)) && visit(node.body)
120
+ end
121
+
122
+ def visit_ClassVariable(node)
123
+ false # never allowed
124
+ end
125
+
126
+ def visit_ClassVariableAssignment(node)
127
+ false # never allowed
128
+ end
129
+
130
+ def visit_Char(node)
131
+ true
132
+ end
133
+
134
+ def visit_Constant(node)
135
+ const_allowed?(node.token)
136
+ end
137
+
138
+ def visit_ConstantAssignment(node)
139
+ visit(node.lvalue) && visit(node.rvalue)
140
+ end
141
+
142
+ def visit_Defined(node)
143
+ false # never allowed (though it's probably safe)
144
+ end
145
+
146
+ def visit_Else(node)
147
+ node.elements.all? { |e| visit(e) }
148
+ end
149
+
150
+ def visit_ExecutableString(node)
151
+ false # never allowed
152
+ end
153
+
154
+ def visit_Float(node)
155
+ true
156
+ end
157
+
158
+ def visit_For(node)
159
+ visit(node.variable) && visit(node.range) && visit(node.statements)
160
+ end
161
+
162
+ def visit_GlobalVariable(node)
163
+ false # never allowed
164
+ end
165
+
166
+ def visit_GlobalVariableAssignment(node)
167
+ false # never allowed
168
+ end
169
+
170
+ def visit_Hash(node)
171
+ node.assocs.nil? || node.assocs.all? { |e| visit(e) }
172
+ end
173
+
174
+ def visit_Identifier(node)
175
+ !CALL_BLACKLIST.include?(node.token)
176
+ end
177
+
178
+ def visit_If(node)
179
+ visit(node.expression) && node.elements.all? { |e| visit(e) } && node.blocks.all? { |e| visit(e) }
180
+ end
181
+ alias_method :visit_Unless, :visit_If
182
+
183
+ def visit_IfMod(node)
184
+ visit(node.expression) && node.elements.all? { |e| visit(e) }
185
+ end
186
+ alias_method :visit_UnlessMod, :visit_IfMod
187
+
188
+ def visit_IfOp(node)
189
+ visit(node.condition) && visit(node.then_part) && visit(node.else_part)
190
+ end
191
+
192
+ def visit_InstanceVariable(node)
193
+ true
194
+ end
195
+
196
+ def visit_InstanceVariableAssignment(node)
197
+ visit(node.rvalue)
198
+ end
199
+
200
+ def visit_Integer(node)
201
+ true
202
+ end
203
+
204
+ KEYWORD_WHITELIST = %w[
205
+ false
206
+ nil
207
+ self
208
+ true
209
+ ].to_set.freeze
210
+
211
+ def visit_Keyword(node)
212
+ KEYWORD_WHITELIST.include?(node.token)
213
+ end
214
+
215
+ def visit_Label(node)
216
+ true
217
+ end
218
+
219
+ def visit_LocalVariableAssignment(node)
220
+ visit(node.rvalue)
221
+ end
222
+
223
+ def visit_Method(node)
224
+ [node.target, node.params, node.body].compact.all? { |e| visit(e) }
225
+ end
226
+
227
+ def visit_Module(node)
228
+ visit(node.const) && visit(node.body)
229
+ end
230
+
231
+ def visit_MultiAssignment(node)
232
+ visit(node.lvalue) && visit(node.rvalue)
233
+ end
234
+
235
+ def visit_MultiAssignmentList(node)
236
+ node.elements.all? { |e| visit(e) }
237
+ end
238
+
239
+ def visit_Params(node)
240
+ node.elements.all? { |e| visit(e) }
241
+ end
242
+
243
+ def visit_Program(node)
244
+ node.elements.all? { |e| visit(e) }
245
+ end
246
+
247
+ def visit_Range(node)
248
+ visit(node.min) && visit(node.max)
249
+ end
250
+
251
+ def visit_RescueMod(node)
252
+ node.elements.all? { |e| visit(e) } && visit(node.expression)
253
+ end
254
+
255
+ def visit_RescueParams(node)
256
+ node.elements.all? { |e| visit(e) }
257
+ end
258
+
259
+ def visit_SingletonClass(node)
260
+ visit(node.superclass) && visit(node.body)
261
+ end
262
+
263
+ def visit_SplatArg(node)
264
+ visit(node.arg)
265
+ end
266
+
267
+ def visit_Statements(node)
268
+ node.elements.all? { |e| visit(e) }
269
+ end
270
+
271
+ def visit_String(node)
272
+ # embedded strings can have statements in them, so check those
273
+ node.elements.reject { |e| e.is_a?(::String) }.all? { |e| visit(e) }
274
+ end
275
+
276
+ def visit_StringConcat(node)
277
+ node.elements.all? { |e| visit(e) }
278
+ end
279
+
280
+ def visit_Symbol(node)
281
+ true
282
+ end
283
+
284
+ def visit_Unary(node)
285
+ visit(node.operand)
286
+ end
287
+
288
+ def visit_Until(node)
289
+ false # never allowed
290
+ end
291
+ alias_method :visit_UntilMod, :visit_Until
292
+
293
+ def visit_When(node)
294
+ visit(node.expression) && node.elements.all? { |e| visit(e) }
295
+ end
296
+
297
+ def visit_While(node)
298
+ false # never allowed
299
+ end
300
+ alias_method :visit_WhileMod, :visit_While
301
+
302
+ private
303
+
304
+ CONST_BLACKLIST = %w[
305
+ ARGF
306
+ ARGV
307
+ Array
308
+ Base64
309
+ Class
310
+ Dir
311
+ ENV
312
+ Enumerable
313
+ Error
314
+ Exception
315
+ Fiber
316
+ File
317
+ FileUtils
318
+ GC
319
+ Gem
320
+ Hash
321
+ IO
322
+ IRB
323
+ Kernel
324
+ Module
325
+ Net
326
+ Object
327
+ ObjectSpace
328
+ OpenSSL
329
+ OpenURI
330
+ PLATFORM
331
+ Proc
332
+ Process
333
+ RUBY_COPYRIGHT
334
+ RUBY_DESCRIPTION
335
+ RUBY_ENGINE
336
+ RUBY_PATCHLEVEL
337
+ RUBY_PLATFORM
338
+ RUBY_RELEASE_DATE
339
+ RUBY_VERSION
340
+ Rails
341
+ STDERR
342
+ STDIN
343
+ STDOUT
344
+ String
345
+ TOPLEVEL_BINDING
346
+ Thread
347
+ VERSION
348
+ ].freeze
349
+
350
+ def initialize_const_blacklist
351
+ CONST_BLACKLIST.each { |const| blacklist_const(const) }
352
+ end
353
+ end
354
+ end
@@ -0,0 +1,23 @@
1
+ require 'ruby_cop/ruby/node'
2
+ require 'ruby_cop/ruby/list'
3
+ require 'ruby_cop/ruby/array'
4
+ require 'ruby_cop/ruby/args'
5
+ require 'ruby_cop/ruby/assignment'
6
+ require 'ruby_cop/ruby/assoc'
7
+ require 'ruby_cop/ruby/statements'
8
+ require 'ruby_cop/ruby/blocks'
9
+ require 'ruby_cop/ruby/call'
10
+ require 'ruby_cop/ruby/case'
11
+ require 'ruby_cop/ruby/tokens'
12
+ require 'ruby_cop/ruby/constants'
13
+ require 'ruby_cop/ruby/definitions'
14
+ require 'ruby_cop/ruby/for'
15
+ require 'ruby_cop/ruby/hash'
16
+ require 'ruby_cop/ruby/if'
17
+ require 'ruby_cop/ruby/operators'
18
+ require 'ruby_cop/ruby/params'
19
+ require 'ruby_cop/ruby/position'
20
+ require 'ruby_cop/ruby/range'
21
+ require 'ruby_cop/ruby/string'
22
+ require 'ruby_cop/ruby/variables'
23
+ require 'ruby_cop/ruby/while'
@@ -0,0 +1,26 @@
1
+ module RubyCop
2
+ module Ruby
3
+ class Args < List
4
+ attr_reader :block
5
+
6
+ def add_block(block)
7
+ @block = block
8
+ end
9
+
10
+ def to_array
11
+ Array.new(@elements)
12
+ end
13
+ end
14
+
15
+ class Arg < Node
16
+ def initialize(arg)
17
+ @arg = arg
18
+ end
19
+
20
+ attr_reader :arg
21
+ end
22
+
23
+ class SplatArg < Arg
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ module RubyCop
2
+ module Ruby
3
+ class Array < List
4
+ # def inspect
5
+ # '[%s]' % @elements.collect { |e| e.inspect }.join(', ')
6
+ # end
7
+
8
+ def to_array
9
+ self
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,43 @@
1
+ module RubyCop
2
+ module Ruby
3
+ class Assignment < Node
4
+ def initialize(lvalue, rvalue, operator)
5
+ @lvalue = lvalue
6
+ @rvalue = rvalue
7
+ @operator = operator
8
+ end
9
+
10
+ attr_reader :lvalue
11
+ attr_reader :rvalue
12
+ attr_reader :operator
13
+
14
+ # def inspect
15
+ # "#{@lvalue.inspect} #{@operator} #{@rvalue.inspect}"
16
+ # end
17
+ end
18
+
19
+ class ClassVariableAssignment < Assignment
20
+ end
21
+
22
+ class ConstantAssignment < Assignment
23
+ end
24
+
25
+ class GlobalVariableAssignment < Assignment
26
+ end
27
+
28
+ class InstanceVariableAssignment < Assignment
29
+ end
30
+
31
+ class LocalVariableAssignment < Assignment
32
+ end
33
+
34
+ class MultiAssignment < Assignment
35
+ end
36
+
37
+ class MultiAssignmentList < List
38
+ def assignment(rvalue, operator)
39
+ MultiAssignment.new(self, rvalue, operator)
40
+ end
41
+ end
42
+ end
43
+ end