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.
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
@@ -18,7 +18,7 @@ module RailsBestPractices
18
18
  end
19
19
 
20
20
  def interesting_nodes
21
- [:ivar]
21
+ [:var_ref]
22
22
  end
23
23
 
24
24
  def interesting_files
@@ -27,8 +27,10 @@ module RailsBestPractices
27
27
 
28
28
  # check ivar node in partial view file,
29
29
  # it is an instance variable, and should be replaced with local variable.
30
- def start_ivar(node)
31
- add_error "replace instance variable with local variable"
30
+ def start_var_ref(node)
31
+ if node.to_s.start_with?('@')
32
+ add_error "replace instance variable with local variable"
33
+ end
32
34
  end
33
35
  end
34
36
  end
@@ -10,15 +10,15 @@ module RailsBestPractices
10
10
  def url
11
11
  "#"
12
12
  end
13
- # remember use count for the local or instance variable in the call or attrasgn node.
13
+ # remember use count for the variable in the call or assign node.
14
14
  #
15
- # find the local variable or instance variable in the call or attrasgn node,
15
+ # find the variable in the call or assign node,
16
16
  # then save it to as key in @variable_use_count hash, and add the call count (hash value).
17
17
  def remember_variable_use_count(node)
18
18
  variable_node = variable(node)
19
19
  if variable_node
20
- variable_use_count[variable_node] ||= 0
21
- variable_use_count[variable_node] += 1
20
+ variable_use_count[variable_node.to_s] ||= 0
21
+ variable_use_count[variable_node.to_s] += 1
22
22
  end
23
23
  end
24
24
 
@@ -32,32 +32,13 @@ module RailsBestPractices
32
32
  @variable_use_count = nil
33
33
  end
34
34
 
35
- # find local variable or instance variable in the most inner call node, e.g.
36
- #
37
- # if the call node is
38
- #
39
- # s(:call, s(:ivar, :@post), :editors, s(:arglist)),
40
- #
41
- # or it is
42
- #
43
- # s(:call,
44
- # s(:call, s(:ivar, :@post), :editors, s(:arglist)),
45
- # :include?,
46
- # s(:arglist, s(:call, nil, :current_user, s(:arglist)))
47
- # )
48
- #
49
- # then the variable both are s(:ivar, :@post).
50
- #
35
+ # find variable in the call or field node.
51
36
  def variable(node)
52
- while node.subject.node_type == :call
37
+ while [:call, :field, :method_add_arg, :method_add_block].include?(node.subject.sexp_type)
53
38
  node = node.subject
54
39
  end
55
- subject_node = node.subject
56
- if [:ivar, :lvar].include?(subject_node.node_type) and subject_node[1] != :_erbout
57
- subject_node
58
- else
59
- nil
60
- end
40
+ return if [:fcall, :hash].include?(node.subject.sexp_type)
41
+ node.subject
61
42
  end
62
43
 
63
44
  # get the models from Prepares.
@@ -80,16 +61,6 @@ module RailsBestPractices
80
61
  def model_attributes
81
62
  @model_attributes ||= Prepares.model_attributes
82
63
  end
83
-
84
- # compare two sexp nodes' to_s.
85
- #
86
- # equal?(":test", :test) => true
87
- # equai?("@test", :test) => true
88
- def equal?(node, expected_node)
89
- actual = node.to_s.downcase
90
- expected = expected_node.to_s.downcase
91
- actual == expected || actual == ':' + expected || actual == '@' + expected
92
- end
93
64
  end
94
65
  end
95
66
  end
@@ -10,7 +10,7 @@ module RailsBestPractices
10
10
  # Implementation:
11
11
  #
12
12
  # Review process:
13
- # check all render method calls in controller files,
13
+ # check all render method commands in controller files,
14
14
  # if there is a key 'action', 'template' or 'file' in the argument,
15
15
  # then they should be replaced by simplified syntax.
16
16
  class SimplifyRenderInControllersReview < Review
@@ -19,19 +19,23 @@ module RailsBestPractices
19
19
  end
20
20
 
21
21
  def interesting_nodes
22
- [:call]
22
+ [:command]
23
23
  end
24
24
 
25
25
  def interesting_files
26
26
  CONTROLLER_FILES
27
27
  end
28
28
 
29
- # check call node in the controller file,
29
+ # check command node in the controller file,
30
30
  # if its message is render and the arguments contain a key action, template or file,
31
31
  # then it should be replaced by simplified syntax.
32
- def start_call(call_node)
33
- if :render == call_node.message && call_node.arguments[1].to_s =~ /"(action|template|file)" =>/
34
- add_error 'simplify render in controllers'
32
+ def start_command(node)
33
+ if "render" == node.message.to_s
34
+ keys = node.arguments.all[0].hash_keys
35
+ if keys && keys.size == 1 &&
36
+ (keys.include?("action") || keys.include?("template") || keys.include?("file"))
37
+ add_error 'simplify render in controllers'
38
+ end
35
39
  end
36
40
  end
37
41
  end
@@ -10,7 +10,7 @@ module RailsBestPractices
10
10
  # Implementation:
11
11
  #
12
12
  # Review process:
13
- # check all render method calls in view files,
13
+ # check all render method commands in view files,
14
14
  # if there is a key 'partial' in the argument, then they should be replaced by simplified syntax.
15
15
  class SimplifyRenderInViewsReview < Review
16
16
  def url
@@ -18,19 +18,22 @@ module RailsBestPractices
18
18
  end
19
19
 
20
20
  def interesting_nodes
21
- [:call]
21
+ [:command]
22
22
  end
23
23
 
24
24
  def interesting_files
25
25
  VIEW_FILES
26
26
  end
27
27
 
28
- # check call node in view file,
28
+ # check command node in view file,
29
29
  # if its message is render and the arguments contain a key partial,
30
30
  # then it should be replaced by simplified syntax.
31
- def start_call(call_node)
32
- if :render == call_node.message && call_node.arguments[1].to_s =~ /"partial" =>/
33
- add_error 'simplify render in views'
31
+ def start_command(node)
32
+ if "render" == node.message.to_s
33
+ hash_node = node.arguments.all[0]
34
+ if hash_node && hash_node.hash_keys && hash_node.hash_keys.include?("partial")
35
+ add_error 'simplify render in views'
36
+ end
34
37
  end
35
38
  end
36
39
  end
@@ -13,9 +13,6 @@ module RailsBestPractices
13
13
  # check all first code line in method definitions (actions),
14
14
  # if they are duplicated, then they should be moved to before_filter.
15
15
  class UseBeforeFilterReview < Review
16
-
17
- PROTECTED_PRIVATE_CALLS = [[:call, nil, :protected, [:arglist]], [:call, nil, :private, [:arglist]]]
18
-
19
16
  def url
20
17
  "http://rails-bestpractices.com/posts/22-use-before_filter"
21
18
  end
@@ -35,87 +32,32 @@ module RailsBestPractices
35
32
 
36
33
  # check class define node to see if there are method define nodes whose first code line are duplicated.
37
34
  #
38
- # it will check every defn nodes in the class node until protected or private identification,
39
- # if there are defn nodes who have the same first code line, like
40
- #
41
- # s(:class, :PostsController, s(:const, :ApplicationController),
42
- # s(:scope,
43
- # s(:block,
44
- # s(:defn, :show, s(:args),
45
- # s(:scope,
46
- # s(:block,
47
- # s(:iasgn, :@post,
48
- # s(:call,
49
- # s(:call, s(:call, nil, :current_user, s(:arglist)), :posts, s(:arglist)),
50
- # :find,
51
- # s(:arglist,
52
- # s(:call, s(:call, nil, :params, s(:arglist)), :[], s(:arglist, s(:lit, :id)))
53
- # )
54
- # )
55
- # )
56
- # )
57
- # )
58
- # ),
59
- # s(:defn, :edit, s(:args),
60
- # s(:scope,
61
- # s(:block,
62
- # s(:iasgn, :@post,
63
- # s(:call,
64
- # s(:call, s(:call, nil, :current_user, s(:arglist)), :posts, s(:arglist)),
65
- # :find,
66
- # s(:arglist,
67
- # s(:call, s(:call, nil, :params, s(:arglist)), :[], s(:arglist, s(:lit, :id)))
68
- # )
69
- # )
70
- # )
71
- # )
72
- # )
73
- # )
74
- # )
75
- # )
76
- # )
77
- #
35
+ # it will check every def nodes in the class node until protected or private identification,
36
+ # if there are defn nodes who have the same first code line,
78
37
  # then these duplicated first code lines should be moved to before_filter.
79
- def start_class(class_node)
38
+ def start_class(node)
80
39
  @first_sentences = {}
81
40
 
82
- class_node.body.children.each do |child_node|
83
- break if PROTECTED_PRIVATE_CALLS.include? child_node
84
- remember_first_sentence(child_node) if :defn == child_node.node_type
41
+ node.body.statements.each do |statement_node|
42
+ break if :var_ref == statement_node.sexp_type && ["protected", "private"].include?(statement_node.to_s)
43
+ remember_first_sentence(statement_node) if :def == statement_node.sexp_type
85
44
  end
86
- @first_sentences.each do |first_sentence, defn_nodes|
87
- if defn_nodes.size > @customize_count
88
- add_error "use before_filter for #{defn_nodes.collect(&:method_name).join(',')}", class_node.file, defn_nodes.collect(&:line).join(',')
45
+ @first_sentences.each do |first_sentence, def_nodes|
46
+ if def_nodes.size > @customize_count
47
+ add_error "use before_filter for #{def_nodes.map { |node| node.method_name.to_s }.join(',')}", node.file, def_nodes.map(&:line).join(',')
89
48
  end
90
49
  end
91
50
  end
92
51
 
93
52
  private
94
53
  # check method define node, and remember the first sentence.
95
- # first sentence may be :iasgn, :lasgn, :attrasgn, :call node, like
96
- #
97
- # s(:defn, :show, s(:args),
98
- # s(:scope,
99
- # s(:block,
100
- # s(:iasgn, :@post,
101
- # s(:call,
102
- # s(:call, s(:call, nil, :current_user, s(:arglist)), :posts, s(:arglist)),
103
- # :find,
104
- # s(:arglist,
105
- # s(:call, s(:call, nil, :params, s(:arglist)), :[], s(:arglist, s(:lit, :id)))
106
- # )
107
- # )
108
- # )
109
- # )
110
- # )
111
- # )
112
- #
113
- # the first sentence of defn node is :iasgn node.
114
- def remember_first_sentence(defn_node)
115
- first_sentence = defn_node.body[1]
54
+ def remember_first_sentence(node)
55
+ first_sentence = node.body.statements.first
56
+ return unless first_sentence
57
+ first_sentence = first_sentence.remove_line_and_column
116
58
  unless first_sentence == s(:nil)
117
59
  @first_sentences[first_sentence] ||= []
118
- @first_sentences[first_sentence] << defn_node
60
+ @first_sentences[first_sentence] << node
119
61
  end
120
62
  end
121
63
  end
@@ -12,7 +12,7 @@ module RailsBestPractices
12
12
  # Review process:
13
13
  # check model define nodes in all controller files,
14
14
  # if there is an attribute assignment node with message xxx_id=,
15
- # and after it, there is a call node with message :save or :save!,
15
+ # and after it, there is a call node with message "save" or "save!",
16
16
  # and the subjects of attribute assignment node and call node are the same,
17
17
  # then model association should be used instead of xxx_id assignment.
18
18
  class UseModelAssociationReview < Review
@@ -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,56 +30,44 @@ module RailsBestPractices
30
30
 
31
31
  # check method define nodes to see if there are some attribute assignments that can use model association instead.
32
32
  #
33
- # it will check attribute assignment node with message xxx_id=, and call node with message :save or :save!
33
+ # it will check attribute assignment node with message xxx_id=, and call node with message "save" or "save!"
34
34
  #
35
35
  # 1. if there is an attribute assignment node with message xxx_id=,
36
36
  # then remember the subject of attribute assignment node.
37
- # 2. after assignment, if there is a call node with message :save or :save!,
37
+ # 2. after assignment, if there is a call node with message "save" or "save!",
38
38
  # and the subject of call node is one of the subject of attribute assignment node,
39
39
  # then the attribute assignment should be replaced by using model association.
40
- def start_defn(node)
41
- @attrasgns = {}
40
+ def start_def(node)
41
+ @assignments = {}
42
42
  node.recursive_children do |child|
43
- case child.node_type
44
- when :attrasgn
43
+ case child.sexp_type
44
+ when :assign
45
45
  attribute_assignment(child)
46
46
  when :call
47
47
  call_assignment(child)
48
48
  else
49
49
  end
50
50
  end
51
- @attrasgns = nil
51
+ @assignments = nil
52
52
  end
53
53
 
54
54
  private
55
- # check an attribute assignment node, if its message is xxx_id, like
56
- #
57
- # s(:attrasgn, s(:ivar, :@post), :user_id=,
58
- # s(:arglist,
59
- # s(:call, s(:call, nil, :current_user, s(:arglist)), :id, s(:arglist))
60
- # )
61
- # )
62
- #
63
- # then remember the subject of the attribute assignment in @attrasgns.
64
- #
65
- # @attrasgns => { s(:ivar, :@post) => true }
55
+ # check an attribute assignment node, if its message is xxx_id,
56
+ # then remember the subject of the attribute assignment in @assignments.
66
57
  def attribute_assignment(node)
67
- if node.message.to_s =~ /_id=$/
68
- subject = node.subject
69
- @attrasgns[subject] = true
58
+ if node.left_value.message.to_s =~ /_id$/
59
+ subject = node.left_value.subject.to_s
60
+ @assignments[subject] = true
70
61
  end
71
62
  end
72
63
 
73
- # check a call node with message :save or :save!,
74
- # if the subject of call node exists in @attrasgns, like
75
- #
76
- # s(:call, s(:ivar, :@post), :save, s(:arglist))
77
- #
64
+ # check a call node with message "save" or "save!",
65
+ # if the subject of call node exists in @assignments,
78
66
  # then the attribute assignment should be replaced by using model association.
79
67
  def call_assignment(node)
80
- if [:save, :save!].include? node.message
81
- subject = node.subject
82
- add_error "use model association (for #{subject})" if @attrasgns[subject]
68
+ if ["save", "save!"].include? node.message.to_s
69
+ subject = node.subject.to_s
70
+ add_error "use model association (for #{subject})" if @assignments[subject]
83
71
  end
84
72
  end
85
73
  end
@@ -19,7 +19,7 @@ module RailsBestPractices
19
19
  end
20
20
 
21
21
  def interesting_nodes
22
- [:class, :defn]
22
+ [:class, :def]
23
23
  end
24
24
 
25
25
  def interesting_files
@@ -28,12 +28,12 @@ module RailsBestPractices
28
28
 
29
29
  # check class node to remember the ActionMailer class name.
30
30
  def start_class(node)
31
- @klazz_name = node.class_name
31
+ @klazz_name = node.class_name.to_s
32
32
  end
33
33
 
34
- # check defn node and find if the corresponding views exist or not?
35
- def start_defn(node)
36
- name = node.method_name
34
+ # check def node and find if the corresponding views exist or not?
35
+ def start_def(node)
36
+ name = node.method_name.to_s
37
37
  return unless deliver_method?(name)
38
38
  if rails2_canonical_mailer_views?(name) || rails3_canonical_mailer_views?(name)
39
39
  add_error("use multipart/alternative as content_type of email")
@@ -12,7 +12,7 @@ module RailsBestPractices
12
12
  # Implementation:
13
13
  #
14
14
  # Review process:
15
- # check all call nodes to see if they are callback definitions, like after_create, before_destroy,
15
+ # check all command nodes to see if they are callback definitions, like after_create, before_destroy,
16
16
  # if so, remember the callback methods.
17
17
  #
18
18
  # check all method define nodes to see
@@ -25,7 +25,7 @@ module RailsBestPractices
25
25
  end
26
26
 
27
27
  def interesting_nodes
28
- [:defn, :call]
28
+ [:def, :command]
29
29
  end
30
30
 
31
31
  def interesting_files
@@ -37,15 +37,11 @@ module RailsBestPractices
37
37
  @callbacks = []
38
38
  end
39
39
 
40
- # check a call node.
40
+ # check a command node.
41
41
  #
42
- # if it is a callback definition, like
43
- #
44
- # after_create :send_create_notification
45
- # before_destroy :send_destroy_notification
46
- #
47
- # then remember its callback methods (:send_create_notification).
48
- def start_call(node)
42
+ # if it is a callback definition,
43
+ # then remember its callback methods.
44
+ def start_command(node)
49
45
  remember_callback(node)
50
46
  end
51
47
 
@@ -54,67 +50,53 @@ module RailsBestPractices
54
50
  # if it is callback method,
55
51
  # and there is a actionmailer deliver call in the method define node,
56
52
  # then it should be replaced by using observer.
57
- def start_defn(node)
58
- if callback_method?(node) and deliver_mailer?(node)
53
+ def start_def(node)
54
+ if callback_method?(node) && deliver_mailer?(node)
59
55
  add_error "use observer"
60
56
  end
61
57
  end
62
58
 
63
59
  private
64
- # check a call node, if it is a callback definition, such as after_create, before_create, like
65
- #
66
- # s(:call, nil, :after_create,
67
- # s(:arglist, s(:lit, :send_create_notification))
68
- # )
69
- #
60
+ # check a command node, if it is a callback definition, such as after_create, before_create,
70
61
  # then save the callback methods in @callbacks
71
- #
72
- # @callbacks => [:send_create_notification]
73
62
  def remember_callback(node)
74
63
  if node.message.to_s =~ /^after_|^before_/
75
- node.arguments[1..-1].each do |argument|
64
+ node.arguments.all.each do |argument|
76
65
  # ignore callback like after_create Comment.new
77
- @callbacks << argument.to_s if :lit == argument.node_type
66
+ @callbacks << argument.to_s if :symbol_literal == argument.sexp_type
78
67
  end
79
68
  end
80
69
  end
81
70
 
82
71
  # check a defn node to see if the method name exists in the @callbacks.
83
72
  def callback_method?(node)
84
- @callbacks.find { |callback| equal?(callback, node.method_name) }
73
+ @callbacks.find { |callback| callback == node.method_name.to_s }
85
74
  end
86
75
 
87
- # check a defn node to see if it contains a actionmailer deliver call.
76
+ # check a def node to see if it contains a actionmailer deliver call.
88
77
  #
89
78
  # for rails2
90
79
  #
91
80
  # if the message of call node is deliver_xxx,
92
- # and the subject of the call node exists in @callbacks, like
93
- #
94
- # s(:call, s(:const, :ProjectMailer), :deliver_notification,
95
- # s(:arglist, s(:self), s(:lvar, :member))
96
- # )
81
+ # and the subject of the call node exists in @callbacks,
97
82
  #
98
83
  # for rails3
99
84
  #
100
85
  # if the message of call node is deliver,
101
- # and the subject of the call node is with subject node who exists in @callbacks, like
102
- #
103
- # s(:call,
104
- # s(:call, s(:const, :ProjectMailer), :notification,
105
- # s(:arglist, s(:self), s(:lvar, :member))
106
- # ),
107
- # :deliver,
108
- # s(:arglist)
109
- # )
86
+ # and the subject of the call node is with subject node who exists in @callbacks,
110
87
  #
111
88
  # then the call node is actionmailer deliver call.
112
89
  def deliver_mailer?(node)
113
- node.grep_nodes(:node_type => :call) do |child_node|
90
+ node.grep_nodes(:sexp_type => :call) do |child_node|
114
91
  # rails2 actionmailer deliver
115
92
  return true if child_node.message.to_s =~ /^deliver_/ && mailers.include?(child_node.subject.to_s)
116
93
  # rails3 actionmailer deliver
117
- return true if :deliver == child_node.message && mailers.include?(child_node.subject.subject.to_s)
94
+ if "deliver" == child_node.message.to_s
95
+ if :method_add_arg == child_node.subject.sexp_type &&
96
+ mailers.include?(child_node.subject[1].subject.to_s)
97
+ return true
98
+ end
99
+ end
118
100
  end
119
101
  false
120
102
  end