rails_best_practices 1.9.1 → 1.10.0

Sign up to get free protection for your applications and to get access to all the features.
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