rails_best_practices 0.10.1 → 1.0.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/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
|