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