rails_best_practices 1.10.1 → 1.11.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/.gitignore +1 -0
- data/README.md +11 -6
- data/assets/result.html.erb +76 -46
- data/install_supported_rubies.sh +3 -0
- data/lib/rails_best_practices.rb +2 -1
- data/lib/rails_best_practices/analyzer.rb +10 -8
- data/lib/rails_best_practices/core.rb +0 -4
- data/lib/rails_best_practices/core/check.rb +41 -117
- data/lib/rails_best_practices/core/error.rb +3 -9
- data/lib/rails_best_practices/core/runner.rb +20 -80
- data/lib/rails_best_practices/lexicals/long_line_check.rb +2 -1
- data/lib/rails_best_practices/lexicals/remove_tab_check.rb +1 -3
- data/lib/rails_best_practices/lexicals/remove_trailing_whitespace_check.rb +1 -3
- data/lib/rails_best_practices/prepares/config_prepare.rb +1 -1
- data/lib/rails_best_practices/prepares/controller_prepare.rb +7 -8
- data/lib/rails_best_practices/prepares/helper_prepare.rb +2 -2
- data/lib/rails_best_practices/prepares/mailer_prepare.rb +1 -1
- data/lib/rails_best_practices/prepares/model_prepare.rb +6 -7
- data/lib/rails_best_practices/prepares/route_prepare.rb +12 -13
- data/lib/rails_best_practices/prepares/schema_prepare.rb +2 -2
- data/lib/rails_best_practices/reviews/add_model_virtual_attribute_review.rb +19 -15
- data/lib/rails_best_practices/reviews/always_add_db_index_review.rb +10 -17
- data/lib/rails_best_practices/reviews/dry_bundler_in_capistrano_review.rb +2 -5
- data/lib/rails_best_practices/reviews/hash_syntax_review.rb +3 -30
- data/lib/rails_best_practices/reviews/isolate_seed_data_review.rb +7 -10
- data/lib/rails_best_practices/reviews/keep_finders_on_their_own_model_review.rb +5 -9
- data/lib/rails_best_practices/reviews/law_of_demeter_review.rb +10 -13
- data/lib/rails_best_practices/reviews/move_code_into_controller_review.rb +6 -9
- data/lib/rails_best_practices/reviews/move_code_into_helper_review.rb +2 -5
- data/lib/rails_best_practices/reviews/move_code_into_model_review.rb +7 -13
- data/lib/rails_best_practices/reviews/move_finder_to_named_scope_review.rb +3 -6
- data/lib/rails_best_practices/reviews/move_model_logic_into_model_review.rb +6 -9
- data/lib/rails_best_practices/reviews/needless_deep_nesting_review.rb +3 -6
- data/lib/rails_best_practices/reviews/not_use_default_route_review.rb +4 -7
- data/lib/rails_best_practices/reviews/not_use_time_ago_in_words_review.rb +2 -5
- data/lib/rails_best_practices/reviews/overuse_route_customizations_review.rb +7 -10
- data/lib/rails_best_practices/reviews/protect_mass_assignment_review.rb +2 -5
- data/lib/rails_best_practices/reviews/remove_empty_helpers_review.rb +2 -5
- data/lib/rails_best_practices/reviews/remove_unused_methods_in_controllers_review.rb +8 -6
- data/lib/rails_best_practices/reviews/remove_unused_methods_in_helpers_review.rb +1 -2
- data/lib/rails_best_practices/reviews/remove_unused_methods_in_models_review.rb +4 -5
- data/lib/rails_best_practices/reviews/replace_complex_creation_with_factory_method_review.rb +9 -12
- data/lib/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review.rb +2 -13
- data/lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb +18 -26
- data/lib/rails_best_practices/reviews/review.rb +6 -7
- data/lib/rails_best_practices/reviews/simplify_render_in_controllers_review.rb +2 -5
- data/lib/rails_best_practices/reviews/simplify_render_in_views_review.rb +2 -5
- data/lib/rails_best_practices/reviews/use_before_filter_review.rb +2 -5
- data/lib/rails_best_practices/reviews/use_model_association_review.rb +11 -14
- data/lib/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review.rb +11 -8
- data/lib/rails_best_practices/reviews/use_observer_review.rb +8 -11
- data/lib/rails_best_practices/reviews/use_parentheses_in_method_def_review.rb +1 -1
- data/lib/rails_best_practices/reviews/use_query_attribute_review.rb +12 -18
- data/lib/rails_best_practices/reviews/use_say_with_time_in_migrations_review.rb +7 -10
- data/lib/rails_best_practices/reviews/use_scope_access_review.rb +4 -10
- data/lib/rails_best_practices/version.rb +1 -1
- data/rails_best_practices.gemspec +1 -1
- data/rails_best_practices.yml +5 -5
- data/spec/rails_best_practices/core/check_spec.rb +0 -67
- data/spec/rails_best_practices/prepares/controller_prepare_spec.rb +0 -1
- data/spec/rails_best_practices/prepares/model_prepare_spec.rb +0 -4
- data/spec/rails_best_practices/reviews/hash_syntax_review_spec.rb +3 -30
- data/spec/rails_best_practices/reviews/remove_unused_methods_in_controllers_review_spec.rb +22 -0
- data/spec/rails_best_practices/reviews/remove_unused_methods_in_models_review_spec.rb +19 -0
- data/spec/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review_spec.rb +2 -2
- data/spec/spec_helper.rb +0 -4
- metadata +28 -41
- data/Gemfile.lock +0 -71
- data/lib/rails_best_practices/core/checking_visitor.rb +0 -80
- data/lib/rails_best_practices/core/nil.rb +0 -37
- data/lib/rails_best_practices/core_ext/enumerable.rb +0 -9
- data/lib/rails_best_practices/core_ext/sexp.rb +0 -840
- data/spec/rails_best_practices/core/checking_visitor_spec.rb +0 -79
- data/spec/rails_best_practices/core/nil_spec.rb +0 -37
- data/spec/rails_best_practices/core_ext/enumerable_spec.rb +0 -7
- data/spec/rails_best_practices/core_ext/sexp_spec.rb +0 -613
@@ -15,14 +15,14 @@ module RailsBestPractices
|
|
15
15
|
@model_attributes = Prepares.model_attributes
|
16
16
|
end
|
17
17
|
|
18
|
-
|
18
|
+
add_callback :start_command do |node|
|
19
19
|
if "create_table" == node.message.to_s
|
20
20
|
@last_klazz = node.arguments.all.first.to_s.classify
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
24
|
# check command_call node to remember the model attributes.
|
25
|
-
|
25
|
+
add_callback :start_command_call do |node|
|
26
26
|
if ATTRIBUTE_TYPES.include? node.message.to_s
|
27
27
|
attribute_name = node.arguments.all.first.to_s
|
28
28
|
@model_attributes.add_attribute(@last_klazz, attribute_name, node.message.to_s)
|
@@ -11,17 +11,14 @@ module RailsBestPractices
|
|
11
11
|
#
|
12
12
|
# Review process:
|
13
13
|
# check method define nodes in all controller files,
|
14
|
-
# if there are more than one [] method calls with the same
|
14
|
+
# if there are more than one [] method calls with the same receiver and arguments,
|
15
15
|
# but assigned to one model's different attribute.
|
16
16
|
# and after these method calls, there is a save method call for that model,
|
17
17
|
# then the model needs to add a virtual attribute.
|
18
18
|
class AddModelVirtualAttributeReview < Review
|
19
19
|
interesting_nodes :def
|
20
20
|
interesting_files CONTROLLER_FILES
|
21
|
-
|
22
|
-
def url
|
23
|
-
"http://rails-bestpractices.com/posts/4-add-model-virtual-attribute"
|
24
|
-
end
|
21
|
+
url "http://rails-bestpractices.com/posts/4-add-model-virtual-attribute"
|
25
22
|
|
26
23
|
# check method define nodes to see if there are some attribute assignments that can use model virtual attribute instead in review process.
|
27
24
|
#
|
@@ -31,10 +28,10 @@ module RailsBestPractices
|
|
31
28
|
# 2. the messages of attribute assignment nodes housld be different (:first_name= , :last_name=)
|
32
29
|
# 3. the argument of call nodes with message :[] should be same (:full_name)
|
33
30
|
# 4. there should be a call node with message :save or :save! after attribute assignment nodes
|
34
|
-
# 5. and the
|
31
|
+
# 5. and the receiver of save or save! call node should be the same with the receiver of attribute assignment nodes
|
35
32
|
#
|
36
33
|
# then the attribute assignment nodes can add model virtual attribute instead.
|
37
|
-
|
34
|
+
add_callback :start_def do |node|
|
38
35
|
@assignments = {}
|
39
36
|
node.recursive_children do |child|
|
40
37
|
case child.sexp_type
|
@@ -55,30 +52,37 @@ module RailsBestPractices
|
|
55
52
|
return unless :field == left_value.sexp_type && :call == right_value.sexp_type
|
56
53
|
aref_node = right_value.grep_node(sexp_type: :aref)
|
57
54
|
if aref_node
|
58
|
-
assignments(left_value.
|
55
|
+
assignments(left_value.receiver.to_s) << {message: left_value.message.to_s, arguments: aref_node.to_s}
|
59
56
|
end
|
60
57
|
end
|
61
58
|
|
62
59
|
# check a call node with message "save" or "save!",
|
63
|
-
# if there exists an attribute assignment for the
|
60
|
+
# if there exists an attribute assignment for the receiver of this call node,
|
64
61
|
# and if the arguments of this attribute assignments has duplicated entries (different message and same arguments),
|
65
62
|
# then this node needs to add a virtual attribute.
|
66
63
|
def call_assignment(node)
|
67
64
|
if ["save", "save!"].include? node.message.to_s
|
68
|
-
|
69
|
-
add_error "add model virtual attribute (for #{
|
65
|
+
receiver = node.receiver.to_s
|
66
|
+
add_error "add model virtual attribute (for #{receiver})" if params_dup?(assignments(receiver).collect {|h| h[:arguments]})
|
70
67
|
end
|
71
68
|
end
|
72
69
|
|
73
70
|
# if the nodes are duplicated.
|
74
71
|
def params_dup?(nodes)
|
75
72
|
return false if nodes.nil?
|
76
|
-
!nodes.
|
73
|
+
!dups(nodes).empty?
|
74
|
+
end
|
75
|
+
|
76
|
+
# get the assignments of receiver.
|
77
|
+
def assignments(receiver)
|
78
|
+
@assignments[receiver] ||= []
|
77
79
|
end
|
78
80
|
|
79
|
-
#
|
80
|
-
|
81
|
-
|
81
|
+
# Get the duplicate entries from an Enumerable.
|
82
|
+
#
|
83
|
+
# @return [Enumerable] the duplicate entries.
|
84
|
+
def dups(nodes)
|
85
|
+
nodes.inject({}) {|h,v| h[v]=h[v].to_i+1; h}.reject{|k,v| v==1}.keys
|
82
86
|
end
|
83
87
|
end
|
84
88
|
end
|
@@ -11,10 +11,10 @@ module RailsBestPractices
|
|
11
11
|
#
|
12
12
|
# Review process:
|
13
13
|
# only check the command and command_calls nodes and at the end of review process,
|
14
|
-
# if the
|
15
|
-
# if the
|
14
|
+
# if the receiver of command node is "create_table", then remember the table names
|
15
|
+
# if the receiver of command_call node is "integer" and suffix with id, then remember it as foreign key
|
16
16
|
# if the sujbect of command_call node is "string", the name of it is _type suffixed and there is an integer column _id suffixed, then remember it as polymorphic foreign key
|
17
|
-
# if the
|
17
|
+
# if the receiver of command node is "add_index", then remember the index columns
|
18
18
|
# after all of these, at the end of review process
|
19
19
|
#
|
20
20
|
# ActiveRecord::Schema.define(version: 20101201111111) do
|
@@ -24,14 +24,9 @@ module RailsBestPractices
|
|
24
24
|
# if there are any foreign keys not existed in index columns,
|
25
25
|
# then the foreign keys should add db index.
|
26
26
|
class AlwaysAddDbIndexReview < Review
|
27
|
-
include Afterable
|
28
|
-
|
29
27
|
interesting_nodes :command, :command_call
|
30
28
|
interesting_files SCHEMA_FILE
|
31
|
-
|
32
|
-
def url
|
33
|
-
"http://rails-bestpractices.com/posts/21-always-add-db-index"
|
34
|
-
end
|
29
|
+
url "http://rails-bestpractices.com/posts/21-always-add-db-index"
|
35
30
|
|
36
31
|
def initialize
|
37
32
|
super
|
@@ -44,11 +39,9 @@ module RailsBestPractices
|
|
44
39
|
#
|
45
40
|
# if the message of command_call node is "create_table", then remember the table name.
|
46
41
|
# if the message of command_call node is "add_index", then remember it as index columns.
|
47
|
-
|
48
|
-
|
49
|
-
when "integer", "string"
|
42
|
+
add_callback :start_command_call do |node|
|
43
|
+
if %w(integer string).include? node.message.to_s
|
50
44
|
remember_foreign_key_columns(node)
|
51
|
-
else
|
52
45
|
end
|
53
46
|
end
|
54
47
|
|
@@ -59,7 +52,7 @@ module RailsBestPractices
|
|
59
52
|
#
|
60
53
|
# if the message of command node is "type" and the name of argument is _type suffixed,
|
61
54
|
# then remember it with _id suffixed column as polymorphic foreign key.
|
62
|
-
|
55
|
+
add_callback :start_command do |node|
|
63
56
|
case node.message.to_s
|
64
57
|
when "create_table"
|
65
58
|
remember_table_nodes(node)
|
@@ -73,14 +66,14 @@ module RailsBestPractices
|
|
73
66
|
# compare foreign keys and index columns,
|
74
67
|
# if there are any foreign keys not existed in index columns,
|
75
68
|
# then we should add db index for that foreign keys.
|
76
|
-
|
69
|
+
add_callback :after_check do
|
77
70
|
remove_table_not_exist_foreign_keys
|
78
71
|
remove_only_type_foreign_keys
|
79
72
|
combine_polymorphic_foreign_keys
|
80
73
|
@foreign_keys.each do |table, foreign_key|
|
81
74
|
table_node = @table_nodes[table]
|
82
75
|
foreign_key.each do |column|
|
83
|
-
if
|
76
|
+
if not_indexed?(table, column)
|
84
77
|
add_error "always add db index (#{table} => [#{Array(column).join(', ')}])", table_node.file, table_node.line
|
85
78
|
end
|
86
79
|
end
|
@@ -160,7 +153,7 @@ module RailsBestPractices
|
|
160
153
|
end
|
161
154
|
|
162
155
|
# check if the table's column is indexed.
|
163
|
-
def
|
156
|
+
def not_indexed?(table, column)
|
164
157
|
index_columns = @index_columns[table]
|
165
158
|
!index_columns || !index_columns.any? { |e| greater_than_or_equal(Array(e), Array(column)) }
|
166
159
|
end
|
@@ -17,13 +17,10 @@ module RailsBestPractices
|
|
17
17
|
class DryBundlerInCapistranoReview < Review
|
18
18
|
interesting_nodes :command
|
19
19
|
interesting_files DEPLOY_FILES
|
20
|
-
|
21
|
-
def url
|
22
|
-
"http://rails-bestpractices.com/posts/51-dry-bundler-in-capistrano"
|
23
|
-
end
|
20
|
+
url "http://rails-bestpractices.com/posts/51-dry-bundler-in-capistrano"
|
24
21
|
|
25
22
|
# check call node to see if it is with message "namespace" and argument "bundler".
|
26
|
-
|
23
|
+
add_callback :start_command do |node|
|
27
24
|
if "namespace" == node.message.to_s && "bundler" == node.arguments.all[0].to_s
|
28
25
|
add_error "dry bundler in capistrano"
|
29
26
|
end
|
@@ -15,24 +15,13 @@ module RailsBestPractices
|
|
15
15
|
|
16
16
|
VALID_SYMBOL_KEY = /\A[@$_A-Za-z]([_\w]*[!_=?\w])?\z/
|
17
17
|
|
18
|
-
def initialize(options = {})
|
19
|
-
super()
|
20
|
-
@only_symbol = options[:only_symbol]
|
21
|
-
@only_string = options[:only_string]
|
22
|
-
end
|
23
|
-
|
24
18
|
# check hash node to see if it is ruby 1.8 style.
|
25
|
-
|
26
|
-
if !empty_hash?(node) &&
|
27
|
-
hash_is_18?(node) &&
|
28
|
-
valid_keys?(node) &&
|
29
|
-
!haml_class_node?(node)
|
19
|
+
add_callback :start_hash, :start_bare_assoc_hash do |node|
|
20
|
+
if !empty_hash?(node) && hash_is_18?(node) && valid_keys?(node)
|
30
21
|
add_error "change Hash Syntax to 1.9"
|
31
22
|
end
|
32
23
|
end
|
33
24
|
|
34
|
-
alias_method :start_bare_assoc_hash, :start_hash
|
35
|
-
|
36
25
|
protected
|
37
26
|
# check if hash node is empty.
|
38
27
|
def empty_hash?(node)
|
@@ -44,18 +33,7 @@ module RailsBestPractices
|
|
44
33
|
pair_nodes = :hash == node.sexp_type ? node[1][1] : node[1]
|
45
34
|
return false if pair_nodes.blank?
|
46
35
|
|
47
|
-
pair_nodes.
|
48
|
-
if @only_symbol
|
49
|
-
return true if :symbol_literal == pair_nodes[i][1].sexp_type
|
50
|
-
elsif @only_string
|
51
|
-
return true if :string_literal == pair_nodes[i][1].sexp_type
|
52
|
-
elsif :symbol_literal == pair_nodes[i][1].sexp_type ||
|
53
|
-
:string_literal == pair_nodes[i][1].sexp_type
|
54
|
-
return true
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
false
|
36
|
+
pair_nodes.any? { |pair_node| :symbol_literal == pair_node[1].sexp_type }
|
59
37
|
end
|
60
38
|
|
61
39
|
# check if the hash keys are valid to be converted to ruby 1.9
|
@@ -63,11 +41,6 @@ module RailsBestPractices
|
|
63
41
|
def valid_keys?(node)
|
64
42
|
node.hash_keys.all? { |key| key =~ VALID_SYMBOL_KEY }
|
65
43
|
end
|
66
|
-
|
67
|
-
# check if hash is generated by haml class or id nodes.
|
68
|
-
def haml_class_node?(node)
|
69
|
-
node.hash_size == 1 && (node.hash_keys.first == "class" || node.hash_keys.first == "id")
|
70
|
-
end
|
71
44
|
end
|
72
45
|
end
|
73
46
|
end
|
@@ -18,15 +18,12 @@ module RailsBestPractices
|
|
18
18
|
# if the message is "create" or "create!",
|
19
19
|
# then it should be isolated to db seed.
|
20
20
|
# if the message is "save" or "save!",
|
21
|
-
# and the
|
21
|
+
# and the receiver is included in new variables,
|
22
22
|
# then it should be isolated to db seed.
|
23
23
|
class IsolateSeedDataReview < Review
|
24
24
|
interesting_nodes :call, :assign
|
25
25
|
interesting_files MIGRATION_FILES
|
26
|
-
|
27
|
-
def url
|
28
|
-
"http://rails-bestpractices.com/posts/20-isolating-seed-data"
|
29
|
-
end
|
26
|
+
url "http://rails-bestpractices.com/posts/20-isolating-seed-data"
|
30
27
|
|
31
28
|
def initialize
|
32
29
|
super
|
@@ -37,7 +34,7 @@ module RailsBestPractices
|
|
37
34
|
#
|
38
35
|
# if the right value of the node is a call node with "new" message,
|
39
36
|
# then remember it as new variables.
|
40
|
-
|
37
|
+
add_callback :start_assign do |node|
|
41
38
|
remember_new_variable(node)
|
42
39
|
end
|
43
40
|
|
@@ -47,9 +44,9 @@ module RailsBestPractices
|
|
47
44
|
# then you should isolate it to seed data.
|
48
45
|
#
|
49
46
|
# if the message of the call node is "save" or "save!",
|
50
|
-
# and the
|
47
|
+
# and the receiver of the call node is included in @new_variables,
|
51
48
|
# then you should isolate it to seed data.
|
52
|
-
|
49
|
+
add_callback :start_call do |node|
|
53
50
|
if ["create", "create!"].include? node.message.to_s
|
54
51
|
add_error("isolate seed data")
|
55
52
|
elsif ["save", "save!"].include? node.message.to_s
|
@@ -68,9 +65,9 @@ module RailsBestPractices
|
|
68
65
|
end
|
69
66
|
end
|
70
67
|
|
71
|
-
# see if the
|
68
|
+
# see if the receiver of the call node is included in the @new_varaibles.
|
72
69
|
def new_record?(node)
|
73
|
-
@new_variables.include? node.
|
70
|
+
@new_variables.include? node.receiver.to_s
|
74
71
|
end
|
75
72
|
end
|
76
73
|
end
|
@@ -19,24 +19,20 @@ module RailsBestPractices
|
|
19
19
|
class KeepFindersOnTheirOwnModelReview < Review
|
20
20
|
interesting_nodes :method_add_arg
|
21
21
|
interesting_files MODEL_FILES
|
22
|
+
url "http://rails-bestpractices.com/posts/13-keep-finders-on-their-own-model"
|
22
23
|
|
23
24
|
FINDERS = %w(find all first last)
|
24
25
|
|
25
|
-
def url
|
26
|
-
"http://rails-bestpractices.com/posts/13-keep-finders-on-their-own-model"
|
27
|
-
end
|
28
|
-
|
29
26
|
# check all the call nodes to see if there is a finder for other model.
|
30
27
|
#
|
31
28
|
# if the call node is
|
32
29
|
#
|
33
30
|
# 1. the message of call node is one of the find, all, first or last
|
34
|
-
# 2. the
|
31
|
+
# 2. the receiver of call node is also a call node (it's the other model)
|
35
32
|
# 3. the any of its arguments is a hash (complex finder)
|
36
33
|
#
|
37
34
|
# then it should keep finders on its own model.
|
38
|
-
|
39
|
-
def start_method_add_arg(node)
|
35
|
+
add_callback :start_method_add_arg do |node|
|
40
36
|
add_error "keep finders on their own model" if other_finder?(node)
|
41
37
|
end
|
42
38
|
|
@@ -44,12 +40,12 @@ module RailsBestPractices
|
|
44
40
|
# check if the call node is the finder of other model.
|
45
41
|
#
|
46
42
|
# the message of the node should be one of find, all, first or last,
|
47
|
-
# and the
|
43
|
+
# and the receiver of the node should be with message :call (this is the other model),
|
48
44
|
# and any of its arguments is a hash,
|
49
45
|
# then it is the finder of other model.
|
50
46
|
def other_finder?(node)
|
51
47
|
FINDERS.include?(node[1].message.to_s) &&
|
52
|
-
:call == node[1].
|
48
|
+
:call == node[1].receiver.sexp_type &&
|
53
49
|
node.arguments.grep_nodes_count(sexp_type: :bare_assoc_hash) > 0
|
54
50
|
end
|
55
51
|
end
|
@@ -11,28 +11,25 @@ module RailsBestPractices
|
|
11
11
|
#
|
12
12
|
# Review process:
|
13
13
|
# check all method calls to see if there is method call to the association object.
|
14
|
-
# if there is a call node whose
|
14
|
+
# if there is a call node whose receiver is an object of model (compare by name),
|
15
15
|
# and whose message is an association of that model (also compare by name),
|
16
16
|
# and outer the call node, it is also a call node,
|
17
17
|
# then it violate the law of demeter.
|
18
18
|
class LawOfDemeterReview < Review
|
19
19
|
interesting_nodes :call
|
20
20
|
interesting_files ALL_FILES
|
21
|
+
url "http://rails-bestpractices.com/posts/15-the-law-of-demeter"
|
21
22
|
|
22
23
|
ASSOCIATION_METHODS = %w(belongs_to has_one)
|
23
24
|
|
24
|
-
def url
|
25
|
-
"http://rails-bestpractices.com/posts/15-the-law-of-demeter"
|
26
|
-
end
|
27
|
-
|
28
25
|
# check the call node,
|
29
26
|
#
|
30
|
-
# if the
|
31
|
-
# and the
|
32
|
-
# and the message of the
|
27
|
+
# if the receiver of the call node is also a call node,
|
28
|
+
# and the receiver of the receiver call node matchs one of the class names,
|
29
|
+
# and the message of the receiver call node matchs one of the association name with the class name,
|
33
30
|
# then it violates the law of demeter.
|
34
|
-
|
35
|
-
if :call == node.
|
31
|
+
add_callback :start_call do |node|
|
32
|
+
if :call == node.receiver.sexp_type && need_delegate?(node)
|
36
33
|
add_error "law of demeter"
|
37
34
|
end
|
38
35
|
end
|
@@ -40,13 +37,13 @@ module RailsBestPractices
|
|
40
37
|
private
|
41
38
|
# check if the call node can use delegate to avoid violating law of demeter.
|
42
39
|
#
|
43
|
-
# if the
|
44
|
-
# and the message of
|
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,
|
45
42
|
# then it needs delegate.
|
46
43
|
def need_delegate?(node)
|
47
44
|
return unless variable(node)
|
48
45
|
class_name = variable(node).to_s.sub('@', '').classify
|
49
|
-
association_name = node.
|
46
|
+
association_name = node.receiver.message.to_s
|
50
47
|
association = model_associations.get_association(class_name, association_name)
|
51
48
|
attribute_name = node.message.to_s
|
52
49
|
association && ASSOCIATION_METHODS.include?(association["meta"]) &&
|
@@ -14,35 +14,32 @@ module RailsBestPractices
|
|
14
14
|
class MoveCodeIntoControllerReview < Review
|
15
15
|
interesting_nodes :method_add_arg, :assign
|
16
16
|
interesting_files VIEW_FILES
|
17
|
+
url "http://rails-bestpractices.com/posts/24-move-code-into-controller"
|
17
18
|
|
18
19
|
FINDERS = %w(find all first last)
|
19
20
|
|
20
|
-
def url
|
21
|
-
"http://rails-bestpractices.com/posts/24-move-code-into-controller"
|
22
|
-
end
|
23
|
-
|
24
21
|
# check method_add_arg nodes.
|
25
22
|
#
|
26
|
-
# if the
|
23
|
+
# if the receiver of the method_add_arg node is a constant,
|
27
24
|
# and the message of the method_add_arg node is one of the find, all, first and last,
|
28
25
|
# then it is a finder and should be moved to controller.
|
29
|
-
|
26
|
+
add_callback :start_method_add_arg do |node|
|
30
27
|
add_error "move code into controller" if finder?(node)
|
31
28
|
end
|
32
29
|
|
33
30
|
# check assign nodes.
|
34
31
|
#
|
35
|
-
# if the
|
32
|
+
# if the receiver of the right value node is a constant,
|
36
33
|
# and the message of the right value node is one of the find, all, first and last,
|
37
34
|
# then it is a finder and should be moved to controller.
|
38
|
-
|
35
|
+
add_callback :start_assign do |node|
|
39
36
|
add_error "move code into controller", node.file, node.right_value.line if finder?(node.right_value)
|
40
37
|
end
|
41
38
|
|
42
39
|
private
|
43
40
|
# check if the node is a finder call node.
|
44
41
|
def finder?(node)
|
45
|
-
node.
|
42
|
+
node.receiver.const? && FINDERS.include?(node.message.to_s)
|
46
43
|
end
|
47
44
|
end
|
48
45
|
end
|
@@ -21,10 +21,7 @@ module RailsBestPractices
|
|
21
21
|
class MoveCodeIntoHelperReview < Review
|
22
22
|
interesting_nodes :method_add_arg
|
23
23
|
interesting_files VIEW_FILES
|
24
|
-
|
25
|
-
def url
|
26
|
-
"http://rails-bestpractices.com/posts/26-move-code-into-helper"
|
27
|
-
end
|
24
|
+
url "http://rails-bestpractices.com/posts/26-move-code-into-helper"
|
28
25
|
|
29
26
|
def initialize(options = {})
|
30
27
|
super()
|
@@ -36,7 +33,7 @@ module RailsBestPractices
|
|
36
33
|
# if the first argument of options_for_select method call is an array,
|
37
34
|
# and the size of the array is more than @array_count defined,
|
38
35
|
# then the options_for_select helper should be moved into helper.
|
39
|
-
|
36
|
+
add_callback :start_method_add_arg do |node|
|
40
37
|
add_error "move code into helper (array_count >= #{@array_count})" if complex_select_options?(node)
|
41
38
|
end
|
42
39
|
|