rails_best_practices 1.19.2 → 1.20.1
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 +7 -7
- data/Gemfile +3 -5
- data/Gemfile.lock +125 -0
- data/Guardfile +2 -0
- data/README.md +6 -6
- data/Rakefile +2 -17
- data/assets/result.html.erb +2 -0
- data/lib/rails_best_practices.rb +3 -2
- data/lib/rails_best_practices/analyzer.rb +61 -49
- 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 +64 -56
- 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 +67 -73
- 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 +24 -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 -89
- 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 +26 -19
- 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 +18 -15
- 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 +68 -66
- 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 +38 -43
- 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/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 +64 -31
- 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 +16 -18
@@ -43,24 +43,24 @@ module RailsBestPractices
|
|
43
43
|
|
44
44
|
private
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
end
|
46
|
+
# check an attribute assignment node, if its message is xxx_id,
|
47
|
+
# then remember the receiver of the attribute assignment in @assignments.
|
48
|
+
def attribute_assignment(node)
|
49
|
+
if node.left_value.message.is_a?(Sexp) && node.left_value.message.to_s =~ /_id$/
|
50
|
+
receiver = node.left_value.receiver.to_s
|
51
|
+
@assignments[receiver] = true
|
53
52
|
end
|
53
|
+
end
|
54
54
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
end
|
55
|
+
# check a call node with message "save" or "save!",
|
56
|
+
# if the receiver of call node exists in @assignments,
|
57
|
+
# then the attribute assignment should be replaced by using model association.
|
58
|
+
def call_assignment(node)
|
59
|
+
if ['save', 'save!'].include? node.message.to_s
|
60
|
+
receiver = node.receiver.to_s
|
61
|
+
add_error "use model association (for #{receiver})" if @assignments[receiver]
|
63
62
|
end
|
63
|
+
end
|
64
64
|
end
|
65
65
|
end
|
66
66
|
end
|
data/lib/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review.rb
CHANGED
@@ -11,6 +11,7 @@ module RailsBestPractices
|
|
11
11
|
# Review process:
|
12
12
|
# check class node to remember the class name,
|
13
13
|
# and check the method definition nodes to see if the corresponding mailer views exist or not.
|
14
|
+
|
14
15
|
class UseMultipartAlternativeAsContentTypeOfEmailReview < Review
|
15
16
|
interesting_nodes :class, :def
|
16
17
|
interesting_files MAILER_FILES
|
@@ -31,30 +32,31 @@ module RailsBestPractices
|
|
31
32
|
|
32
33
|
private
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
# check if rails3's syntax mailer views are canonical.
|
40
|
-
#
|
41
|
-
# @param [String] name method name in action_mailer
|
42
|
-
def rails3_canonical_mailer_views?(name)
|
43
|
-
return true if mailer_files(name).empty?
|
44
|
-
return true if mailer_files(name).none? { |filename| filename.index 'html' }
|
45
|
-
mailer_files(name).any? { |filename| filename.index 'html' } &&
|
46
|
-
mailer_files(name).any? { |filename| filename.index 'text' }
|
47
|
-
end
|
35
|
+
# check if rails's syntax mailer views are canonical.
|
36
|
+
#
|
37
|
+
# @param [String] name method name in action_mailer
|
38
|
+
def rails_canonical_mailer_views?(name); end
|
48
39
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
40
|
+
# check if rails3's syntax mailer views are canonical.
|
41
|
+
#
|
42
|
+
# @param [String] name method name in action_mailer
|
43
|
+
def rails3_canonical_mailer_views?(name)
|
44
|
+
return true if mailer_files(name).empty?
|
45
|
+
return true if mailer_files(name).none? { |filename| filename.index 'html' }
|
53
46
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
47
|
+
mailer_files(name).any? { |filename| filename.index 'html' } &&
|
48
|
+
mailer_files(name).any? { |filename| filename.index 'text' }
|
49
|
+
end
|
50
|
+
|
51
|
+
# all mail view files for a method name.
|
52
|
+
def mailer_files(name)
|
53
|
+
Dir.entries(mailer_directory) { |filename| filename.index name.to_s }
|
54
|
+
end
|
55
|
+
|
56
|
+
# the view directory of mailer.
|
57
|
+
def mailer_directory
|
58
|
+
File.join(Core::Runner.base_path, "app/views/#{@klazz_name.to_s.underscore}")
|
59
|
+
end
|
58
60
|
end
|
59
61
|
end
|
60
62
|
end
|
@@ -49,42 +49,42 @@ module RailsBestPractices
|
|
49
49
|
|
50
50
|
private
|
51
51
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
52
|
+
# check a command node, if it is a callback definition, such as after_create, before_create,
|
53
|
+
# then save the callback methods in @callbacks
|
54
|
+
def remember_callback(node)
|
55
|
+
if node.message.to_s =~ /^after_|^before_/
|
56
|
+
node.arguments.all.each do |argument|
|
57
|
+
# ignore callback like after_create Comment.new
|
58
|
+
@callbacks << argument.to_s if argument.sexp_type == :symbol_literal
|
60
59
|
end
|
61
60
|
end
|
61
|
+
end
|
62
62
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
63
|
+
# check a defn node to see if the method name exists in the @callbacks.
|
64
|
+
def callback_method?(node)
|
65
|
+
@callbacks.find { |callback| callback == node.method_name.to_s }
|
66
|
+
end
|
67
67
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
end
|
68
|
+
# check a def node to see if it contains a actionmailer deliver call.
|
69
|
+
#
|
70
|
+
# if the message of call node is deliver,
|
71
|
+
# and the receiver of the call node is with receiver node who exists in @callbacks,
|
72
|
+
# then the call node is actionmailer deliver call.
|
73
|
+
def deliver_mailer?(node)
|
74
|
+
node.grep_nodes(sexp_type: :call) do |child_node|
|
75
|
+
if child_node.message.to_s == 'deliver'
|
76
|
+
if child_node.receiver.sexp_type == :method_add_arg &&
|
77
|
+
mailers.include?(child_node.receiver[1].receiver.to_s)
|
78
|
+
return true
|
80
79
|
end
|
81
80
|
end
|
82
|
-
false
|
83
81
|
end
|
82
|
+
false
|
83
|
+
end
|
84
84
|
|
85
|
-
|
86
|
-
|
87
|
-
|
85
|
+
def mailers
|
86
|
+
@mailers ||= Prepares.mailers
|
87
|
+
end
|
88
88
|
end
|
89
89
|
end
|
90
90
|
end
|
@@ -21,13 +21,13 @@ module RailsBestPractices
|
|
21
21
|
|
22
22
|
protected
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
def no_parentheses_around_parameters?(def_node)
|
25
|
+
def_node[2][0] != :parent
|
26
|
+
end
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
def has_parameters?(def_node)
|
29
|
+
def_node[2][0] == :params && !def_node[2][1..-1].compact.empty?
|
30
|
+
end
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
@@ -34,84 +34,86 @@ module RailsBestPractices
|
|
34
34
|
#
|
35
35
|
# then the call node can use query attribute instead.
|
36
36
|
add_callback :start_if, :start_unless, :start_elsif, :start_ifop, :start_if_mod, :start_unless_mod do |node|
|
37
|
-
all_conditions =
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
all_conditions.each do |condition_node|
|
43
|
-
if query_attribute_node = query_attribute_node(condition_node)
|
44
|
-
receiver_node = query_attribute_node.receiver
|
45
|
-
add_error "use query attribute (#{receiver_node.receiver}.#{receiver_node.message}?)",
|
46
|
-
node.file,
|
47
|
-
query_attribute_node.line_number
|
37
|
+
all_conditions =
|
38
|
+
if node.conditional_statement == node.conditional_statement.all_conditions
|
39
|
+
[node.conditional_statement]
|
40
|
+
else
|
41
|
+
node.conditional_statement.all_conditions
|
48
42
|
end
|
43
|
+
all_conditions.each do |condition_node|
|
44
|
+
next unless query_attribute_node = query_attribute_node(condition_node)
|
45
|
+
|
46
|
+
receiver_node = query_attribute_node.receiver
|
47
|
+
add_error "use query attribute (#{receiver_node.receiver}.#{receiver_node.message}?)",
|
48
|
+
node.file,
|
49
|
+
query_attribute_node.line_number
|
49
50
|
end
|
50
51
|
end
|
51
52
|
|
52
53
|
private
|
53
54
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
end
|
71
|
-
nil
|
55
|
+
# recursively check conditional statement nodes to see if there is a call node that may be
|
56
|
+
# possible query attribute.
|
57
|
+
def query_attribute_node(conditional_statement_node)
|
58
|
+
case conditional_statement_node.sexp_type
|
59
|
+
when :and, :or
|
60
|
+
node =
|
61
|
+
query_attribute_node(conditional_statement_node[1]) || query_attribute_node(conditional_statement_node[2])
|
62
|
+
node.file = conditional_statement_code.file
|
63
|
+
return node
|
64
|
+
when :not
|
65
|
+
node = query_attribute_node(conditional_statement_node[1])
|
66
|
+
node.file = conditional_statement_node.file
|
67
|
+
when :call
|
68
|
+
return conditional_statement_node if possible_query_attribute?(conditional_statement_node)
|
69
|
+
when :binary
|
70
|
+
return conditional_statement_node if possible_query_attribute?(conditional_statement_node)
|
72
71
|
end
|
72
|
+
nil
|
73
|
+
end
|
74
|
+
|
75
|
+
# check if the node may use query attribute instead.
|
76
|
+
#
|
77
|
+
# if the node contains two method calls, e.g. @user.login.nil?
|
78
|
+
#
|
79
|
+
# for the first call, the receiver should be one of the class names and
|
80
|
+
# the message should be one of the attribute name.
|
81
|
+
#
|
82
|
+
# for the second call, the message should be one of nil?, blank? or present? or
|
83
|
+
# it is compared with an empty string.
|
84
|
+
#
|
85
|
+
# the node that may use query attribute.
|
86
|
+
def possible_query_attribute?(node)
|
87
|
+
return false unless node.receiver.sexp_type == :call
|
73
88
|
|
74
|
-
|
75
|
-
|
76
|
-
# if the node contains two method calls, e.g. @user.login.nil?
|
77
|
-
#
|
78
|
-
# for the first call, the receiver should be one of the class names and
|
79
|
-
# the message should be one of the attribute name.
|
80
|
-
#
|
81
|
-
# for the second call, the message should be one of nil?, blank? or present? or
|
82
|
-
# it is compared with an empty string.
|
83
|
-
#
|
84
|
-
# the node that may use query attribute.
|
85
|
-
def possible_query_attribute?(node)
|
86
|
-
return false unless :call == node.receiver.sexp_type
|
87
|
-
variable_node = variable(node)
|
88
|
-
message_node = node.grep_node(receiver: variable_node.to_s).message
|
89
|
+
variable_node = variable(node)
|
90
|
+
message_node = node.grep_node(receiver: variable_node.to_s).message
|
89
91
|
|
90
|
-
|
91
|
-
|
92
|
-
|
92
|
+
is_model?(variable_node) && model_attribute?(variable_node, message_node.to_s) &&
|
93
|
+
(QUERY_METHODS.include?(node.message.to_s) || compare_with_empty_string?(node))
|
94
|
+
end
|
93
95
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
class_name = variable_node.to_s.sub(/^@/, '').classify
|
98
|
-
models.include?(class_name)
|
99
|
-
end
|
96
|
+
# check if the receiver is one of the models.
|
97
|
+
def is_model?(variable_node)
|
98
|
+
return false if variable_node.const?
|
100
99
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
class_name = variable_node.to_s.sub(/^@/, '').classify
|
105
|
-
attribute_type = model_attributes.get_attribute_type(class_name, message)
|
106
|
-
attribute_type && !%w[integer float].include?(attribute_type)
|
107
|
-
end
|
100
|
+
class_name = variable_node.to_s.sub(/^@/, '').classify
|
101
|
+
models.include?(class_name)
|
102
|
+
end
|
108
103
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
104
|
+
# check if the receiver and message is one of the model's attribute.
|
105
|
+
# the receiver should match one of the class model name, and the message should match one of attribute name.
|
106
|
+
def model_attribute?(variable_node, message)
|
107
|
+
class_name = variable_node.to_s.sub(/^@/, '').classify
|
108
|
+
attribute_type = model_attributes.get_attribute_type(class_name, message)
|
109
|
+
attribute_type && !%w[integer float].include?(attribute_type)
|
110
|
+
end
|
111
|
+
|
112
|
+
# check if the node is with node type :binary, node message :== and node argument is empty string.
|
113
|
+
def compare_with_empty_string?(node)
|
114
|
+
node.sexp_type == :binary && ['==', '!='].include?(node.message.to_s) &&
|
115
|
+
s(:string_literal, s(:string_content)) == node.argument
|
116
|
+
end
|
115
117
|
end
|
116
118
|
end
|
117
119
|
end
|
@@ -31,14 +31,15 @@ module RailsBestPractices
|
|
31
31
|
node.body.statements.each do |child_node|
|
32
32
|
next if child_node.grep_nodes_count(sexp_type: %i[fcall command], message: WITH_SAY_METHODS) > 0
|
33
33
|
|
34
|
-
receiver_node =
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
34
|
+
receiver_node =
|
35
|
+
if child_node.sexp_type == :method_add_block
|
36
|
+
child_node[1]
|
37
|
+
elsif child_node.sexp_type == :method_add_arg
|
38
|
+
child_node[1]
|
39
|
+
else
|
40
|
+
child_node
|
41
|
+
end
|
42
|
+
if receiver_node.sexp_type == :call
|
42
43
|
add_error('use say with time in migrations', node.file, child_node.line_number)
|
43
44
|
end
|
44
45
|
end
|
@@ -30,28 +30,30 @@ module RailsBestPractices
|
|
30
30
|
|
31
31
|
private
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
33
|
+
# check a if node to see
|
34
|
+
#
|
35
|
+
# if the conditional statement is compared with current_user or current_user.id,
|
36
|
+
# and there is a redirect_to method call in the block body,
|
37
|
+
# then it should be replaced by using scope access.
|
38
|
+
def current_user_redirect?(node)
|
39
|
+
all_conditions =
|
40
|
+
if node.conditional_statement == node.conditional_statement.all_conditions
|
40
41
|
[node.conditional_statement]
|
41
42
|
else
|
42
43
|
node.conditional_statement.all_conditions
|
43
44
|
end
|
44
|
-
|
45
|
+
results =
|
46
|
+
all_conditions.map do |condition_node|
|
45
47
|
['==', '!='].include?(condition_node.message.to_s) &&
|
46
48
|
(current_user?(condition_node.argument) || current_user?(condition_node.receiver))
|
47
49
|
end
|
48
|
-
|
49
|
-
|
50
|
+
results.any? { |result| result == true } && node.body.grep_node(message: 'redirect_to')
|
51
|
+
end
|
50
52
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
53
|
+
# check a call node to see if it uses current_user, or current_user.id.
|
54
|
+
def current_user?(node)
|
55
|
+
node.to_s == 'current_user' || (node.receiver.to_s == 'current_user' && node.message.to_s == 'id')
|
56
|
+
end
|
55
57
|
end
|
56
58
|
end
|
57
59
|
end
|
@@ -18,7 +18,8 @@ module RailsBestPractices
|
|
18
18
|
# check command node to see if load 'deploy/assets'
|
19
19
|
add_callback :start_command do |node|
|
20
20
|
if Prepares.gems.gem_version('rails').to_i == 3
|
21
|
-
if !Prepares.gems.has_gem?('turbo-sprockets-rails3') &&
|
21
|
+
if !Prepares.gems.has_gem?('turbo-sprockets-rails3') && node.message.to_s == 'load' &&
|
22
|
+
node.arguments.to_s == 'deploy/assets'
|
22
23
|
add_error 'speed up assets precompile with turbo-sprockets-rails3'
|
23
24
|
end
|
24
25
|
end
|
@@ -1,59 +1,54 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require File.expand_path('
|
3
|
+
require File.expand_path('lib/rails_best_practices/version', __dir__)
|
4
4
|
|
5
|
-
Gem::Specification.new do |
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'rails_best_practices'
|
7
|
+
spec.version = RailsBestPractices::VERSION
|
8
|
+
spec.platform = Gem::Platform::RUBY
|
9
|
+
spec.authors = ['Richard Huang']
|
10
|
+
spec.email = ['flyerhzm@gmail.com']
|
11
|
+
spec.homepage = 'http://rails-bestpractices.com'
|
12
|
+
spec.summary = 'a code metric tool for rails codes.'
|
13
|
+
spec.description = 'a code metric tool for rails codes, written in Ruby.'
|
14
|
+
spec.license = 'MIT'
|
15
15
|
|
16
|
-
|
17
|
-
|
16
|
+
spec.required_ruby_version = '>= 1.9.0'
|
17
|
+
spec.required_rubygems_version = '>= 1.3.6'
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
s.add_dependency('ruby-progressbar')
|
19
|
+
spec.add_dependency('activesupport')
|
20
|
+
spec.add_dependency('code_analyzer', '>= 0.5.2')
|
21
|
+
spec.add_dependency('erubis')
|
22
|
+
spec.add_dependency('i18n')
|
23
|
+
spec.add_dependency('json')
|
24
|
+
spec.add_dependency('require_all', '~> 3.0')
|
25
|
+
spec.add_dependency('ruby-progressbar')
|
27
26
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
27
|
+
spec.add_development_dependency('awesome_print')
|
28
|
+
spec.add_development_dependency('bundler')
|
29
|
+
spec.add_development_dependency('haml')
|
30
|
+
spec.add_development_dependency('rake')
|
31
|
+
spec.add_development_dependency('rspec')
|
32
|
+
spec.add_development_dependency('slim')
|
34
33
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
34
|
+
spec.files = `git ls-files`.split($/)
|
35
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
36
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
37
|
+
spec.require_paths = %w[lib assets]
|
39
38
|
|
40
|
-
|
41
|
-
#{'*' * 80}
|
39
|
+
spec.post_install_message = <<~POST_INSTALL_MESSAGE
|
40
|
+
#{'*' * 80}
|
42
41
|
|
43
|
-
|
42
|
+
rails_best_practices is a code metric tool to check the quality of rails codes.
|
44
43
|
|
45
|
-
|
44
|
+
I highly recommend you browse the Rails Best Practices website first.
|
46
45
|
|
47
|
-
|
46
|
+
http://rails-bestpractices.com
|
48
47
|
|
49
|
-
|
48
|
+
Enjoy!
|
50
49
|
|
51
|
-
|
50
|
+
Richard Huang (flyerhzm@gmail.com)
|
52
51
|
|
53
|
-
|
54
|
-
|
55
|
-
Richard Huang (flyerhzm@gmail.com)
|
56
|
-
|
57
|
-
#{'*' * 80}
|
52
|
+
#{'*' * 80}
|
58
53
|
POST_INSTALL_MESSAGE
|
59
54
|
end
|