rails_best_practices 1.8.0 → 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rvmrc +1 -1
- data/.travis.yml +1 -1
- data/Gemfile.lock +1 -1
- data/README.md +4 -2
- data/install_supported_rubies.sh +1 -1
- data/lib/rails_best_practices/core.rb +0 -1
- data/lib/rails_best_practices/core/check.rb +22 -3
- data/lib/rails_best_practices/core/checking_visitor.rb +24 -21
- data/lib/rails_best_practices/core/model_associations.rb +1 -1
- data/lib/rails_best_practices/core/routes.rb +3 -1
- data/lib/rails_best_practices/core_ext/sexp.rb +20 -13
- data/lib/rails_best_practices/prepares/controller_prepare.rb +8 -1
- data/lib/rails_best_practices/prepares/model_prepare.rb +1 -1
- data/lib/rails_best_practices/prepares/route_prepare.rb +16 -8
- data/lib/rails_best_practices/reviews.rb +1 -0
- data/lib/rails_best_practices/reviews/always_add_db_index_review.rb +1 -1
- data/lib/rails_best_practices/reviews/protect_mass_assignment_review.rb +45 -0
- data/lib/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review.rb +9 -1
- data/lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb +2 -2
- data/lib/rails_best_practices/reviews/use_before_filter_review.rb +1 -1
- data/lib/rails_best_practices/version.rb +1 -1
- data/rails_best_practices.gemspec +1 -1
- data/rails_best_practices.yml +1 -0
- data/rake_rubies.sh +2 -2
- data/spec/rails_best_practices/core_ext/sexp_spec.rb +15 -4
- data/spec/rails_best_practices/prepares/route_prepare_spec.rb +25 -2
- data/spec/rails_best_practices/reviews/protect_mass_assignment_review_spec.rb +67 -0
- metadata +30 -28
- data/lib/rails_best_practices/core_ext/string.rb +0 -5
data/.rvmrc
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
rvm_gemset_create_on_use_flag=1
|
2
|
-
rvm gemset use ruby-1.9.
|
2
|
+
rvm gemset use ruby-1.9.3-p125@rails_best_practices
|
data/.travis.yml
CHANGED
@@ -1 +1 @@
|
|
1
|
-
rvm: 1.9.
|
1
|
+
rvm: 1.9.3
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -19,6 +19,8 @@ following template engines:
|
|
19
19
|
* haml
|
20
20
|
* slim
|
21
21
|
|
22
|
+
rails_best_practices works well only in ruby 1.9.2 and ruby 1.9.3 so far.
|
23
|
+
|
22
24
|
Usage
|
23
25
|
-----
|
24
26
|
|
@@ -78,8 +80,6 @@ Install
|
|
78
80
|
|
79
81
|
rails_best_practices gem is rewritten based on ripper instead of ruby_parser to support ruby 1.9 new syntax.
|
80
82
|
|
81
|
-
Ruby 1.9
|
82
|
-
|
83
83
|
gem install rails_best_practices
|
84
84
|
|
85
85
|
or add in Gemfile
|
@@ -143,6 +143,7 @@ Now you can customize this configuration file, the default configuration is as f
|
|
143
143
|
RemoveUnusedMethodsInControllersCheck: { except_methods: [] }
|
144
144
|
RemoveUnusedMethodsInHelpersCheck: { except_methods: [] }
|
145
145
|
NotUseTimeAgoInWordsCheck: {}
|
146
|
+
ProtectMassAssignmentCheck: {}
|
146
147
|
|
147
148
|
You can remove or comment one review to disable it, and you can change the options.
|
148
149
|
|
@@ -172,6 +173,7 @@ Model
|
|
172
173
|
3. Use observer
|
173
174
|
4. Use query attribute
|
174
175
|
5. Remove unused methods in models
|
176
|
+
6. Protect mass assignment
|
175
177
|
|
176
178
|
Mailer
|
177
179
|
|
data/install_supported_rubies.sh
CHANGED
@@ -15,7 +15,6 @@ require 'rails_best_practices/core/controllers'
|
|
15
15
|
require 'rails_best_practices/core/helpers'
|
16
16
|
require 'rails_best_practices/core/routes'
|
17
17
|
|
18
|
-
require 'rails_best_practices/core_ext/string'
|
19
18
|
require 'rails_best_practices/core_ext/sexp'
|
20
19
|
require 'rails_best_practices/core_ext/enumerable'
|
21
20
|
require 'rails_best_practices/core_ext/erubis'
|
@@ -238,7 +238,7 @@ module RailsBestPractices
|
|
238
238
|
module Callable
|
239
239
|
def self.included(base)
|
240
240
|
base.class_eval do
|
241
|
-
interesting_nodes :call, :fcall, :var_ref, :command_call, :command, :alias, :bare_assoc_hash, :method_add_arg
|
241
|
+
interesting_nodes :call, :fcall, :var_ref, :vcall, :command_call, :command, :alias, :bare_assoc_hash, :method_add_arg
|
242
242
|
|
243
243
|
# remembe the message of call node.
|
244
244
|
add_callback "start_call" do |node|
|
@@ -255,6 +255,11 @@ module RailsBestPractices
|
|
255
255
|
mark_used(node)
|
256
256
|
end
|
257
257
|
|
258
|
+
# remembe name of vcall node.
|
259
|
+
add_callback "start_vcall" do |node|
|
260
|
+
mark_used(node)
|
261
|
+
end
|
262
|
+
|
258
263
|
# skip start_command callback for these nodes
|
259
264
|
def skip_command_callback_nodes
|
260
265
|
[]
|
@@ -346,7 +351,7 @@ module RailsBestPractices
|
|
346
351
|
module InheritedResourcesable
|
347
352
|
def self.included(base)
|
348
353
|
base.class_eval do
|
349
|
-
interesting_nodes :class, :var_ref
|
354
|
+
interesting_nodes :class, :var_ref, :vcall
|
350
355
|
interesting_files CONTROLLER_FILES
|
351
356
|
|
352
357
|
# check if the controller is inherit from InheritedResources::Base.
|
@@ -362,6 +367,13 @@ module RailsBestPractices
|
|
362
367
|
@inherited_resources = true
|
363
368
|
end
|
364
369
|
end
|
370
|
+
|
371
|
+
# check if there is a DSL call inherit_resources.
|
372
|
+
add_callback "start_vcall" do |node|
|
373
|
+
if "inherit_resources" == node.to_s
|
374
|
+
@inherited_resources = true
|
375
|
+
end
|
376
|
+
end
|
365
377
|
end
|
366
378
|
end
|
367
379
|
end
|
@@ -396,7 +408,7 @@ module RailsBestPractices
|
|
396
408
|
module Accessable
|
397
409
|
def self.included(base)
|
398
410
|
base.class_eval do
|
399
|
-
interesting_nodes :var_ref, :class, :module
|
411
|
+
interesting_nodes :var_ref, :vcall, :class, :module
|
400
412
|
|
401
413
|
# remember the current access control for methods.
|
402
414
|
add_callback "start_var_ref" do |node|
|
@@ -405,6 +417,13 @@ module RailsBestPractices
|
|
405
417
|
end
|
406
418
|
end
|
407
419
|
|
420
|
+
# remember the current access control for methods.
|
421
|
+
add_callback "start_vcall" do |node|
|
422
|
+
if %w(public protected private).include? node.to_s
|
423
|
+
@access_control = node.to_s
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
408
427
|
# set access control to "public" by default.
|
409
428
|
add_callback "start_class" do |node|
|
410
429
|
@access_control = "public"
|
@@ -49,27 +49,30 @@ module RailsBestPractices
|
|
49
49
|
# then run the reivew for that node.
|
50
50
|
[:prepare, :review].each do |process|
|
51
51
|
class_eval <<-EOS
|
52
|
-
def #{process}(node)
|
53
|
-
checks = @#{process}_checks[node.sexp_type]
|
54
|
-
if checks
|
55
|
-
checks.each { |check|
|
56
|
-
if check.parse_file?(node.file)
|
57
|
-
check.node_start(node)
|
58
|
-
end
|
59
|
-
}
|
60
|
-
end
|
61
|
-
node.children.each { |sexp|
|
62
|
-
sexp.file = node.file
|
63
|
-
sexp.#{process}(self)
|
64
|
-
}
|
65
|
-
if checks
|
66
|
-
checks.each { |check|
|
67
|
-
if check.parse_file?(node.file)
|
68
|
-
check.node_end(node)
|
69
|
-
end
|
70
|
-
}
|
71
|
-
end
|
72
|
-
|
52
|
+
def #{process}(node) # def review(node)
|
53
|
+
checks = @#{process}_checks[node.sexp_type] # checks = @review_checks[node.sexp_type]
|
54
|
+
if checks # if checks
|
55
|
+
checks.each { |check| # checks.each { |check|
|
56
|
+
if check.parse_file?(node.file) # if check.parse_file?(node.file)
|
57
|
+
check.node_start(node) # check.node_start(node)
|
58
|
+
end # end
|
59
|
+
} # }
|
60
|
+
end # end
|
61
|
+
node.children.each { |sexp| # node.children.each { |sexp|
|
62
|
+
sexp.file = node.file # sexp.filename = node.file
|
63
|
+
sexp.#{process}(self) # sexp.review(self)
|
64
|
+
} # }
|
65
|
+
if checks # if checks
|
66
|
+
checks.each { |check| # checks.each { |check|
|
67
|
+
if check.parse_file?(node.file) # if check.parse_file?(node.file)
|
68
|
+
check.node_end(node) # check.node_end(node)
|
69
|
+
end # end
|
70
|
+
} # }
|
71
|
+
end # end
|
72
|
+
rescue Exception # rescue Exception
|
73
|
+
puts "find error in file: \#{node.file} line: \#{node.line}" # puts "find error in file: \#{node.file} line: \#{node.line}"
|
74
|
+
raise $! # raise $!
|
75
|
+
end # end
|
73
76
|
EOS
|
74
77
|
end
|
75
78
|
end
|
@@ -48,7 +48,7 @@ module RailsBestPractices
|
|
48
48
|
# @param [String] association_name
|
49
49
|
# @return [String] association's class name
|
50
50
|
def get_association_class_name(table_name, association_name)
|
51
|
-
associations = @associations.select { |model, model_associations| model.
|
51
|
+
associations = @associations.select { |model, model_associations| model.gsub("::", "").tableize == table_name }.values.first and
|
52
52
|
association_meta = associations.select { |name, meta| name == association_name }.values.first and
|
53
53
|
association_meta["class_name"]
|
54
54
|
end
|
@@ -8,7 +8,9 @@ module RailsBestPractices
|
|
8
8
|
# @param [String] controller name
|
9
9
|
# @param [String] action name
|
10
10
|
def add_route(namespaces, controller_name, action_name)
|
11
|
-
|
11
|
+
if controller_name.present?
|
12
|
+
self << Route.new(namespaces, controller_name, action_name)
|
13
|
+
end
|
12
14
|
end
|
13
15
|
end
|
14
16
|
|
@@ -22,7 +22,7 @@ class Sexp
|
|
22
22
|
# => 2
|
23
23
|
def line
|
24
24
|
if [:def, :defs, :command, :command_call, :call, :fcall, :method_add_arg, :method_add_block,
|
25
|
-
:var_ref, :const_ref, :const_path_ref, :class, :module, :if, :unless, :elsif, :binary,
|
25
|
+
:var_ref, :vcall, :const_ref, :const_path_ref, :class, :module, :if, :unless, :elsif, :binary,
|
26
26
|
:alias, :symbol_literal, :symbol, :aref].include? sexp_type
|
27
27
|
self[1].line
|
28
28
|
elsif :array == sexp_type
|
@@ -56,17 +56,20 @@ class Sexp
|
|
56
56
|
# :sexp_type => :call,
|
57
57
|
# :subject => "Post",
|
58
58
|
# :message => ["find", "new"]
|
59
|
+
# :to_s => "devise"
|
59
60
|
#
|
60
|
-
# the condition key is one of :sexp_type, :subject
|
61
|
+
# the condition key is one of :sexp_type, :subject, :message, :to_s,
|
61
62
|
# the condition value can be Symbol, Array or Sexp.
|
62
63
|
def grep_nodes(options)
|
63
64
|
sexp_type = options[:sexp_type]
|
64
65
|
subject = options[:subject]
|
65
66
|
message = options[:message]
|
67
|
+
to_s = options[:to_s]
|
66
68
|
self.recursive_children do |child|
|
67
69
|
if (!sexp_type || (sexp_type.is_a?(Array) ? sexp_type.include?(child.sexp_type) : sexp_type == child.sexp_type)) &&
|
68
70
|
(!subject || (subject.is_a?(Array) ? subject.include?(child.subject.to_s) : subject == child.subject.to_s)) &&
|
69
|
-
(!message || (message.is_a?(Array) ? message.include?(child.message.to_s) : message == child.message.to_s))
|
71
|
+
(!message || (message.is_a?(Array) ? message.include?(child.message.to_s) : message == child.message.to_s)) &&
|
72
|
+
(!to_s || (to_s.is_a?(Array) ? to_s.include?(child.to_s) : to_s == child.to_s))
|
70
73
|
yield child
|
71
74
|
end
|
72
75
|
end
|
@@ -82,7 +85,7 @@ class Sexp
|
|
82
85
|
# :subject => s(:const, Post),
|
83
86
|
# :message => [:find, :new]
|
84
87
|
#
|
85
|
-
# the condition key is one of :sexp_type, :subject, :message,
|
88
|
+
# the condition key is one of :sexp_type, :subject, :message, and to_s,
|
86
89
|
# the condition value can be Symbol, Array or Sexp.
|
87
90
|
def grep_node(options)
|
88
91
|
result = RailsBestPractices::Core::Nil.new
|
@@ -295,13 +298,17 @@ class Sexp
|
|
295
298
|
nodes = []
|
296
299
|
case sexp_type
|
297
300
|
when :args_add_block, :array
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
301
|
+
if self[1].sexp_type == :args_new
|
302
|
+
nodes << self[2]
|
303
|
+
else
|
304
|
+
node = self[1]
|
305
|
+
while true
|
306
|
+
if [:args_add, :args_add_star].include? node.sexp_type
|
307
|
+
nodes.unshift node[2]
|
308
|
+
node = node[1]
|
309
|
+
elsif :args_new == node.sexp_type
|
310
|
+
break
|
311
|
+
end
|
305
312
|
end
|
306
313
|
end
|
307
314
|
end
|
@@ -754,7 +761,7 @@ class Sexp
|
|
754
761
|
def to_s
|
755
762
|
case sexp_type
|
756
763
|
when :string_literal, :xstring_literal, :string_content, :const_ref, :symbol_literal, :symbol,
|
757
|
-
:args_add_block, :var_ref, :var_field,
|
764
|
+
:args_add_block, :var_ref, :vcall, :var_field,
|
758
765
|
:@ident, :@tstring_content, :@const, :@ivar, :@kw, :@gvar, :@cvar
|
759
766
|
self[1].to_s
|
760
767
|
when :string_add
|
@@ -788,7 +795,7 @@ class Sexp
|
|
788
795
|
|
789
796
|
# check if the self node is a const.
|
790
797
|
def const?
|
791
|
-
:@const == self.sexp_type || (:var_ref
|
798
|
+
:@const == self.sexp_type || ([:var_ref, :vcall].include?(self.sexp_type) && :@const == self[1].sexp_type)
|
792
799
|
end
|
793
800
|
|
794
801
|
# true
|
@@ -10,7 +10,7 @@ module RailsBestPractices
|
|
10
10
|
include Core::Check::Accessable
|
11
11
|
include Core::Check::Afterable
|
12
12
|
|
13
|
-
interesting_nodes :class, :var_ref, :command, :def
|
13
|
+
interesting_nodes :class, :var_ref, :vcall, :command, :def
|
14
14
|
interesting_files CONTROLLER_FILES
|
15
15
|
|
16
16
|
DEFAULT_ACTIONS = %w(index show new create edit update destroy)
|
@@ -47,6 +47,13 @@ module RailsBestPractices
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
+
# check if there is a DSL call inherit_resources.
|
51
|
+
def start_vcall(node)
|
52
|
+
if @inherited_resources
|
53
|
+
@actions = DEFAULT_ACTIONS
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
50
57
|
# restrict actions for inherited_resources
|
51
58
|
def start_command(node)
|
52
59
|
if "include" == node.message.to_s
|
@@ -9,7 +9,7 @@ module RailsBestPractices
|
|
9
9
|
include Core::Check::Accessable
|
10
10
|
include Core::Check::Afterable
|
11
11
|
|
12
|
-
interesting_nodes :class, :def, :defs, :command, :
|
12
|
+
interesting_nodes :class, :def, :defs, :command, :alias
|
13
13
|
interesting_files MODEL_FILES
|
14
14
|
|
15
15
|
ASSOCIATION_METHODS = %w(belongs_to has_one has_many has_and_belongs_to_many embeds_many embeds_one embedded_in many one)
|
@@ -28,7 +28,11 @@ module RailsBestPractices
|
|
28
28
|
first_argument = node.arguments.all.first
|
29
29
|
second_argument = node.arguments.all[1]
|
30
30
|
if @controller_names.last
|
31
|
-
|
31
|
+
if :bare_assoc_hash == first_argument.sexp_type
|
32
|
+
action_name = first_argument.hash_values.first.to_s
|
33
|
+
else
|
34
|
+
action_name = first_argument.to_s
|
35
|
+
end
|
32
36
|
@routes.add_route(current_namespaces, current_controller_name, action_name)
|
33
37
|
else
|
34
38
|
if :bare_assoc_hash == first_argument.sexp_type
|
@@ -83,7 +87,7 @@ module RailsBestPractices
|
|
83
87
|
else
|
84
88
|
options = node.arguments.all.last
|
85
89
|
if options.hash_value("controller").present?
|
86
|
-
@controller_name = options.hash_value("controller").to_s
|
90
|
+
@controller_name = [:option, options.hash_value("controller").to_s]
|
87
91
|
end
|
88
92
|
action_name = options.hash_value("action").present? ? options.hash_value("action").to_s : "*"
|
89
93
|
@routes.add_route(current_namespaces, current_controller_name, action_name)
|
@@ -100,11 +104,15 @@ module RailsBestPractices
|
|
100
104
|
if node.arguments.all.last.hash_value("module").present?
|
101
105
|
@namespaces << node.arguments.all.last.hash_value("module").to_s
|
102
106
|
end
|
103
|
-
|
107
|
+
if node.arguments.all.last.hash_value("controller").present?
|
108
|
+
@controller_name = [:scope, node.arguments.all.last.hash_value("controller").to_s]
|
109
|
+
else
|
110
|
+
@controller_name = @controller_name.try(:first) == :scope ? @controller_name : nil
|
111
|
+
end
|
104
112
|
when "with_options"
|
105
113
|
argument = node.arguments.all.last
|
106
114
|
if :bare_assoc_hash == argument.sexp_type && argument.hash_value("controller").present?
|
107
|
-
@controller_name = argument.hash_value("controller").to_s
|
115
|
+
@controller_name = [:with_option, argument.hash_value("controller").to_s]
|
108
116
|
end
|
109
117
|
else
|
110
118
|
# do nothing
|
@@ -127,7 +135,7 @@ module RailsBestPractices
|
|
127
135
|
|
128
136
|
# remember current controller name, used for nested resources.
|
129
137
|
def start_do_block(node)
|
130
|
-
@controller_names << @controller_name
|
138
|
+
@controller_names << @controller_name.try(:last)
|
131
139
|
end
|
132
140
|
|
133
141
|
# remove current controller name, and use upper lever resource name.
|
@@ -140,13 +148,13 @@ module RailsBestPractices
|
|
140
148
|
def add_#{route_name}_routes(node)
|
141
149
|
resource_names = node.arguments.all.select { |argument| :symbol_literal == argument.sexp_type }
|
142
150
|
resource_names.each do |resource_name|
|
143
|
-
@controller_name = node.arguments.all.first.to_s
|
151
|
+
@controller_name = [:#{route_name}, node.arguments.all.first.to_s]
|
144
152
|
options = node.arguments.all.last
|
145
153
|
if options.hash_value("module").present?
|
146
154
|
@namespaces << options.hash_value("module").to_s
|
147
155
|
end
|
148
156
|
if options.hash_value("controller").present?
|
149
|
-
@controller_name = options.hash_value("controller").to_s
|
157
|
+
@controller_name = [:#{route_name}, options.hash_value("controller").to_s]
|
150
158
|
end
|
151
159
|
action_names = if options.hash_value("only").present?
|
152
160
|
get_#{route_name}_actions(options.hash_value("only").to_object)
|
@@ -201,7 +209,7 @@ module RailsBestPractices
|
|
201
209
|
end
|
202
210
|
|
203
211
|
def current_controller_name
|
204
|
-
@controller_names.last || @controller_name
|
212
|
+
@controller_names.last || @controller_name.try(:last)
|
205
213
|
end
|
206
214
|
end
|
207
215
|
end
|
@@ -30,3 +30,4 @@ require 'rails_best_practices/reviews/remove_unused_methods_in_models_review'
|
|
30
30
|
require 'rails_best_practices/reviews/remove_unused_methods_in_controllers_review'
|
31
31
|
require 'rails_best_practices/reviews/remove_unused_methods_in_helpers_review'
|
32
32
|
require 'rails_best_practices/reviews/not_use_time_ago_in_words_review'
|
33
|
+
require 'rails_best_practices/reviews/protect_mass_assignment_review'
|
@@ -130,7 +130,7 @@ module RailsBestPractices
|
|
130
130
|
foreign_keys.delete_if do |key|
|
131
131
|
if key =~ /_id$/
|
132
132
|
class_name = Prepares.model_associations.get_association_class_name(table, key[0..-4])
|
133
|
-
class_name ? !@table_nodes[class_name.
|
133
|
+
class_name ? !@table_nodes[class_name.gsub("::", "").tableize] : !@table_nodes[key[0..-4].pluralize]
|
134
134
|
end
|
135
135
|
end
|
136
136
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rails_best_practices/reviews/review'
|
3
|
+
|
4
|
+
module RailsBestPractices
|
5
|
+
module Reviews
|
6
|
+
# Review model files to make sure to use attr_accessible or attr_protected to protect mass assignment.
|
7
|
+
#
|
8
|
+
# See the best practices details here http://rails-bestpractices.com/posts/148-protect-mass-assignment.
|
9
|
+
#
|
10
|
+
# Implmentation:
|
11
|
+
#
|
12
|
+
# Review process:
|
13
|
+
# check class node to see if there is a command with message attr_accessible or attr_protected.
|
14
|
+
class ProtectMassAssignmentReview < Review
|
15
|
+
interesting_nodes :class
|
16
|
+
interesting_files MODEL_FILES
|
17
|
+
|
18
|
+
def url
|
19
|
+
"http://rails-bestpractices.com/posts/148-protect-mass-assignment"
|
20
|
+
end
|
21
|
+
|
22
|
+
# check class node, grep all command nodes, if none of them is with message attr_accessible or attr_protected,
|
23
|
+
# then it should add attr_accessible or attr_protected to protect mass assignment.
|
24
|
+
def start_class(node)
|
25
|
+
if !rails_builtin?(node) && !devise?(node) && !authlogic?(node)
|
26
|
+
add_error "protect mass assignment"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def rails_builtin?(node)
|
32
|
+
node.grep_node(:sexp_type => :command, :message => %w(attr_accessible attr_protected)).present?
|
33
|
+
end
|
34
|
+
|
35
|
+
def devise?(node)
|
36
|
+
node.grep_node(:sexp_type => :command, :message => "devise").present?
|
37
|
+
end
|
38
|
+
|
39
|
+
def authlogic?(node)
|
40
|
+
node.grep_node(:sexp_type => :vcall, :to_s => "acts_as_authentic").present? ||
|
41
|
+
node.grep_node(:sexp_type => :fcall, :message => "acts_as_authentic").present?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review.rb
CHANGED
@@ -13,7 +13,7 @@ module RailsBestPractices
|
|
13
13
|
# check all instance variable in partial view files,
|
14
14
|
# if exist, then they should be replaced with local variable
|
15
15
|
class ReplaceInstanceVariableWithLocalVariableReview < Review
|
16
|
-
interesting_nodes :var_ref
|
16
|
+
interesting_nodes :var_ref, :vcall
|
17
17
|
interesting_files PARTIAL_VIEW_FILES
|
18
18
|
|
19
19
|
def url
|
@@ -27,6 +27,14 @@ module RailsBestPractices
|
|
27
27
|
add_error "replace instance variable with local variable"
|
28
28
|
end
|
29
29
|
end
|
30
|
+
|
31
|
+
# check ivar node in partial view file,
|
32
|
+
# it is an instance variable, and should be replaced with local variable.
|
33
|
+
def start_vcall(node)
|
34
|
+
if node.to_s.start_with?('@')
|
35
|
+
add_error "replace instance variable with local variable"
|
36
|
+
end
|
37
|
+
end
|
30
38
|
end
|
31
39
|
end
|
32
40
|
end
|
@@ -86,10 +86,10 @@ module RailsBestPractices
|
|
86
86
|
if hash_key_exist?(option_node,"controller")
|
87
87
|
name = option_node.hash_value("controller").to_s
|
88
88
|
else
|
89
|
-
name = node.arguments.all.first.to_s.
|
89
|
+
name = node.arguments.all.first.to_s.gsub("::", "").tableize
|
90
90
|
end
|
91
91
|
else
|
92
|
-
name = node.arguments.all.first.to_s.
|
92
|
+
name = node.arguments.all.first.to_s.gsub("::", "").tableize
|
93
93
|
end
|
94
94
|
namespaced_class_name(name)
|
95
95
|
end
|
@@ -34,7 +34,7 @@ module RailsBestPractices
|
|
34
34
|
@first_sentences = {}
|
35
35
|
|
36
36
|
node.body.statements.each do |statement_node|
|
37
|
-
break if :var_ref
|
37
|
+
break if [:var_ref, :vcall].include?(statement_node.sexp_type) && ["protected", "private"].include?(statement_node.to_s)
|
38
38
|
remember_first_sentence(statement_node) if :def == statement_node.sexp_type
|
39
39
|
end
|
40
40
|
@first_sentences.each do |first_sentence, def_nodes|
|
data/rails_best_practices.yml
CHANGED
data/rake_rubies.sh
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
#!/bin/bash
|
2
|
-
rubies=( 1.9.2-
|
2
|
+
rubies=( 1.9.2-p290 1.9.3-p125 )
|
3
3
|
gemset="rails_best_practices"
|
4
4
|
|
5
5
|
for x in ${rubies[*]}
|
6
6
|
do
|
7
7
|
echo $x@$gemset
|
8
|
-
rvm $x@$gemset do bundle exec rake spec
|
8
|
+
rvm $x@$gemset do bundle exec rake spec
|
9
9
|
done
|
@@ -48,13 +48,19 @@ describe Sexp do
|
|
48
48
|
it "should get the call nodes with subject current_user" do
|
49
49
|
nodes = []
|
50
50
|
@node.grep_nodes(:sexp_type => :call, :subject => "current_user") { |node| nodes << node }
|
51
|
-
nodes.should == [s(:call, s(:
|
51
|
+
nodes.should == [s(:call, s(:vcall, s(:@ident, "current_user", s(2, 8))), :".", s(:@ident, "posts", s(2, 21)))]
|
52
52
|
end
|
53
53
|
|
54
54
|
it "should get the call nodes with different messages" do
|
55
55
|
nodes = []
|
56
56
|
@node.grep_nodes(:sexp_type => :call, :message => ["posts", "find"]) { |node| nodes << node }
|
57
|
-
nodes.should == [s(:call, s(:call, s(:
|
57
|
+
nodes.should == [s(:call, s(:call, s(:vcall, s(:@ident, "current_user", s(2, 8))), :".", s(:@ident, "posts", s(2, 21))), :".", s(:@ident, "find", s(2, 27))), s(:call, s(:vcall, s(:@ident, "current_user", s(2, 8))), :".", s(:@ident, "posts", s(2, 21)))]
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should get the vcall node with to_s" do
|
61
|
+
nodes = []
|
62
|
+
@node.grep_nodes(:sexp_type => :vcall, :to_s => "current_user") { |node| nodes << node }
|
63
|
+
nodes.should == [s(:vcall, s(:@ident, "current_user", s(2, 8)))]
|
58
64
|
end
|
59
65
|
end
|
60
66
|
|
@@ -70,7 +76,7 @@ describe Sexp do
|
|
70
76
|
|
71
77
|
it "should get first node with empty argument" do
|
72
78
|
node = @node.grep_node(:sexp_type => :call, :subject => "current_user")
|
73
|
-
node.should == s(:call, s(:
|
79
|
+
node.should == s(:call, s(:vcall, s(:@ident, "current_user", s(2, 8))), :".", s(:@ident, "posts", s(2, 21)))
|
74
80
|
end
|
75
81
|
end
|
76
82
|
|
@@ -221,7 +227,7 @@ describe Sexp do
|
|
221
227
|
node.arguments.sexp_type.should == :args_add_block
|
222
228
|
end
|
223
229
|
|
224
|
-
it "should get the arguments of
|
230
|
+
it "should get the arguments of method_add_arg" do
|
225
231
|
node = parse_content("User.find(:all)").grep_node(:sexp_type => :method_add_arg)
|
226
232
|
node.arguments.sexp_type.should == :args_add_block
|
227
233
|
end
|
@@ -245,6 +251,11 @@ describe Sexp do
|
|
245
251
|
node.all.map(&:to_s).should == ["hello", "world"]
|
246
252
|
end
|
247
253
|
|
254
|
+
it "should get all arguments with &:" do
|
255
|
+
node = parse_content("user.posts.map(&:title)").grep_node(:sexp_type => :args_add_block)
|
256
|
+
node.all.map(&:to_s).should == ["title"]
|
257
|
+
end
|
258
|
+
|
248
259
|
it "no error for args_add_star" do
|
249
260
|
node = parse_content("send(:\"\#{route}_url\", *args)").grep_node(:sexp_type => :args_add_block)
|
250
261
|
lambda { node.all }.should_not raise_error
|
@@ -505,11 +505,23 @@ describe RailsBestPractices::Prepares::RoutePrepare do
|
|
505
505
|
scope "/admin" do
|
506
506
|
resources :comments, :only => [:index]
|
507
507
|
end
|
508
|
+
scope "/:username", controller: :users do
|
509
|
+
get '/' => :show
|
510
|
+
scope 'topic' do
|
511
|
+
get 'preview', :as => 'preview_user', :action => 'preview'
|
512
|
+
end
|
513
|
+
end
|
508
514
|
end
|
509
515
|
EOF
|
510
516
|
runner.prepare('config/routes.rb', content)
|
511
517
|
routes = RailsBestPractices::Prepares.routes
|
512
|
-
routes.map(&:to_s).should == [
|
518
|
+
routes.map(&:to_s).should == [
|
519
|
+
"Admin::PostsController#index",
|
520
|
+
"Admin::DiscussionsController#index",
|
521
|
+
"CommentsController#index",
|
522
|
+
"UsersController#show",
|
523
|
+
"UsersController#preview"
|
524
|
+
]
|
513
525
|
end
|
514
526
|
end
|
515
527
|
|
@@ -531,7 +543,7 @@ describe RailsBestPractices::Prepares::RoutePrepare do
|
|
531
543
|
|
532
544
|
it "should add routes for another get/post" do
|
533
545
|
content =<<-EOF
|
534
|
-
RailsBestPracticesCom::Application.routes.draw
|
546
|
+
RailsBestPracticesCom::Application.routes.draw
|
535
547
|
get "/login", to: 'sessions#new', as: :login
|
536
548
|
end
|
537
549
|
EOF
|
@@ -622,5 +634,16 @@ describe RailsBestPractices::Prepares::RoutePrepare do
|
|
622
634
|
routes = RailsBestPractices::Prepares.routes
|
623
635
|
routes.last.to_s.should == "SprintsController#stop"
|
624
636
|
end
|
637
|
+
|
638
|
+
it "should not parse wrong route" do
|
639
|
+
content =<<-EOF
|
640
|
+
RailsBestPracticesCom::Application.routes.draw do
|
641
|
+
match ':controller/:action' => '#index', :as => :auto_complete
|
642
|
+
end
|
643
|
+
EOF
|
644
|
+
runner.prepare('config/routes.rb', content)
|
645
|
+
routes = RailsBestPractices::Prepares.routes
|
646
|
+
routes.size.should == 0
|
647
|
+
end
|
625
648
|
end
|
626
649
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RailsBestPractices::Reviews::ProtectMassAssignmentReview do
|
4
|
+
let(:runner) { RailsBestPractices::Core::Runner.new(:reviews => RailsBestPractices::Reviews::ProtectMassAssignmentReview.new) }
|
5
|
+
|
6
|
+
it "should protect mass assignment" do
|
7
|
+
content =<<-EOF
|
8
|
+
class User < ActiveRecord::Base
|
9
|
+
end
|
10
|
+
EOF
|
11
|
+
runner.review('app/models/user.rb', content)
|
12
|
+
runner.should have(1).errors
|
13
|
+
runner.errors[0].to_s.should == "app/models/user.rb:1 - protect mass assignment"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should not protect mass assignment with attr_accessible" do
|
17
|
+
content =<<-EOF
|
18
|
+
class User < ActiveRecord::Base
|
19
|
+
attr_accessible :email, :password, :password_confirmation
|
20
|
+
end
|
21
|
+
EOF
|
22
|
+
runner.review('app/models/user.rb', content)
|
23
|
+
runner.should have(0).errors
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should not protect mass assignment with attr_protected" do
|
27
|
+
content =<<-EOF
|
28
|
+
class User < ActiveRecord::Base
|
29
|
+
attr_protected :role
|
30
|
+
end
|
31
|
+
EOF
|
32
|
+
runner.review('app/models/user.rb', content)
|
33
|
+
runner.should have(0).errors
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should not protect mass assignment if using devise" do
|
37
|
+
content =<<-EOF
|
38
|
+
class User < ActiveRecord::Base
|
39
|
+
devise :database_authenticatable, :registerable, :confirmable, :recoverable, :stretches => 20
|
40
|
+
end
|
41
|
+
EOF
|
42
|
+
runner.review('app/models/user.rb', content)
|
43
|
+
runner.should have(0).errors
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should not protect mass assignment if using authlogic with configuration" do
|
47
|
+
content =<<-EOF
|
48
|
+
class User < ActiveRecord::Base
|
49
|
+
acts_as_authentic do |c|
|
50
|
+
c.my_config_option = my_value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
EOF
|
54
|
+
runner.review('app/models/user.rb', content)
|
55
|
+
runner.should have(0).errors
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should not protect mass assignment if using authlogic without configuration" do
|
59
|
+
content =<<-EOF
|
60
|
+
class User < ActiveRecord::Base
|
61
|
+
acts_as_authentic
|
62
|
+
end
|
63
|
+
EOF
|
64
|
+
runner.review('app/models/user.rb', content)
|
65
|
+
runner.should have(0).errors
|
66
|
+
end
|
67
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_best_practices
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.9.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-03-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sexp_processor
|
16
|
-
requirement: &
|
16
|
+
requirement: &70152469216300 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70152469216300
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: progressbar
|
27
|
-
requirement: &
|
27
|
+
requirement: &70152469214420 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70152469214420
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: colored
|
38
|
-
requirement: &
|
38
|
+
requirement: &70152469213480 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70152469213480
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: erubis
|
49
|
-
requirement: &
|
49
|
+
requirement: &70152469212320 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70152469212320
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: i18n
|
60
|
-
requirement: &
|
60
|
+
requirement: &70152469211160 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70152469211160
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: activesupport
|
71
|
-
requirement: &
|
71
|
+
requirement: &70152469209960 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70152469209960
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: rake
|
82
|
-
requirement: &
|
82
|
+
requirement: &70152469209140 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70152469209140
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: rspec
|
93
|
-
requirement: &
|
93
|
+
requirement: &70152469208480 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70152469208480
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: haml
|
104
|
-
requirement: &
|
104
|
+
requirement: &70152469207680 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
@@ -109,10 +109,10 @@ dependencies:
|
|
109
109
|
version: '0'
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *70152469207680
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: slim
|
115
|
-
requirement: &
|
115
|
+
requirement: &70152469206760 !ruby/object:Gem::Requirement
|
116
116
|
none: false
|
117
117
|
requirements:
|
118
118
|
- - ! '>='
|
@@ -120,10 +120,10 @@ dependencies:
|
|
120
120
|
version: '0'
|
121
121
|
type: :development
|
122
122
|
prerelease: false
|
123
|
-
version_requirements: *
|
123
|
+
version_requirements: *70152469206760
|
124
124
|
- !ruby/object:Gem::Dependency
|
125
125
|
name: bundler
|
126
|
-
requirement: &
|
126
|
+
requirement: &70152469205560 !ruby/object:Gem::Requirement
|
127
127
|
none: false
|
128
128
|
requirements:
|
129
129
|
- - ! '>='
|
@@ -131,7 +131,7 @@ dependencies:
|
|
131
131
|
version: '0'
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
|
-
version_requirements: *
|
134
|
+
version_requirements: *70152469205560
|
135
135
|
description: a code metric tool for rails codes, written in Ruby.
|
136
136
|
email:
|
137
137
|
- flyerhzm@gmail.com
|
@@ -179,7 +179,6 @@ files:
|
|
179
179
|
- lib/rails_best_practices/core_ext/enumerable.rb
|
180
180
|
- lib/rails_best_practices/core_ext/erubis.rb
|
181
181
|
- lib/rails_best_practices/core_ext/sexp.rb
|
182
|
-
- lib/rails_best_practices/core_ext/string.rb
|
183
182
|
- lib/rails_best_practices/lexicals.rb
|
184
183
|
- lib/rails_best_practices/lexicals/remove_tab_check.rb
|
185
184
|
- lib/rails_best_practices/lexicals/remove_trailing_whitespace_check.rb
|
@@ -206,6 +205,7 @@ files:
|
|
206
205
|
- lib/rails_best_practices/reviews/not_use_default_route_review.rb
|
207
206
|
- lib/rails_best_practices/reviews/not_use_time_ago_in_words_review.rb
|
208
207
|
- lib/rails_best_practices/reviews/overuse_route_customizations_review.rb
|
208
|
+
- lib/rails_best_practices/reviews/protect_mass_assignment_review.rb
|
209
209
|
- lib/rails_best_practices/reviews/remove_empty_helpers_review.rb
|
210
210
|
- lib/rails_best_practices/reviews/remove_unused_methods_in_controllers_review.rb
|
211
211
|
- lib/rails_best_practices/reviews/remove_unused_methods_in_helpers_review.rb
|
@@ -270,6 +270,7 @@ files:
|
|
270
270
|
- spec/rails_best_practices/reviews/not_use_default_route_review_spec.rb
|
271
271
|
- spec/rails_best_practices/reviews/not_use_times_ago_in_words_review_spec.rb
|
272
272
|
- spec/rails_best_practices/reviews/overuse_route_customizations_review_spec.rb
|
273
|
+
- spec/rails_best_practices/reviews/protect_mass_assignment_review_spec.rb
|
273
274
|
- spec/rails_best_practices/reviews/remove_empty_helpers_review_spec.rb
|
274
275
|
- spec/rails_best_practices/reviews/remove_unused_methods_in_controllers_review_spec.rb
|
275
276
|
- spec/rails_best_practices/reviews/remove_unused_methods_in_helpers_review_spec.rb
|
@@ -292,7 +293,7 @@ licenses: []
|
|
292
293
|
post_install_message: ! "********************************************************************************\n\n
|
293
294
|
\ rails_best_practices is a code metric tool to check the quality of rails codes.\n\n
|
294
295
|
\ I highly recommend you browse the Rails Best Practices website first.\n\n http://rails-bestpractices.com\n\n
|
295
|
-
\ Please also try our online service\n\n
|
296
|
+
\ Please also try our online service\n\n http://railsbp.com\n\n Enjoy!\n\n
|
296
297
|
\ Richard Huang (flyerhzm@gmail.com)\n\n********************************************************************************\n"
|
297
298
|
rdoc_options: []
|
298
299
|
require_paths:
|
@@ -306,7 +307,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
306
307
|
version: '0'
|
307
308
|
segments:
|
308
309
|
- 0
|
309
|
-
hash:
|
310
|
+
hash: -964066537248826324
|
310
311
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
311
312
|
none: false
|
312
313
|
requirements:
|
@@ -315,7 +316,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
315
316
|
version: 1.3.6
|
316
317
|
requirements: []
|
317
318
|
rubyforge_project:
|
318
|
-
rubygems_version: 1.8.
|
319
|
+
rubygems_version: 1.8.17
|
319
320
|
signing_key:
|
320
321
|
specification_version: 3
|
321
322
|
summary: a code metric tool for rails codes.
|
@@ -363,6 +364,7 @@ test_files:
|
|
363
364
|
- spec/rails_best_practices/reviews/not_use_default_route_review_spec.rb
|
364
365
|
- spec/rails_best_practices/reviews/not_use_times_ago_in_words_review_spec.rb
|
365
366
|
- spec/rails_best_practices/reviews/overuse_route_customizations_review_spec.rb
|
367
|
+
- spec/rails_best_practices/reviews/protect_mass_assignment_review_spec.rb
|
366
368
|
- spec/rails_best_practices/reviews/remove_empty_helpers_review_spec.rb
|
367
369
|
- spec/rails_best_practices/reviews/remove_unused_methods_in_controllers_review_spec.rb
|
368
370
|
- spec/rails_best_practices/reviews/remove_unused_methods_in_helpers_review_spec.rb
|