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.
- data/.rvmrc +1 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +10 -2
- data/README.md +33 -27
- data/lib/rails_best_practices/analyzer.rb +13 -13
- data/lib/rails_best_practices/core/check.rb +7 -6
- data/lib/rails_best_practices/core/checking_visitor.rb +1 -1
- data/lib/rails_best_practices/core/runner.rb +2 -3
- data/lib/rails_best_practices/core_ext/sexp.rb +18 -17
- data/lib/rails_best_practices/lexicals.rb +1 -0
- data/lib/rails_best_practices/lexicals/long_line_check.rb +31 -0
- data/lib/rails_best_practices/prepares/config_prepare.rb +1 -1
- data/lib/rails_best_practices/reviews.rb +2 -0
- data/lib/rails_best_practices/reviews/add_model_virtual_attribute_review.rb +2 -2
- data/lib/rails_best_practices/reviews/always_add_db_index_review.rb +1 -1
- data/lib/rails_best_practices/reviews/hash_syntax_review.rb +63 -0
- data/lib/rails_best_practices/reviews/keep_finders_on_their_own_model_review.rb +1 -1
- data/lib/rails_best_practices/reviews/move_code_into_model_review.rb +1 -1
- data/lib/rails_best_practices/reviews/move_finder_to_named_scope_review.rb +1 -1
- data/lib/rails_best_practices/reviews/move_model_logic_into_model_review.rb +1 -1
- data/lib/rails_best_practices/reviews/needless_deep_nesting_review.rb +1 -1
- data/lib/rails_best_practices/reviews/overuse_route_customizations_review.rb +1 -1
- data/lib/rails_best_practices/reviews/protect_mass_assignment_review.rb +15 -6
- data/lib/rails_best_practices/reviews/remove_unused_methods_in_models_review.rb +4 -2
- data/lib/rails_best_practices/reviews/replace_complex_creation_with_factory_method_review.rb +8 -4
- data/lib/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review.rb +2 -1
- data/lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb +52 -8
- data/lib/rails_best_practices/reviews/simplify_render_in_views_review.rb +14 -2
- data/lib/rails_best_practices/reviews/use_before_filter_review.rb +8 -3
- data/lib/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review.rb +2 -1
- data/lib/rails_best_practices/reviews/use_observer_review.rb +1 -1
- data/lib/rails_best_practices/reviews/use_parentheses_in_method_def_review.rb +33 -0
- data/lib/rails_best_practices/reviews/use_query_attribute_review.rb +16 -6
- data/lib/rails_best_practices/reviews/use_say_with_time_in_migrations_review.rb +9 -6
- data/lib/rails_best_practices/reviews/use_scope_access_review.rb +8 -3
- data/lib/rails_best_practices/version.rb +1 -1
- data/rails_best_practices.yml +28 -25
- data/rake_rubies.sh +1 -1
- data/spec/rails_best_practices/analyzer_spec.rb +1 -1
- data/spec/rails_best_practices/core/check_spec.rb +7 -7
- data/spec/rails_best_practices/core/checking_visitor_spec.rb +7 -7
- data/spec/rails_best_practices/core/error_spec.rb +12 -12
- data/spec/rails_best_practices/core_ext/sexp_spec.rb +103 -85
- data/spec/rails_best_practices/lexicals/long_line_check_spec.rb +47 -0
- data/spec/rails_best_practices/lexicals/remove_tab_check_spec.rb +1 -1
- data/spec/rails_best_practices/lexicals/remove_trailing_whitespace_check_spec.rb +1 -1
- data/spec/rails_best_practices/prepares/config_prepare_spec.rb +1 -1
- data/spec/rails_best_practices/prepares/controller_prepare_spec.rb +1 -1
- data/spec/rails_best_practices/prepares/helper_prepare_spec.rb +1 -1
- data/spec/rails_best_practices/prepares/mailer_prepare_spec.rb +1 -1
- data/spec/rails_best_practices/prepares/model_prepare_spec.rb +4 -4
- data/spec/rails_best_practices/prepares/route_prepare_spec.rb +54 -54
- data/spec/rails_best_practices/prepares/schema_prepare_spec.rb +6 -6
- data/spec/rails_best_practices/reviews/add_model_virtual_attribute_review_spec.rb +4 -4
- data/spec/rails_best_practices/reviews/always_add_db_index_review_spec.rb +46 -46
- data/spec/rails_best_practices/reviews/dry_bundler_in_capistrano_review_spec.rb +3 -3
- data/spec/rails_best_practices/reviews/hash_syntax_review_spec.rb +67 -0
- data/spec/rails_best_practices/reviews/isolate_seed_data_review_spec.rb +8 -8
- data/spec/rails_best_practices/reviews/keep_finders_on_their_own_model_review_spec.rb +9 -9
- data/spec/rails_best_practices/reviews/law_of_demeter_review_spec.rb +7 -7
- data/spec/rails_best_practices/reviews/move_code_into_controller_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/move_code_into_helper_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/move_code_into_model_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/move_finder_to_named_scope_review_spec.rb +13 -13
- data/spec/rails_best_practices/reviews/move_model_logic_into_model_review_spec.rb +2 -2
- data/spec/rails_best_practices/reviews/needless_deep_nesting_review_spec.rb +3 -3
- data/spec/rails_best_practices/reviews/not_use_default_route_review_spec.rb +3 -3
- data/spec/rails_best_practices/reviews/not_use_times_ago_in_words_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/overuse_route_customizations_review_spec.rb +26 -26
- data/spec/rails_best_practices/reviews/protect_mass_assignment_review_spec.rb +11 -2
- data/spec/rails_best_practices/reviews/remove_empty_helpers_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/remove_unused_methods_in_controllers_review_spec.rb +8 -8
- data/spec/rails_best_practices/reviews/remove_unused_methods_in_helpers_review_spec.rb +2 -2
- data/spec/rails_best_practices/reviews/remove_unused_methods_in_models_review_spec.rb +25 -10
- data/spec/rails_best_practices/reviews/replace_complex_creation_with_factory_method_review_spec.rb +3 -3
- data/spec/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/restrict_auto_generated_routes_review_spec.rb +28 -28
- data/spec/rails_best_practices/reviews/simplify_render_in_controllers_review_spec.rb +4 -4
- data/spec/rails_best_practices/reviews/simplify_render_in_views_review_spec.rb +15 -7
- data/spec/rails_best_practices/reviews/use_before_filter_review_spec.rb +3 -3
- data/spec/rails_best_practices/reviews/use_model_association_review_spec.rb +3 -3
- data/spec/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review_spec.rb +3 -3
- data/spec/rails_best_practices/reviews/use_observer_review_spec.rb +5 -5
- data/spec/rails_best_practices/reviews/use_parenthesis_in_method_def_spec.rb +41 -0
- data/spec/rails_best_practices/reviews/use_query_attribute_review_spec.rb +3 -3
- data/spec/rails_best_practices/reviews/use_say_with_time_in_migrations_review_spec.rb +8 -8
- data/spec/rails_best_practices/reviews/use_scope_access_review_spec.rb +9 -9
- data/spec/spec_helper.rb +1 -1
- metadata +36 -29
- data/.rspec.example +0 -2
- 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(:
|
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(:
|
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(:
|
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(:
|
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(:
|
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(:
|
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) &&
|
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(:
|
40
|
-
node.grep_node(:
|
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(:
|
45
|
+
node.grep_node(sexp_type: :command, message: "devise").present?
|
45
46
|
end
|
46
47
|
|
47
48
|
def authlogic?(node)
|
48
|
-
node.grep_node(:
|
49
|
-
node.grep_node(:
|
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
|
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
|
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
|
data/lib/rails_best_practices/reviews/replace_complex_creation_with_factory_method_review.rb
CHANGED
@@ -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
|
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
|
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
|
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
|
-
|
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
|
data/lib/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review.rb
CHANGED
@@ -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
|
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
|
-
|
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
|
-
|
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
|
-
|
67
|
-
|
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
|
-
|
78
|
-
|
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"
|
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"
|
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
|
-
|
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
|
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
|
-
|
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(',')}",
|
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
|
data/lib/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review.rb
CHANGED
@@ -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
|
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(:
|
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
|
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}?)",
|
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
|
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]) ||
|
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(:
|
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 &&
|
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
|