rails_best_practices 1.9.1 → 1.10.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 (91) hide show
  1. data/.rvmrc +1 -1
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +10 -2
  4. data/README.md +33 -27
  5. data/lib/rails_best_practices/analyzer.rb +13 -13
  6. data/lib/rails_best_practices/core/check.rb +7 -6
  7. data/lib/rails_best_practices/core/checking_visitor.rb +1 -1
  8. data/lib/rails_best_practices/core/runner.rb +2 -3
  9. data/lib/rails_best_practices/core_ext/sexp.rb +18 -17
  10. data/lib/rails_best_practices/lexicals.rb +1 -0
  11. data/lib/rails_best_practices/lexicals/long_line_check.rb +31 -0
  12. data/lib/rails_best_practices/prepares/config_prepare.rb +1 -1
  13. data/lib/rails_best_practices/reviews.rb +2 -0
  14. data/lib/rails_best_practices/reviews/add_model_virtual_attribute_review.rb +2 -2
  15. data/lib/rails_best_practices/reviews/always_add_db_index_review.rb +1 -1
  16. data/lib/rails_best_practices/reviews/hash_syntax_review.rb +63 -0
  17. data/lib/rails_best_practices/reviews/keep_finders_on_their_own_model_review.rb +1 -1
  18. data/lib/rails_best_practices/reviews/move_code_into_model_review.rb +1 -1
  19. data/lib/rails_best_practices/reviews/move_finder_to_named_scope_review.rb +1 -1
  20. data/lib/rails_best_practices/reviews/move_model_logic_into_model_review.rb +1 -1
  21. data/lib/rails_best_practices/reviews/needless_deep_nesting_review.rb +1 -1
  22. data/lib/rails_best_practices/reviews/overuse_route_customizations_review.rb +1 -1
  23. data/lib/rails_best_practices/reviews/protect_mass_assignment_review.rb +15 -6
  24. data/lib/rails_best_practices/reviews/remove_unused_methods_in_models_review.rb +4 -2
  25. data/lib/rails_best_practices/reviews/replace_complex_creation_with_factory_method_review.rb +8 -4
  26. data/lib/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review.rb +2 -1
  27. data/lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb +52 -8
  28. data/lib/rails_best_practices/reviews/simplify_render_in_views_review.rb +14 -2
  29. data/lib/rails_best_practices/reviews/use_before_filter_review.rb +8 -3
  30. data/lib/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review.rb +2 -1
  31. data/lib/rails_best_practices/reviews/use_observer_review.rb +1 -1
  32. data/lib/rails_best_practices/reviews/use_parentheses_in_method_def_review.rb +33 -0
  33. data/lib/rails_best_practices/reviews/use_query_attribute_review.rb +16 -6
  34. data/lib/rails_best_practices/reviews/use_say_with_time_in_migrations_review.rb +9 -6
  35. data/lib/rails_best_practices/reviews/use_scope_access_review.rb +8 -3
  36. data/lib/rails_best_practices/version.rb +1 -1
  37. data/rails_best_practices.yml +28 -25
  38. data/rake_rubies.sh +1 -1
  39. data/spec/rails_best_practices/analyzer_spec.rb +1 -1
  40. data/spec/rails_best_practices/core/check_spec.rb +7 -7
  41. data/spec/rails_best_practices/core/checking_visitor_spec.rb +7 -7
  42. data/spec/rails_best_practices/core/error_spec.rb +12 -12
  43. data/spec/rails_best_practices/core_ext/sexp_spec.rb +103 -85
  44. data/spec/rails_best_practices/lexicals/long_line_check_spec.rb +47 -0
  45. data/spec/rails_best_practices/lexicals/remove_tab_check_spec.rb +1 -1
  46. data/spec/rails_best_practices/lexicals/remove_trailing_whitespace_check_spec.rb +1 -1
  47. data/spec/rails_best_practices/prepares/config_prepare_spec.rb +1 -1
  48. data/spec/rails_best_practices/prepares/controller_prepare_spec.rb +1 -1
  49. data/spec/rails_best_practices/prepares/helper_prepare_spec.rb +1 -1
  50. data/spec/rails_best_practices/prepares/mailer_prepare_spec.rb +1 -1
  51. data/spec/rails_best_practices/prepares/model_prepare_spec.rb +4 -4
  52. data/spec/rails_best_practices/prepares/route_prepare_spec.rb +54 -54
  53. data/spec/rails_best_practices/prepares/schema_prepare_spec.rb +6 -6
  54. data/spec/rails_best_practices/reviews/add_model_virtual_attribute_review_spec.rb +4 -4
  55. data/spec/rails_best_practices/reviews/always_add_db_index_review_spec.rb +46 -46
  56. data/spec/rails_best_practices/reviews/dry_bundler_in_capistrano_review_spec.rb +3 -3
  57. data/spec/rails_best_practices/reviews/hash_syntax_review_spec.rb +67 -0
  58. data/spec/rails_best_practices/reviews/isolate_seed_data_review_spec.rb +8 -8
  59. data/spec/rails_best_practices/reviews/keep_finders_on_their_own_model_review_spec.rb +9 -9
  60. data/spec/rails_best_practices/reviews/law_of_demeter_review_spec.rb +7 -7
  61. data/spec/rails_best_practices/reviews/move_code_into_controller_review_spec.rb +1 -1
  62. data/spec/rails_best_practices/reviews/move_code_into_helper_review_spec.rb +1 -1
  63. data/spec/rails_best_practices/reviews/move_code_into_model_review_spec.rb +1 -1
  64. data/spec/rails_best_practices/reviews/move_finder_to_named_scope_review_spec.rb +13 -13
  65. data/spec/rails_best_practices/reviews/move_model_logic_into_model_review_spec.rb +2 -2
  66. data/spec/rails_best_practices/reviews/needless_deep_nesting_review_spec.rb +3 -3
  67. data/spec/rails_best_practices/reviews/not_use_default_route_review_spec.rb +3 -3
  68. data/spec/rails_best_practices/reviews/not_use_times_ago_in_words_review_spec.rb +1 -1
  69. data/spec/rails_best_practices/reviews/overuse_route_customizations_review_spec.rb +26 -26
  70. data/spec/rails_best_practices/reviews/protect_mass_assignment_review_spec.rb +11 -2
  71. data/spec/rails_best_practices/reviews/remove_empty_helpers_review_spec.rb +1 -1
  72. data/spec/rails_best_practices/reviews/remove_unused_methods_in_controllers_review_spec.rb +8 -8
  73. data/spec/rails_best_practices/reviews/remove_unused_methods_in_helpers_review_spec.rb +2 -2
  74. data/spec/rails_best_practices/reviews/remove_unused_methods_in_models_review_spec.rb +25 -10
  75. data/spec/rails_best_practices/reviews/replace_complex_creation_with_factory_method_review_spec.rb +3 -3
  76. data/spec/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review_spec.rb +1 -1
  77. data/spec/rails_best_practices/reviews/restrict_auto_generated_routes_review_spec.rb +28 -28
  78. data/spec/rails_best_practices/reviews/simplify_render_in_controllers_review_spec.rb +4 -4
  79. data/spec/rails_best_practices/reviews/simplify_render_in_views_review_spec.rb +15 -7
  80. data/spec/rails_best_practices/reviews/use_before_filter_review_spec.rb +3 -3
  81. data/spec/rails_best_practices/reviews/use_model_association_review_spec.rb +3 -3
  82. data/spec/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review_spec.rb +3 -3
  83. data/spec/rails_best_practices/reviews/use_observer_review_spec.rb +5 -5
  84. data/spec/rails_best_practices/reviews/use_parenthesis_in_method_def_spec.rb +41 -0
  85. data/spec/rails_best_practices/reviews/use_query_attribute_review_spec.rb +3 -3
  86. data/spec/rails_best_practices/reviews/use_say_with_time_in_migrations_review_spec.rb +8 -8
  87. data/spec/rails_best_practices/reviews/use_scope_access_review_spec.rb +9 -9
  88. data/spec/spec_helper.rb +1 -1
  89. metadata +36 -29
  90. data/.rspec.example +0 -2
  91. data/.rvmrc.example +0 -2
@@ -50,7 +50,7 @@ module RailsBestPractices
50
50
  def other_finder?(node)
51
51
  FINDERS.include?(node[1].message.to_s) &&
52
52
  :call == node[1].subject.sexp_type &&
53
- node.arguments.grep_nodes_count(:sexp_type => :bare_assoc_hash) > 0
53
+ node.arguments.grep_nodes_count(sexp_type: :bare_assoc_hash) > 0
54
54
  end
55
55
  end
56
56
  end
@@ -32,7 +32,7 @@ module RailsBestPractices
32
32
  # if there are multiple call and assignment nodes who have the same subject,
33
33
  # and the subject is a variable, then the conditional statement nodes should be moved into model.
34
34
  def start_if(node)
35
- node.conditional_statement.grep_nodes(:sexp_type => :call) { |child_node| remember_variable_use_count(child_node) }
35
+ node.conditional_statement.grep_nodes(sexp_type: :call) { |child_node| remember_variable_use_count(child_node) }
36
36
 
37
37
  variable_use_count.each do |variable_node, count|
38
38
  add_error "move code into model (#{variable_node} use_count > #{@use_count})" if count > @use_count
@@ -41,7 +41,7 @@ module RailsBestPractices
41
41
  def finder?(node)
42
42
  FINDERS.include?(node[1].message.to_s) &&
43
43
  :call == node[1].sexp_type &&
44
- node.arguments.grep_nodes_count(:sexp_type => :bare_assoc_hash) > 0
44
+ node.arguments.grep_nodes_count(sexp_type: :bare_assoc_hash) > 0
45
45
  end
46
46
  end
47
47
  end
@@ -34,7 +34,7 @@ module RailsBestPractices
34
34
  # and the subject is a variable,
35
35
  # then these method calls and attribute assignments should be moved into model.
36
36
  def start_def(node)
37
- node.grep_nodes(:sexp_type => [:call, :assign]) do |child_node|
37
+ node.grep_nodes(sexp_type: [:call, :assign]) do |child_node|
38
38
  remember_variable_use_count(child_node)
39
39
  end
40
40
 
@@ -66,7 +66,7 @@ module RailsBestPractices
66
66
  def recursively_check(node)
67
67
  shallow = @shallow_nodes.include? node
68
68
  if [:command_call, :command].include?(node[1].sexp_type) && ["resources", "resource"].include?(node[1].message.to_s)
69
- hash_node = node[1].arguments.grep_node(:sexp_type => :bare_assoc_hash)
69
+ hash_node = node[1].arguments.grep_node(sexp_type: :bare_assoc_hash)
70
70
  shallow = (hash_node && "true" == hash_node.hash_value("shallow").to_s) unless shallow
71
71
  @counter += 1
72
72
  node.block.statements.each do |stmt_node|
@@ -95,7 +95,7 @@ module RailsBestPractices
95
95
  # then calculate the count of call nodes, whose message is get, post, update or delete,
96
96
  # it is just the count of member and collection custom routes.
97
97
  def member_and_collection_count_for_rails3(node)
98
- "resources" == node[1].message.to_s ? node.grep_nodes_count(:sexp_type => :command, :message => VERBS) : 0
98
+ "resources" == node[1].message.to_s ? node.grep_nodes_count(sexp_type: :command, message: VERBS) : 0
99
99
  end
100
100
  end
101
101
  end
@@ -25,7 +25,8 @@ module RailsBestPractices
25
25
  # and if not use devise or authlogic,
26
26
  # then it should add attr_accessible or attr_protected to protect mass assignment.
27
27
  def start_class(node)
28
- if !whitelist_attributes_config? && !rails_builtin?(node) && !devise?(node) && !authlogic?(node)
28
+ if !whitelist_attributes_config? && !rails_builtin?(node) && !devise?(node) &&
29
+ !authlogic?(node) && is_active_record?(node)
29
30
  add_error "protect mass assignment"
30
31
  end
31
32
  end
@@ -36,17 +37,25 @@ module RailsBestPractices
36
37
  end
37
38
 
38
39
  def rails_builtin?(node)
39
- node.grep_node(:sexp_type => [:vcall, :var_ref], :to_s => "attr_accessible").present? ||
40
- node.grep_node(:sexp_type => :command, :message => %w(attr_accessible attr_protected)).present?
40
+ node.grep_node(sexp_type: [:vcall, :var_ref], to_s: "attr_accessible").present? ||
41
+ node.grep_node(sexp_type: :command, message: %w(attr_accessible attr_protected)).present?
41
42
  end
42
43
 
43
44
  def devise?(node)
44
- node.grep_node(:sexp_type => :command, :message => "devise").present?
45
+ node.grep_node(sexp_type: :command, message: "devise").present?
45
46
  end
46
47
 
47
48
  def authlogic?(node)
48
- node.grep_node(:sexp_type => [:vcall, :var_ref], :to_s => "acts_as_authentic").present? ||
49
- node.grep_node(:sexp_type => :fcall, :message => "acts_as_authentic").present?
49
+ node.grep_node(sexp_type: [:vcall, :var_ref], to_s: "acts_as_authentic").present? ||
50
+ node.grep_node(sexp_type: :fcall, message: "acts_as_authentic").present?
51
+ end
52
+
53
+ def is_active_record?(node)
54
+ node.grep_node(sexp_type: [:const_path_ref, :@const], to_s: "ActiveRecord::Base").present?
55
+ end
56
+
57
+ def is_active_record?(node)
58
+ node.grep_node(:sexp_type => [:const_path_ref, :@const], :to_s => "ActiveRecord::Base").present?
50
59
  end
51
60
  end
52
61
  end
@@ -63,7 +63,8 @@ module RailsBestPractices
63
63
  end
64
64
  end
65
65
 
66
- # mark key method and value method for options_from_collection_for_select and option_groups_from_collection_for_select.
66
+ # mark key method and value method for options_from_collection_for_select and
67
+ # option_groups_from_collection_for_select.
67
68
  def start_method_add_arg(node)
68
69
  arguments = node.arguments.all
69
70
  case node.message.to_s
@@ -99,7 +100,8 @@ module RailsBestPractices
99
100
  human_attribute_name
100
101
  assign_attributes
101
102
  to_xml to_json to_param
102
- before_save before_create before_update before_destroy after_save after_create after_update after_destroy after_find after_initialize
103
+ before_save before_create before_update before_destroy after_save after_create
104
+ after_update after_destroy after_find after_initialize
103
105
  method_missing
104
106
  ).map { |method_name| "*\##{method_name}" }
105
107
  end
@@ -3,9 +3,11 @@ require 'rails_best_practices/reviews/review'
3
3
 
4
4
  module RailsBestPractices
5
5
  module Reviews
6
- # Review a controller file to make sure that complex model creation should not exist in controller, should be replaced with factory method.
6
+ # Review a controller file to make sure that complex model creation should not exist in
7
+ # controller, should be replaced with factory method.
7
8
  #
8
- # See the best practice details here http://rails-bestpractices.com/posts/6-replace-complex-creation-with-factory-method.
9
+ # See the best practice details here
10
+ # http://rails-bestpractices.com/posts/6-replace-complex-creation-with-factory-method.
9
11
  #
10
12
  # Implementation:
11
13
  #
@@ -28,7 +30,8 @@ module RailsBestPractices
28
30
  @assigns_count = options['attribute_assignment_count'] || 2
29
31
  end
30
32
 
31
- # check method define node to see if there are multiple assignments, more than @assigns_count, on one variable before save.
33
+ # check method define node to see if there are multiple assignments, more than
34
+ # @assigns_count, on one variable before save.
32
35
  #
33
36
  # it wll check every attrasgn nodes in method define node,
34
37
  # if there are multiple assign nodes who have the same subject,
@@ -58,7 +61,8 @@ module RailsBestPractices
58
61
  if ["save", "save!"].include? node.message.to_s
59
62
  variable = node.subject.to_s
60
63
  if variable_use_count[variable].to_i > @assigns_count
61
- add_error "replace complex creation with factory method (#{variable} attribute_assignment_count > #{@assigns_count})"
64
+ hint = "#{variable} attribute_assignment_count > #{@assigns_count}"
65
+ add_error "replace complex creation with factory method (#{hint})"
62
66
  end
63
67
  end
64
68
  end
@@ -5,7 +5,8 @@ module RailsBestPractices
5
5
  module Reviews
6
6
  # Review a partail view file to make sure there is no instance variable.
7
7
  #
8
- # See the best practice details here http://rails-bestpractices.com/posts/27-replace-instance-variable-with-local-variable.
8
+ # See the best practice details here
9
+ # http://rails-bestpractices.com/posts/27-replace-instance-variable-with-local-variable.
9
10
  #
10
11
  # Implementation:
11
12
  #
@@ -28,31 +28,57 @@ module RailsBestPractices
28
28
  def initialize
29
29
  super
30
30
  @namespaces = []
31
+ @resource_controllers = []
31
32
  end
32
33
 
33
34
  # check if the generated routes have the corresponding actions in controller for rails3 routes.
34
35
  def start_command(node)
35
36
  if "resources" == node.message.to_s
36
37
  check_resources(node)
38
+ @resource_controllers << node.arguments.all.first.to_s
37
39
  elsif "resource" == node.message.to_s
38
40
  check_resource(node)
41
+ @resource_controllers << node.arguments.all.first.to_s
42
+ end
43
+ end
44
+
45
+ def end_command(node)
46
+ if "resources" == node.message.to_s
47
+ @resource_controllers.pop
48
+ elsif "resource" == node.message.to_s
49
+ @resource_controllers.pop
39
50
  end
40
51
  end
41
52
 
42
53
  # remember the namespace.
43
54
  def start_method_add_block(node)
44
- if "namespace" == node.message.to_s
55
+ case node.message.to_s
56
+ when "namespace"
57
+ return unless check_method_add_block?(node)
45
58
  @namespaces << node.arguments.all.first.to_s
59
+ when "resources", "resource"
60
+ return unless check_method_add_block?(node)
61
+ @resource_controllers << node.arguments.all.first.to_s
62
+ else
46
63
  end
47
64
  end
48
65
 
49
66
  # end of namespace call.
50
67
  def end_method_add_block(node)
51
- if "namespace" == node.message.to_s
68
+ return unless check_method_add_block?(node)
69
+
70
+ case node.message.to_s
71
+ when "namespace"
52
72
  @namespaces.pop
73
+ when "resources", "resource"
74
+ @resource_controllers.pop
53
75
  end
54
76
  end
55
77
 
78
+ def check_method_add_block?(node)
79
+ :command == node[1].sexp_type || (:command_call == node[1].sexp_type && "map" != node.subject.to_s)
80
+ end
81
+
56
82
  # check if the generated routes have the corresponding actions in controller for rails2 routes.
57
83
  alias_method :start_command_call, :start_command
58
84
 
@@ -63,8 +89,9 @@ module RailsBestPractices
63
89
  return unless Prepares.controllers.include? controller_name
64
90
  resources_methods = resources_methods(node)
65
91
  unless resources_methods.all? { |meth| Prepares.controller_methods.has_method?(controller_name, meth) }
66
- only_methods = (resources_methods & Prepares.controller_methods.get_methods(controller_name).map(&:method_name)).map { |meth| ":#{meth}" }.join(", ")
67
- add_error "restrict auto-generated routes (:only => [#{only_methods}])"
92
+ prepared_method_names = Prepares.controller_methods.get_methods(controller_name).map(&:method_name)
93
+ only_methods = (resources_methods & prepared_method_names).map { |meth| ":#{meth}" }.join(", ")
94
+ add_error "restrict auto-generated routes #{friendly_route_name(node)} (only: [#{only_methods}])"
68
95
  end
69
96
  end
70
97
 
@@ -74,8 +101,9 @@ module RailsBestPractices
74
101
  return unless Prepares.controllers.include? controller_name
75
102
  resource_methods = resource_methods(node)
76
103
  unless resource_methods.all? { |meth| Prepares.controller_methods.has_method?(controller_name, meth) }
77
- only_methods = (resource_methods & Prepares.controller_methods.get_methods(controller_name).map(&:method_name)).map { |meth| ":#{meth}" }.join(", ")
78
- add_error "restrict auto-generated routes (:only => [#{only_methods}])"
104
+ prepared_method_names = Prepares.controller_methods.get_methods(controller_name).map(&:method_name)
105
+ only_methods = (resource_methods & prepared_method_names).map { |meth| ":#{meth}" }.join(", ")
106
+ add_error "restrict auto-generated routes #{friendly_route_name(node)} (only: [#{only_methods}])"
79
107
  end
80
108
  end
81
109
 
@@ -113,7 +141,11 @@ module RailsBestPractices
113
141
  if hash_key_exist?(option_node, "only")
114
142
  option_node.hash_value("only").to_s == "none" ? [] : Array(option_node.hash_value("only").to_object)
115
143
  elsif hash_key_exist?(option_node, "except")
116
- option_node.hash_value("except").to_s == "all" ? [] : (methods - Array(option_node.hash_value("except").to_object))
144
+ if option_node.hash_value("except").to_s == "all"
145
+ []
146
+ else
147
+ (methods - Array(option_node.hash_value("except").to_object))
148
+ end
117
149
  else
118
150
  methods
119
151
  end
@@ -131,7 +163,11 @@ module RailsBestPractices
131
163
  if hash_key_exist?(option_node, "only")
132
164
  option_node.hash_value("only").to_s == "none" ? [] : Array(option_node.hash_value("only").to_object)
133
165
  elsif hash_key_exist?(option_node, "except")
134
- option_node.hash_value("except").to_s == "all" ? [] : (methods - Array(option_node.hash_value("except").to_object))
166
+ if option_node.hash_value("except").to_s == "all"
167
+ []
168
+ else
169
+ (methods - Array(option_node.hash_value("except").to_object))
170
+ end
135
171
  else
136
172
  methods
137
173
  end
@@ -147,6 +183,14 @@ module RailsBestPractices
147
183
  def hash_key_exist?(node, key)
148
184
  node.hash_keys && node.hash_keys.include?(key)
149
185
  end
186
+
187
+ def friendly_route_name(node)
188
+ if @resource_controllers.last == node.arguments.to_s
189
+ [@namespaces.join("/"), @resource_controllers.join("/")].delete_if(&:blank?).join("/")
190
+ else
191
+ [@namespaces.join("/"), @resource_controllers.join("/"), node.arguments.to_s].delete_if(&:blank?).join("/")
192
+ end
193
+ end
150
194
  end
151
195
  end
152
196
  end
@@ -16,6 +16,8 @@ module RailsBestPractices
16
16
  interesting_nodes :command
17
17
  interesting_files VIEW_FILES
18
18
 
19
+ VALID_KEYS = %w(object collection locals)
20
+
19
21
  def url
20
22
  "http://rails-bestpractices.com/posts/61-simplify-render-in-views"
21
23
  end
@@ -27,12 +29,22 @@ module RailsBestPractices
27
29
  if "render" == node.message.to_s
28
30
  hash_node = node.arguments.all.first
29
31
  if hash_node && :bare_assoc_hash == hash_node.sexp_type &&
30
- hash_node.hash_keys.include?("partial") &&
31
- !hash_node.hash_value("partial").to_s.include?('/')
32
+ include_partial?(hash_node) && valid_hash?(hash_node)
32
33
  add_error 'simplify render in views'
33
34
  end
34
35
  end
35
36
  end
37
+
38
+ protected
39
+ def include_partial?(hash_node)
40
+ hash_node.hash_keys.include?("partial") && !hash_node.hash_value("partial").to_s.include?('/')
41
+ end
42
+
43
+ def valid_hash?(hash_node)
44
+ keys = hash_node.hash_keys
45
+ keys.delete("partial")
46
+ (keys - VALID_KEYS).empty?
47
+ end
36
48
  end
37
49
  end
38
50
  end
@@ -3,7 +3,8 @@ require 'rails_best_practices/reviews/review'
3
3
 
4
4
  module RailsBestPractices
5
5
  module Reviews
6
- # Review a controller file to make sure to use before_filter to remove duplicated first code line in different action.
6
+ # Review a controller file to make sure to use before_filter to remove duplicated first code
7
+ # line in different action.
7
8
  #
8
9
  # See the best practice detailed here http://rails-bestpractices.com/posts/22-use-before_filter.
9
10
  #
@@ -34,12 +35,16 @@ module RailsBestPractices
34
35
  @first_sentences = {}
35
36
 
36
37
  node.body.statements.each do |statement_node|
37
- break if [:var_ref, :vcall].include?(statement_node.sexp_type) && ["protected", "private"].include?(statement_node.to_s)
38
+ var_ref_or_vcall_included = [:var_ref, :vcall].include?(statement_node.sexp_type)
39
+ private_or_protected_included = ["protected", "private"].include?(statement_node.to_s)
40
+ break if var_ref_or_vcall_included && private_or_protected_included
38
41
  remember_first_sentence(statement_node) if :def == statement_node.sexp_type
39
42
  end
40
43
  @first_sentences.each do |first_sentence, def_nodes|
41
44
  if def_nodes.size > @customize_count
42
- add_error "use before_filter for #{def_nodes.map { |node| node.method_name.to_s }.join(',')}", node.file, def_nodes.map(&:line).join(',')
45
+ add_error "use before_filter for #{def_nodes.map { |node| node.method_name.to_s }.join(',')}",
46
+ node.file,
47
+ def_nodes.map(&:line).join(',')
43
48
  end
44
49
  end
45
50
  end
@@ -6,7 +6,8 @@ module RailsBestPractices
6
6
  module Reviews
7
7
  # Make sure to use multipart/alternative as content_type of email.
8
8
  #
9
- # See the best practice details here http://rails-bestpractices.com/posts/41-use-multipart-alternative-as-content_type-of-email.
9
+ # See the best practice details here
10
+ # http://rails-bestpractices.com/posts/41-use-multipart-alternative-as-content_type-of-email.
10
11
  #
11
12
  # Implementation:
12
13
  #
@@ -82,7 +82,7 @@ module RailsBestPractices
82
82
  #
83
83
  # then the call node is actionmailer deliver call.
84
84
  def deliver_mailer?(node)
85
- node.grep_nodes(:sexp_type => :call) do |child_node|
85
+ node.grep_nodes(sexp_type: :call) do |child_node|
86
86
  # rails2 actionmailer deliver
87
87
  return true if child_node.message.to_s =~ /^deliver_/ && mailers.include?(child_node.subject.to_s)
88
88
  # rails3 actionmailer deliver
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+ require 'rails_best_practices/reviews/review'
3
+
4
+ module RailsBestPractices
5
+ module Reviews
6
+ # Check if method definition has parentheses around parameters.
7
+ #
8
+ # Review process:
9
+ # check def node in all files,
10
+ # if params node with values, but not wrapped by paren node,
11
+ # then it should use parentheses around parameters.
12
+ class UseParenthesesInMethodDefReview < Review
13
+ interesting_nodes :def
14
+ interesting_files ALL_FILES
15
+
16
+ # check def node to see if parameters are wrapped by parentheses.
17
+ def start_def(node)
18
+ if no_parentheses_around_parameters?(node) && has_parameters?(node)
19
+ add_error("use parentheses around parameters in method definitions")
20
+ end
21
+ end
22
+
23
+ protected
24
+ def no_parentheses_around_parameters?(def_node)
25
+ :parent != def_node[2][0]
26
+ end
27
+
28
+ def has_parameters?(def_node)
29
+ :params == def_node[2][0] && !def_node[2][1..-1].compact.empty?
30
+ end
31
+ end
32
+ end
33
+ end
@@ -38,11 +38,17 @@ module RailsBestPractices
38
38
  #
39
39
  # then the call node can use query attribute instead.
40
40
  def start_if(node)
41
- all_conditions = node.conditional_statement == node.conditional_statement.all_conditions ? [node.conditional_statement] : node.conditional_statement.all_conditions
41
+ all_conditions = if node.conditional_statement == node.conditional_statement.all_conditions
42
+ [node.conditional_statement]
43
+ else
44
+ node.conditional_statement.all_conditions
45
+ end
42
46
  all_conditions.each do |condition_node|
43
47
  if query_attribute_node = query_attribute_node(condition_node)
44
48
  subject_node = query_attribute_node.subject
45
- add_error "use query attribute (#{subject_node.subject}.#{subject_node.message}?)", node.file, query_attribute_node.line
49
+ add_error "use query attribute (#{subject_node.subject}.#{subject_node.message}?)",
50
+ node.file,
51
+ query_attribute_node.line
46
52
  end
47
53
  end
48
54
  end
@@ -51,11 +57,13 @@ module RailsBestPractices
51
57
  alias_method :start_elsif, :start_if
52
58
 
53
59
  private
54
- # recursively check conditional statement nodes to see if there is a call node that may be possible query attribute.
60
+ # recursively check conditional statement nodes to see if there is a call node that may be
61
+ # possible query attribute.
55
62
  def query_attribute_node(conditional_statement_node)
56
63
  case conditional_statement_node.sexp_type
57
64
  when :and, :or
58
- node = query_attribute_node(conditional_statement_node[1]) || query_attribute_node(conditional_statement_node[2])
65
+ node = query_attribute_node(conditional_statement_node[1]) ||
66
+ query_attribute_node(conditional_statement_node[2])
59
67
  node.file = conditional_statement_code.file
60
68
  return node
61
69
  when :not
@@ -83,7 +91,7 @@ module RailsBestPractices
83
91
  def possible_query_attribute?(node)
84
92
  return false unless :call == node.subject.sexp_type
85
93
  variable_node = variable(node)
86
- message_node = node.grep_node(:subject => variable_node.to_s).message
94
+ message_node = node.grep_node(subject: variable_node.to_s).message
87
95
 
88
96
  is_model?(variable_node) && model_attribute?(variable_node, message_node.to_s) &&
89
97
  (QUERY_METHODS.include?(node.message.to_s) || compare_with_empty_string?(node))
@@ -106,7 +114,9 @@ module RailsBestPractices
106
114
 
107
115
  # check if the node is with node type :binary, node message :== and node argument is empty string.
108
116
  def compare_with_empty_string?(node)
109
- :binary == node.sexp_type && ["==", "!="].include?(node.message.to_s) && s(:string_literal, s(:string_content)) == node.argument
117
+ :binary == node.sexp_type &&
118
+ ["==", "!="].include?(node.message.to_s) &&
119
+ s(:string_literal, s(:string_content)) == node.argument
110
120
  end
111
121
  end
112
122
  end