rails_best_practices 0.10.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +20 -0
- data/assets/result.html.haml +1 -1
- data/lib/rails_best_practices.rb +5 -3
- data/lib/rails_best_practices/core.rb +1 -1
- data/lib/rails_best_practices/core/check.rb +9 -12
- data/lib/rails_best_practices/core/checking_visitor.rb +9 -6
- data/lib/rails_best_practices/core/model_associations.rb +1 -1
- data/lib/rails_best_practices/core/nil.rb +5 -1
- data/lib/rails_best_practices/core/runner.rb +5 -5
- data/lib/rails_best_practices/core_ext/sexp.rb +688 -0
- data/lib/rails_best_practices/prepares/mailer_prepare.rb +4 -5
- data/lib/rails_best_practices/prepares/model_prepare.rb +16 -26
- data/lib/rails_best_practices/prepares/schema_prepare.rb +11 -17
- data/lib/rails_best_practices/reviews/add_model_virtual_attribute_review.rb +24 -75
- data/lib/rails_best_practices/reviews/always_add_db_index_review.rb +39 -113
- data/lib/rails_best_practices/reviews/dry_bundler_in_capistrano_review.rb +6 -16
- data/lib/rails_best_practices/reviews/isolate_seed_data_review.rb +16 -32
- data/lib/rails_best_practices/reviews/keep_finders_on_their_own_model_review.rb +11 -20
- data/lib/rails_best_practices/reviews/law_of_demeter_review.rb +7 -28
- data/lib/rails_best_practices/reviews/move_code_into_controller_review.rb +16 -14
- data/lib/rails_best_practices/reviews/move_code_into_helper_review.rb +10 -28
- data/lib/rails_best_practices/reviews/move_code_into_model_review.rb +12 -11
- data/lib/rails_best_practices/reviews/move_finder_to_named_scope_review.rb +13 -24
- data/lib/rails_best_practices/reviews/move_model_logic_into_model_review.rb +9 -9
- data/lib/rails_best_practices/reviews/needless_deep_nesting_review.rb +24 -68
- data/lib/rails_best_practices/reviews/not_use_default_route_review.rb +15 -22
- data/lib/rails_best_practices/reviews/overuse_route_customizations_review.rb +31 -91
- data/lib/rails_best_practices/reviews/remove_empty_helpers_review.rb +4 -2
- data/lib/rails_best_practices/reviews/replace_complex_creation_with_factory_method_review.rb +20 -18
- data/lib/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review.rb +5 -3
- data/lib/rails_best_practices/reviews/review.rb +8 -37
- data/lib/rails_best_practices/reviews/simplify_render_in_controllers_review.rb +10 -6
- data/lib/rails_best_practices/reviews/simplify_render_in_views_review.rb +9 -6
- data/lib/rails_best_practices/reviews/use_before_filter_review.rb +14 -72
- data/lib/rails_best_practices/reviews/use_model_association_review.rb +19 -31
- data/lib/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review.rb +5 -5
- data/lib/rails_best_practices/reviews/use_observer_review.rb +22 -40
- data/lib/rails_best_practices/reviews/use_query_attribute_review.rb +34 -39
- data/lib/rails_best_practices/reviews/use_say_with_time_in_migrations_review.rb +14 -38
- data/lib/rails_best_practices/reviews/use_scope_access_review.rb +13 -44
- data/lib/rails_best_practices/version.rb +1 -1
- data/spec/rails_best_practices/core/check_spec.rb +5 -5
- data/spec/rails_best_practices/core/checking_visitor_spec.rb +4 -4
- data/spec/rails_best_practices/core/model_associations_spec.rb +4 -4
- data/spec/rails_best_practices/core/nil_spec.rb +7 -1
- data/spec/rails_best_practices/core_ext/sexp_spec.rb +430 -0
- data/spec/rails_best_practices/prepares/model_prepare_spec.rb +12 -12
- data/spec/rails_best_practices/prepares/schema_prepare_spec.rb +6 -6
- data/spec/rails_best_practices/reviews/move_code_into_controller_review_spec.rb +14 -2
- data/spec/rails_best_practices/reviews/move_code_into_helper_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/needless_deep_nesting_review_spec.rb +3 -3
- data/spec/rails_best_practices/reviews/not_use_default_route_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/overuse_route_customizations_review_spec.rb +15 -1
- data/spec/rails_best_practices/reviews/simplify_render_in_controllers_review_spec.rb +3 -3
- data/spec/rails_best_practices/reviews/use_query_attribute_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/use_say_with_time_in_migrations_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/use_scope_access_review_spec.rb +4 -4
- data/spec/rails_best_practices_spec.rb +1 -3
- data/spec/spec_helper.rb +4 -0
- metadata +6 -8
- data/lib/rails_best_practices/core/visitable_sexp.rb +0 -444
- data/spec/rails_best_practices/core/visitable_sexp_spec.rb +0 -272
- data/spec/rails_best_practices/reviews/review_spec.rb +0 -11
@@ -11,8 +11,8 @@ module RailsBestPractices
|
|
11
11
|
#
|
12
12
|
# Review process:
|
13
13
|
# check all method defines in the controller files,
|
14
|
-
# if there are multiple method calls
|
15
|
-
# and the subject is a
|
14
|
+
# if there are multiple method calls apply to one subject,
|
15
|
+
# and the subject is a variable,
|
16
16
|
# then they are complex model logic, and they should be moved into model.
|
17
17
|
class MoveModelLogicIntoModelReview < Review
|
18
18
|
def url
|
@@ -20,7 +20,7 @@ module RailsBestPractices
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def interesting_nodes
|
23
|
-
[:
|
23
|
+
[:def]
|
24
24
|
end
|
25
25
|
|
26
26
|
def interesting_files
|
@@ -32,14 +32,14 @@ module RailsBestPractices
|
|
32
32
|
@use_count = options['use_count'] || 4
|
33
33
|
end
|
34
34
|
|
35
|
-
# check method define node to see if there are multiple method calls
|
35
|
+
# check method define node to see if there are multiple method calls on one varialbe.
|
36
36
|
#
|
37
|
-
# it will check every call
|
38
|
-
# if there are multiple call
|
39
|
-
# and the subject is a
|
37
|
+
# it will check every call nodes,
|
38
|
+
# if there are multiple call nodes who have the same subject,
|
39
|
+
# and the subject is a variable,
|
40
40
|
# then these method calls and attribute assignments should be moved into model.
|
41
|
-
def
|
42
|
-
node.grep_nodes(:
|
41
|
+
def start_def(node)
|
42
|
+
node.grep_nodes(:sexp_type => [:call, :assign]) do |child_node|
|
43
43
|
remember_variable_use_count(child_node)
|
44
44
|
end
|
45
45
|
|
@@ -10,20 +10,17 @@ module RailsBestPractices
|
|
10
10
|
# Implementation:
|
11
11
|
#
|
12
12
|
# Review process:
|
13
|
-
# chech all
|
13
|
+
# chech all method_add_block nodes in route file.
|
14
14
|
#
|
15
|
-
# it is a recursively check in
|
15
|
+
# it is a recursively check in method_add_block node,
|
16
16
|
#
|
17
|
-
# if it is a
|
17
|
+
# if it is a method_add_block node,
|
18
18
|
# increment @counter at the beginning of resources,
|
19
19
|
# decrement @counter at the end of resrouces,
|
20
|
-
# recursively check nodes in
|
20
|
+
# recursively check nodes in block body.
|
21
21
|
#
|
22
|
-
# if
|
23
|
-
#
|
24
|
-
#
|
25
|
-
# if it is a :call node,
|
26
|
-
# and the message of the node is :resources or :resource,
|
22
|
+
# if the child node is a command_call or command node,
|
23
|
+
# and the message of the node is "resources" or "resource",
|
27
24
|
# and the @counter is greater than @nested_count defined,
|
28
25
|
# then it is a needless deep nesting.
|
29
26
|
class NeedlessDeepNestingReview < Review
|
@@ -32,7 +29,7 @@ module RailsBestPractices
|
|
32
29
|
end
|
33
30
|
|
34
31
|
def interesting_nodes
|
35
|
-
[:
|
32
|
+
[:method_add_block]
|
36
33
|
end
|
37
34
|
|
38
35
|
def interesting_files
|
@@ -45,83 +42,42 @@ module RailsBestPractices
|
|
45
42
|
@nested_count = options['nested_count'] || 2
|
46
43
|
end
|
47
44
|
|
48
|
-
# check all
|
49
|
-
#
|
50
|
-
# It is a recursively check,
|
45
|
+
# check all method_add_block node.
|
51
46
|
#
|
52
|
-
# if it is a
|
53
|
-
#
|
54
|
-
# resources posts do
|
55
|
-
# ...
|
56
|
-
# end
|
47
|
+
# It is a recursively check, if it is a method_add_block node,
|
57
48
|
# increment @counter at the beginning of resources,
|
58
|
-
# decrement @counter at the end of
|
49
|
+
# decrement @counter at the end of method_add_block resources,
|
59
50
|
# recursively check the block body.
|
60
51
|
#
|
61
|
-
# if
|
62
|
-
#
|
63
|
-
# resources :posts do
|
64
|
-
# resources :comments
|
65
|
-
# resources :votes
|
66
|
-
# end
|
67
|
-
#
|
68
|
-
# just recursively check each child node in block node.
|
69
|
-
#
|
70
|
-
# if it is a :call node with message :resources or :resource, like
|
71
|
-
#
|
72
|
-
# resources :comments
|
73
|
-
#
|
52
|
+
# if the child node is a command_call or command node with message "resources" or "resource",
|
74
53
|
# test if the @counter is greater than or equal to @nested_count,
|
75
54
|
# if so, it is a needless deep nesting.
|
76
|
-
def
|
55
|
+
def start_method_add_block(node)
|
56
|
+
@file = node.file
|
77
57
|
recursively_check(node)
|
78
58
|
end
|
79
59
|
|
80
60
|
private
|
81
61
|
# check nested route.
|
82
62
|
#
|
83
|
-
# if the
|
84
|
-
# and the subject of the node is with message :resources or :resource, like
|
85
|
-
#
|
86
|
-
# s(:iter,
|
87
|
-
# s(:call, nil, :resources,
|
88
|
-
# s(:arglist, s(:lit, :posts))
|
89
|
-
# ),
|
90
|
-
# nil,
|
91
|
-
# s(:call, nil, :resources,
|
92
|
-
# s(:arglist, s(:lit, :comments))
|
93
|
-
# )
|
94
|
-
# )
|
95
|
-
#
|
63
|
+
# if the subject of the method_add_block is with message "resources" or "resource",
|
96
64
|
# then increment the @counter, recursively check the block body, and decrement the @counter.
|
97
65
|
#
|
98
|
-
# if the node type is
|
99
|
-
#
|
100
|
-
# s(:block,
|
101
|
-
# s(:call, nil, :resources, s(:arglist, s(:lit, :comments))),
|
102
|
-
# s(:call, nil, :resources, s(:arglist, s(:lit, :votes)))
|
103
|
-
# )
|
104
|
-
#
|
105
|
-
# then check the each child node in the block.
|
106
|
-
#
|
107
|
-
# if the node type is :call,
|
108
|
-
# and the message of node is :resources or :resource, like
|
109
|
-
#
|
110
|
-
# s(:call, nil, :resources, s(:arglist, s(:lit, :comments)))
|
111
|
-
#
|
66
|
+
# if the node type is command_call or command,
|
67
|
+
# and its message is resources or resource,
|
112
68
|
# then check if @counter is greater than or equal to @nested_count,
|
113
69
|
# if so, it is the needless deep nesting.
|
114
70
|
def recursively_check(node)
|
115
|
-
if :
|
116
|
-
|
117
|
-
return if
|
71
|
+
if [:command_call, :command].include?(node[1].sexp_type) && ["resources", "resource"].include?(node[1].message.to_s)
|
72
|
+
hash_node = node[1].arguments.grep_node(:sexp_type => :bare_assoc_hash)
|
73
|
+
return if hash_node && "true" == hash_node.hash_value("shallow").to_s
|
118
74
|
@counter += 1
|
119
|
-
|
75
|
+
node.block.statements.each do |stmt_node|
|
76
|
+
recursively_check(stmt_node)
|
77
|
+
end
|
120
78
|
@counter -= 1
|
121
|
-
elsif :
|
122
|
-
|
123
|
-
elsif :call == node.node_type && [:resources, :resource].include?(node.message)
|
124
|
-
add_error "needless deep nesting (nested_count > #{@nested_count})", node.file, node.line if @counter >= @nested_count
|
79
|
+
elsif [:command_call, :command].include?(node.sexp_type) && ["resources", "resource"].include?(node.message.to_s)
|
80
|
+
add_error "needless deep nesting (nested_count > #{@nested_count})", @file, node.line if @counter >= @nested_count
|
125
81
|
end
|
126
82
|
end
|
127
83
|
end
|
@@ -10,7 +10,7 @@ module RailsBestPractices
|
|
10
10
|
# Implementation:
|
11
11
|
#
|
12
12
|
# Review process:
|
13
|
-
# check all method
|
13
|
+
# check all method command_call or command node to see if it is the same as rails default route.
|
14
14
|
#
|
15
15
|
# map.connect ':controller/:action/:id'
|
16
16
|
# map.connect ':controller/:action/:id.:format'
|
@@ -24,33 +24,26 @@ module RailsBestPractices
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def interesting_nodes
|
27
|
-
[:
|
27
|
+
[:command_call, :command]
|
28
28
|
end
|
29
29
|
|
30
30
|
def interesting_files
|
31
31
|
ROUTE_FILE
|
32
32
|
end
|
33
33
|
|
34
|
-
# check all
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
#
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
# s(:call, nil, :match,
|
48
|
-
# s(:arglist, s(:str, ":controller(/:action(/:id(.:format)))"))
|
49
|
-
# )
|
50
|
-
def start_call(node)
|
51
|
-
if s(:call, s(:lvar, :map), :connect, s(:arglist, s(:str, ":controller/:action/:id"))) == node ||
|
52
|
-
s(:call, s(:lvar, :map), :connect, s(:arglist, s(:str, ":controller/:action/:id.:format"))) == node ||
|
53
|
-
s(:call, nil, :match, s(:arglist, s(:str, ":controller(/:action(/:id(.:format)))"))) == node
|
34
|
+
# check all command call nodes, compare with rails2 default route
|
35
|
+
def start_command_call(node)
|
36
|
+
if "map" == node.subject.to_s && "connect" == node.message.to_s &&
|
37
|
+
(":controller/:action/:id" == node.arguments.all[0].to_s ||
|
38
|
+
":controller/:action/:id.:format" == node.arguments.all[0].to_s)
|
39
|
+
add_error "not use default route"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# check all command nodes, compare with rails3 default route
|
44
|
+
def start_command(node)
|
45
|
+
if "match" == node.message.to_s &&
|
46
|
+
":controller(/:action(/:id(.:format)))" == node.arguments.all[0].to_s
|
54
47
|
add_error "not use default route"
|
55
48
|
end
|
56
49
|
end
|
@@ -14,29 +14,29 @@ module RailsBestPractices
|
|
14
14
|
#
|
15
15
|
# for rails2
|
16
16
|
#
|
17
|
-
# check all
|
18
|
-
# if the message of
|
19
|
-
# and the second argument of
|
17
|
+
# check all command_call nodes in route file.
|
18
|
+
# if the message of command_call node is resources,
|
19
|
+
# and the second argument of command_call node is a hash,
|
20
20
|
# and the count of the pair (key/value) in hash is greater than @customize_count,
|
21
21
|
# then these custom routes are overuse.
|
22
22
|
#
|
23
23
|
# for rails3
|
24
24
|
#
|
25
|
-
# check all
|
26
|
-
# if the subject of
|
27
|
-
# and in the block body of
|
28
|
-
# whose message is
|
25
|
+
# check all method_add_block nodes in route file.
|
26
|
+
# if the subject of method_add_block node is with message resources,
|
27
|
+
# and in the block body of method_add_block node, there are more than @customize_count command nodes,
|
28
|
+
# whose message is get, post, update or delete,
|
29
29
|
# then these custom routes are overuse.
|
30
30
|
class OveruseRouteCustomizationsReview < Review
|
31
31
|
|
32
|
-
VERBS =
|
32
|
+
VERBS = %w(get post update delete)
|
33
33
|
|
34
34
|
def url
|
35
35
|
"http://rails-bestpractices.com/posts/10-overuse-route-customizations"
|
36
36
|
end
|
37
37
|
|
38
38
|
def interesting_nodes
|
39
|
-
[:
|
39
|
+
[:command_call, :method_add_block]
|
40
40
|
end
|
41
41
|
|
42
42
|
def interesting_files
|
@@ -48,120 +48,60 @@ module RailsBestPractices
|
|
48
48
|
@customize_count = options['customize_count'] || 3
|
49
49
|
end
|
50
50
|
|
51
|
-
# check
|
51
|
+
# check command_call node to see if the count of member and collection custom routes is more than @customize_count defined.
|
52
52
|
# this is for rails2 syntax.
|
53
53
|
#
|
54
|
-
# if the message of call node is
|
54
|
+
# if the message of call node is "resources",
|
55
55
|
# and the second argument of call node is a hash,
|
56
|
-
# and the count of the pair (key/value) in hash is greater than @customize_count,
|
57
|
-
#
|
58
|
-
# map.resources :posts, :member => { :create_comment => :post,
|
59
|
-
# :update_comment => :update,
|
60
|
-
# :delete_comment => :delete },
|
61
|
-
# :collection => { :comments => :get }
|
62
|
-
#
|
56
|
+
# and the count of the pair (key/value) in hash is greater than @customize_count,
|
63
57
|
# then they are overuse route customizations.
|
64
|
-
def
|
58
|
+
def start_command_call(node)
|
65
59
|
if member_and_collection_count_for_rails2(node) > @customize_count
|
66
60
|
add_error "overuse route customizations (customize_count > #{@customize_count})", node.file, node.subject.line
|
67
61
|
end
|
68
62
|
end
|
69
63
|
|
70
|
-
# check
|
64
|
+
# check method_add_block node to see if the count of member and collection custom routes is more than @customize_count defined.
|
71
65
|
# this is for rails3 syntax.
|
72
66
|
#
|
73
|
-
# if the subject of
|
74
|
-
# and in the block body of
|
75
|
-
# whose message is :get, :post, :update or :delete,
|
76
|
-
#
|
77
|
-
# resources :posts do
|
78
|
-
# member do
|
79
|
-
# post :create_comment
|
80
|
-
# update :update_comment
|
81
|
-
# delete :delete_comment
|
82
|
-
# end
|
83
|
-
#
|
84
|
-
# collection do
|
85
|
-
# get :comments
|
86
|
-
# end
|
87
|
-
# end
|
88
|
-
#
|
67
|
+
# if the subject of method_add_block node is with message "resources",
|
68
|
+
# and in the block body of method_add_block node, there are more than @customize_count call nodes,
|
69
|
+
# whose message is :get, :post, :update or :delete,
|
89
70
|
# then they are overuse route customizations.
|
90
|
-
def
|
71
|
+
def start_method_add_block(node)
|
91
72
|
if member_and_collection_count_for_rails3(node) > @customize_count
|
92
|
-
add_error "overuse route customizations (customize_count > #{@customize_count})", node.file, node.
|
73
|
+
add_error "overuse route customizations (customize_count > #{@customize_count})", node.file, node.line
|
93
74
|
end
|
94
75
|
end
|
95
76
|
|
96
77
|
private
|
97
|
-
# check
|
78
|
+
# check command_call node to calculate the count of member and collection custom routes.
|
98
79
|
# this is for rails2 syntax.
|
99
80
|
#
|
100
|
-
# if the message of
|
81
|
+
# if the message of command_call node is "resources",
|
101
82
|
# and the second argument is a hash,
|
102
83
|
# then calculate the pair (key/value) count,
|
103
84
|
# it is just the count of member and collection custom routes.
|
104
|
-
#
|
105
|
-
# s(:call, s(:lvar, :map), :resources,
|
106
|
-
# s(:arglist,
|
107
|
-
# s(:lit, :posts),
|
108
|
-
# s(:hash,
|
109
|
-
# s(:lit, :member),
|
110
|
-
# s(:hash,
|
111
|
-
# s(:lit, :create_comment),
|
112
|
-
# s(:lit, :post),
|
113
|
-
# s(:lit, :update_comment),
|
114
|
-
# s(:lit, :update),
|
115
|
-
# s(:lit, :delete_comment),
|
116
|
-
# s(:lit, :delete)
|
117
|
-
# ),
|
118
|
-
# s(:lit, :collection),
|
119
|
-
# s(:hash,
|
120
|
-
# s(:lit, :comments),
|
121
|
-
# s(:lit, :get)
|
122
|
-
# )
|
123
|
-
# )
|
124
|
-
# )
|
125
|
-
# )
|
126
85
|
def member_and_collection_count_for_rails2(node)
|
127
|
-
if
|
128
|
-
hash_node = node.arguments[
|
129
|
-
if hash_node
|
130
|
-
|
86
|
+
if "resources" == node.message.to_s
|
87
|
+
hash_node = node.arguments.all[1]
|
88
|
+
if hash_node && :bare_assoc_hash == hash_node.sexp_type
|
89
|
+
member_node = hash_node.hash_value("member")
|
90
|
+
collection_node = hash_node.hash_value("collection")
|
91
|
+
return (member_node.hash_size || member_node.array_size) + (collection_node.hash_size || collection_node.array_size)
|
131
92
|
end
|
132
93
|
end
|
133
94
|
0
|
134
95
|
end
|
135
96
|
|
136
|
-
# check
|
97
|
+
# check method_add_block node to calculate the count of member and collection custom routes.
|
137
98
|
# this is for rails3 syntax.
|
138
99
|
#
|
139
|
-
# if its subject is with message
|
140
|
-
# then calculate the count of call nodes, whose message is
|
100
|
+
# if its subject is with message "resources",
|
101
|
+
# then calculate the count of call nodes, whose message is get, post, update or delete,
|
141
102
|
# it is just the count of member and collection custom routes.
|
142
|
-
#
|
143
|
-
# s(:iter,
|
144
|
-
# s(:call, nil, :resources, s(:arglist, s(:lit, :posts))),
|
145
|
-
# nil,
|
146
|
-
# s(:block,
|
147
|
-
# s(:iter,
|
148
|
-
# s(:call, nil, :member, s(:arglist)),
|
149
|
-
# nil,
|
150
|
-
# s(:block,
|
151
|
-
# s(:call, nil, :post, s(:arglist, s(:lit, :create_comment))),
|
152
|
-
# s(:call, nil, :post, s(:arglist, s(:lit, :update_comment))),
|
153
|
-
# s(:call, nil, :post, s(:arglist, s(:lit, :delete_comment)))
|
154
|
-
# )
|
155
|
-
# ),
|
156
|
-
# s(:iter,
|
157
|
-
# s(:call, nil, :collection, s(:arglist)),
|
158
|
-
# nil,
|
159
|
-
# s(:call, nil, :get, s(:arglist, s(:lit, :comments)))
|
160
|
-
# )
|
161
|
-
# )
|
162
|
-
# )
|
163
103
|
def member_and_collection_count_for_rails3(node)
|
164
|
-
|
104
|
+
"resources" == node[1].message.to_s ? node.grep_nodes_count(:sexp_type => :command, :message => VERBS) : 0
|
165
105
|
end
|
166
106
|
end
|
167
107
|
end
|
@@ -25,8 +25,10 @@ module RailsBestPractices
|
|
25
25
|
end
|
26
26
|
|
27
27
|
# check the body of module node, if it is nil, then it should be removed.
|
28
|
-
def start_module(
|
29
|
-
|
28
|
+
def start_module(node)
|
29
|
+
if s(:bodystmt, s(:stmts_add, s(:stmts_new), s(:void_stmt)), nil, nil, nil) == node.body
|
30
|
+
add_error "remove empty helpers", node.file, node.line
|
31
|
+
end
|
30
32
|
end
|
31
33
|
end
|
32
34
|
end
|
data/lib/rails_best_practices/reviews/replace_complex_creation_with_factory_method_review.rb
CHANGED
@@ -12,8 +12,8 @@ module RailsBestPractices
|
|
12
12
|
# Review process:
|
13
13
|
# check all method defines in the controller files,
|
14
14
|
# if there are multiple attribute assignments apply to one subject,
|
15
|
-
# and the subject is a
|
16
|
-
# and after them there is a call node with message
|
15
|
+
# and the subject is a variable,
|
16
|
+
# and after them there is a call node with message "save" or "save!",
|
17
17
|
# then these attribute assignments are complex creation, should be replaced with factory method.
|
18
18
|
class ReplaceComplexCreationWithFactoryMethodReview < Review
|
19
19
|
def url
|
@@ -21,7 +21,7 @@ module RailsBestPractices
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def interesting_nodes
|
24
|
-
[:
|
24
|
+
[:def]
|
25
25
|
end
|
26
26
|
|
27
27
|
def interesting_files
|
@@ -30,21 +30,23 @@ module RailsBestPractices
|
|
30
30
|
|
31
31
|
def initialize(options = {})
|
32
32
|
super()
|
33
|
-
@
|
33
|
+
@assigns_count = options['attribute_assignment_count'] || 2
|
34
34
|
end
|
35
35
|
|
36
|
-
# check method define node to see if there are multiple
|
36
|
+
# check method define node to see if there are multiple assignments, more than @assigns_count, on one variable before save.
|
37
37
|
#
|
38
38
|
# it wll check every attrasgn nodes in method define node,
|
39
|
-
# if there are multiple
|
40
|
-
# and the subject is a
|
41
|
-
# and after them, there is a call node with message
|
39
|
+
# if there are multiple assign nodes who have the same subject,
|
40
|
+
# and the subject is a variable,
|
41
|
+
# and after them, there is a call node with message "save" or "save!",
|
42
42
|
# then these attribute assignments are complex creation, should be replaced with factory method.
|
43
|
-
def
|
43
|
+
def start_def(node)
|
44
44
|
node.recursive_children do |child_node|
|
45
|
-
case child_node.
|
46
|
-
when :
|
47
|
-
|
45
|
+
case child_node.sexp_type
|
46
|
+
when :assign
|
47
|
+
if :"." == child_node.subject[2]
|
48
|
+
remember_variable_use_count(child_node)
|
49
|
+
end
|
48
50
|
when :call
|
49
51
|
check_variable_save(child_node)
|
50
52
|
else
|
@@ -54,14 +56,14 @@ module RailsBestPractices
|
|
54
56
|
end
|
55
57
|
|
56
58
|
private
|
57
|
-
# check the call node to see if it is with message
|
58
|
-
# and the count attribute assignment on the subject of the call node is greater than @
|
59
|
+
# check the call node to see if it is with message "save" or "save!",
|
60
|
+
# and the count attribute assignment on the subject of the call node is greater than @assign_count defined,
|
59
61
|
# then it is a complex creation, should be replaced with factory method.
|
60
62
|
def check_variable_save(node)
|
61
|
-
if [
|
62
|
-
variable = node.subject
|
63
|
-
if variable_use_count[variable].to_i > @
|
64
|
-
add_error "replace complex creation with factory method (#{variable} attribute_assignment_count > #{@
|
63
|
+
if ["save", "save!"].include? node.message.to_s
|
64
|
+
variable = node.subject.to_s
|
65
|
+
if variable_use_count[variable].to_i > @assigns_count
|
66
|
+
add_error "replace complex creation with factory method (#{variable} attribute_assignment_count > #{@assigns_count})"
|
65
67
|
end
|
66
68
|
end
|
67
69
|
end
|