rails_best_practices 1.8.0 → 1.9.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 (29) hide show
  1. data/.rvmrc +1 -1
  2. data/.travis.yml +1 -1
  3. data/Gemfile.lock +1 -1
  4. data/README.md +4 -2
  5. data/install_supported_rubies.sh +1 -1
  6. data/lib/rails_best_practices/core.rb +0 -1
  7. data/lib/rails_best_practices/core/check.rb +22 -3
  8. data/lib/rails_best_practices/core/checking_visitor.rb +24 -21
  9. data/lib/rails_best_practices/core/model_associations.rb +1 -1
  10. data/lib/rails_best_practices/core/routes.rb +3 -1
  11. data/lib/rails_best_practices/core_ext/sexp.rb +20 -13
  12. data/lib/rails_best_practices/prepares/controller_prepare.rb +8 -1
  13. data/lib/rails_best_practices/prepares/model_prepare.rb +1 -1
  14. data/lib/rails_best_practices/prepares/route_prepare.rb +16 -8
  15. data/lib/rails_best_practices/reviews.rb +1 -0
  16. data/lib/rails_best_practices/reviews/always_add_db_index_review.rb +1 -1
  17. data/lib/rails_best_practices/reviews/protect_mass_assignment_review.rb +45 -0
  18. data/lib/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review.rb +9 -1
  19. data/lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb +2 -2
  20. data/lib/rails_best_practices/reviews/use_before_filter_review.rb +1 -1
  21. data/lib/rails_best_practices/version.rb +1 -1
  22. data/rails_best_practices.gemspec +1 -1
  23. data/rails_best_practices.yml +1 -0
  24. data/rake_rubies.sh +2 -2
  25. data/spec/rails_best_practices/core_ext/sexp_spec.rb +15 -4
  26. data/spec/rails_best_practices/prepares/route_prepare_spec.rb +25 -2
  27. data/spec/rails_best_practices/reviews/protect_mass_assignment_review_spec.rb +67 -0
  28. metadata +30 -28
  29. data/lib/rails_best_practices/core_ext/string.rb +0 -5
data/.rvmrc CHANGED
@@ -1,2 +1,2 @@
1
1
  rvm_gemset_create_on_use_flag=1
2
- rvm gemset use ruby-1.9.2-p290@rails_best_practices
2
+ rvm gemset use ruby-1.9.3-p125@rails_best_practices
data/.travis.yml CHANGED
@@ -1 +1 @@
1
- rvm: 1.9.2
1
+ rvm: 1.9.3
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rails_best_practices (1.8.0)
4
+ rails_best_practices (1.9.0)
5
5
  activesupport
6
6
  colored
7
7
  erubis
data/README.md CHANGED
@@ -19,6 +19,8 @@ following template engines:
19
19
  * haml
20
20
  * slim
21
21
 
22
+ rails_best_practices works well only in ruby 1.9.2 and ruby 1.9.3 so far.
23
+
22
24
  Usage
23
25
  -----
24
26
 
@@ -78,8 +80,6 @@ Install
78
80
 
79
81
  rails_best_practices gem is rewritten based on ripper instead of ruby_parser to support ruby 1.9 new syntax.
80
82
 
81
- Ruby 1.9
82
-
83
83
  gem install rails_best_practices
84
84
 
85
85
  or add in Gemfile
@@ -143,6 +143,7 @@ Now you can customize this configuration file, the default configuration is as f
143
143
  RemoveUnusedMethodsInControllersCheck: { except_methods: [] }
144
144
  RemoveUnusedMethodsInHelpersCheck: { except_methods: [] }
145
145
  NotUseTimeAgoInWordsCheck: {}
146
+ ProtectMassAssignmentCheck: {}
146
147
 
147
148
  You can remove or comment one review to disable it, and you can change the options.
148
149
 
@@ -172,6 +173,7 @@ Model
172
173
  3. Use observer
173
174
  4. Use query attribute
174
175
  5. Remove unused methods in models
176
+ 6. Protect mass assignment
175
177
 
176
178
  Mailer
177
179
 
@@ -1,5 +1,5 @@
1
1
  #!/bin/bash
2
- rubies=( 1.8.7 1.9.2 ree )
2
+ rubies=( 1.9.2 1.9.3 )
3
3
  for x in ${rubies[*]}
4
4
  do
5
5
  rvm install $x
@@ -15,7 +15,6 @@ require 'rails_best_practices/core/controllers'
15
15
  require 'rails_best_practices/core/helpers'
16
16
  require 'rails_best_practices/core/routes'
17
17
 
18
- require 'rails_best_practices/core_ext/string'
19
18
  require 'rails_best_practices/core_ext/sexp'
20
19
  require 'rails_best_practices/core_ext/enumerable'
21
20
  require 'rails_best_practices/core_ext/erubis'
@@ -238,7 +238,7 @@ module RailsBestPractices
238
238
  module Callable
239
239
  def self.included(base)
240
240
  base.class_eval do
241
- interesting_nodes :call, :fcall, :var_ref, :command_call, :command, :alias, :bare_assoc_hash, :method_add_arg
241
+ interesting_nodes :call, :fcall, :var_ref, :vcall, :command_call, :command, :alias, :bare_assoc_hash, :method_add_arg
242
242
 
243
243
  # remembe the message of call node.
244
244
  add_callback "start_call" do |node|
@@ -255,6 +255,11 @@ module RailsBestPractices
255
255
  mark_used(node)
256
256
  end
257
257
 
258
+ # remembe name of vcall node.
259
+ add_callback "start_vcall" do |node|
260
+ mark_used(node)
261
+ end
262
+
258
263
  # skip start_command callback for these nodes
259
264
  def skip_command_callback_nodes
260
265
  []
@@ -346,7 +351,7 @@ module RailsBestPractices
346
351
  module InheritedResourcesable
347
352
  def self.included(base)
348
353
  base.class_eval do
349
- interesting_nodes :class, :var_ref
354
+ interesting_nodes :class, :var_ref, :vcall
350
355
  interesting_files CONTROLLER_FILES
351
356
 
352
357
  # check if the controller is inherit from InheritedResources::Base.
@@ -362,6 +367,13 @@ module RailsBestPractices
362
367
  @inherited_resources = true
363
368
  end
364
369
  end
370
+
371
+ # check if there is a DSL call inherit_resources.
372
+ add_callback "start_vcall" do |node|
373
+ if "inherit_resources" == node.to_s
374
+ @inherited_resources = true
375
+ end
376
+ end
365
377
  end
366
378
  end
367
379
  end
@@ -396,7 +408,7 @@ module RailsBestPractices
396
408
  module Accessable
397
409
  def self.included(base)
398
410
  base.class_eval do
399
- interesting_nodes :var_ref, :class, :module
411
+ interesting_nodes :var_ref, :vcall, :class, :module
400
412
 
401
413
  # remember the current access control for methods.
402
414
  add_callback "start_var_ref" do |node|
@@ -405,6 +417,13 @@ module RailsBestPractices
405
417
  end
406
418
  end
407
419
 
420
+ # remember the current access control for methods.
421
+ add_callback "start_vcall" do |node|
422
+ if %w(public protected private).include? node.to_s
423
+ @access_control = node.to_s
424
+ end
425
+ end
426
+
408
427
  # set access control to "public" by default.
409
428
  add_callback "start_class" do |node|
410
429
  @access_control = "public"
@@ -49,27 +49,30 @@ module RailsBestPractices
49
49
  # then run the reivew for that node.
50
50
  [:prepare, :review].each do |process|
51
51
  class_eval <<-EOS
52
- def #{process}(node) # def review(node)
53
- checks = @#{process}_checks[node.sexp_type] # checks = @review_checks[node.sexp_type]
54
- if checks # if checks
55
- checks.each { |check| # checks.each { |check|
56
- if check.parse_file?(node.file) # if check.parse_file?(node.file)
57
- check.node_start(node) # check.node_start(node)
58
- end # end
59
- } # }
60
- end # end
61
- node.children.each { |sexp| # node.children.each { |sexp|
62
- sexp.file = node.file # sexp.filename = node.file
63
- sexp.#{process}(self) # sexp.review(self)
64
- } # }
65
- if checks # if checks
66
- checks.each { |check| # checks.each { |check|
67
- if check.parse_file?(node.file) # if check.parse_file?(node.file)
68
- check.node_end(node) # check.node_end(node)
69
- end # end
70
- } # }
71
- end # end
72
- end # end
52
+ def #{process}(node) # def review(node)
53
+ checks = @#{process}_checks[node.sexp_type] # checks = @review_checks[node.sexp_type]
54
+ if checks # if checks
55
+ checks.each { |check| # checks.each { |check|
56
+ if check.parse_file?(node.file) # if check.parse_file?(node.file)
57
+ check.node_start(node) # check.node_start(node)
58
+ end # end
59
+ } # }
60
+ end # end
61
+ node.children.each { |sexp| # node.children.each { |sexp|
62
+ sexp.file = node.file # sexp.filename = node.file
63
+ sexp.#{process}(self) # sexp.review(self)
64
+ } # }
65
+ if checks # if checks
66
+ checks.each { |check| # checks.each { |check|
67
+ if check.parse_file?(node.file) # if check.parse_file?(node.file)
68
+ check.node_end(node) # check.node_end(node)
69
+ end # end
70
+ } # }
71
+ end # end
72
+ rescue Exception # rescue Exception
73
+ puts "find error in file: \#{node.file} line: \#{node.line}" # puts "find error in file: \#{node.file} line: \#{node.line}"
74
+ raise $! # raise $!
75
+ end # end
73
76
  EOS
74
77
  end
75
78
  end
@@ -48,7 +48,7 @@ module RailsBestPractices
48
48
  # @param [String] association_name
49
49
  # @return [String] association's class name
50
50
  def get_association_class_name(table_name, association_name)
51
- associations = @associations.select { |model, model_associations| model.table_name == table_name }.values.first and
51
+ associations = @associations.select { |model, model_associations| model.gsub("::", "").tableize == table_name }.values.first and
52
52
  association_meta = associations.select { |name, meta| name == association_name }.values.first and
53
53
  association_meta["class_name"]
54
54
  end
@@ -8,7 +8,9 @@ module RailsBestPractices
8
8
  # @param [String] controller name
9
9
  # @param [String] action name
10
10
  def add_route(namespaces, controller_name, action_name)
11
- self << Route.new(namespaces, controller_name, action_name)
11
+ if controller_name.present?
12
+ self << Route.new(namespaces, controller_name, action_name)
13
+ end
12
14
  end
13
15
  end
14
16
 
@@ -22,7 +22,7 @@ class Sexp
22
22
  # => 2
23
23
  def line
24
24
  if [:def, :defs, :command, :command_call, :call, :fcall, :method_add_arg, :method_add_block,
25
- :var_ref, :const_ref, :const_path_ref, :class, :module, :if, :unless, :elsif, :binary,
25
+ :var_ref, :vcall, :const_ref, :const_path_ref, :class, :module, :if, :unless, :elsif, :binary,
26
26
  :alias, :symbol_literal, :symbol, :aref].include? sexp_type
27
27
  self[1].line
28
28
  elsif :array == sexp_type
@@ -56,17 +56,20 @@ class Sexp
56
56
  # :sexp_type => :call,
57
57
  # :subject => "Post",
58
58
  # :message => ["find", "new"]
59
+ # :to_s => "devise"
59
60
  #
60
- # the condition key is one of :sexp_type, :subject or :message,
61
+ # the condition key is one of :sexp_type, :subject, :message, :to_s,
61
62
  # the condition value can be Symbol, Array or Sexp.
62
63
  def grep_nodes(options)
63
64
  sexp_type = options[:sexp_type]
64
65
  subject = options[:subject]
65
66
  message = options[:message]
67
+ to_s = options[:to_s]
66
68
  self.recursive_children do |child|
67
69
  if (!sexp_type || (sexp_type.is_a?(Array) ? sexp_type.include?(child.sexp_type) : sexp_type == child.sexp_type)) &&
68
70
  (!subject || (subject.is_a?(Array) ? subject.include?(child.subject.to_s) : subject == child.subject.to_s)) &&
69
- (!message || (message.is_a?(Array) ? message.include?(child.message.to_s) : message == child.message.to_s))
71
+ (!message || (message.is_a?(Array) ? message.include?(child.message.to_s) : message == child.message.to_s)) &&
72
+ (!to_s || (to_s.is_a?(Array) ? to_s.include?(child.to_s) : to_s == child.to_s))
70
73
  yield child
71
74
  end
72
75
  end
@@ -82,7 +85,7 @@ class Sexp
82
85
  # :subject => s(:const, Post),
83
86
  # :message => [:find, :new]
84
87
  #
85
- # the condition key is one of :sexp_type, :subject, :message,
88
+ # the condition key is one of :sexp_type, :subject, :message, and to_s,
86
89
  # the condition value can be Symbol, Array or Sexp.
87
90
  def grep_node(options)
88
91
  result = RailsBestPractices::Core::Nil.new
@@ -295,13 +298,17 @@ class Sexp
295
298
  nodes = []
296
299
  case sexp_type
297
300
  when :args_add_block, :array
298
- node = self[1]
299
- while true
300
- if [:args_add, :args_add_star].include? node.sexp_type
301
- nodes.unshift node[2]
302
- node = node[1]
303
- elsif :args_new == node.sexp_type
304
- break
301
+ if self[1].sexp_type == :args_new
302
+ nodes << self[2]
303
+ else
304
+ node = self[1]
305
+ while true
306
+ if [:args_add, :args_add_star].include? node.sexp_type
307
+ nodes.unshift node[2]
308
+ node = node[1]
309
+ elsif :args_new == node.sexp_type
310
+ break
311
+ end
305
312
  end
306
313
  end
307
314
  end
@@ -754,7 +761,7 @@ class Sexp
754
761
  def to_s
755
762
  case sexp_type
756
763
  when :string_literal, :xstring_literal, :string_content, :const_ref, :symbol_literal, :symbol,
757
- :args_add_block, :var_ref, :var_field,
764
+ :args_add_block, :var_ref, :vcall, :var_field,
758
765
  :@ident, :@tstring_content, :@const, :@ivar, :@kw, :@gvar, :@cvar
759
766
  self[1].to_s
760
767
  when :string_add
@@ -788,7 +795,7 @@ class Sexp
788
795
 
789
796
  # check if the self node is a const.
790
797
  def const?
791
- :@const == self.sexp_type || (:var_ref == self.sexp_type && :@const == self[1].sexp_type)
798
+ :@const == self.sexp_type || ([:var_ref, :vcall].include?(self.sexp_type) && :@const == self[1].sexp_type)
792
799
  end
793
800
 
794
801
  # true
@@ -10,7 +10,7 @@ module RailsBestPractices
10
10
  include Core::Check::Accessable
11
11
  include Core::Check::Afterable
12
12
 
13
- interesting_nodes :class, :var_ref, :command, :def
13
+ interesting_nodes :class, :var_ref, :vcall, :command, :def
14
14
  interesting_files CONTROLLER_FILES
15
15
 
16
16
  DEFAULT_ACTIONS = %w(index show new create edit update destroy)
@@ -47,6 +47,13 @@ module RailsBestPractices
47
47
  end
48
48
  end
49
49
 
50
+ # check if there is a DSL call inherit_resources.
51
+ def start_vcall(node)
52
+ if @inherited_resources
53
+ @actions = DEFAULT_ACTIONS
54
+ end
55
+ end
56
+
50
57
  # restrict actions for inherited_resources
51
58
  def start_command(node)
52
59
  if "include" == node.message.to_s
@@ -9,7 +9,7 @@ module RailsBestPractices
9
9
  include Core::Check::Accessable
10
10
  include Core::Check::Afterable
11
11
 
12
- interesting_nodes :class, :def, :defs, :command, :var_ref, :alias
12
+ interesting_nodes :class, :def, :defs, :command, :alias
13
13
  interesting_files MODEL_FILES
14
14
 
15
15
  ASSOCIATION_METHODS = %w(belongs_to has_one has_many has_and_belongs_to_many embeds_many embeds_one embedded_in many one)
@@ -28,7 +28,11 @@ module RailsBestPractices
28
28
  first_argument = node.arguments.all.first
29
29
  second_argument = node.arguments.all[1]
30
30
  if @controller_names.last
31
- action_name = first_argument.to_s
31
+ if :bare_assoc_hash == first_argument.sexp_type
32
+ action_name = first_argument.hash_values.first.to_s
33
+ else
34
+ action_name = first_argument.to_s
35
+ end
32
36
  @routes.add_route(current_namespaces, current_controller_name, action_name)
33
37
  else
34
38
  if :bare_assoc_hash == first_argument.sexp_type
@@ -83,7 +87,7 @@ module RailsBestPractices
83
87
  else
84
88
  options = node.arguments.all.last
85
89
  if options.hash_value("controller").present?
86
- @controller_name = options.hash_value("controller").to_s
90
+ @controller_name = [:option, options.hash_value("controller").to_s]
87
91
  end
88
92
  action_name = options.hash_value("action").present? ? options.hash_value("action").to_s : "*"
89
93
  @routes.add_route(current_namespaces, current_controller_name, action_name)
@@ -100,11 +104,15 @@ module RailsBestPractices
100
104
  if node.arguments.all.last.hash_value("module").present?
101
105
  @namespaces << node.arguments.all.last.hash_value("module").to_s
102
106
  end
103
- @controller_name = nil
107
+ if node.arguments.all.last.hash_value("controller").present?
108
+ @controller_name = [:scope, node.arguments.all.last.hash_value("controller").to_s]
109
+ else
110
+ @controller_name = @controller_name.try(:first) == :scope ? @controller_name : nil
111
+ end
104
112
  when "with_options"
105
113
  argument = node.arguments.all.last
106
114
  if :bare_assoc_hash == argument.sexp_type && argument.hash_value("controller").present?
107
- @controller_name = argument.hash_value("controller").to_s
115
+ @controller_name = [:with_option, argument.hash_value("controller").to_s]
108
116
  end
109
117
  else
110
118
  # do nothing
@@ -127,7 +135,7 @@ module RailsBestPractices
127
135
 
128
136
  # remember current controller name, used for nested resources.
129
137
  def start_do_block(node)
130
- @controller_names << @controller_name
138
+ @controller_names << @controller_name.try(:last)
131
139
  end
132
140
 
133
141
  # remove current controller name, and use upper lever resource name.
@@ -140,13 +148,13 @@ module RailsBestPractices
140
148
  def add_#{route_name}_routes(node)
141
149
  resource_names = node.arguments.all.select { |argument| :symbol_literal == argument.sexp_type }
142
150
  resource_names.each do |resource_name|
143
- @controller_name = node.arguments.all.first.to_s
151
+ @controller_name = [:#{route_name}, node.arguments.all.first.to_s]
144
152
  options = node.arguments.all.last
145
153
  if options.hash_value("module").present?
146
154
  @namespaces << options.hash_value("module").to_s
147
155
  end
148
156
  if options.hash_value("controller").present?
149
- @controller_name = options.hash_value("controller").to_s
157
+ @controller_name = [:#{route_name}, options.hash_value("controller").to_s]
150
158
  end
151
159
  action_names = if options.hash_value("only").present?
152
160
  get_#{route_name}_actions(options.hash_value("only").to_object)
@@ -201,7 +209,7 @@ module RailsBestPractices
201
209
  end
202
210
 
203
211
  def current_controller_name
204
- @controller_names.last || @controller_name
212
+ @controller_names.last || @controller_name.try(:last)
205
213
  end
206
214
  end
207
215
  end
@@ -30,3 +30,4 @@ require 'rails_best_practices/reviews/remove_unused_methods_in_models_review'
30
30
  require 'rails_best_practices/reviews/remove_unused_methods_in_controllers_review'
31
31
  require 'rails_best_practices/reviews/remove_unused_methods_in_helpers_review'
32
32
  require 'rails_best_practices/reviews/not_use_time_ago_in_words_review'
33
+ require 'rails_best_practices/reviews/protect_mass_assignment_review'
@@ -130,7 +130,7 @@ module RailsBestPractices
130
130
  foreign_keys.delete_if do |key|
131
131
  if key =~ /_id$/
132
132
  class_name = Prepares.model_associations.get_association_class_name(table, key[0..-4])
133
- class_name ? !@table_nodes[class_name.table_name] : !@table_nodes[key[0..-4].pluralize]
133
+ class_name ? !@table_nodes[class_name.gsub("::", "").tableize] : !@table_nodes[key[0..-4].pluralize]
134
134
  end
135
135
  end
136
136
  end
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+ require 'rails_best_practices/reviews/review'
3
+
4
+ module RailsBestPractices
5
+ module Reviews
6
+ # Review model files to make sure to use attr_accessible or attr_protected to protect mass assignment.
7
+ #
8
+ # See the best practices details here http://rails-bestpractices.com/posts/148-protect-mass-assignment.
9
+ #
10
+ # Implmentation:
11
+ #
12
+ # Review process:
13
+ # check class node to see if there is a command with message attr_accessible or attr_protected.
14
+ class ProtectMassAssignmentReview < Review
15
+ interesting_nodes :class
16
+ interesting_files MODEL_FILES
17
+
18
+ def url
19
+ "http://rails-bestpractices.com/posts/148-protect-mass-assignment"
20
+ end
21
+
22
+ # check class node, grep all command nodes, if none of them is with message attr_accessible or attr_protected,
23
+ # then it should add attr_accessible or attr_protected to protect mass assignment.
24
+ def start_class(node)
25
+ if !rails_builtin?(node) && !devise?(node) && !authlogic?(node)
26
+ add_error "protect mass assignment"
27
+ end
28
+ end
29
+
30
+ private
31
+ def rails_builtin?(node)
32
+ node.grep_node(:sexp_type => :command, :message => %w(attr_accessible attr_protected)).present?
33
+ end
34
+
35
+ def devise?(node)
36
+ node.grep_node(:sexp_type => :command, :message => "devise").present?
37
+ end
38
+
39
+ def authlogic?(node)
40
+ node.grep_node(:sexp_type => :vcall, :to_s => "acts_as_authentic").present? ||
41
+ node.grep_node(:sexp_type => :fcall, :message => "acts_as_authentic").present?
42
+ end
43
+ end
44
+ end
45
+ end
@@ -13,7 +13,7 @@ module RailsBestPractices
13
13
  # check all instance variable in partial view files,
14
14
  # if exist, then they should be replaced with local variable
15
15
  class ReplaceInstanceVariableWithLocalVariableReview < Review
16
- interesting_nodes :var_ref
16
+ interesting_nodes :var_ref, :vcall
17
17
  interesting_files PARTIAL_VIEW_FILES
18
18
 
19
19
  def url
@@ -27,6 +27,14 @@ module RailsBestPractices
27
27
  add_error "replace instance variable with local variable"
28
28
  end
29
29
  end
30
+
31
+ # check ivar node in partial view file,
32
+ # it is an instance variable, and should be replaced with local variable.
33
+ def start_vcall(node)
34
+ if node.to_s.start_with?('@')
35
+ add_error "replace instance variable with local variable"
36
+ end
37
+ end
30
38
  end
31
39
  end
32
40
  end
@@ -86,10 +86,10 @@ module RailsBestPractices
86
86
  if hash_key_exist?(option_node,"controller")
87
87
  name = option_node.hash_value("controller").to_s
88
88
  else
89
- name = node.arguments.all.first.to_s.table_name
89
+ name = node.arguments.all.first.to_s.gsub("::", "").tableize
90
90
  end
91
91
  else
92
- name = node.arguments.all.first.to_s.table_name
92
+ name = node.arguments.all.first.to_s.gsub("::", "").tableize
93
93
  end
94
94
  namespaced_class_name(name)
95
95
  end
@@ -34,7 +34,7 @@ module RailsBestPractices
34
34
  @first_sentences = {}
35
35
 
36
36
  node.body.statements.each do |statement_node|
37
- break if :var_ref == statement_node.sexp_type && ["protected", "private"].include?(statement_node.to_s)
37
+ break if [:var_ref, :vcall].include?(statement_node.sexp_type) && ["protected", "private"].include?(statement_node.to_s)
38
38
  remember_first_sentence(statement_node) if :def == statement_node.sexp_type
39
39
  end
40
40
  @first_sentences.each do |first_sentence, def_nodes|
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module RailsBestPractices
3
- VERSION = "1.8.0"
3
+ VERSION = "1.9.0"
4
4
  end
@@ -42,7 +42,7 @@ Gem::Specification.new do |s|
42
42
 
43
43
  Please also try our online service
44
44
 
45
- https://railsbp.com
45
+ http://railsbp.com
46
46
 
47
47
  Enjoy!
48
48
 
@@ -31,3 +31,4 @@ RemoveUnusedMethodsInModelsCheck: { except_methods: [] }
31
31
  RemoveUnusedMethodsInControllersCheck: { except_methods: [] }
32
32
  RemoveUnusedMethodsInHelpersCheck: { except_methods: [] }
33
33
  NotUseTimeAgoInWordsCheck: { }
34
+ ProtectMassAssignmentCheck: { }
data/rake_rubies.sh CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/bin/bash
2
- rubies=( 1.9.2-p180 1.9.2-p290 1.9.3-p0 )
2
+ rubies=( 1.9.2-p290 1.9.3-p125 )
3
3
  gemset="rails_best_practices"
4
4
 
5
5
  for x in ${rubies[*]}
6
6
  do
7
7
  echo $x@$gemset
8
- rvm $x@$gemset do bundle exec rake spec:progress
8
+ rvm $x@$gemset do bundle exec rake spec
9
9
  done
@@ -48,13 +48,19 @@ describe Sexp do
48
48
  it "should get the call nodes with subject current_user" do
49
49
  nodes = []
50
50
  @node.grep_nodes(:sexp_type => :call, :subject => "current_user") { |node| nodes << node }
51
- nodes.should == [s(:call, s(:var_ref, s(:@ident, "current_user", s(2, 8))), :".", s(:@ident, "posts", s(2, 21)))]
51
+ nodes.should == [s(:call, s(:vcall, s(:@ident, "current_user", s(2, 8))), :".", s(:@ident, "posts", s(2, 21)))]
52
52
  end
53
53
 
54
54
  it "should get the call nodes with different messages" do
55
55
  nodes = []
56
56
  @node.grep_nodes(:sexp_type => :call, :message => ["posts", "find"]) { |node| nodes << node }
57
- nodes.should == [s(:call, s(:call, s(:var_ref, s(:@ident, "current_user", s(2, 8))), :".", s(:@ident, "posts", s(2, 21))), :".", s(:@ident, "find", s(2, 27))), s(:call, s(:var_ref, s(:@ident, "current_user", s(2, 8))), :".", s(:@ident, "posts", s(2, 21)))]
57
+ nodes.should == [s(:call, s(:call, s(:vcall, s(:@ident, "current_user", s(2, 8))), :".", s(:@ident, "posts", s(2, 21))), :".", s(:@ident, "find", s(2, 27))), s(:call, s(:vcall, s(:@ident, "current_user", s(2, 8))), :".", s(:@ident, "posts", s(2, 21)))]
58
+ end
59
+
60
+ it "should get the vcall node with to_s" do
61
+ nodes = []
62
+ @node.grep_nodes(:sexp_type => :vcall, :to_s => "current_user") { |node| nodes << node }
63
+ nodes.should == [s(:vcall, s(:@ident, "current_user", s(2, 8)))]
58
64
  end
59
65
  end
60
66
 
@@ -70,7 +76,7 @@ describe Sexp do
70
76
 
71
77
  it "should get first node with empty argument" do
72
78
  node = @node.grep_node(:sexp_type => :call, :subject => "current_user")
73
- node.should == s(:call, s(:var_ref, s(:@ident, "current_user", s(2, 8))), :".", s(:@ident, "posts", s(2, 21)))
79
+ node.should == s(:call, s(:vcall, s(:@ident, "current_user", s(2, 8))), :".", s(:@ident, "posts", s(2, 21)))
74
80
  end
75
81
  end
76
82
 
@@ -221,7 +227,7 @@ describe Sexp do
221
227
  node.arguments.sexp_type.should == :args_add_block
222
228
  end
223
229
 
224
- it "should get the arguments of method_add_args" do
230
+ it "should get the arguments of method_add_arg" do
225
231
  node = parse_content("User.find(:all)").grep_node(:sexp_type => :method_add_arg)
226
232
  node.arguments.sexp_type.should == :args_add_block
227
233
  end
@@ -245,6 +251,11 @@ describe Sexp do
245
251
  node.all.map(&:to_s).should == ["hello", "world"]
246
252
  end
247
253
 
254
+ it "should get all arguments with &:" do
255
+ node = parse_content("user.posts.map(&:title)").grep_node(:sexp_type => :args_add_block)
256
+ node.all.map(&:to_s).should == ["title"]
257
+ end
258
+
248
259
  it "no error for args_add_star" do
249
260
  node = parse_content("send(:\"\#{route}_url\", *args)").grep_node(:sexp_type => :args_add_block)
250
261
  lambda { node.all }.should_not raise_error
@@ -505,11 +505,23 @@ describe RailsBestPractices::Prepares::RoutePrepare do
505
505
  scope "/admin" do
506
506
  resources :comments, :only => [:index]
507
507
  end
508
+ scope "/:username", controller: :users do
509
+ get '/' => :show
510
+ scope 'topic' do
511
+ get 'preview', :as => 'preview_user', :action => 'preview'
512
+ end
513
+ end
508
514
  end
509
515
  EOF
510
516
  runner.prepare('config/routes.rb', content)
511
517
  routes = RailsBestPractices::Prepares.routes
512
- routes.map(&:to_s).should == ["Admin::PostsController#index", "Admin::DiscussionsController#index", "CommentsController#index"]
518
+ routes.map(&:to_s).should == [
519
+ "Admin::PostsController#index",
520
+ "Admin::DiscussionsController#index",
521
+ "CommentsController#index",
522
+ "UsersController#show",
523
+ "UsersController#preview"
524
+ ]
513
525
  end
514
526
  end
515
527
 
@@ -531,7 +543,7 @@ describe RailsBestPractices::Prepares::RoutePrepare do
531
543
 
532
544
  it "should add routes for another get/post" do
533
545
  content =<<-EOF
534
- RailsBestPracticesCom::Application.routes.draw do
546
+ RailsBestPracticesCom::Application.routes.draw
535
547
  get "/login", to: 'sessions#new', as: :login
536
548
  end
537
549
  EOF
@@ -622,5 +634,16 @@ describe RailsBestPractices::Prepares::RoutePrepare do
622
634
  routes = RailsBestPractices::Prepares.routes
623
635
  routes.last.to_s.should == "SprintsController#stop"
624
636
  end
637
+
638
+ it "should not parse wrong route" do
639
+ content =<<-EOF
640
+ RailsBestPracticesCom::Application.routes.draw do
641
+ match ':controller/:action' => '#index', :as => :auto_complete
642
+ end
643
+ EOF
644
+ runner.prepare('config/routes.rb', content)
645
+ routes = RailsBestPractices::Prepares.routes
646
+ routes.size.should == 0
647
+ end
625
648
  end
626
649
  end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe RailsBestPractices::Reviews::ProtectMassAssignmentReview do
4
+ let(:runner) { RailsBestPractices::Core::Runner.new(:reviews => RailsBestPractices::Reviews::ProtectMassAssignmentReview.new) }
5
+
6
+ it "should protect mass assignment" do
7
+ content =<<-EOF
8
+ class User < ActiveRecord::Base
9
+ end
10
+ EOF
11
+ runner.review('app/models/user.rb', content)
12
+ runner.should have(1).errors
13
+ runner.errors[0].to_s.should == "app/models/user.rb:1 - protect mass assignment"
14
+ end
15
+
16
+ it "should not protect mass assignment with attr_accessible" do
17
+ content =<<-EOF
18
+ class User < ActiveRecord::Base
19
+ attr_accessible :email, :password, :password_confirmation
20
+ end
21
+ EOF
22
+ runner.review('app/models/user.rb', content)
23
+ runner.should have(0).errors
24
+ end
25
+
26
+ it "should not protect mass assignment with attr_protected" do
27
+ content =<<-EOF
28
+ class User < ActiveRecord::Base
29
+ attr_protected :role
30
+ end
31
+ EOF
32
+ runner.review('app/models/user.rb', content)
33
+ runner.should have(0).errors
34
+ end
35
+
36
+ it "should not protect mass assignment if using devise" do
37
+ content =<<-EOF
38
+ class User < ActiveRecord::Base
39
+ devise :database_authenticatable, :registerable, :confirmable, :recoverable, :stretches => 20
40
+ end
41
+ EOF
42
+ runner.review('app/models/user.rb', content)
43
+ runner.should have(0).errors
44
+ end
45
+
46
+ it "should not protect mass assignment if using authlogic with configuration" do
47
+ content =<<-EOF
48
+ class User < ActiveRecord::Base
49
+ acts_as_authentic do |c|
50
+ c.my_config_option = my_value
51
+ end
52
+ end
53
+ EOF
54
+ runner.review('app/models/user.rb', content)
55
+ runner.should have(0).errors
56
+ end
57
+
58
+ it "should not protect mass assignment if using authlogic without configuration" do
59
+ content =<<-EOF
60
+ class User < ActiveRecord::Base
61
+ acts_as_authentic
62
+ end
63
+ EOF
64
+ runner.review('app/models/user.rb', content)
65
+ runner.should have(0).errors
66
+ end
67
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_best_practices
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 1.9.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-24 00:00:00.000000000Z
12
+ date: 2012-03-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sexp_processor
16
- requirement: &70270463469100 !ruby/object:Gem::Requirement
16
+ requirement: &70152469216300 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70270463469100
24
+ version_requirements: *70152469216300
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: progressbar
27
- requirement: &70270463467440 !ruby/object:Gem::Requirement
27
+ requirement: &70152469214420 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70270463467440
35
+ version_requirements: *70152469214420
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: colored
38
- requirement: &70270463456860 !ruby/object:Gem::Requirement
38
+ requirement: &70152469213480 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70270463456860
46
+ version_requirements: *70152469213480
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: erubis
49
- requirement: &70270463455020 !ruby/object:Gem::Requirement
49
+ requirement: &70152469212320 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *70270463455020
57
+ version_requirements: *70152469212320
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: i18n
60
- requirement: &70270463453880 !ruby/object:Gem::Requirement
60
+ requirement: &70152469211160 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *70270463453880
68
+ version_requirements: *70152469211160
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: activesupport
71
- requirement: &70270463452620 !ruby/object:Gem::Requirement
71
+ requirement: &70152469209960 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :runtime
78
78
  prerelease: false
79
- version_requirements: *70270463452620
79
+ version_requirements: *70152469209960
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rake
82
- requirement: &70270463451560 !ruby/object:Gem::Requirement
82
+ requirement: &70152469209140 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *70270463451560
90
+ version_requirements: *70152469209140
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: rspec
93
- requirement: &70270463450820 !ruby/object:Gem::Requirement
93
+ requirement: &70152469208480 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: '0'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *70270463450820
101
+ version_requirements: *70152469208480
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: haml
104
- requirement: &70270463450120 !ruby/object:Gem::Requirement
104
+ requirement: &70152469207680 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ! '>='
@@ -109,10 +109,10 @@ dependencies:
109
109
  version: '0'
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *70270463450120
112
+ version_requirements: *70152469207680
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: slim
115
- requirement: &70270463444400 !ruby/object:Gem::Requirement
115
+ requirement: &70152469206760 !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
118
118
  - - ! '>='
@@ -120,10 +120,10 @@ dependencies:
120
120
  version: '0'
121
121
  type: :development
122
122
  prerelease: false
123
- version_requirements: *70270463444400
123
+ version_requirements: *70152469206760
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: bundler
126
- requirement: &70270463443380 !ruby/object:Gem::Requirement
126
+ requirement: &70152469205560 !ruby/object:Gem::Requirement
127
127
  none: false
128
128
  requirements:
129
129
  - - ! '>='
@@ -131,7 +131,7 @@ dependencies:
131
131
  version: '0'
132
132
  type: :development
133
133
  prerelease: false
134
- version_requirements: *70270463443380
134
+ version_requirements: *70152469205560
135
135
  description: a code metric tool for rails codes, written in Ruby.
136
136
  email:
137
137
  - flyerhzm@gmail.com
@@ -179,7 +179,6 @@ files:
179
179
  - lib/rails_best_practices/core_ext/enumerable.rb
180
180
  - lib/rails_best_practices/core_ext/erubis.rb
181
181
  - lib/rails_best_practices/core_ext/sexp.rb
182
- - lib/rails_best_practices/core_ext/string.rb
183
182
  - lib/rails_best_practices/lexicals.rb
184
183
  - lib/rails_best_practices/lexicals/remove_tab_check.rb
185
184
  - lib/rails_best_practices/lexicals/remove_trailing_whitespace_check.rb
@@ -206,6 +205,7 @@ files:
206
205
  - lib/rails_best_practices/reviews/not_use_default_route_review.rb
207
206
  - lib/rails_best_practices/reviews/not_use_time_ago_in_words_review.rb
208
207
  - lib/rails_best_practices/reviews/overuse_route_customizations_review.rb
208
+ - lib/rails_best_practices/reviews/protect_mass_assignment_review.rb
209
209
  - lib/rails_best_practices/reviews/remove_empty_helpers_review.rb
210
210
  - lib/rails_best_practices/reviews/remove_unused_methods_in_controllers_review.rb
211
211
  - lib/rails_best_practices/reviews/remove_unused_methods_in_helpers_review.rb
@@ -270,6 +270,7 @@ files:
270
270
  - spec/rails_best_practices/reviews/not_use_default_route_review_spec.rb
271
271
  - spec/rails_best_practices/reviews/not_use_times_ago_in_words_review_spec.rb
272
272
  - spec/rails_best_practices/reviews/overuse_route_customizations_review_spec.rb
273
+ - spec/rails_best_practices/reviews/protect_mass_assignment_review_spec.rb
273
274
  - spec/rails_best_practices/reviews/remove_empty_helpers_review_spec.rb
274
275
  - spec/rails_best_practices/reviews/remove_unused_methods_in_controllers_review_spec.rb
275
276
  - spec/rails_best_practices/reviews/remove_unused_methods_in_helpers_review_spec.rb
@@ -292,7 +293,7 @@ licenses: []
292
293
  post_install_message: ! "********************************************************************************\n\n
293
294
  \ rails_best_practices is a code metric tool to check the quality of rails codes.\n\n
294
295
  \ I highly recommend you browse the Rails Best Practices website first.\n\n http://rails-bestpractices.com\n\n
295
- \ Please also try our online service\n\n https://railsbp.com\n\n Enjoy!\n\n
296
+ \ Please also try our online service\n\n http://railsbp.com\n\n Enjoy!\n\n
296
297
  \ Richard Huang (flyerhzm@gmail.com)\n\n********************************************************************************\n"
297
298
  rdoc_options: []
298
299
  require_paths:
@@ -306,7 +307,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
306
307
  version: '0'
307
308
  segments:
308
309
  - 0
309
- hash: 920336894600409116
310
+ hash: -964066537248826324
310
311
  required_rubygems_version: !ruby/object:Gem::Requirement
311
312
  none: false
312
313
  requirements:
@@ -315,7 +316,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
315
316
  version: 1.3.6
316
317
  requirements: []
317
318
  rubyforge_project:
318
- rubygems_version: 1.8.15
319
+ rubygems_version: 1.8.17
319
320
  signing_key:
320
321
  specification_version: 3
321
322
  summary: a code metric tool for rails codes.
@@ -363,6 +364,7 @@ test_files:
363
364
  - spec/rails_best_practices/reviews/not_use_default_route_review_spec.rb
364
365
  - spec/rails_best_practices/reviews/not_use_times_ago_in_words_review_spec.rb
365
366
  - spec/rails_best_practices/reviews/overuse_route_customizations_review_spec.rb
367
+ - spec/rails_best_practices/reviews/protect_mass_assignment_review_spec.rb
366
368
  - spec/rails_best_practices/reviews/remove_empty_helpers_review_spec.rb
367
369
  - spec/rails_best_practices/reviews/remove_unused_methods_in_controllers_review_spec.rb
368
370
  - spec/rails_best_practices/reviews/remove_unused_methods_in_helpers_review_spec.rb
@@ -1,5 +0,0 @@
1
- class String
2
- def table_name
3
- self.gsub("::", "").tableize
4
- end
5
- end