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.
Files changed (63) hide show
  1. data/README.md +20 -0
  2. data/assets/result.html.haml +1 -1
  3. data/lib/rails_best_practices.rb +5 -3
  4. data/lib/rails_best_practices/core.rb +1 -1
  5. data/lib/rails_best_practices/core/check.rb +9 -12
  6. data/lib/rails_best_practices/core/checking_visitor.rb +9 -6
  7. data/lib/rails_best_practices/core/model_associations.rb +1 -1
  8. data/lib/rails_best_practices/core/nil.rb +5 -1
  9. data/lib/rails_best_practices/core/runner.rb +5 -5
  10. data/lib/rails_best_practices/core_ext/sexp.rb +688 -0
  11. data/lib/rails_best_practices/prepares/mailer_prepare.rb +4 -5
  12. data/lib/rails_best_practices/prepares/model_prepare.rb +16 -26
  13. data/lib/rails_best_practices/prepares/schema_prepare.rb +11 -17
  14. data/lib/rails_best_practices/reviews/add_model_virtual_attribute_review.rb +24 -75
  15. data/lib/rails_best_practices/reviews/always_add_db_index_review.rb +39 -113
  16. data/lib/rails_best_practices/reviews/dry_bundler_in_capistrano_review.rb +6 -16
  17. data/lib/rails_best_practices/reviews/isolate_seed_data_review.rb +16 -32
  18. data/lib/rails_best_practices/reviews/keep_finders_on_their_own_model_review.rb +11 -20
  19. data/lib/rails_best_practices/reviews/law_of_demeter_review.rb +7 -28
  20. data/lib/rails_best_practices/reviews/move_code_into_controller_review.rb +16 -14
  21. data/lib/rails_best_practices/reviews/move_code_into_helper_review.rb +10 -28
  22. data/lib/rails_best_practices/reviews/move_code_into_model_review.rb +12 -11
  23. data/lib/rails_best_practices/reviews/move_finder_to_named_scope_review.rb +13 -24
  24. data/lib/rails_best_practices/reviews/move_model_logic_into_model_review.rb +9 -9
  25. data/lib/rails_best_practices/reviews/needless_deep_nesting_review.rb +24 -68
  26. data/lib/rails_best_practices/reviews/not_use_default_route_review.rb +15 -22
  27. data/lib/rails_best_practices/reviews/overuse_route_customizations_review.rb +31 -91
  28. data/lib/rails_best_practices/reviews/remove_empty_helpers_review.rb +4 -2
  29. data/lib/rails_best_practices/reviews/replace_complex_creation_with_factory_method_review.rb +20 -18
  30. data/lib/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review.rb +5 -3
  31. data/lib/rails_best_practices/reviews/review.rb +8 -37
  32. data/lib/rails_best_practices/reviews/simplify_render_in_controllers_review.rb +10 -6
  33. data/lib/rails_best_practices/reviews/simplify_render_in_views_review.rb +9 -6
  34. data/lib/rails_best_practices/reviews/use_before_filter_review.rb +14 -72
  35. data/lib/rails_best_practices/reviews/use_model_association_review.rb +19 -31
  36. data/lib/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review.rb +5 -5
  37. data/lib/rails_best_practices/reviews/use_observer_review.rb +22 -40
  38. data/lib/rails_best_practices/reviews/use_query_attribute_review.rb +34 -39
  39. data/lib/rails_best_practices/reviews/use_say_with_time_in_migrations_review.rb +14 -38
  40. data/lib/rails_best_practices/reviews/use_scope_access_review.rb +13 -44
  41. data/lib/rails_best_practices/version.rb +1 -1
  42. data/spec/rails_best_practices/core/check_spec.rb +5 -5
  43. data/spec/rails_best_practices/core/checking_visitor_spec.rb +4 -4
  44. data/spec/rails_best_practices/core/model_associations_spec.rb +4 -4
  45. data/spec/rails_best_practices/core/nil_spec.rb +7 -1
  46. data/spec/rails_best_practices/core_ext/sexp_spec.rb +430 -0
  47. data/spec/rails_best_practices/prepares/model_prepare_spec.rb +12 -12
  48. data/spec/rails_best_practices/prepares/schema_prepare_spec.rb +6 -6
  49. data/spec/rails_best_practices/reviews/move_code_into_controller_review_spec.rb +14 -2
  50. data/spec/rails_best_practices/reviews/move_code_into_helper_review_spec.rb +1 -1
  51. data/spec/rails_best_practices/reviews/needless_deep_nesting_review_spec.rb +3 -3
  52. data/spec/rails_best_practices/reviews/not_use_default_route_review_spec.rb +1 -1
  53. data/spec/rails_best_practices/reviews/overuse_route_customizations_review_spec.rb +15 -1
  54. data/spec/rails_best_practices/reviews/simplify_render_in_controllers_review_spec.rb +3 -3
  55. data/spec/rails_best_practices/reviews/use_query_attribute_review_spec.rb +1 -1
  56. data/spec/rails_best_practices/reviews/use_say_with_time_in_migrations_review_spec.rb +1 -1
  57. data/spec/rails_best_practices/reviews/use_scope_access_review_spec.rb +4 -4
  58. data/spec/rails_best_practices_spec.rb +1 -3
  59. data/spec/spec_helper.rb +4 -0
  60. metadata +6 -8
  61. data/lib/rails_best_practices/core/visitable_sexp.rb +0 -444
  62. data/spec/rails_best_practices/core/visitable_sexp_spec.rb +0 -272
  63. 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 or attribute assignments apply to one subject,
15
- # and the subject is a local variable or an instance variable,
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
- [:defn]
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 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 on one varialbe.
36
36
  #
37
- # it will check every call and attrasgn nodes,
38
- # if there are multiple call and attrasgn nodes who have the same subject,
39
- # and the subject is a local variable or an instance variable,
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 start_defn(node)
42
- node.grep_nodes(:node_type => [:call, :attrasgn]) do |child_node|
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 iter nodes in route file.
13
+ # chech all method_add_block nodes in route file.
14
14
  #
15
- # it is a recursively check in :iter node,
15
+ # it is a recursively check in method_add_block node,
16
16
  #
17
- # if it is a :iter node,
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 iter's block body.
20
+ # recursively check nodes in block body.
21
21
  #
22
- # if it is a :block node,
23
- # then recursively check all child nodes in block node.
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
- [:call, :iter]
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 iter node.
49
- #
50
- # It is a recursively check,
45
+ # check all method_add_block node.
51
46
  #
52
- # if it is a :iter node, like
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 iter resources,
49
+ # decrement @counter at the end of method_add_block resources,
59
50
  # recursively check the block body.
60
51
  #
61
- # if it is a :block node, like
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 start_iter(node)
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 node type is :iter,
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 :block, it is the block body of :iter node, like
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 :iter == node.node_type && :resources == node.subject.message
116
- options = eval(node.subject.arguments[2].to_s)
117
- return if options && options["shallow"] == true
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
- recursively_check(node.body)
75
+ node.block.statements.each do |stmt_node|
76
+ recursively_check(stmt_node)
77
+ end
120
78
  @counter -= 1
121
- elsif :block == node.node_type
122
- node.children.each { |child_node| recursively_check(child_node) }
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 call to see if any method call is the same as rails default route.
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
- [:call]
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 method calls, it just compare with rails default route
35
- #
36
- # rails2
37
- #
38
- # s(:call, s(:lvar, :map), :connect,
39
- # s(:arglist, s(:str, ":controller/:action/:id"))
40
- # )
41
- # s(:call, s(:lvar, :map), :connect,
42
- # s(:arglist, s(:str, ":controller/:action/:id.:format"))
43
- # )
44
- #
45
- # rails3
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 call nodes in route file.
18
- # if the message of call node is resources,
19
- # and the second argument of call node is a hash,
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 iter nodes in route file.
26
- # if the subject of iter node is with message resources,
27
- # and in the block body of iter node, there are more than @customize_count call nodes,
28
- # whose message is :get, :post, :update or :delete,
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 = [:get, :post, :update, :delete]
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
- [:call, :iter]
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 call node to see if the count of member and collection custom routes is more than @customize_count defined.
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 :resources,
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, like
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 start_call(node)
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 iter node to see if the count of member and collection custom routes is more than @customize_count defined.
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 iter node is with message :resources,
74
- # and in the block body of iter node, there are more than @customize_count call nodes,
75
- # whose message is :get, :post, :update or :delete, like
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 start_iter(node)
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.subject.line
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 call node to calculate the count of member and collection custom routes.
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 call node is :resources,
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 :resources == node.message
128
- hash_node = node.arguments[2]
129
- if hash_node
130
- return (hash_node.grep_nodes_count(:node_type => :lit) - hash_node.grep_nodes_count(:node_type => :hash)) / 2
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 iter node to calculate the count of member and collection custom routes.
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 :resources,
140
- # then calculate the count of call nodes, whose message is :get, :post, :update or :delete,
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
- :resources == node.subject.message ? node.grep_nodes_count(:node_type => :call, :message => VERBS) : 0
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(module_node)
29
- add_error "remove empty helpers" if module_node.body.is_a?(Core::Nil)
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
@@ -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 local variable or an instance variable,
16
- # and after them there is a call node with message :save or :save!,
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
- [:defn]
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
- @attrasgn_count = options['attribute_assignment_count'] || 2
33
+ @assigns_count = options['attribute_assignment_count'] || 2
34
34
  end
35
35
 
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.
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 attrasgn nodes who have the same subject,
40
- # and the subject is a local variable or an instance variable,
41
- # and after them, there is a call node with message :save or :save!,
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 start_defn(node)
43
+ def start_def(node)
44
44
  node.recursive_children do |child_node|
45
- case child_node.node_type
46
- when :attrasgn
47
- remember_variable_use_count(child_node)
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 :save or :save!,
58
- # and the count attribute assignment on the subject of the call node is greater than @attrasgn_count defined,
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 [:save, :save!].include? node.message
62
- variable = node.subject
63
- if variable_use_count[variable].to_i > @attrasgn_count
64
- add_error "replace complex creation with factory method (#{variable} attribute_assignment_count > #{@attrasgn_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