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.
Files changed (76) hide show
  1. data/.gitignore +1 -0
  2. data/README.md +11 -6
  3. data/assets/result.html.erb +76 -46
  4. data/install_supported_rubies.sh +3 -0
  5. data/lib/rails_best_practices.rb +2 -1
  6. data/lib/rails_best_practices/analyzer.rb +10 -8
  7. data/lib/rails_best_practices/core.rb +0 -4
  8. data/lib/rails_best_practices/core/check.rb +41 -117
  9. data/lib/rails_best_practices/core/error.rb +3 -9
  10. data/lib/rails_best_practices/core/runner.rb +20 -80
  11. data/lib/rails_best_practices/lexicals/long_line_check.rb +2 -1
  12. data/lib/rails_best_practices/lexicals/remove_tab_check.rb +1 -3
  13. data/lib/rails_best_practices/lexicals/remove_trailing_whitespace_check.rb +1 -3
  14. data/lib/rails_best_practices/prepares/config_prepare.rb +1 -1
  15. data/lib/rails_best_practices/prepares/controller_prepare.rb +7 -8
  16. data/lib/rails_best_practices/prepares/helper_prepare.rb +2 -2
  17. data/lib/rails_best_practices/prepares/mailer_prepare.rb +1 -1
  18. data/lib/rails_best_practices/prepares/model_prepare.rb +6 -7
  19. data/lib/rails_best_practices/prepares/route_prepare.rb +12 -13
  20. data/lib/rails_best_practices/prepares/schema_prepare.rb +2 -2
  21. data/lib/rails_best_practices/reviews/add_model_virtual_attribute_review.rb +19 -15
  22. data/lib/rails_best_practices/reviews/always_add_db_index_review.rb +10 -17
  23. data/lib/rails_best_practices/reviews/dry_bundler_in_capistrano_review.rb +2 -5
  24. data/lib/rails_best_practices/reviews/hash_syntax_review.rb +3 -30
  25. data/lib/rails_best_practices/reviews/isolate_seed_data_review.rb +7 -10
  26. data/lib/rails_best_practices/reviews/keep_finders_on_their_own_model_review.rb +5 -9
  27. data/lib/rails_best_practices/reviews/law_of_demeter_review.rb +10 -13
  28. data/lib/rails_best_practices/reviews/move_code_into_controller_review.rb +6 -9
  29. data/lib/rails_best_practices/reviews/move_code_into_helper_review.rb +2 -5
  30. data/lib/rails_best_practices/reviews/move_code_into_model_review.rb +7 -13
  31. data/lib/rails_best_practices/reviews/move_finder_to_named_scope_review.rb +3 -6
  32. data/lib/rails_best_practices/reviews/move_model_logic_into_model_review.rb +6 -9
  33. data/lib/rails_best_practices/reviews/needless_deep_nesting_review.rb +3 -6
  34. data/lib/rails_best_practices/reviews/not_use_default_route_review.rb +4 -7
  35. data/lib/rails_best_practices/reviews/not_use_time_ago_in_words_review.rb +2 -5
  36. data/lib/rails_best_practices/reviews/overuse_route_customizations_review.rb +7 -10
  37. data/lib/rails_best_practices/reviews/protect_mass_assignment_review.rb +2 -5
  38. data/lib/rails_best_practices/reviews/remove_empty_helpers_review.rb +2 -5
  39. data/lib/rails_best_practices/reviews/remove_unused_methods_in_controllers_review.rb +8 -6
  40. data/lib/rails_best_practices/reviews/remove_unused_methods_in_helpers_review.rb +1 -2
  41. data/lib/rails_best_practices/reviews/remove_unused_methods_in_models_review.rb +4 -5
  42. data/lib/rails_best_practices/reviews/replace_complex_creation_with_factory_method_review.rb +9 -12
  43. data/lib/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review.rb +2 -13
  44. data/lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb +18 -26
  45. data/lib/rails_best_practices/reviews/review.rb +6 -7
  46. data/lib/rails_best_practices/reviews/simplify_render_in_controllers_review.rb +2 -5
  47. data/lib/rails_best_practices/reviews/simplify_render_in_views_review.rb +2 -5
  48. data/lib/rails_best_practices/reviews/use_before_filter_review.rb +2 -5
  49. data/lib/rails_best_practices/reviews/use_model_association_review.rb +11 -14
  50. data/lib/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review.rb +11 -8
  51. data/lib/rails_best_practices/reviews/use_observer_review.rb +8 -11
  52. data/lib/rails_best_practices/reviews/use_parentheses_in_method_def_review.rb +1 -1
  53. data/lib/rails_best_practices/reviews/use_query_attribute_review.rb +12 -18
  54. data/lib/rails_best_practices/reviews/use_say_with_time_in_migrations_review.rb +7 -10
  55. data/lib/rails_best_practices/reviews/use_scope_access_review.rb +4 -10
  56. data/lib/rails_best_practices/version.rb +1 -1
  57. data/rails_best_practices.gemspec +1 -1
  58. data/rails_best_practices.yml +5 -5
  59. data/spec/rails_best_practices/core/check_spec.rb +0 -67
  60. data/spec/rails_best_practices/prepares/controller_prepare_spec.rb +0 -1
  61. data/spec/rails_best_practices/prepares/model_prepare_spec.rb +0 -4
  62. data/spec/rails_best_practices/reviews/hash_syntax_review_spec.rb +3 -30
  63. data/spec/rails_best_practices/reviews/remove_unused_methods_in_controllers_review_spec.rb +22 -0
  64. data/spec/rails_best_practices/reviews/remove_unused_methods_in_models_review_spec.rb +19 -0
  65. data/spec/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review_spec.rb +2 -2
  66. data/spec/spec_helper.rb +0 -4
  67. metadata +28 -41
  68. data/Gemfile.lock +0 -71
  69. data/lib/rails_best_practices/core/checking_visitor.rb +0 -80
  70. data/lib/rails_best_practices/core/nil.rb +0 -37
  71. data/lib/rails_best_practices/core_ext/enumerable.rb +0 -9
  72. data/lib/rails_best_practices/core_ext/sexp.rb +0 -840
  73. data/spec/rails_best_practices/core/checking_visitor_spec.rb +0 -79
  74. data/spec/rails_best_practices/core/nil_spec.rb +0 -37
  75. data/spec/rails_best_practices/core_ext/enumerable_spec.rb +0 -7
  76. 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
- def start_command(node)
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
- def start_command_call(node)
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 subject and arguments,
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 subject of save or save! call node should be the same with the subject of attribute assignment nodes
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
- def start_def(node)
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.subject.to_s) << {message: left_value.message.to_s, arguments: aref_node.to_s}
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 subject of this call node,
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
- subject = node.subject.to_s
69
- add_error "add model virtual attribute (for #{subject})" if params_dup?(assignments(subject).collect {|h| h[:arguments]})
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.dups.empty?
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
- # get the assignments of subject.
80
- def assignments(subject)
81
- @assignments[subject] ||= []
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 subject of command node is "create_table", then remember the table names
15
- # if the subject of command_call node is "integer" and suffix with id, then remember it as foreign key
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 subject of command node is "add_index", then remember the index columns
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
- def start_command_call(node)
48
- case node.message.to_s
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
- def start_command(node)
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
- def after_review
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 indexed?(table, column)
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 indexed?(table, column)
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
- def start_command(node)
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
- def start_hash(node)
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.size.times do |i|
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 subject is included in new variables,
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
- def start_assign(node)
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 subject of the call node is included in @new_variables,
47
+ # and the receiver of the call node is included in @new_variables,
51
48
  # then you should isolate it to seed data.
52
- def start_call(node)
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 subject of the call node is included in the @new_varaibles.
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.subject.to_s
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 subject of call node is also a call node (it's the other model)
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 subject of the node should be with message :call (this is the other model),
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].subject.sexp_type &&
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 subject is an object of model (compare by name),
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 subject of the call node is also a call node,
31
- # and the subject of the subject call node matchs one of the class names,
32
- # and the message of the subject call node matchs one of the association name with the class name,
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
- def start_call(node)
35
- if :call == node.subject.sexp_type && need_delegate?(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 subject of subject of the call node matchs any in model names,
44
- # and the message of subject of the call node matchs any in association names,
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.subject.message.to_s
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 subject of the method_add_arg node is a constant,
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
- def start_method_add_arg(node)
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 subject of the right value node is a constant,
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
- def start_assign(node)
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.subject.const? && FINDERS.include?(node.message.to_s)
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
- def start_method_add_arg(node)
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