rails_best_practices 0.6.6 → 0.6.7
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +0 -1
- data/README.md +28 -24
- data/Rakefile +0 -8
- data/install_supported_rubies.sh +2 -3
- data/lib/rails_best_practices.rb +8 -7
- data/lib/rails_best_practices/core.rb +1 -0
- data/lib/rails_best_practices/core/check.rb +68 -0
- data/lib/rails_best_practices/core/checking_visitor.rb +18 -15
- data/lib/rails_best_practices/core/runner.rb +22 -12
- data/lib/rails_best_practices/core/visitable_sexp.rb +6 -2
- data/lib/rails_best_practices/prepares.rb +11 -0
- data/lib/rails_best_practices/prepares/mailer_prepare.rb +33 -0
- data/lib/rails_best_practices/prepares/model_prepare.rb +60 -0
- data/lib/rails_best_practices/reviews.rb +23 -0
- data/lib/rails_best_practices/{checks/add_model_virtual_attribute_check.rb → reviews/add_model_virtual_attribute_review.rb} +6 -9
- data/lib/rails_best_practices/{checks/always_add_db_index_check.rb → reviews/always_add_db_index_review.rb} +9 -12
- data/lib/rails_best_practices/{checks/dry_bundler_in_capistrano_check.rb → reviews/dry_bundler_in_capistrano_review.rb} +8 -11
- data/lib/rails_best_practices/{checks/isolate_seed_data_check.rb → reviews/isolate_seed_data_review.rb} +11 -14
- data/lib/rails_best_practices/{checks/keep_finders_on_their_own_model_check.rb → reviews/keep_finders_on_their_own_model_review.rb} +7 -10
- data/lib/rails_best_practices/{checks/law_of_demeter_check.rb → reviews/law_of_demeter_review.rb} +10 -14
- data/lib/rails_best_practices/{checks/move_code_into_controller_check.rb → reviews/move_code_into_controller_review.rb} +8 -11
- data/lib/rails_best_practices/{checks/move_code_into_helper_check.rb → reviews/move_code_into_helper_review.rb} +7 -10
- data/lib/rails_best_practices/{checks/move_code_into_model_check.rb → reviews/move_code_into_model_review.rb} +7 -10
- data/lib/rails_best_practices/{checks/move_finder_to_named_scope_check.rb → reviews/move_finder_to_named_scope_review.rb} +7 -10
- data/lib/rails_best_practices/{checks/move_model_logic_into_model_check.rb → reviews/move_model_logic_into_model_review.rb} +8 -11
- data/lib/rails_best_practices/{checks/needless_deep_nesting_check.rb → reviews/needless_deep_nesting_review.rb} +8 -11
- data/lib/rails_best_practices/{checks/not_use_default_route_check.rb → reviews/not_use_default_route_review.rb} +7 -10
- data/lib/rails_best_practices/{checks/overuse_route_customizations_check.rb → reviews/overuse_route_customizations_review.rb} +10 -13
- data/lib/rails_best_practices/{checks/replace_complex_creation_with_factory_method_check.rb → reviews/replace_complex_creation_with_factory_method_review.rb} +8 -11
- data/lib/rails_best_practices/{checks/replace_instance_variable_with_local_variable_check.rb → reviews/replace_instance_variable_with_local_variable_review.rb} +7 -10
- data/lib/rails_best_practices/reviews/review.rb +92 -0
- data/lib/rails_best_practices/{checks/use_before_filter_check.rb → reviews/use_before_filter_review.rb} +8 -11
- data/lib/rails_best_practices/{checks/use_model_association_check.rb → reviews/use_model_association_review.rb} +8 -11
- data/lib/rails_best_practices/{checks/use_observer_check.rb → reviews/use_observer_review.rb} +14 -41
- data/lib/rails_best_practices/{checks/use_query_attribute_check.rb → reviews/use_query_attribute_review.rb} +20 -16
- data/lib/rails_best_practices/{checks/use_say_with_time_in_migrations_check.rb → reviews/use_say_with_time_in_migrations_review.rb} +8 -11
- data/lib/rails_best_practices/{checks/use_scope_access_check.rb → reviews/use_scope_access_review.rb} +8 -11
- data/lib/rails_best_practices/version.rb +1 -1
- data/rails_best_practices.gemspec +3 -2
- data/rails_best_practices.yml +22 -22
- data/rake_rubies.sh +3 -2
- data/spec/rails_best_practices/core/check_spec.rb +41 -0
- data/spec/rails_best_practices/core/checking_visitor_spec.rb +78 -0
- data/spec/rails_best_practices/core/visitable_sexp_spec.rb +39 -36
- data/spec/rails_best_practices/prepares/mailer_prepare_spec.rb +14 -0
- data/spec/rails_best_practices/prepares/model_prepare_spec.rb +22 -0
- data/spec/rails_best_practices/{checks/add_model_virtual_attribute_check_spec.rb → reviews/add_model_virtual_attribute_review_spec.rb} +17 -25
- data/spec/rails_best_practices/{checks/always_add_db_index_check_spec.rb → reviews/always_add_db_index_review_spec.rb} +28 -41
- data/spec/rails_best_practices/{checks/dry_bundler_in_capistrano_check_spec.rb → reviews/dry_bundler_in_capistrano_review_spec.rb} +7 -11
- data/spec/rails_best_practices/{checks/isolate_seed_data_check_spec.rb → reviews/isolate_seed_data_review_spec.rb} +13 -20
- data/spec/rails_best_practices/{checks/keep_finders_on_their_own_model_check_spec.rb → reviews/keep_finders_on_their_own_model_review_spec.rb} +16 -24
- data/spec/rails_best_practices/{checks/law_of_demeter_check_spec.rb → reviews/law_of_demeter_review_spec.rb} +24 -26
- data/spec/rails_best_practices/reviews/move_code_into_controller_review_spec.rb +29 -0
- data/spec/rails_best_practices/reviews/move_code_into_helper_review_spec.rb +24 -0
- data/spec/rails_best_practices/{checks/move_code_into_model_check_spec.rb → reviews/move_code_into_model_review_spec.rb} +12 -18
- data/spec/rails_best_practices/{checks/move_finder_to_named_scope_check_spec.rb → reviews/move_finder_to_named_scope_review_spec.rb} +12 -16
- data/spec/rails_best_practices/{checks/move_model_logic_into_model_check_spec.rb → reviews/move_model_logic_into_model_review_spec.rb} +7 -11
- data/spec/rails_best_practices/{checks/needless_deep_nesting_check_spec.rb → reviews/needless_deep_nesting_review_spec.rb} +26 -37
- data/spec/rails_best_practices/{checks/not_use_default_route_check_spec.rb → reviews/not_use_default_route_review_spec.rb} +13 -19
- data/spec/rails_best_practices/{checks/overuse_route_customizations_check_spec.rb → reviews/overuse_route_customizations_review_spec.rb} +27 -39
- data/spec/rails_best_practices/{checks/replace_complex_creation_with_factory_method_check_spec.rb → reviews/replace_complex_creation_with_factory_method_review_spec.rb} +10 -15
- data/spec/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review_spec.rb +31 -0
- data/spec/rails_best_practices/reviews/review_spec.rb +11 -0
- data/spec/rails_best_practices/{checks/use_before_filter_check_spec.rb → reviews/use_before_filter_review_spec.rb} +11 -17
- data/spec/rails_best_practices/{checks/use_model_association_check_spec.rb → reviews/use_model_association_review_spec.rb} +12 -18
- data/spec/rails_best_practices/{checks/use_observer_check_spec.rb → reviews/use_observer_review_spec.rb} +28 -29
- data/spec/rails_best_practices/reviews/use_query_attribute_review_spec.rb +190 -0
- data/spec/rails_best_practices/{checks/use_say_with_time_in_migrations_check_spec.rb → reviews/use_say_with_time_in_migrations_review_spec.rb} +14 -23
- data/spec/rails_best_practices/{checks/use_scope_access_check_spec.rb → reviews/use_scope_access_review_spec.rb} +28 -37
- data/spec/rails_best_practices_spec.rb +4 -4
- data/spec/spec_helper.rb +1 -0
- metadata +128 -102
- data/lib/rails_best_practices/checks.rb +0 -23
- data/lib/rails_best_practices/checks/check.rb +0 -203
- data/spec/rails_best_practices/checks/check_spec.rb +0 -57
- data/spec/rails_best_practices/checks/move_code_into_controller_check_spec.rb +0 -33
- data/spec/rails_best_practices/checks/move_code_into_helper_check_spec.rb +0 -28
- data/spec/rails_best_practices/checks/replace_instance_variable_with_local_variable_check_spec.rb +0 -36
- data/spec/rails_best_practices/checks/use_query_attribute_check_spec.rb +0 -192
@@ -1,31 +1,28 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require 'rails_best_practices/
|
2
|
+
require 'rails_best_practices/reviews/review'
|
3
3
|
|
4
4
|
module RailsBestPractices
|
5
|
-
module
|
6
|
-
#
|
5
|
+
module Reviews
|
6
|
+
# Review a view file to make sure there is no complex logic call for model.
|
7
7
|
#
|
8
8
|
# See the best practice details here http://rails-bestpractices.com/posts/25-move-code-into-model.
|
9
9
|
#
|
10
10
|
# Implementation:
|
11
11
|
#
|
12
|
-
# Prepare process:
|
13
|
-
# none
|
14
|
-
#
|
15
12
|
# Review process:
|
16
13
|
# check if there are multiple method calls or attribute assignments apply to one subject,
|
17
14
|
# and the subject is a local variable or instance variable,
|
18
15
|
# then they should be moved into model.
|
19
|
-
class
|
16
|
+
class MoveCodeIntoModelReview < Review
|
20
17
|
def url
|
21
18
|
"http://rails-bestpractices.com/posts/25-move-code-into-model"
|
22
19
|
end
|
23
20
|
|
24
|
-
def
|
21
|
+
def interesting_nodes
|
25
22
|
[:if]
|
26
23
|
end
|
27
24
|
|
28
|
-
def
|
25
|
+
def interesting_files
|
29
26
|
VIEW_FILES
|
30
27
|
end
|
31
28
|
|
@@ -41,7 +38,7 @@ module RailsBestPractices
|
|
41
38
|
# if there are multiple call and attrasgn nodes who have the same subject,
|
42
39
|
# and the subject is a local variable or an instance variable,
|
43
40
|
# then the conditional statement nodes should be moved into model.
|
44
|
-
def
|
41
|
+
def start_if(node)
|
45
42
|
node.conditional_statement.grep_nodes(:node_type => [:call, :attrasgn]) { |child_node| remember_variable_use_count(child_node) }
|
46
43
|
|
47
44
|
variable_use_count.each do |variable_node, count|
|
@@ -1,23 +1,20 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require 'rails_best_practices/
|
2
|
+
require 'rails_best_practices/reviews/review'
|
3
3
|
|
4
4
|
module RailsBestPractices
|
5
|
-
module
|
6
|
-
#
|
5
|
+
module Reviews
|
6
|
+
# Review a controller file to make sure there are no complex finder.
|
7
7
|
#
|
8
8
|
# See the best practice details here http://rails-bestpractices.com/posts/1-move-finder-to-named_scope.
|
9
9
|
#
|
10
10
|
# Implementation:
|
11
11
|
#
|
12
|
-
# Prepare process:
|
13
|
-
# none
|
14
|
-
#
|
15
12
|
# Review process:
|
16
13
|
# check all method calls in controller files.
|
17
14
|
# if there is any call node with message find, all, first or last,
|
18
15
|
# and it has a hash argument,
|
19
16
|
# then it is a complex finder, and should be moved to model's named scope.
|
20
|
-
class
|
17
|
+
class MoveFinderToNamedScopeReview < Review
|
21
18
|
|
22
19
|
FINDER = [:find, :all, :first, :last]
|
23
20
|
|
@@ -25,18 +22,18 @@ module RailsBestPractices
|
|
25
22
|
"http://rails-bestpractices.com/posts/1-move-finder-to-named_scope"
|
26
23
|
end
|
27
24
|
|
28
|
-
def
|
25
|
+
def interesting_nodes
|
29
26
|
[:call]
|
30
27
|
end
|
31
28
|
|
32
|
-
def
|
29
|
+
def interesting_files
|
33
30
|
CONTROLLER_FILES
|
34
31
|
end
|
35
32
|
|
36
33
|
# check call node if its message is one of :find, :all, :first or :last,
|
37
34
|
# and it has a hash argument,
|
38
35
|
# then the call node is the finder that should be moved to model's named_scope.
|
39
|
-
def
|
36
|
+
def start_call(node)
|
40
37
|
add_error "move finder to named_scope" if finder?(node)
|
41
38
|
end
|
42
39
|
|
@@ -1,32 +1,29 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require 'rails_best_practices/
|
2
|
+
require 'rails_best_practices/reviews/review'
|
3
3
|
|
4
4
|
module RailsBestPractices
|
5
|
-
module
|
6
|
-
#
|
5
|
+
module Reviews
|
6
|
+
# Review a controller file to make sure that complex model logic should not exist in controller, should be moved into a model.
|
7
7
|
#
|
8
8
|
# See the best practice details here http://rails-bestpractices.com/posts/7-move-model-logic-into-the-model.
|
9
9
|
#
|
10
10
|
# Implementation:
|
11
11
|
#
|
12
|
-
# Prepare process:
|
13
|
-
# none
|
14
|
-
#
|
15
12
|
# Review process:
|
16
13
|
# check all method defines in the controller files,
|
17
14
|
# if there are multiple method calls or attribute assignments apply to one subject,
|
18
15
|
# and the subject is a local variable or an instance variable,
|
19
16
|
# then they are complex model logic, and they should be moved into model.
|
20
|
-
class
|
17
|
+
class MoveModelLogicIntoModelReview < Review
|
21
18
|
def url
|
22
19
|
"http://rails-bestpractices.com/posts/7-move-model-logic-into-the-model"
|
23
20
|
end
|
24
21
|
|
25
|
-
def
|
22
|
+
def interesting_nodes
|
26
23
|
[:defn]
|
27
24
|
end
|
28
25
|
|
29
|
-
def
|
26
|
+
def interesting_files
|
30
27
|
CONTROLLER_FILES
|
31
28
|
end
|
32
29
|
|
@@ -35,13 +32,13 @@ module RailsBestPractices
|
|
35
32
|
@use_count = options['use_count'] || 4
|
36
33
|
end
|
37
34
|
|
38
|
-
# check method define node to see if there are multiple method calls and attribute assignments (more than @use_count defined) on one local variable or instance varialbe
|
35
|
+
# check method define node to see if there are multiple method calls and attribute assignments (more than @use_count defined) on one local variable or instance varialbe.
|
39
36
|
#
|
40
37
|
# it will check every call and attrasgn nodes,
|
41
38
|
# if there are multiple call and attrasgn nodes who have the same subject,
|
42
39
|
# and the subject is a local variable or an instance variable,
|
43
40
|
# then these method calls and attribute assignments should be moved into model.
|
44
|
-
def
|
41
|
+
def start_defn(node)
|
45
42
|
node.grep_nodes(:node_type => [:call, :attrasgn]) do |child_node|
|
46
43
|
remember_variable_use_count(child_node)
|
47
44
|
end
|
@@ -1,17 +1,14 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require 'rails_best_practices/
|
2
|
+
require 'rails_best_practices/reviews/review'
|
3
3
|
|
4
4
|
module RailsBestPractices
|
5
|
-
module
|
6
|
-
#
|
5
|
+
module Reviews
|
6
|
+
# Review config/routes.rb file to make sure not to use too deep nesting routes.
|
7
7
|
#
|
8
8
|
# See the best practice details here http://rails-bestpractices.com/posts/11-needless-deep-nesting.
|
9
9
|
#
|
10
10
|
# Implementation:
|
11
11
|
#
|
12
|
-
# Prepare process:
|
13
|
-
# none
|
14
|
-
#
|
15
12
|
# Review process:
|
16
13
|
# chech all iter nodes in route file.
|
17
14
|
#
|
@@ -29,16 +26,16 @@ module RailsBestPractices
|
|
29
26
|
# and the message of the node is :resources or :resource,
|
30
27
|
# and the @counter is greater than @nested_count defined,
|
31
28
|
# then it is a needless deep nesting.
|
32
|
-
class
|
29
|
+
class NeedlessDeepNestingReview < Review
|
33
30
|
def url
|
34
31
|
"http://rails-bestpractices.com/posts/11-needless-deep-nesting"
|
35
32
|
end
|
36
33
|
|
37
|
-
def
|
34
|
+
def interesting_nodes
|
38
35
|
[:call, :iter]
|
39
36
|
end
|
40
37
|
|
41
|
-
def
|
38
|
+
def interesting_files
|
42
39
|
ROUTE_FILE
|
43
40
|
end
|
44
41
|
|
@@ -48,7 +45,7 @@ module RailsBestPractices
|
|
48
45
|
@nested_count = options['nested_count'] || 2
|
49
46
|
end
|
50
47
|
|
51
|
-
# check all iter node
|
48
|
+
# check all iter node.
|
52
49
|
#
|
53
50
|
# It is a recursively check,
|
54
51
|
#
|
@@ -76,7 +73,7 @@ module RailsBestPractices
|
|
76
73
|
#
|
77
74
|
# test if the @counter is greater than or equal to @nested_count,
|
78
75
|
# if so, it is a needless deep nesting.
|
79
|
-
def
|
76
|
+
def start_iter(node)
|
80
77
|
recursively_check(node)
|
81
78
|
end
|
82
79
|
|
@@ -1,17 +1,14 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require 'rails_best_practices/
|
2
|
+
require 'rails_best_practices/reviews/review'
|
3
3
|
|
4
4
|
module RailsBestPractices
|
5
|
-
module
|
6
|
-
#
|
5
|
+
module Reviews
|
6
|
+
# Review config/routes file to make sure not use default route that rails generated.
|
7
7
|
#
|
8
8
|
# See the best practice details here http://rails-bestpractices.com/posts/12-not-use-default-route-if-you-use-restful-design
|
9
9
|
#
|
10
10
|
# Implementation:
|
11
11
|
#
|
12
|
-
# Prepare process:
|
13
|
-
# none
|
14
|
-
#
|
15
12
|
# Review process:
|
16
13
|
# check all method call to see if any method call is the same as rails default route.
|
17
14
|
#
|
@@ -21,16 +18,16 @@ module RailsBestPractices
|
|
21
18
|
# or
|
22
19
|
#
|
23
20
|
# match ':controller(/:action(/:id(.:format)))'
|
24
|
-
class
|
21
|
+
class NotUseDefaultRouteReview < Review
|
25
22
|
def url
|
26
23
|
"http://rails-bestpractices.com/posts/12-not-use-default-route-if-you-use-restful-design"
|
27
24
|
end
|
28
25
|
|
29
|
-
def
|
26
|
+
def interesting_nodes
|
30
27
|
[:call]
|
31
28
|
end
|
32
29
|
|
33
|
-
def
|
30
|
+
def interesting_files
|
34
31
|
ROUTE_FILE
|
35
32
|
end
|
36
33
|
|
@@ -50,7 +47,7 @@ module RailsBestPractices
|
|
50
47
|
# s(:call, nil, :match,
|
51
48
|
# s(:arglist, s(:str, ":controller(/:action(/:id(.:format)))"))
|
52
49
|
# )
|
53
|
-
def
|
50
|
+
def start_call(node)
|
54
51
|
if s(:call, s(:lvar, :map), :connect, s(:arglist, s(:str, ":controller/:action/:id"))) == node ||
|
55
52
|
s(:call, s(:lvar, :map), :connect, s(:arglist, s(:str, ":controller/:action/:id.:format"))) == node ||
|
56
53
|
s(:call, nil, :match, s(:arglist, s(:str, ":controller(/:action(/:id(.:format)))"))) == node
|
@@ -1,17 +1,14 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require 'rails_best_practices/
|
2
|
+
require 'rails_best_practices/reviews/review'
|
3
3
|
|
4
4
|
module RailsBestPractices
|
5
|
-
module
|
6
|
-
#
|
5
|
+
module Reviews
|
6
|
+
# Review config/routes.rb file to make sure there are no overuse route customizations.
|
7
7
|
#
|
8
8
|
# See the best practice details here http://rails-bestpractices.com/posts/10-overuse-route-customizations.
|
9
9
|
#
|
10
10
|
# Implementation:
|
11
11
|
#
|
12
|
-
# Prepare process:
|
13
|
-
# none
|
14
|
-
#
|
15
12
|
# Review process:
|
16
13
|
# the check methods are different for rails2 and rails3 syntax.
|
17
14
|
#
|
@@ -30,7 +27,7 @@ module RailsBestPractices
|
|
30
27
|
# and in the block body of iter node, there are more than @customize_count call nodes,
|
31
28
|
# whose message is :get, :post, :update or :delete,
|
32
29
|
# then these custom routes are overuse.
|
33
|
-
class
|
30
|
+
class OveruseRouteCustomizationsReview < Review
|
34
31
|
|
35
32
|
VERBS = [:get, :post, :update, :delete]
|
36
33
|
|
@@ -38,11 +35,11 @@ module RailsBestPractices
|
|
38
35
|
"http://rails-bestpractices.com/posts/10-overuse-route-customizations"
|
39
36
|
end
|
40
37
|
|
41
|
-
def
|
38
|
+
def interesting_nodes
|
42
39
|
[:call, :iter]
|
43
40
|
end
|
44
41
|
|
45
|
-
def
|
42
|
+
def interesting_files
|
46
43
|
ROUTE_FILE
|
47
44
|
end
|
48
45
|
|
@@ -51,7 +48,7 @@ module RailsBestPractices
|
|
51
48
|
@customize_count = options['customize_count'] || 3
|
52
49
|
end
|
53
50
|
|
54
|
-
# check call node to see if the count of member and collection custom routes is more than @customize_count defined
|
51
|
+
# check call node to see if the count of member and collection custom routes is more than @customize_count defined.
|
55
52
|
# this is for rails2 syntax.
|
56
53
|
#
|
57
54
|
# if the message of call node is :resources,
|
@@ -64,13 +61,13 @@ module RailsBestPractices
|
|
64
61
|
# :collection => { :comments => :get }
|
65
62
|
#
|
66
63
|
# then they are overuse route customizations.
|
67
|
-
def
|
64
|
+
def start_call(node)
|
68
65
|
if member_and_collection_count_for_rails2(node) > @customize_count
|
69
66
|
add_error "overuse route customizations (customize_count > #{@customize_count})", node.file, node.subject.line
|
70
67
|
end
|
71
68
|
end
|
72
69
|
|
73
|
-
# check iter node to see if the count of member and collection custom routes is more than @customize_count defined
|
70
|
+
# check iter node to see if the count of member and collection custom routes is more than @customize_count defined.
|
74
71
|
# this is for rails3 syntax.
|
75
72
|
#
|
76
73
|
# if the subject of iter node is with message :resources,
|
@@ -90,7 +87,7 @@ module RailsBestPractices
|
|
90
87
|
# end
|
91
88
|
#
|
92
89
|
# then they are overuse route customizations.
|
93
|
-
def
|
90
|
+
def start_iter(node)
|
94
91
|
if member_and_collection_count_for_rails3(node) > @customize_count
|
95
92
|
add_error "overuse route customizations (customize_count > #{@customize_count})", node.file, node.subject.line
|
96
93
|
end
|
@@ -1,33 +1,30 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require 'rails_best_practices/
|
2
|
+
require 'rails_best_practices/reviews/review'
|
3
3
|
|
4
4
|
module RailsBestPractices
|
5
|
-
module
|
6
|
-
#
|
5
|
+
module Reviews
|
6
|
+
# Review a controller file to make sure that complex model creation should not exist in controller, should be replaced with factory method.
|
7
7
|
#
|
8
8
|
# See the best practice details here http://rails-bestpractices.com/posts/6-replace-complex-creation-with-factory-method.
|
9
9
|
#
|
10
10
|
# Implementation:
|
11
11
|
#
|
12
|
-
# Prepare process:
|
13
|
-
# none
|
14
|
-
#
|
15
12
|
# Review process:
|
16
13
|
# check all method defines in the controller files,
|
17
14
|
# if there are multiple attribute assignments apply to one subject,
|
18
15
|
# and the subject is a local variable or an instance variable,
|
19
16
|
# and after them there is a call node with message :save or :save!,
|
20
17
|
# then these attribute assignments are complex creation, should be replaced with factory method.
|
21
|
-
class
|
18
|
+
class ReplaceComplexCreationWithFactoryMethodReview < Review
|
22
19
|
def url
|
23
20
|
"http://rails-bestpractices.com/posts/6-replace-complex-creation-with-factory-method"
|
24
21
|
end
|
25
22
|
|
26
|
-
def
|
23
|
+
def interesting_nodes
|
27
24
|
[:defn]
|
28
25
|
end
|
29
26
|
|
30
|
-
def
|
27
|
+
def interesting_files
|
31
28
|
CONTROLLER_FILES
|
32
29
|
end
|
33
30
|
|
@@ -36,14 +33,14 @@ module RailsBestPractices
|
|
36
33
|
@attrasgn_count = options['attribute_assignment_count'] || 2
|
37
34
|
end
|
38
35
|
|
39
|
-
# check method define node to see if there are multiple attribute assignments, more than @attrasgn_count, on one local variable or instance variable before save
|
36
|
+
# check method define node to see if there are multiple attribute assignments, more than @attrasgn_count, on one local variable or instance variable before save.
|
40
37
|
#
|
41
38
|
# it wll check every attrasgn nodes in method define node,
|
42
39
|
# if there are multiple attrasgn nodes who have the same subject,
|
43
40
|
# and the subject is a local variable or an instance variable,
|
44
41
|
# and after them, there is a call node with message :save or :save!,
|
45
42
|
# then these attribute assignments are complex creation, should be replaced with factory method.
|
46
|
-
def
|
43
|
+
def start_defn(node)
|
47
44
|
node.recursive_children do |child_node|
|
48
45
|
case child_node.node_type
|
49
46
|
when :attrasgn
|
@@ -1,36 +1,33 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require 'rails_best_practices/
|
2
|
+
require 'rails_best_practices/reviews/review'
|
3
3
|
|
4
4
|
module RailsBestPractices
|
5
|
-
module
|
6
|
-
#
|
5
|
+
module Reviews
|
6
|
+
# Review a partail view file to make sure there is no instance variable.
|
7
7
|
#
|
8
8
|
# See the best practice details here http://rails-bestpractices.com/posts/27-replace-instance-variable-with-local-variable.
|
9
9
|
#
|
10
10
|
# Implementation:
|
11
11
|
#
|
12
|
-
# Prepare process:
|
13
|
-
# none
|
14
|
-
#
|
15
12
|
# Review process:
|
16
13
|
# check all instance variable in partial view files,
|
17
14
|
# if exist, then they should be replaced with local variable
|
18
|
-
class
|
15
|
+
class ReplaceInstanceVariableWithLocalVariableReview < Review
|
19
16
|
def url
|
20
17
|
"http://rails-bestpractices.com/posts/27-replace-instance-variable-with-local-variable"
|
21
18
|
end
|
22
19
|
|
23
|
-
def
|
20
|
+
def interesting_nodes
|
24
21
|
[:ivar]
|
25
22
|
end
|
26
23
|
|
27
|
-
def
|
24
|
+
def interesting_files
|
28
25
|
PARTIAL_VIEW_FILES
|
29
26
|
end
|
30
27
|
|
31
28
|
# check ivar node in partial view file,
|
32
29
|
# it is an instance variable, and should be replaced with local variable.
|
33
|
-
def
|
30
|
+
def start_ivar(node)
|
34
31
|
add_error "replace instance variable with local variable"
|
35
32
|
end
|
36
33
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rails_best_practices/core/check'
|
3
|
+
require 'rails_best_practices/core/error'
|
4
|
+
|
5
|
+
module RailsBestPractices
|
6
|
+
module Reviews
|
7
|
+
# A Review class that takes charge of reviewing one rails best practice.
|
8
|
+
class Review < Core::Check
|
9
|
+
attr_reader :errors
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
super
|
13
|
+
@errors = []
|
14
|
+
end
|
15
|
+
|
16
|
+
# add error if source code violates rails best practice.
|
17
|
+
# error is the string message for violation of the rails best practice
|
18
|
+
# file is the filename of source code
|
19
|
+
# line is the line number of the source code which is reviewing
|
20
|
+
def add_error(error, file = @node.file, line = @node.line)
|
21
|
+
@errors << RailsBestPractices::Core::Error.new("#{file}", "#{line}", error, url)
|
22
|
+
end
|
23
|
+
|
24
|
+
# remember use count for the local or instance variable in the call or attrasgn node.
|
25
|
+
#
|
26
|
+
# find the local variable or instance variable in the call or attrasgn node,
|
27
|
+
# then save it to as key in @variable_use_count hash, and add the call count (hash value).
|
28
|
+
def remember_variable_use_count(node)
|
29
|
+
variable_node = variable(node)
|
30
|
+
if variable_node
|
31
|
+
variable_use_count[variable_node] ||= 0
|
32
|
+
variable_use_count[variable_node] += 1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# return @variable_use_count hash.
|
37
|
+
def variable_use_count
|
38
|
+
@variable_use_count ||= {}
|
39
|
+
end
|
40
|
+
|
41
|
+
# reset @variable_use_count hash.
|
42
|
+
def reset_variable_use_count
|
43
|
+
@variable_use_count = nil
|
44
|
+
end
|
45
|
+
|
46
|
+
# find local variable or instance variable in the most inner call node, e.g.
|
47
|
+
#
|
48
|
+
# if the call node is
|
49
|
+
#
|
50
|
+
# s(:call, s(:ivar, :@post), :editors, s(:arglist)),
|
51
|
+
#
|
52
|
+
# or it is
|
53
|
+
#
|
54
|
+
# s(:call,
|
55
|
+
# s(:call, s(:ivar, :@post), :editors, s(:arglist)),
|
56
|
+
# :include?,
|
57
|
+
# s(:arglist, s(:call, nil, :current_user, s(:arglist)))
|
58
|
+
# )
|
59
|
+
#
|
60
|
+
# then the variable both are s(:ivar, :@post).
|
61
|
+
#
|
62
|
+
def variable(node)
|
63
|
+
while node.subject.node_type == :call
|
64
|
+
node = node.subject
|
65
|
+
end
|
66
|
+
subject_node = node.subject
|
67
|
+
if [:ivar, :lvar].include?(subject_node.node_type) and subject_node[1] != :_erbout
|
68
|
+
subject_node
|
69
|
+
else
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# get the model associations from Prepares.
|
75
|
+
#
|
76
|
+
# @return [Hash]
|
77
|
+
def model_associations
|
78
|
+
@model_associations ||= Prepares.model_associations
|
79
|
+
end
|
80
|
+
|
81
|
+
# compare two sexp nodes' to_s.
|
82
|
+
#
|
83
|
+
# equal?(":test", :test) => true
|
84
|
+
# equai?("@test", :test) => true
|
85
|
+
def equal?(node, expected_node)
|
86
|
+
actual = node.to_s.downcase
|
87
|
+
expected = expected_node.to_s.downcase
|
88
|
+
actual == expected || actual == ':' + expected || actual == '@' + expected
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|