rails_best_practices 1.20.0 → 1.22.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.
Files changed (140) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/Gemfile +2 -1
  4. data/Gemfile.lock +49 -43
  5. data/Guardfile +2 -0
  6. data/Rakefile +2 -0
  7. data/assets/result.html.erb +2 -0
  8. data/lib/rails_best_practices/analyzer.rb +59 -48
  9. data/lib/rails_best_practices/core/check.rb +39 -32
  10. data/lib/rails_best_practices/core/checks_loader.rb +8 -6
  11. data/lib/rails_best_practices/core/configs.rb +1 -2
  12. data/lib/rails_best_practices/core/controllers.rb +1 -2
  13. data/lib/rails_best_practices/core/error.rb +1 -1
  14. data/lib/rails_best_practices/core/helpers.rb +1 -2
  15. data/lib/rails_best_practices/core/mailers.rb +1 -2
  16. data/lib/rails_best_practices/core/methods.rb +21 -16
  17. data/lib/rails_best_practices/core/model_associations.rb +9 -4
  18. data/lib/rails_best_practices/core/models.rb +1 -2
  19. data/lib/rails_best_practices/core/modules.rb +1 -1
  20. data/lib/rails_best_practices/core/routes.rb +2 -2
  21. data/lib/rails_best_practices/core/runner.rb +49 -34
  22. data/lib/rails_best_practices/inline_disables/comment_ripper.rb +19 -0
  23. data/lib/rails_best_practices/inline_disables/inline_disable.rb +50 -0
  24. data/lib/rails_best_practices/inline_disables.rb +3 -0
  25. data/lib/rails_best_practices/lexicals/long_line_check.rb +7 -3
  26. data/lib/rails_best_practices/option_parser.rb +22 -6
  27. data/lib/rails_best_practices/prepares/controller_prepare.rb +15 -3
  28. data/lib/rails_best_practices/prepares/gemfile_prepare.rb +1 -1
  29. data/lib/rails_best_practices/prepares/helper_prepare.rb +6 -1
  30. data/lib/rails_best_practices/prepares/initializer_prepare.rb +2 -2
  31. data/lib/rails_best_practices/prepares/mailer_prepare.rb +1 -0
  32. data/lib/rails_best_practices/prepares/model_prepare.rb +52 -12
  33. data/lib/rails_best_practices/prepares/route_prepare.rb +16 -10
  34. data/lib/rails_best_practices/prepares.rb +1 -1
  35. data/lib/rails_best_practices/reviews/add_model_virtual_attribute_review.rb +15 -13
  36. data/lib/rails_best_practices/reviews/always_add_db_index_review.rb +34 -29
  37. data/lib/rails_best_practices/reviews/check_destroy_return_value_review.rb +14 -5
  38. data/lib/rails_best_practices/reviews/check_save_return_value_review.rb +19 -8
  39. data/lib/rails_best_practices/reviews/hash_syntax_review.rb +5 -5
  40. data/lib/rails_best_practices/reviews/isolate_seed_data_review.rb +4 -4
  41. data/lib/rails_best_practices/reviews/keep_finders_on_their_own_model_review.rb +7 -8
  42. data/lib/rails_best_practices/reviews/law_of_demeter_review.rb +6 -6
  43. data/lib/rails_best_practices/reviews/move_code_into_controller_review.rb +1 -1
  44. data/lib/rails_best_practices/reviews/move_code_into_helper_review.rb +6 -7
  45. data/lib/rails_best_practices/reviews/move_finder_to_named_scope_review.rb +7 -8
  46. data/lib/rails_best_practices/reviews/needless_deep_nesting_review.rb +12 -10
  47. data/lib/rails_best_practices/reviews/not_use_default_route_review.rb +1 -2
  48. data/lib/rails_best_practices/reviews/overuse_route_customizations_review.rb +5 -5
  49. data/lib/rails_best_practices/reviews/protect_mass_assignment_review.rb +5 -2
  50. data/lib/rails_best_practices/reviews/remove_unused_methods_in_controllers_review.rb +6 -3
  51. data/lib/rails_best_practices/reviews/remove_unused_methods_in_helpers_review.rb +6 -4
  52. data/lib/rails_best_practices/reviews/remove_unused_methods_in_models_review.rb +29 -9
  53. data/lib/rails_best_practices/reviews/replace_complex_creation_with_factory_method_review.rb +3 -3
  54. data/lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb +17 -15
  55. data/lib/rails_best_practices/reviews/simplify_render_in_controllers_review.rb +1 -2
  56. data/lib/rails_best_practices/reviews/simplify_render_in_views_review.rb +3 -3
  57. data/lib/rails_best_practices/reviews/use_before_filter_review.rb +2 -1
  58. data/lib/rails_best_practices/reviews/use_model_association_review.rb +5 -5
  59. data/lib/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review.rb +9 -8
  60. data/lib/rails_best_practices/reviews/use_observer_review.rb +9 -9
  61. data/lib/rails_best_practices/reviews/use_query_attribute_review.rb +26 -26
  62. data/lib/rails_best_practices/reviews/use_say_with_time_in_migrations_review.rb +8 -7
  63. data/lib/rails_best_practices/reviews/use_scope_access_review.rb +17 -15
  64. data/lib/rails_best_practices/reviews/use_turbo_sprockets_rails3_review.rb +2 -1
  65. data/lib/rails_best_practices/version.rb +1 -1
  66. data/lib/rails_best_practices.rb +2 -2
  67. data/rails_best_practices.gemspec +39 -38
  68. data/spec/fixtures/lib/rails_best_practices/plugins/reviews/not_use_rails_root_review.rb +1 -2
  69. data/spec/rails_best_practices/analyzer_spec.rb +73 -42
  70. data/spec/rails_best_practices/core/check_spec.rb +5 -5
  71. data/spec/rails_best_practices/core/checks_loader_spec.rb +3 -3
  72. data/spec/rails_best_practices/core/configs_spec.rb +1 -1
  73. data/spec/rails_best_practices/core/controllers_spec.rb +1 -1
  74. data/spec/rails_best_practices/core/error_spec.rb +21 -21
  75. data/spec/rails_best_practices/core/except_methods_spec.rb +7 -7
  76. data/spec/rails_best_practices/core/gems_spec.rb +4 -4
  77. data/spec/rails_best_practices/core/helpers_spec.rb +1 -1
  78. data/spec/rails_best_practices/core/klasses_spec.rb +3 -3
  79. data/spec/rails_best_practices/core/mailers_spec.rb +1 -1
  80. data/spec/rails_best_practices/core/methods_spec.rb +6 -6
  81. data/spec/rails_best_practices/core/model_associations_spec.rb +10 -6
  82. data/spec/rails_best_practices/core/model_attributes_spec.rb +4 -4
  83. data/spec/rails_best_practices/core/models_spec.rb +1 -1
  84. data/spec/rails_best_practices/core/modules_spec.rb +5 -5
  85. data/spec/rails_best_practices/core/routes_spec.rb +5 -5
  86. data/spec/rails_best_practices/core/runner_spec.rb +9 -7
  87. data/spec/rails_best_practices/core_ext/erubis_spec.rb +10 -10
  88. data/spec/rails_best_practices/inline_disables/inline_disable_spec.rb +62 -0
  89. data/spec/rails_best_practices/lexicals/long_line_check_spec.rb +11 -10
  90. data/spec/rails_best_practices/lexicals/remove_tab_check_spec.rb +6 -6
  91. data/spec/rails_best_practices/lexicals/remove_trailing_whitespace_check_spec.rb +6 -6
  92. data/spec/rails_best_practices/prepares/config_prepare_spec.rb +2 -2
  93. data/spec/rails_best_practices/prepares/controller_prepare_spec.rb +18 -10
  94. data/spec/rails_best_practices/prepares/gemfile_prepare_spec.rb +2 -2
  95. data/spec/rails_best_practices/prepares/helper_prepare_spec.rb +3 -3
  96. data/spec/rails_best_practices/prepares/initializer_prepare_spec.rb +3 -3
  97. data/spec/rails_best_practices/prepares/mailer_prepare_spec.rb +2 -2
  98. data/spec/rails_best_practices/prepares/model_prepare_spec.rb +79 -43
  99. data/spec/rails_best_practices/prepares/route_prepare_spec.rb +138 -77
  100. data/spec/rails_best_practices/prepares/schema_prepare_spec.rb +2 -2
  101. data/spec/rails_best_practices/reviews/add_model_virtual_attribute_review_spec.rb +18 -12
  102. data/spec/rails_best_practices/reviews/always_add_db_index_review_spec.rb +28 -22
  103. data/spec/rails_best_practices/reviews/check_destroy_return_value_review_spec.rb +15 -13
  104. data/spec/rails_best_practices/reviews/check_save_return_value_review_spec.rb +31 -21
  105. data/spec/rails_best_practices/reviews/default_scope_is_evil_review_spec.rb +6 -6
  106. data/spec/rails_best_practices/reviews/dry_bundler_in_capistrano_review_spec.rb +5 -5
  107. data/spec/rails_best_practices/reviews/hash_syntax_review_spec.rb +9 -9
  108. data/spec/rails_best_practices/reviews/isolate_seed_data_review_spec.rb +7 -7
  109. data/spec/rails_best_practices/reviews/keep_finders_on_their_own_model_review_spec.rb +9 -9
  110. data/spec/rails_best_practices/reviews/law_of_demeter_review_spec.rb +21 -14
  111. data/spec/rails_best_practices/reviews/move_code_into_controller_review_spec.rb +6 -6
  112. data/spec/rails_best_practices/reviews/move_code_into_helper_review_spec.rb +11 -6
  113. data/spec/rails_best_practices/reviews/move_code_into_model_review_spec.rb +26 -16
  114. data/spec/rails_best_practices/reviews/move_finder_to_named_scope_review_spec.rb +7 -7
  115. data/spec/rails_best_practices/reviews/move_model_logic_into_model_review_spec.rb +9 -7
  116. data/spec/rails_best_practices/reviews/needless_deep_nesting_review_spec.rb +9 -9
  117. data/spec/rails_best_practices/reviews/not_rescue_exception_review_spec.rb +9 -9
  118. data/spec/rails_best_practices/reviews/not_use_default_route_review_spec.rb +5 -5
  119. data/spec/rails_best_practices/reviews/not_use_time_ago_in_words_review_spec.rb +7 -7
  120. data/spec/rails_best_practices/reviews/overuse_route_customizations_review_spec.rb +7 -7
  121. data/spec/rails_best_practices/reviews/protect_mass_assignment_review_spec.rb +24 -19
  122. data/spec/rails_best_practices/reviews/remove_empty_helpers_review_spec.rb +6 -6
  123. data/spec/rails_best_practices/reviews/remove_unused_methods_in_controllers_review_spec.rb +44 -31
  124. data/spec/rails_best_practices/reviews/remove_unused_methods_in_helpers_review_spec.rb +17 -12
  125. data/spec/rails_best_practices/reviews/remove_unused_methods_in_models_review_spec.rb +46 -44
  126. data/spec/rails_best_practices/reviews/replace_complex_creation_with_factory_method_review_spec.rb +10 -8
  127. data/spec/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review_spec.rb +16 -10
  128. data/spec/rails_best_practices/reviews/restrict_auto_generated_routes_review_spec.rb +54 -31
  129. data/spec/rails_best_practices/reviews/simplify_render_in_controllers_review_spec.rb +9 -9
  130. data/spec/rails_best_practices/reviews/simplify_render_in_views_review_spec.rb +13 -13
  131. data/spec/rails_best_practices/reviews/use_before_filter_review_spec.rb +11 -9
  132. data/spec/rails_best_practices/reviews/use_model_association_review_spec.rb +7 -7
  133. data/spec/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review_spec.rb +21 -17
  134. data/spec/rails_best_practices/reviews/use_observer_review_spec.rb +6 -6
  135. data/spec/rails_best_practices/reviews/use_parentheses_in_method_def_review_spec.rb +9 -7
  136. data/spec/rails_best_practices/reviews/use_query_attribute_review_spec.rb +31 -24
  137. data/spec/rails_best_practices/reviews/use_say_with_time_in_migrations_review_spec.rb +15 -11
  138. data/spec/rails_best_practices/reviews/use_scope_access_review_spec.rb +14 -14
  139. data/spec/rails_best_practices/reviews/use_turbo_sprockets_rails3_review_spec.rb +10 -8
  140. metadata +12 -7
@@ -38,10 +38,9 @@ module RailsBestPractices
38
38
  else
39
39
  action_names = [second_argument.hash_value('to').to_s]
40
40
  end
41
- elsif first_argument.sexp_type == :symbol_literal && second_argument.try(:sexp_type) && \
41
+ elsif first_argument.sexp_type == :symbol_literal && second_argument.try(:sexp_type) &&
42
42
  second_argument.sexp_type == :symbol_literal
43
- action_names = node.arguments.all.select \
44
- { |arg| arg.sexp_type == :symbol_literal }.map(&:to_s)
43
+ action_names = node.arguments.all.select { |arg| arg.sexp_type == :symbol_literal }.map(&:to_s)
45
44
  else
46
45
  action_names = [first_argument.to_s]
47
46
  end
@@ -84,7 +83,10 @@ module RailsBestPractices
84
83
  action_name = options.hash_value('action').present? ? options.hash_value('action').to_s : '*'
85
84
  @routes.add_route(current_namespaces, controller_name, action_name)
86
85
  else
87
- route_node = options.hash_values.find { |value_node| value_node.sexp_type == :string_literal && value_node.to_s.include?('#') }
86
+ route_node =
87
+ options.hash_values.find do |value_node|
88
+ value_node.sexp_type == :string_literal && value_node.to_s.include?('#')
89
+ end
88
90
  if route_node.present?
89
91
  controller_name, action_name = route_node.to_s.split('#')
90
92
  @routes.add_route(current_namespaces, controller_name.underscore, action_name)
@@ -101,7 +103,10 @@ module RailsBestPractices
101
103
  options = node.arguments.all.last
102
104
  case options.sexp_type
103
105
  when :bare_assoc_hash
104
- route_node = options.hash_values.find { |value_node| value_node.sexp_type == :string_literal && value_node.to_s.include?('#') }
106
+ route_node =
107
+ options.hash_values.find do |value_node|
108
+ value_node.sexp_type == :string_literal && value_node.to_s.include?('#')
109
+ end
105
110
  if route_node.present?
106
111
  controller_name, action_name = route_node.to_s.split('#')
107
112
  @routes.add_route(current_namespaces, controller_name.underscore, action_name)
@@ -145,11 +150,12 @@ module RailsBestPractices
145
150
  if node.arguments.all.last.hash_value('module').present?
146
151
  @namespaces << node.arguments.all.last.hash_value('module').to_s
147
152
  end
148
- if node.arguments.all.last.hash_value('controller').present?
149
- @controller_name = [:scope, node.arguments.all.last.hash_value('controller').to_s]
150
- else
151
- @controller_name = @controller_name.try(:first) == :scope ? @controller_name : nil
152
- end
153
+ @controller_name =
154
+ if node.arguments.all.last.hash_value('controller').present?
155
+ [:scope, node.arguments.all.last.hash_value('controller').to_s]
156
+ else
157
+ @controller_name.try(:first) == :scope ? @controller_name : nil
158
+ end
153
159
  when 'with_options'
154
160
  argument = node.arguments.all.last
155
161
  if argument.sexp_type == :bare_assoc_hash && argument.hash_value('controller').present?
@@ -4,7 +4,7 @@ require_rel 'prepares'
4
4
 
5
5
  module RailsBestPractices
6
6
  module Prepares
7
- class <<self
7
+ class << self
8
8
  def klasses
9
9
  models + mailers + controllers
10
10
  end
@@ -46,8 +46,8 @@ module RailsBestPractices
46
46
 
47
47
  private
48
48
 
49
- # check an attribute assignment node, if there is a array reference node in the right value of assignment node,
50
- # then remember this attribute assignment.
49
+ # check an attribute assignment node, if there is a array reference node in the right value of assignment node,
50
+ # then remember this attribute assignment.
51
51
  def assign(node)
52
52
  left_value = node.left_value
53
53
  right_value = node.right_value
@@ -59,34 +59,36 @@ module RailsBestPractices
59
59
  end
60
60
  end
61
61
 
62
- # check a call node with message "save" or "save!",
63
- # if there exists an attribute assignment for the receiver of this call node,
64
- # and if the arguments of this attribute assignments has duplicated entries (different message and same arguments),
65
- # then this node needs to add a virtual attribute.
62
+ # check a call node with message "save" or "save!",
63
+ # if there exists an attribute assignment for the receiver of this call node,
64
+ # and if the arguments of this attribute assignments has duplicated entries (different message and same arguments),
65
+ # then this node needs to add a virtual attribute.
66
66
  def call_assignment(node)
67
67
  if ['save', 'save!'].include? node.message.to_s
68
68
  receiver = node.receiver.to_s
69
- add_error "add model virtual attribute (for #{receiver})" if params_dup?(assignments(receiver).collect { |h| h[:arguments] })
69
+ add_error "add model virtual attribute (for #{receiver})" if params_dup?(
70
+ assignments(receiver).collect { |h| h[:arguments] }
71
+ )
70
72
  end
71
73
  end
72
74
 
73
- # if the nodes are duplicated.
75
+ # if the nodes are duplicated.
74
76
  def params_dup?(nodes)
75
77
  return false if nodes.nil?
76
78
 
77
79
  !dups(nodes).empty?
78
80
  end
79
81
 
80
- # get the assignments of receiver.
82
+ # get the assignments of receiver.
81
83
  def assignments(receiver)
82
84
  @assignments[receiver] ||= []
83
85
  end
84
86
 
85
- # Get the duplicate entries from an Enumerable.
86
- #
87
- # @return [Enumerable] the duplicate entries.
87
+ # Get the duplicate entries from an Enumerable.
88
+ #
89
+ # @return [Enumerable] the duplicate entries.
88
90
  def dups(nodes)
89
- nodes.each_with_object({}) { |v, h| h[v] = h[v].to_i + 1; }.reject { |_k, v| v == 1 }.keys
91
+ nodes.each_with_object({}) { |v, h| h[v] = h[v].to_i + 1 }.reject { |_k, v| v == 1 }.keys
90
92
  end
91
93
  end
92
94
  end
@@ -75,18 +75,20 @@ module RailsBestPractices
75
75
  @foreign_keys.each do |table, foreign_key|
76
76
  table_node = @table_nodes[table]
77
77
  foreign_key.each do |column|
78
- if not_indexed?(table, column)
79
- add_error "always add db index (#{table} => [#{Array(column).join(', ')}])", table_node.file, table_node.line_number
80
- end
78
+ next unless not_indexed?(table, column)
79
+
80
+ add_error "always add db index (#{table} => [#{Array(column).join(', ')}])",
81
+ table_node.file,
82
+ table_node.line_number
81
83
  end
82
84
  end
83
85
  end
84
86
 
85
87
  private
86
88
 
87
- # remember the node as index columns, when used outside a table
88
- # block, i.e.
89
- # add_index :table_name, :column_name
89
+ # remember the node as index columns, when used outside a table
90
+ # block, i.e.
91
+ # add_index :table_name, :column_name
90
92
  def remember_index_columns_outside_table(node)
91
93
  table_name = node.arguments.all.first.to_s
92
94
  index_column = node.arguments.all[1].to_object
@@ -95,9 +97,9 @@ module RailsBestPractices
95
97
  @index_columns[table_name] << index_column
96
98
  end
97
99
 
98
- # remember the node as index columns, when used inside a table
99
- # block, i.e.
100
- # t.index [:column_name, ...]
100
+ # remember the node as index columns, when used inside a table
101
+ # block, i.e.
102
+ # t.index [:column_name, ...]
101
103
  def remember_index_columns_inside_table(node)
102
104
  table_name = @table_name
103
105
  index_column = node.arguments.all.first.to_object
@@ -106,31 +108,33 @@ module RailsBestPractices
106
108
  @index_columns[table_name] << index_column
107
109
  end
108
110
 
109
- # remember table nodes
111
+ # remember table nodes
110
112
  def remember_table_nodes(node)
111
113
  @table_name = node.arguments.all.first.to_s
112
114
  @table_nodes[@table_name] = node
113
115
  end
114
116
 
115
- # remember foreign key columns
117
+ # remember foreign key columns
116
118
  def remember_foreign_key_columns(node)
117
119
  table_name = @table_name
118
120
  foreign_key_column = node.arguments.all.first.to_s
119
121
  @foreign_keys[table_name] ||= []
120
122
  if foreign_key_column =~ /(.*?)_id$/
121
- if @foreign_keys[table_name].delete("#{$1}_type")
122
- @foreign_keys[table_name] << ["#{$1}_id", "#{$1}_type"]
123
- else
124
- @foreign_keys[table_name] << foreign_key_column
125
- end
123
+ @foreign_keys[table_name] <<
124
+ if @foreign_keys[table_name].delete("#{Regexp.last_match(1)}_type")
125
+ ["#{Regexp.last_match(1)}_id", "#{Regexp.last_match(1)}_type"]
126
+ else
127
+ foreign_key_column
128
+ end
126
129
  foreign_id_column = foreign_key_column
127
130
  elsif foreign_key_column =~ /(.*?)_type$/
128
- if @foreign_keys[table_name].delete("#{$1}_id")
129
- @foreign_keys[table_name] << ["#{$1}_id", "#{$1}_type"]
130
- else
131
- @foreign_keys[table_name] << foreign_key_column
132
- end
133
- foreign_id_column = "#{$1}_id"
131
+ @foreign_keys[table_name] <<
132
+ if @foreign_keys[table_name].delete("#{Regexp.last_match(1)}_id")
133
+ ["#{Regexp.last_match(1)}_id", "#{Regexp.last_match(1)}_type"]
134
+ else
135
+ foreign_key_column
136
+ end
137
+ foreign_id_column = "#{Regexp.last_match(1)}_id"
134
138
  end
135
139
 
136
140
  if foreign_id_column
@@ -142,7 +146,7 @@ module RailsBestPractices
142
146
  end
143
147
  end
144
148
 
145
- # remove the non foreign keys without corresponding tables.
149
+ # remove the non foreign keys without corresponding tables.
146
150
  def remove_table_not_exist_foreign_keys
147
151
  @foreign_keys.each do |table, foreign_keys|
148
152
  foreign_keys.delete_if do |key|
@@ -154,21 +158,22 @@ module RailsBestPractices
154
158
  end
155
159
  end
156
160
 
157
- # remove the non foreign keys with only _type column.
161
+ # remove the non foreign keys with only _type column.
158
162
  def remove_only_type_foreign_keys
159
163
  @foreign_keys.each do |_table, foreign_keys|
160
164
  foreign_keys.delete_if { |key| key.is_a?(String) && key =~ /_type$/ }
161
165
  end
162
166
  end
163
167
 
164
- # combine polymorphic foreign keys, e.g.
165
- # [tagger_id], [tagger_type] => [tagger_id, tagger_type]
168
+ # combine polymorphic foreign keys, e.g.
169
+ # [tagger_id], [tagger_type] => [tagger_id, tagger_type]
166
170
  def combine_polymorphic_foreign_keys
167
171
  @index_columns.each do |_table, foreign_keys|
168
172
  foreign_id_keys = foreign_keys.select { |key| key.size == 1 && key.first =~ /_id/ }
169
173
  foreign_type_keys = foreign_keys.select { |key| key.size == 1 && key.first =~ /_type/ }
170
174
  foreign_id_keys.each do |id_key|
171
- next unless type_key = foreign_type_keys.detect { |type_key| type_key.first == id_key.first.sub(/_id/, '') + '_type' }
175
+ next unless type_key =
176
+ foreign_type_keys.detect { |type_key| type_key.first == id_key.first.sub(/_id/, '') + '_type' }
172
177
 
173
178
  foreign_keys.delete(id_key)
174
179
  foreign_keys.delete(type_key)
@@ -177,13 +182,13 @@ module RailsBestPractices
177
182
  end
178
183
  end
179
184
 
180
- # check if the table's column is indexed.
185
+ # check if the table's column is indexed.
181
186
  def not_indexed?(table, column)
182
187
  index_columns = @index_columns[table]
183
188
  !index_columns || index_columns.none? { |e| greater_than_or_equal(Array(e), Array(column)) }
184
189
  end
185
190
 
186
- # check if more_array is greater than less_array or equal to less_array.
191
+ # check if more_array is greater than less_array or equal to less_array.
187
192
  def greater_than_or_equal(more_array, less_array)
188
193
  more_size = more_array.size
189
194
  less_size = less_array.size
@@ -10,7 +10,17 @@ module RailsBestPractices
10
10
  # Check all "save" calls to check the return value is used by a node we have visited.
11
11
  class CheckDestroyReturnValueReview < Review
12
12
  include Classable
13
- interesting_nodes :call, :command_call, :method_add_arg, :if, :ifop, :elsif, :unless, :if_mod, :unless_mod, :assign, :binary
13
+ interesting_nodes :call,
14
+ :command_call,
15
+ :method_add_arg,
16
+ :if,
17
+ :ifop,
18
+ :elsif,
19
+ :unless,
20
+ :if_mod,
21
+ :unless_mod,
22
+ :assign,
23
+ :binary
14
24
  interesting_files ALL_FILES
15
25
 
16
26
  add_callback :start_if, :start_ifop, :start_elsif, :start_unless, :start_if_mod, :start_unless_mod do |node|
@@ -21,14 +31,13 @@ module RailsBestPractices
21
31
  @used_return_value_of = node.right_value
22
32
  end
23
33
 
34
+ # Consider anything used in an expression like "A or B" as used
24
35
  add_callback :start_binary do |node|
25
- # Consider anything used in an expression like "A or B" as used
26
36
  if %w[&& || and or].include?(node[2].to_s)
27
37
  all_conditions = node.all_conditions
28
38
  # if our current binary is a subset of the @used_return_value_of
29
39
  # then don't overwrite it
30
- already_included = @used_return_value_of &&
31
- (all_conditions - @used_return_value_of).empty?
40
+ already_included = @used_return_value_of && (all_conditions - @used_return_value_of).empty?
32
41
 
33
42
  @used_return_value_of = node.all_conditions unless already_included
34
43
  end
@@ -37,7 +46,7 @@ module RailsBestPractices
37
46
  def return_value_is_used?(node)
38
47
  return false unless @used_return_value_of
39
48
 
40
- node == @used_return_value_of or @used_return_value_of.include?(node)
49
+ (node == @used_return_value_of) || @used_return_value_of.include?(node)
41
50
  end
42
51
 
43
52
  def model_classnames
@@ -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, :command_call, :method_add_arg, :if, :ifop, :elsif, :unless, :if_mod, :unless_mod, :assign, :binary
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
@@ -42,7 +51,7 @@ module RailsBestPractices
42
51
  def return_value_is_used?(node)
43
52
  return false unless @used_return_value_of
44
53
 
45
- node == @used_return_value_of or @used_return_value_of.include?(node)
54
+ (node == @used_return_value_of) || @used_return_value_of.include?(node)
46
55
  end
47
56
 
48
57
  def model_classnames
@@ -58,9 +67,11 @@ module RailsBestPractices
58
67
  end
59
68
  elsif message == 'create'
60
69
  # We're only interested in 'create' calls on model classes:
61
- possible_receiver_classes = [node.receiver.to_s] + classable_modules.map do |mod|
62
- "#{mod}::#{node.receiver}"
63
- end
70
+ possible_receiver_classes =
71
+ [node.receiver.to_s] +
72
+ classable_modules.map do |mod|
73
+ "#{mod}::#{node.receiver}"
74
+ end
64
75
  unless (possible_receiver_classes & model_classnames).empty?
65
76
  add_error "use 'create!' instead of 'create' as the latter may not always save"
66
77
  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,12 +23,12 @@ module RailsBestPractices
23
23
 
24
24
  protected
25
25
 
26
- # check if hash node is empty.
26
+ # check if hash node is empty.
27
27
  def empty_hash?(node)
28
28
  s(:hash, nil) == node || s(:bare_assoc_hash, nil) == node
29
29
  end
30
30
 
31
- # check if hash key/value pairs are ruby 1.8 style.
31
+ # check if hash key/value pairs are ruby 1.8 style.
32
32
  def hash_is_18?(node)
33
33
  pair_nodes = node.sexp_type == :hash ? node[1][1] : node[1]
34
34
  return false if pair_nodes.blank?
@@ -36,8 +36,8 @@ module RailsBestPractices
36
36
  pair_nodes.any? { |pair_node| pair_node[1].sexp_type == :symbol_literal }
37
37
  end
38
38
 
39
- # check if the hash keys are valid to be converted to ruby 1.9
40
- # syntax.
39
+ # check if the hash keys are valid to be converted to ruby 1.9
40
+ # syntax.
41
41
  def valid_keys?(node)
42
42
  node.hash_keys.all? { |key| key =~ VALID_SYMBOL_KEY }
43
43
  end
@@ -55,9 +55,9 @@ module RailsBestPractices
55
55
 
56
56
  private
57
57
 
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.
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
61
  def remember_new_variable(node)
62
62
  right_value = node.right_value
63
63
  if right_value.sexp_type == :method_add_arg && right_value.message.to_s == 'new'
@@ -65,7 +65,7 @@ module RailsBestPractices
65
65
  end
66
66
  end
67
67
 
68
- # see if the receiver 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.
69
69
  def new_record?(node)
70
70
  @new_variables.include? node.receiver.to_s
71
71
  end
@@ -37,15 +37,14 @@ module RailsBestPractices
37
37
 
38
38
  private
39
39
 
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.
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
46
  def other_finder?(node)
47
- FINDERS.include?(node[1].message.to_s) &&
48
- node[1].receiver.sexp_type == :call &&
47
+ FINDERS.include?(node[1].message.to_s) && node[1].receiver.sexp_type == :call &&
49
48
  node.arguments.grep_nodes_count(sexp_type: :bare_assoc_hash) > 0
50
49
  end
51
50
  end
@@ -35,11 +35,11 @@ module RailsBestPractices
35
35
 
36
36
  private
37
37
 
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.
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
43
  def need_delegate?(node)
44
44
  return unless variable(node)
45
45
 
@@ -55,7 +55,7 @@ module RailsBestPractices
55
55
  if association_name =~ /able$/
56
56
  models.each do |class_name|
57
57
  if model_associations.is_association?(class_name, association_name.sub(/able$/, '')) ||
58
- model_associations.is_association?(class_name, association_name.sub(/able$/, 's'))
58
+ model_associations.is_association?(class_name, association_name.sub(/able$/, 's'))
59
59
  return true if model_attributes.is_attribute?(class_name, attribute_name)
60
60
  end
61
61
  end
@@ -37,7 +37,7 @@ module RailsBestPractices
37
37
 
38
38
  private
39
39
 
40
- # check if the node is a finder call node.
40
+ # check if the node is a finder call node.
41
41
  def finder?(node)
42
42
  node.receiver.const? && FINDERS.include?(node.message.to_s)
43
43
  end
@@ -38,14 +38,13 @@ module RailsBestPractices
38
38
 
39
39
  private
40
40
 
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.
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
46
  def complex_select_options?(node)
47
- node[1].message.to_s == 'options_for_select' &&
48
- node.arguments.all.first.sexp_type == :array &&
47
+ node[1].message.to_s == 'options_for_select' && node.arguments.all.first.sexp_type == :array &&
49
48
  node.arguments.all.first.array_size > @array_count
50
49
  end
51
50
  end
@@ -29,15 +29,14 @@ module RailsBestPractices
29
29
 
30
30
  private
31
31
 
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.
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
38
  def finder?(node)
39
- FINDERS.include?(node[1].message.to_s) &&
40
- node[1].sexp_type == :call &&
39
+ FINDERS.include?(node[1].message.to_s) && node[1].sexp_type == :call &&
41
40
  node.arguments.grep_nodes_count(sexp_type: :bare_assoc_hash) > 0
42
41
  end
43
42
  end
@@ -51,17 +51,18 @@ module RailsBestPractices
51
51
 
52
52
  private
53
53
 
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.
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
63
  def recursively_check(node)
64
64
  shallow = @shallow_nodes.include? node
65
+
65
66
  if %i[command_call command].include?(node[1].sexp_type) && %w[resources resource].include?(node[1].message.to_s)
66
67
  hash_node = node[1].arguments.grep_node(sexp_type: :bare_assoc_hash)
67
68
  shallow ||= (hash_node && hash_node.hash_value('shallow').to_s == 'true')
@@ -72,7 +73,8 @@ module RailsBestPractices
72
73
  end
73
74
  @counter -= 1
74
75
  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)
76
+ add_error "needless deep nesting (nested_count > #{@nested_count})", @file, node.line_number if @counter >=
77
+ @nested_count && !@shallow_nodes.include?(node)
76
78
  end
77
79
  end
78
80
  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 node.message.to_s == 'match' &&
28
- node.arguments.all.first.to_s == ':controller(/:action(/:id(.:format)))'
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
@@ -41,11 +41,11 @@ module RailsBestPractices
41
41
 
42
42
  private
43
43
 
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.
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
49
  def member_and_collection_count_for_rails3(node)
50
50
  node[1].message.to_s == 'resources' ? node.grep_nodes_count(sexp_type: :command, message: VERBS) : 0
51
51
  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
@@ -73,13 +74,15 @@ module RailsBestPractices
73
74
  end
74
75
 
75
76
  def check_rails_builtin(node)
76
- if @whitelist_attributes || [node.to_s, node.message.to_s].any? { |str| %w[attr_accessible attr_protected].include? str }
77
+ if @whitelist_attributes ||
78
+ [node.to_s, node.message.to_s].any? { |str| %w[attr_accessible attr_protected].include? str }
77
79
  @mass_assignement = false
78
80
  end
79
81
  end
80
82
 
81
83
  def check_strong_parameters(command_node)
82
- if command_node.message.to_s == 'include' && command_node.arguments.all.first.to_s == 'ActiveModel::ForbiddenAttributesProtection'
84
+ if command_node.message.to_s == 'include' &&
85
+ command_node.arguments.all.first.to_s == 'ActiveModel::ForbiddenAttributesProtection'
83
86
  @mass_assignement = false
84
87
  end
85
88
  end
@@ -11,6 +11,7 @@ module RailsBestPractices
11
11
  # if they are not defined in routes,
12
12
  # and they are not called in controllers,
13
13
  # then they are the unused methods in controllers.
14
+
14
15
  class RemoveUnusedMethodsInControllersReview < Review
15
16
  include Classable
16
17
  include Moduleable
@@ -98,9 +99,11 @@ module RailsBestPractices
98
99
  end
99
100
  end
100
101
  @controller_methods.get_all_unused_methods.each do |method|
101
- unless excepted?(method)
102
- add_error "remove unused methods (#{method.class_name}##{method.method_name})", method.file, method.line_number
103
- end
102
+ next if excepted?(method)
103
+
104
+ add_error "remove unused methods (#{method.class_name}##{method.method_name})",
105
+ method.file,
106
+ method.line_number
104
107
  end
105
108
  end
106
109