rails_best_practices 1.8.0 → 1.9.0
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.
- 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
|