rails_best_practices 1.19.3 → 1.21.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.
- checksums.yaml +5 -5
- data/.gitignore +0 -1
- data/.travis.yml +2 -3
- data/CHANGELOG.md +10 -11
- data/Gemfile +3 -5
- data/Gemfile.lock +125 -0
- data/Guardfile +2 -0
- data/README.md +5 -1
- data/Rakefile +2 -17
- data/assets/result.html.erb +2 -0
- data/lib/rails_best_practices.rb +4 -2
- data/lib/rails_best_practices/analyzer.rb +63 -51
- data/lib/rails_best_practices/cli.rb +22 -0
- data/lib/rails_best_practices/command.rb +1 -131
- data/lib/rails_best_practices/core/check.rb +63 -55
- data/lib/rails_best_practices/core/checks_loader.rb +24 -23
- data/lib/rails_best_practices/core/configs.rb +1 -2
- data/lib/rails_best_practices/core/controllers.rb +1 -2
- data/lib/rails_best_practices/core/error.rb +1 -1
- data/lib/rails_best_practices/core/helpers.rb +1 -2
- data/lib/rails_best_practices/core/mailers.rb +1 -2
- data/lib/rails_best_practices/core/methods.rb +27 -21
- data/lib/rails_best_practices/core/model_associations.rb +10 -5
- data/lib/rails_best_practices/core/models.rb +1 -2
- data/lib/rails_best_practices/core/modules.rb +1 -1
- data/lib/rails_best_practices/core/routes.rb +2 -2
- data/lib/rails_best_practices/core/runner.rb +87 -72
- data/lib/rails_best_practices/inline_disables.rb +3 -0
- data/lib/rails_best_practices/inline_disables/comment_ripper.rb +19 -0
- data/lib/rails_best_practices/inline_disables/inline_disable.rb +50 -0
- data/lib/rails_best_practices/lexicals/long_line_check.rb +7 -3
- data/lib/rails_best_practices/option_parser.rb +156 -0
- data/lib/rails_best_practices/prepares.rb +1 -1
- data/lib/rails_best_practices/prepares/controller_prepare.rb +23 -17
- data/lib/rails_best_practices/prepares/gemfile_prepare.rb +2 -2
- data/lib/rails_best_practices/prepares/helper_prepare.rb +6 -1
- data/lib/rails_best_practices/prepares/initializer_prepare.rb +3 -3
- data/lib/rails_best_practices/prepares/mailer_prepare.rb +2 -1
- data/lib/rails_best_practices/prepares/model_prepare.rb +63 -23
- data/lib/rails_best_practices/prepares/route_prepare.rb +28 -21
- data/lib/rails_best_practices/prepares/schema_prepare.rb +1 -1
- data/lib/rails_best_practices/reviews/add_model_virtual_attribute_review.rb +38 -34
- data/lib/rails_best_practices/reviews/always_add_db_index_review.rb +94 -88
- data/lib/rails_best_practices/reviews/check_destroy_return_value_review.rb +15 -5
- data/lib/rails_best_practices/reviews/check_save_return_value_review.rb +20 -8
- data/lib/rails_best_practices/reviews/default_scope_is_evil_review.rb +1 -1
- data/lib/rails_best_practices/reviews/dry_bundler_in_capistrano_review.rb +1 -1
- data/lib/rails_best_practices/reviews/hash_syntax_review.rb +16 -16
- data/lib/rails_best_practices/reviews/isolate_seed_data_review.rb +12 -12
- data/lib/rails_best_practices/reviews/keep_finders_on_their_own_model_review.rb +10 -11
- data/lib/rails_best_practices/reviews/law_of_demeter_review.rb +25 -24
- data/lib/rails_best_practices/reviews/move_code_into_controller_review.rb +4 -4
- data/lib/rails_best_practices/reviews/move_code_into_helper_review.rb +9 -10
- data/lib/rails_best_practices/reviews/move_finder_to_named_scope_review.rb +10 -11
- data/lib/rails_best_practices/reviews/needless_deep_nesting_review.rb +24 -22
- data/lib/rails_best_practices/reviews/not_rescue_exception_review.rb +1 -1
- data/lib/rails_best_practices/reviews/not_use_default_route_review.rb +1 -2
- data/lib/rails_best_practices/reviews/not_use_time_ago_in_words_review.rb +1 -1
- data/lib/rails_best_practices/reviews/overuse_route_customizations_review.rb +8 -8
- data/lib/rails_best_practices/reviews/protect_mass_assignment_review.rb +35 -32
- data/lib/rails_best_practices/reviews/remove_empty_helpers_review.rb +4 -4
- data/lib/rails_best_practices/reviews/remove_unused_methods_in_controllers_review.rb +20 -17
- data/lib/rails_best_practices/reviews/remove_unused_methods_in_helpers_review.rb +12 -10
- data/lib/rails_best_practices/reviews/remove_unused_methods_in_models_review.rb +38 -18
- data/lib/rails_best_practices/reviews/replace_complex_creation_with_factory_method_review.rb +11 -11
- data/lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb +77 -74
- data/lib/rails_best_practices/reviews/review.rb +2 -1
- data/lib/rails_best_practices/reviews/simplify_render_in_controllers_review.rb +2 -3
- data/lib/rails_best_practices/reviews/simplify_render_in_views_review.rb +12 -12
- data/lib/rails_best_practices/reviews/use_before_filter_review.rb +14 -10
- data/lib/rails_best_practices/reviews/use_model_association_review.rb +15 -15
- data/lib/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review.rb +24 -22
- data/lib/rails_best_practices/reviews/use_observer_review.rb +28 -28
- data/lib/rails_best_practices/reviews/use_parentheses_in_method_def_review.rb +6 -6
- data/lib/rails_best_practices/reviews/use_query_attribute_review.rb +63 -60
- data/lib/rails_best_practices/reviews/use_say_with_time_in_migrations_review.rb +9 -8
- data/lib/rails_best_practices/reviews/use_scope_access_review.rb +16 -14
- data/lib/rails_best_practices/reviews/use_turbo_sprockets_rails3_review.rb +2 -1
- data/lib/rails_best_practices/version.rb +1 -1
- data/rails_best_practices.gemspec +48 -49
- data/spec/fixtures/lib/rails_best_practices/plugins/reviews/not_use_rails_root_review.rb +1 -2
- data/spec/rails_best_practices/analyzer_spec.rb +73 -42
- data/spec/rails_best_practices/core/check_spec.rb +5 -5
- data/spec/rails_best_practices/core/checks_loader_spec.rb +3 -3
- data/spec/rails_best_practices/core/configs_spec.rb +1 -1
- data/spec/rails_best_practices/core/controllers_spec.rb +1 -1
- data/spec/rails_best_practices/core/error_spec.rb +21 -18
- data/spec/rails_best_practices/core/except_methods_spec.rb +7 -7
- data/spec/rails_best_practices/core/gems_spec.rb +4 -4
- data/spec/rails_best_practices/core/helpers_spec.rb +1 -1
- data/spec/rails_best_practices/core/klasses_spec.rb +3 -3
- data/spec/rails_best_practices/core/mailers_spec.rb +1 -1
- data/spec/rails_best_practices/core/methods_spec.rb +6 -6
- data/spec/rails_best_practices/core/model_associations_spec.rb +10 -6
- data/spec/rails_best_practices/core/model_attributes_spec.rb +4 -4
- data/spec/rails_best_practices/core/models_spec.rb +1 -1
- data/spec/rails_best_practices/core/modules_spec.rb +5 -5
- data/spec/rails_best_practices/core/routes_spec.rb +5 -5
- data/spec/rails_best_practices/core/runner_spec.rb +9 -7
- data/spec/rails_best_practices/core_ext/erubis_spec.rb +10 -10
- data/spec/rails_best_practices/inline_disables/inline_disable_spec.rb +62 -0
- data/spec/rails_best_practices/lexicals/long_line_check_spec.rb +32 -31
- data/spec/rails_best_practices/lexicals/remove_tab_check_spec.rb +6 -6
- data/spec/rails_best_practices/lexicals/remove_trailing_whitespace_check_spec.rb +6 -6
- data/spec/rails_best_practices/prepares/config_prepare_spec.rb +2 -2
- data/spec/rails_best_practices/prepares/controller_prepare_spec.rb +18 -10
- data/spec/rails_best_practices/prepares/gemfile_prepare_spec.rb +17 -17
- data/spec/rails_best_practices/prepares/helper_prepare_spec.rb +3 -3
- data/spec/rails_best_practices/prepares/initializer_prepare_spec.rb +3 -3
- data/spec/rails_best_practices/prepares/mailer_prepare_spec.rb +2 -2
- data/spec/rails_best_practices/prepares/model_prepare_spec.rb +79 -43
- data/spec/rails_best_practices/prepares/route_prepare_spec.rb +141 -76
- data/spec/rails_best_practices/prepares/schema_prepare_spec.rb +2 -2
- data/spec/rails_best_practices/reviews/add_model_virtual_attribute_review_spec.rb +18 -12
- data/spec/rails_best_practices/reviews/always_add_db_index_review_spec.rb +28 -22
- data/spec/rails_best_practices/reviews/check_destroy_return_value_review_spec.rb +15 -13
- data/spec/rails_best_practices/reviews/check_save_return_value_review_spec.rb +31 -21
- data/spec/rails_best_practices/reviews/default_scope_is_evil_review_spec.rb +6 -6
- data/spec/rails_best_practices/reviews/dry_bundler_in_capistrano_review_spec.rb +5 -5
- data/spec/rails_best_practices/reviews/hash_syntax_review_spec.rb +13 -13
- data/spec/rails_best_practices/reviews/isolate_seed_data_review_spec.rb +7 -7
- 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 +29 -22
- data/spec/rails_best_practices/reviews/move_code_into_controller_review_spec.rb +6 -6
- data/spec/rails_best_practices/reviews/move_code_into_helper_review_spec.rb +11 -6
- data/spec/rails_best_practices/reviews/move_code_into_model_review_spec.rb +32 -22
- data/spec/rails_best_practices/reviews/move_finder_to_named_scope_review_spec.rb +7 -7
- data/spec/rails_best_practices/reviews/move_model_logic_into_model_review_spec.rb +9 -7
- data/spec/rails_best_practices/reviews/needless_deep_nesting_review_spec.rb +9 -9
- data/spec/rails_best_practices/reviews/not_rescue_exception_review_spec.rb +9 -9
- data/spec/rails_best_practices/reviews/not_use_default_route_review_spec.rb +5 -5
- data/spec/rails_best_practices/reviews/not_use_time_ago_in_words_review_spec.rb +7 -7
- data/spec/rails_best_practices/reviews/overuse_route_customizations_review_spec.rb +7 -7
- data/spec/rails_best_practices/reviews/protect_mass_assignment_review_spec.rb +24 -17
- data/spec/rails_best_practices/reviews/remove_empty_helpers_review_spec.rb +6 -6
- data/spec/rails_best_practices/reviews/remove_unused_methods_in_controllers_review_spec.rb +47 -32
- data/spec/rails_best_practices/reviews/remove_unused_methods_in_helpers_review_spec.rb +21 -14
- data/spec/rails_best_practices/reviews/remove_unused_methods_in_models_review_spec.rb +57 -53
- data/spec/rails_best_practices/reviews/replace_complex_creation_with_factory_method_review_spec.rb +10 -8
- data/spec/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review_spec.rb +20 -14
- data/spec/rails_best_practices/reviews/restrict_auto_generated_routes_review_spec.rb +54 -31
- data/spec/rails_best_practices/reviews/simplify_render_in_controllers_review_spec.rb +9 -9
- data/spec/rails_best_practices/reviews/simplify_render_in_views_review_spec.rb +13 -13
- data/spec/rails_best_practices/reviews/use_before_filter_review_spec.rb +11 -9
- data/spec/rails_best_practices/reviews/use_model_association_review_spec.rb +7 -7
- data/spec/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review_spec.rb +35 -31
- data/spec/rails_best_practices/reviews/use_observer_review_spec.rb +6 -6
- data/spec/rails_best_practices/reviews/use_parentheses_in_method_def_review_spec.rb +10 -8
- data/spec/rails_best_practices/reviews/use_query_attribute_review_spec.rb +31 -24
- data/spec/rails_best_practices/reviews/use_say_with_time_in_migrations_review_spec.rb +15 -11
- data/spec/rails_best_practices/reviews/use_scope_access_review_spec.rb +14 -14
- data/spec/rails_best_practices/reviews/use_turbo_sprockets_rails3_review_spec.rb +61 -59
- metadata +21 -14
@@ -14,7 +14,17 @@ module RailsBestPractices
|
|
14
14
|
# Check all "save" calls to check the return value is used by a node we have visited.
|
15
15
|
class CheckSaveReturnValueReview < Review
|
16
16
|
include Classable
|
17
|
-
interesting_nodes :call,
|
17
|
+
interesting_nodes :call,
|
18
|
+
:command_call,
|
19
|
+
:method_add_arg,
|
20
|
+
:if,
|
21
|
+
:ifop,
|
22
|
+
:elsif,
|
23
|
+
:unless,
|
24
|
+
:if_mod,
|
25
|
+
:unless_mod,
|
26
|
+
:assign,
|
27
|
+
:binary
|
18
28
|
interesting_files ALL_FILES
|
19
29
|
url 'https://rails-bestpractices.com/posts/2012/11/02/check-the-return-value-of-save-otherwise-use-save/'
|
20
30
|
|
@@ -26,14 +36,13 @@ module RailsBestPractices
|
|
26
36
|
@used_return_value_of = node.right_value
|
27
37
|
end
|
28
38
|
|
39
|
+
# Consider anything used in an expression like "A or B" as used
|
29
40
|
add_callback :start_binary do |node|
|
30
|
-
# Consider anything used in an expression like "A or B" as used
|
31
41
|
if %w[&& || and or].include?(node[2].to_s)
|
32
42
|
all_conditions = node.all_conditions
|
33
43
|
# if our current binary is a subset of the @used_return_value_of
|
34
44
|
# then don't overwrite it
|
35
|
-
already_included = @used_return_value_of &&
|
36
|
-
(all_conditions - @used_return_value_of).empty?
|
45
|
+
already_included = @used_return_value_of && (all_conditions - @used_return_value_of).empty?
|
37
46
|
|
38
47
|
@used_return_value_of = node.all_conditions unless already_included
|
39
48
|
end
|
@@ -41,7 +50,8 @@ module RailsBestPractices
|
|
41
50
|
|
42
51
|
def return_value_is_used?(node)
|
43
52
|
return false unless @used_return_value_of
|
44
|
-
|
53
|
+
|
54
|
+
(node == @used_return_value_of) || @used_return_value_of.include?(node)
|
45
55
|
end
|
46
56
|
|
47
57
|
def model_classnames
|
@@ -57,9 +67,11 @@ module RailsBestPractices
|
|
57
67
|
end
|
58
68
|
elsif message == 'create'
|
59
69
|
# We're only interested in 'create' calls on model classes:
|
60
|
-
possible_receiver_classes =
|
61
|
-
|
62
|
-
|
70
|
+
possible_receiver_classes =
|
71
|
+
[node.receiver.to_s] +
|
72
|
+
classable_modules.map do |mod|
|
73
|
+
"#{mod}::#{node.receiver}"
|
74
|
+
end
|
63
75
|
unless (possible_receiver_classes & model_classnames).empty?
|
64
76
|
add_error "use 'create!' instead of 'create' as the latter may not always save"
|
65
77
|
end
|
@@ -20,7 +20,7 @@ module RailsBestPractices
|
|
20
20
|
|
21
21
|
# check call node to see if it is with message "namespace" and argument "bundler".
|
22
22
|
add_callback :start_command do |node|
|
23
|
-
if
|
23
|
+
if node.message.to_s == 'namespace' && node.arguments.all[0].to_s == 'bundler'
|
24
24
|
add_error 'dry bundler in capistrano'
|
25
25
|
end
|
26
26
|
end
|
@@ -12,7 +12,7 @@ module RailsBestPractices
|
|
12
12
|
interesting_nodes :hash, :bare_assoc_hash
|
13
13
|
interesting_files ALL_FILES
|
14
14
|
|
15
|
-
VALID_SYMBOL_KEY = /\A[@$_A-Za-z]([_\w]*[!_=?\w])?\z
|
15
|
+
VALID_SYMBOL_KEY = /\A[@$_A-Za-z]([_\w]*[!_=?\w])?\z/.freeze
|
16
16
|
|
17
17
|
# check hash node to see if it is ruby 1.8 style.
|
18
18
|
add_callback :start_hash, :start_bare_assoc_hash do |node|
|
@@ -23,24 +23,24 @@ module RailsBestPractices
|
|
23
23
|
|
24
24
|
protected
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
# check if hash node is empty.
|
27
|
+
def empty_hash?(node)
|
28
|
+
s(:hash, nil) == node || s(:bare_assoc_hash, nil) == node
|
29
|
+
end
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
# check if hash key/value pairs are ruby 1.8 style.
|
32
|
+
def hash_is_18?(node)
|
33
|
+
pair_nodes = node.sexp_type == :hash ? node[1][1] : node[1]
|
34
|
+
return false if pair_nodes.blank?
|
35
35
|
|
36
|
-
|
37
|
-
|
36
|
+
pair_nodes.any? { |pair_node| pair_node[1].sexp_type == :symbol_literal }
|
37
|
+
end
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
39
|
+
# check if the hash keys are valid to be converted to ruby 1.9
|
40
|
+
# syntax.
|
41
|
+
def valid_keys?(node)
|
42
|
+
node.hash_keys.all? { |key| key =~ VALID_SYMBOL_KEY }
|
43
|
+
end
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
@@ -55,20 +55,20 @@ module RailsBestPractices
|
|
55
55
|
|
56
56
|
private
|
57
57
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
58
|
+
# check assignment node,
|
59
|
+
# if the right vavlue is a method_add_arg node with message "new",
|
60
|
+
# then remember the left value as new variable.
|
61
|
+
def remember_new_variable(node)
|
62
|
+
right_value = node.right_value
|
63
|
+
if right_value.sexp_type == :method_add_arg && right_value.message.to_s == 'new'
|
64
|
+
@new_variables << node.left_value.to_s
|
66
65
|
end
|
66
|
+
end
|
67
67
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
68
|
+
# see if the receiver of the call node is included in the @new_varaibles.
|
69
|
+
def new_record?(node)
|
70
|
+
@new_variables.include? node.receiver.to_s
|
71
|
+
end
|
72
72
|
end
|
73
73
|
end
|
74
74
|
end
|
@@ -37,17 +37,16 @@ module RailsBestPractices
|
|
37
37
|
|
38
38
|
private
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
40
|
+
# check if the call node is the finder of other model.
|
41
|
+
#
|
42
|
+
# the message of the node should be one of find, all, first or last,
|
43
|
+
# and the receiver of the node should be with message :call (this is the other model),
|
44
|
+
# and any of its arguments is a hash,
|
45
|
+
# then it is the finder of other model.
|
46
|
+
def other_finder?(node)
|
47
|
+
FINDERS.include?(node[1].message.to_s) && node[1].receiver.sexp_type == :call &&
|
48
|
+
node.arguments.grep_nodes_count(sexp_type: :bare_assoc_hash) > 0
|
49
|
+
end
|
51
50
|
end
|
52
51
|
end
|
53
52
|
end
|
@@ -28,40 +28,41 @@ module RailsBestPractices
|
|
28
28
|
# and the message of the receiver call node matchs one of the association name with the class name,
|
29
29
|
# then it violates the law of demeter.
|
30
30
|
add_callback :start_call do |node|
|
31
|
-
if
|
31
|
+
if node.receiver.sexp_type == :call && need_delegate?(node)
|
32
32
|
add_error 'law of demeter'
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
36
|
private
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
class_name = variable(node).to_s.sub('@', '').classify
|
46
|
-
association_name = node.receiver.message.to_s
|
47
|
-
association = model_associations.get_association(class_name, association_name)
|
48
|
-
attribute_name = node.message.to_s
|
49
|
-
association && ASSOCIATION_METHODS.include?(association['meta']) &&
|
50
|
-
is_association_attribute?(association['class_name'], association_name, attribute_name)
|
51
|
-
end
|
38
|
+
# check if the call node can use delegate to avoid violating law of demeter.
|
39
|
+
#
|
40
|
+
# if the receiver of receiver of the call node matchs any in model names,
|
41
|
+
# and the message of receiver of the call node matchs any in association names,
|
42
|
+
# then it needs delegate.
|
43
|
+
def need_delegate?(node)
|
44
|
+
return unless variable(node)
|
52
45
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
46
|
+
class_name = variable(node).to_s.sub('@', '').classify
|
47
|
+
association_name = node.receiver.message.to_s
|
48
|
+
association = model_associations.get_association(class_name, association_name)
|
49
|
+
attribute_name = node.message.to_s
|
50
|
+
association && ASSOCIATION_METHODS.include?(association['meta']) &&
|
51
|
+
is_association_attribute?(association['class_name'], association_name, attribute_name)
|
52
|
+
end
|
53
|
+
|
54
|
+
def is_association_attribute?(association_class, association_name, attribute_name)
|
55
|
+
if association_name =~ /able$/
|
56
|
+
models.each do |class_name|
|
57
|
+
if model_associations.is_association?(class_name, association_name.sub(/able$/, '')) ||
|
58
|
+
model_associations.is_association?(class_name, association_name.sub(/able$/, 's'))
|
59
|
+
return true if model_attributes.is_attribute?(class_name, attribute_name)
|
60
60
|
end
|
61
|
-
else
|
62
|
-
model_attributes.is_attribute?(association_class, attribute_name)
|
63
61
|
end
|
62
|
+
else
|
63
|
+
model_attributes.is_attribute?(association_class, attribute_name)
|
64
64
|
end
|
65
|
+
end
|
65
66
|
end
|
66
67
|
end
|
67
68
|
end
|
@@ -37,10 +37,10 @@ module RailsBestPractices
|
|
37
37
|
|
38
38
|
private
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
# check if the node is a finder call node.
|
41
|
+
def finder?(node)
|
42
|
+
node.receiver.const? && FINDERS.include?(node.message.to_s)
|
43
|
+
end
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
@@ -38,16 +38,15 @@ module RailsBestPractices
|
|
38
38
|
|
39
39
|
private
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
41
|
+
# check if the arguments of options_for_select are complex.
|
42
|
+
#
|
43
|
+
# if the first argument is an array,
|
44
|
+
# and the size of array is greater than @array_count you defined,
|
45
|
+
# then it is complext.
|
46
|
+
def complex_select_options?(node)
|
47
|
+
node[1].message.to_s == 'options_for_select' && node.arguments.all.first.sexp_type == :array &&
|
48
|
+
node.arguments.all.first.array_size > @array_count
|
49
|
+
end
|
51
50
|
end
|
52
51
|
end
|
53
52
|
end
|
@@ -29,17 +29,16 @@ module RailsBestPractices
|
|
29
29
|
|
30
30
|
private
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
end
|
32
|
+
# check if the method_add_arg node is a finder.
|
33
|
+
#
|
34
|
+
# if the receiver of method_add_arg node is a constant,
|
35
|
+
# and the message of call method_add_arg is one of find, all, first or last,
|
36
|
+
# and any of its arguments is a hash,
|
37
|
+
# then it is a finder.
|
38
|
+
def finder?(node)
|
39
|
+
FINDERS.include?(node[1].message.to_s) && node[1].sexp_type == :call &&
|
40
|
+
node.arguments.grep_nodes_count(sexp_type: :bare_assoc_hash) > 0
|
41
|
+
end
|
43
42
|
end
|
44
43
|
end
|
45
44
|
end
|
@@ -51,30 +51,32 @@ module RailsBestPractices
|
|
51
51
|
|
52
52
|
private
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
@counter -= 1
|
74
|
-
elsif %i[command_call command].include?(node.sexp_type) && %w[resources resource].include?(node.message.to_s)
|
75
|
-
add_error "needless deep nesting (nested_count > #{@nested_count})", @file, node.line_number if @counter >= @nested_count && !@shallow_nodes.include?(node)
|
54
|
+
# check nested route.
|
55
|
+
#
|
56
|
+
# if the receiver of the method_add_block is with message "resources" or "resource",
|
57
|
+
# then increment the @counter, recursively check the block body, and decrement the @counter.
|
58
|
+
#
|
59
|
+
# if the node type is command_call or command,
|
60
|
+
# and its message is resources or resource,
|
61
|
+
# then check if @counter is greater than or equal to @nested_count,
|
62
|
+
# if so, it is the needless deep nesting.
|
63
|
+
def recursively_check(node)
|
64
|
+
shallow = @shallow_nodes.include? node
|
65
|
+
|
66
|
+
if %i[command_call command].include?(node[1].sexp_type) && %w[resources resource].include?(node[1].message.to_s)
|
67
|
+
hash_node = node[1].arguments.grep_node(sexp_type: :bare_assoc_hash)
|
68
|
+
shallow ||= (hash_node && hash_node.hash_value('shallow').to_s == 'true')
|
69
|
+
@counter += 1
|
70
|
+
node.block_node.statements.each do |stmt_node|
|
71
|
+
@shallow_nodes << stmt_node if shallow
|
72
|
+
recursively_check(stmt_node)
|
76
73
|
end
|
74
|
+
@counter -= 1
|
75
|
+
elsif %i[command_call command].include?(node.sexp_type) && %w[resources resource].include?(node.message.to_s)
|
76
|
+
add_error "needless deep nesting (nested_count > #{@nested_count})", @file, node.line_number if @counter >=
|
77
|
+
@nested_count && !@shallow_nodes.include?(node)
|
77
78
|
end
|
79
|
+
end
|
78
80
|
end
|
79
81
|
end
|
80
82
|
end
|
@@ -18,7 +18,7 @@ module RailsBestPractices
|
|
18
18
|
|
19
19
|
# check rescue node to see if its type is Exception
|
20
20
|
add_callback :start_rescue do |rescue_node|
|
21
|
-
if rescue_node.exception_classes.any? { |rescue_class| 'Exception'
|
21
|
+
if rescue_node.exception_classes.any? { |rescue_class| rescue_class.to_s == 'Exception' }
|
22
22
|
add_error "Don't rescue Exception", rescue_node.file, rescue_node.exception_classes.first.line_number
|
23
23
|
end
|
24
24
|
end
|
@@ -24,8 +24,7 @@ module RailsBestPractices
|
|
24
24
|
|
25
25
|
# check all command nodes
|
26
26
|
add_callback :start_command do |node|
|
27
|
-
if 'match'
|
28
|
-
':controller(/:action(/:id(.:format)))' == node.arguments.all.first.to_s
|
27
|
+
if node.message.to_s == 'match' && node.arguments.all.first.to_s == ':controller(/:action(/:id(.:format)))'
|
29
28
|
add_error 'not use default route'
|
30
29
|
end
|
31
30
|
end
|
@@ -17,7 +17,7 @@ module RailsBestPractices
|
|
17
17
|
|
18
18
|
# check fcall node to see if its message is time_ago_in_words or distance_of_time_in_words_to_now
|
19
19
|
add_callback :start_fcall do |node|
|
20
|
-
if
|
20
|
+
if node.message.to_s == 'time_ago_in_words' || node.message.to_s == 'distance_of_time_in_words_to_now'
|
21
21
|
add_error 'not use time_ago_in_words'
|
22
22
|
end
|
23
23
|
end
|
@@ -41,14 +41,14 @@ module RailsBestPractices
|
|
41
41
|
|
42
42
|
private
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
44
|
+
# check method_add_block node to calculate the count of member and collection custom routes.
|
45
|
+
#
|
46
|
+
# if its receiver is with message "resources",
|
47
|
+
# then calculate the count of call nodes, whose message is get, post, update or delete,
|
48
|
+
# it is just the count of member and collection custom routes.
|
49
|
+
def member_and_collection_count_for_rails3(node)
|
50
|
+
node[1].message.to_s == 'resources' ? node.grep_nodes_count(sexp_type: :command, message: VERBS) : 0
|
51
|
+
end
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
@@ -11,6 +11,7 @@ module RailsBestPractices
|
|
11
11
|
# Review process:
|
12
12
|
# check nodes to see if there is a command with message attr_accessible or attr_protected,
|
13
13
|
# or include ActiveModel::ForbiddenAttributesProtection.
|
14
|
+
|
14
15
|
class ProtectMassAssignmentReview < Review
|
15
16
|
interesting_files MODEL_FILES
|
16
17
|
interesting_nodes :class, :command, :var_ref, :vcall, :fcall
|
@@ -54,53 +55,55 @@ module RailsBestPractices
|
|
54
55
|
|
55
56
|
private
|
56
57
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
end
|
58
|
+
def check_activerecord_version
|
59
|
+
if Prepares.gems.gem_version('activerecord').to_i > 3
|
60
|
+
@mass_assignement = false
|
61
61
|
end
|
62
|
+
end
|
62
63
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
end
|
64
|
+
def check_whitelist_attributes_config
|
65
|
+
if Prepares.configs['config.active_record.whitelist_attributes'] == 'true'
|
66
|
+
@whitelist_attributes = true
|
67
67
|
end
|
68
|
+
end
|
68
69
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
end
|
70
|
+
def check_include_forbidden_attributes_protection_config
|
71
|
+
if Prepares.configs['railsbp.include_forbidden_attributes_protection'] == 'true'
|
72
|
+
@mass_assignement = false
|
73
73
|
end
|
74
|
+
end
|
74
75
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
76
|
+
def check_rails_builtin(node)
|
77
|
+
if @whitelist_attributes ||
|
78
|
+
[node.to_s, node.message.to_s].any? { |str| %w[attr_accessible attr_protected].include? str }
|
79
|
+
@mass_assignement = false
|
79
80
|
end
|
81
|
+
end
|
80
82
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
83
|
+
def check_strong_parameters(command_node)
|
84
|
+
if command_node.message.to_s == 'include' &&
|
85
|
+
command_node.arguments.all.first.to_s == 'ActiveModel::ForbiddenAttributesProtection'
|
86
|
+
@mass_assignement = false
|
85
87
|
end
|
88
|
+
end
|
86
89
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
end
|
90
|
+
def check_devise(command_node)
|
91
|
+
if command_node.message.to_s == 'devise'
|
92
|
+
@mass_assignement = false
|
91
93
|
end
|
94
|
+
end
|
92
95
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
end
|
96
|
+
def check_authlogic(node)
|
97
|
+
if [node.to_s, node.message.to_s].include? 'acts_as_authentic'
|
98
|
+
@mass_assignement = false
|
97
99
|
end
|
100
|
+
end
|
98
101
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
end
|
102
|
+
def check_active_record(const_path_ref_node)
|
103
|
+
if const_path_ref_node.base_class.to_s != 'ActiveRecord::Base'
|
104
|
+
@mass_assignement = false
|
103
105
|
end
|
106
|
+
end
|
104
107
|
end
|
105
108
|
end
|
106
109
|
end
|