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
@@ -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