rails_best_practices 0.10.1 → 1.0.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 (63) hide show
  1. data/README.md +20 -0
  2. data/assets/result.html.haml +1 -1
  3. data/lib/rails_best_practices.rb +5 -3
  4. data/lib/rails_best_practices/core.rb +1 -1
  5. data/lib/rails_best_practices/core/check.rb +9 -12
  6. data/lib/rails_best_practices/core/checking_visitor.rb +9 -6
  7. data/lib/rails_best_practices/core/model_associations.rb +1 -1
  8. data/lib/rails_best_practices/core/nil.rb +5 -1
  9. data/lib/rails_best_practices/core/runner.rb +5 -5
  10. data/lib/rails_best_practices/core_ext/sexp.rb +688 -0
  11. data/lib/rails_best_practices/prepares/mailer_prepare.rb +4 -5
  12. data/lib/rails_best_practices/prepares/model_prepare.rb +16 -26
  13. data/lib/rails_best_practices/prepares/schema_prepare.rb +11 -17
  14. data/lib/rails_best_practices/reviews/add_model_virtual_attribute_review.rb +24 -75
  15. data/lib/rails_best_practices/reviews/always_add_db_index_review.rb +39 -113
  16. data/lib/rails_best_practices/reviews/dry_bundler_in_capistrano_review.rb +6 -16
  17. data/lib/rails_best_practices/reviews/isolate_seed_data_review.rb +16 -32
  18. data/lib/rails_best_practices/reviews/keep_finders_on_their_own_model_review.rb +11 -20
  19. data/lib/rails_best_practices/reviews/law_of_demeter_review.rb +7 -28
  20. data/lib/rails_best_practices/reviews/move_code_into_controller_review.rb +16 -14
  21. data/lib/rails_best_practices/reviews/move_code_into_helper_review.rb +10 -28
  22. data/lib/rails_best_practices/reviews/move_code_into_model_review.rb +12 -11
  23. data/lib/rails_best_practices/reviews/move_finder_to_named_scope_review.rb +13 -24
  24. data/lib/rails_best_practices/reviews/move_model_logic_into_model_review.rb +9 -9
  25. data/lib/rails_best_practices/reviews/needless_deep_nesting_review.rb +24 -68
  26. data/lib/rails_best_practices/reviews/not_use_default_route_review.rb +15 -22
  27. data/lib/rails_best_practices/reviews/overuse_route_customizations_review.rb +31 -91
  28. data/lib/rails_best_practices/reviews/remove_empty_helpers_review.rb +4 -2
  29. data/lib/rails_best_practices/reviews/replace_complex_creation_with_factory_method_review.rb +20 -18
  30. data/lib/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review.rb +5 -3
  31. data/lib/rails_best_practices/reviews/review.rb +8 -37
  32. data/lib/rails_best_practices/reviews/simplify_render_in_controllers_review.rb +10 -6
  33. data/lib/rails_best_practices/reviews/simplify_render_in_views_review.rb +9 -6
  34. data/lib/rails_best_practices/reviews/use_before_filter_review.rb +14 -72
  35. data/lib/rails_best_practices/reviews/use_model_association_review.rb +19 -31
  36. data/lib/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review.rb +5 -5
  37. data/lib/rails_best_practices/reviews/use_observer_review.rb +22 -40
  38. data/lib/rails_best_practices/reviews/use_query_attribute_review.rb +34 -39
  39. data/lib/rails_best_practices/reviews/use_say_with_time_in_migrations_review.rb +14 -38
  40. data/lib/rails_best_practices/reviews/use_scope_access_review.rb +13 -44
  41. data/lib/rails_best_practices/version.rb +1 -1
  42. data/spec/rails_best_practices/core/check_spec.rb +5 -5
  43. data/spec/rails_best_practices/core/checking_visitor_spec.rb +4 -4
  44. data/spec/rails_best_practices/core/model_associations_spec.rb +4 -4
  45. data/spec/rails_best_practices/core/nil_spec.rb +7 -1
  46. data/spec/rails_best_practices/core_ext/sexp_spec.rb +430 -0
  47. data/spec/rails_best_practices/prepares/model_prepare_spec.rb +12 -12
  48. data/spec/rails_best_practices/prepares/schema_prepare_spec.rb +6 -6
  49. data/spec/rails_best_practices/reviews/move_code_into_controller_review_spec.rb +14 -2
  50. data/spec/rails_best_practices/reviews/move_code_into_helper_review_spec.rb +1 -1
  51. data/spec/rails_best_practices/reviews/needless_deep_nesting_review_spec.rb +3 -3
  52. data/spec/rails_best_practices/reviews/not_use_default_route_review_spec.rb +1 -1
  53. data/spec/rails_best_practices/reviews/overuse_route_customizations_review_spec.rb +15 -1
  54. data/spec/rails_best_practices/reviews/simplify_render_in_controllers_review_spec.rb +3 -3
  55. data/spec/rails_best_practices/reviews/use_query_attribute_review_spec.rb +1 -1
  56. data/spec/rails_best_practices/reviews/use_say_with_time_in_migrations_review_spec.rb +1 -1
  57. data/spec/rails_best_practices/reviews/use_scope_access_review_spec.rb +4 -4
  58. data/spec/rails_best_practices_spec.rb +1 -3
  59. data/spec/spec_helper.rb +4 -0
  60. metadata +6 -8
  61. data/lib/rails_best_practices/core/visitable_sexp.rb +0 -444
  62. data/spec/rails_best_practices/core/visitable_sexp_spec.rb +0 -272
  63. data/spec/rails_best_practices/reviews/review_spec.rb +0 -11
@@ -18,10 +18,10 @@ describe RailsBestPractices::Prepares::ModelPrepare do
18
18
  EOF
19
19
  runner.prepare('app/models/project.rb', content)
20
20
  model_associations = RailsBestPractices::Prepares.model_associations
21
- model_associations.get_association("Project", "portfolio").should == {:meta => :belongs_to, :class_name => "Portfolio"}
22
- model_associations.get_association("Project", "project_manager").should == {:meta => :has_one, :class_name => "ProjectManager"}
23
- model_associations.get_association("Project", "milestones").should == {:meta => :has_many, :class_name => "Milestone"}
24
- model_associations.get_association("Project", "categories").should == {:meta => :has_and_belongs_to_many, :class_name => "Category"}
21
+ model_associations.get_association("Project", "portfolio").should == {"meta" => "belongs_to", "class_name" => "Portfolio"}
22
+ model_associations.get_association("Project", "project_manager").should == {"meta" => "has_one", "class_name" => "ProjectManager"}
23
+ model_associations.get_association("Project", "milestones").should == {"meta" => "has_many", "class_name" => "Milestone"}
24
+ model_associations.get_association("Project", "categories").should == {"meta" => "has_and_belongs_to_many", "class_name" => "Category"}
25
25
  end
26
26
 
27
27
  it "should not raise error for finder_sql option" do
@@ -38,45 +38,45 @@ describe RailsBestPractices::Prepares::ModelPrepare do
38
38
  it "should parse belongs_to" do
39
39
  content =<<-EOF
40
40
  class Post < ActiveRecord::Base
41
- belongs_to :author, :class_name => "Person"
41
+ belongs_to :author, "class_name" => "Person"
42
42
  end
43
43
  EOF
44
44
  runner.prepare("app/models/post.rb", content)
45
45
  model_associations = RailsBestPractices::Prepares.model_associations
46
- model_associations.get_association("Post", "author").should == {:meta => :belongs_to, :class_name => "Person"}
46
+ model_associations.get_association("Post", "author").should == {"meta" => "belongs_to", "class_name" => "Person"}
47
47
  end
48
48
 
49
49
  it "should parse has_one" do
50
50
  content =<<-EOF
51
51
  class Project < ActiveRecord::Base
52
- has_one :project_manager, :class_name => "Person"
52
+ has_one :project_manager, "class_name" => "Person"
53
53
  end
54
54
  EOF
55
55
  runner.prepare("app/models/post.rb", content)
56
56
  model_associations = RailsBestPractices::Prepares.model_associations
57
- model_associations.get_association("Project", "project_manager").should == {:meta => :has_one, :class_name => "Person"}
57
+ model_associations.get_association("Project", "project_manager").should == {"meta" => "has_one", "class_name" => "Person"}
58
58
  end
59
59
 
60
60
  it "should parse has_many" do
61
61
  content =<<-EOF
62
62
  class Project < ActiveRecord::Base
63
- has_many :people, :class_name => "Person"
63
+ has_many :people, "class_name" => "Person"
64
64
  end
65
65
  EOF
66
66
  runner.prepare("app/models/project.rb", content)
67
67
  model_associations = RailsBestPractices::Prepares.model_associations
68
- model_associations.get_association("Project", "people").should == {:meta => :has_many, :class_name => "Person"}
68
+ model_associations.get_association("Project", "people").should == {"meta" => "has_many", "class_name" => "Person"}
69
69
  end
70
70
 
71
71
  it "should parse has_and_belongs_to_many" do
72
72
  content =<<-EOF
73
73
  class Citizen < ActiveRecord::Base
74
- has_and_belongs_to_many :nations, :class_name => "Country"
74
+ has_and_belongs_to_many :nations, "class_name" => "Country"
75
75
  end
76
76
  EOF
77
77
  runner.prepare("app/models/citizen.rb", content)
78
78
  model_associations = RailsBestPractices::Prepares.model_associations
79
- model_associations.get_association("Citizen", "nations").should == {:meta => :has_and_belongs_to_many, :class_name => "Country"}
79
+ model_associations.get_association("Citizen", "nations").should == {"meta" => "has_and_belongs_to_many", "class_name" => "Country"}
80
80
  end
81
81
  end
82
82
  end
@@ -18,11 +18,11 @@ describe RailsBestPractices::Prepares::SchemaPrepare do
18
18
  EOF
19
19
  runner.prepare("db/schema.rb", content)
20
20
  model_attributes = RailsBestPractices::Prepares.model_attributes
21
- model_attributes.get_attribute_type("Post", "title").should == :string
22
- model_attributes.get_attribute_type("Post", "body").should == :text
23
- model_attributes.get_attribute_type("Post", "created_at").should == :datetime
24
- model_attributes.get_attribute_type("Post", "user_id").should == :integer
25
- model_attributes.get_attribute_type("Post", "comments_count").should == :integer
26
- model_attributes.get_attribute_type("Post", "published").should == :boolean
21
+ model_attributes.get_attribute_type("Post", "title").should == "string"
22
+ model_attributes.get_attribute_type("Post", "body").should == "text"
23
+ model_attributes.get_attribute_type("Post", "created_at").should == "datetime"
24
+ model_attributes.get_attribute_type("Post", "user_id").should == "integer"
25
+ model_attributes.get_attribute_type("Post", "comments_count").should == "integer"
26
+ model_attributes.get_attribute_type("Post", "published").should == "boolean"
27
27
  end
28
28
  end
@@ -3,9 +3,21 @@ require 'spec_helper'
3
3
  describe RailsBestPractices::Reviews::MoveCodeIntoControllerReview do
4
4
  let(:runner) { RailsBestPractices::Core::Runner.new(:reviews => RailsBestPractices::Reviews::MoveCodeIntoControllerReview.new) }
5
5
 
6
- it "should move code into controller" do
6
+ it "should move code into controller for method call" do
7
7
  content = <<-EOF
8
- <% @posts = Post.find(:all) %>
8
+ <% Post.find(:all).each do |post| %>
9
+ <%=h post.title %>
10
+ <%=h post.content %>
11
+ <% end %>
12
+ EOF
13
+ runner.review('app/views/posts/index.html.erb', content)
14
+ runner.should have(1).errors
15
+ runner.errors[0].to_s.should == "app/views/posts/index.html.erb:1 - move code into controller"
16
+ end
17
+
18
+ it "should move code into controller for assign" do
19
+ content = <<-EOF
20
+ <% @posts = Post.all %>
9
21
  <% @posts.each do |post| %>
10
22
  <%=h post.title %>
11
23
  <%=h post.content %>
@@ -11,7 +11,7 @@ describe RailsBestPractices::Reviews::MoveCodeIntoHelperReview do
11
11
  EOF
12
12
  runner.review('app/views/posts/show.html.erb', content)
13
13
  runner.should have(1).errors
14
- runner.errors[0].to_s.should == "app/views/posts/show.html.erb:3 - move code into helper (array_count >= 2)"
14
+ runner.errors[0].to_s.should == "app/views/posts/show.html.erb:1 - move code into helper (array_count >= 2)"
15
15
  end
16
16
 
17
17
  it "should not move code into helper with simple arguments" do
@@ -93,7 +93,7 @@ describe RailsBestPractices::Reviews::NeedlessDeepNestingReview do
93
93
  EOF
94
94
  runner.review('config/routes.rb', content)
95
95
  runner.should have(1).errors
96
- runner.errors[0].to_s.should == "config/routes.rb:4 - needless deep nesting (nested_count > 2)"
96
+ runner.errors[0].to_s.should == "config/routes.rb:3 - needless deep nesting (nested_count > 2)"
97
97
  end
98
98
 
99
99
  it "should not needless deep nesting for shallow" do
@@ -118,7 +118,7 @@ describe RailsBestPractices::Reviews::NeedlessDeepNestingReview do
118
118
  EOF
119
119
  runner.review('config/routes.rb', content)
120
120
  runner.should have(1).errors
121
- runner.errors[0].to_s.should == "config/routes.rb:4 - needless deep nesting (nested_count > 2)"
121
+ runner.errors[0].to_s.should == "config/routes.rb:3 - needless deep nesting (nested_count > 2)"
122
122
  end
123
123
 
124
124
  it "should needless deep nesting with block node" do
@@ -132,7 +132,7 @@ describe RailsBestPractices::Reviews::NeedlessDeepNestingReview do
132
132
  EOF
133
133
  runner.review('config/routes.rb', content)
134
134
  runner.should have(1).errors
135
- runner.errors[0].to_s.should == "config/routes.rb:4 - needless deep nesting (nested_count > 2)"
135
+ runner.errors[0].to_s.should == "config/routes.rb:3 - needless deep nesting (nested_count > 2)"
136
136
  end
137
137
 
138
138
  it "should no needless deep nesting" do
@@ -41,7 +41,7 @@ describe RailsBestPractices::Reviews::NotUseDefaultRouteReview do
41
41
  EOF
42
42
  runner.review('config/routes.rb', content)
43
43
  runner.should have(1).errors
44
- runner.errors[0].to_s.should == "config/routes.rb:5 - not use default route"
44
+ runner.errors[0].to_s.should == "config/routes.rb:4 - not use default route"
45
45
  end
46
46
 
47
47
  it "should no not use default route" do
@@ -32,7 +32,7 @@ describe RailsBestPractices::Reviews::OveruseRouteCustomizationsReview do
32
32
  runner.errors[0].to_s.should == "config/routes.rb:2 - overuse route customizations (customize_count > 3)"
33
33
  end
34
34
 
35
- it "should overuse route customizations with collection 2" do
35
+ it "should overuse route customizations with hash member and collection" do
36
36
  content = <<-EOF
37
37
  ActionController::Routing::Routes.draw do |map|
38
38
  map.resources :categories do |category|
@@ -48,6 +48,20 @@ describe RailsBestPractices::Reviews::OveruseRouteCustomizationsReview do
48
48
  runner.errors[0].to_s.should == "config/routes.rb:3 - overuse route customizations (customize_count > 3)"
49
49
  end
50
50
 
51
+ it "should overuse route customizations with array member and collection" do
52
+ content = <<-EOF
53
+ ActionController::Routing::Routes.draw do |map|
54
+ map.resources :categories do |category|
55
+ category.resources :posts, :member => [:create_comment, :update_comment, :delete_comment],
56
+ :collection => [:comments]
57
+ end
58
+ end
59
+ EOF
60
+ runner.review('config/routes.rb', content)
61
+ runner.should have(1).errors
62
+ runner.errors[0].to_s.should == "config/routes.rb:3 - overuse route customizations (customize_count > 3)"
63
+ end
64
+
51
65
  it "should not overuse route customizations without customization" do
52
66
  content = <<-EOF
53
67
  ActionController::Routing::Routes.draw do |map|
@@ -11,7 +11,7 @@ describe RailsBestPractices::Reviews::SimplifyRenderInControllersReview do
11
11
  EOF
12
12
  runner.review("app/controllers/posts_controller.rb", content)
13
13
  runner.should have(1).errors
14
- runner.errors[0].to_s.should == "app/controllers/posts_controller.rb:3 - simplify render in controllers"
14
+ runner.errors[0].to_s.should == "app/controllers/posts_controller.rb:2 - simplify render in controllers"
15
15
  end
16
16
 
17
17
  it "should simplify render actions's template" do
@@ -22,7 +22,7 @@ describe RailsBestPractices::Reviews::SimplifyRenderInControllersReview do
22
22
  EOF
23
23
  runner.review("app/controllers/posts_controller.rb", content)
24
24
  runner.should have(1).errors
25
- runner.errors[0].to_s.should == "app/controllers/posts_controller.rb:3 - simplify render in controllers"
25
+ runner.errors[0].to_s.should == "app/controllers/posts_controller.rb:2 - simplify render in controllers"
26
26
  end
27
27
 
28
28
  it "should simplify render an arbitrary file" do
@@ -33,7 +33,7 @@ describe RailsBestPractices::Reviews::SimplifyRenderInControllersReview do
33
33
  EOF
34
34
  runner.review("app/controllers/posts_controller.rb", content)
35
35
  runner.should have(1).errors
36
- runner.errors[0].to_s.should == "app/controllers/posts_controller.rb:3 - simplify render in controllers"
36
+ runner.errors[0].to_s.should == "app/controllers/posts_controller.rb:2 - simplify render in controllers"
37
37
  end
38
38
 
39
39
  it "should not simplify render action view" do
@@ -77,7 +77,7 @@ describe RailsBestPractices::Reviews::UseQueryAttributeReview do
77
77
 
78
78
  it "should use query attribute within and conditions" do
79
79
  content = <<-EOF
80
- <% if @user.active? and @user.login.present? %>
80
+ <% if @user.active? && @user.login.present? %>
81
81
  <%= @user.login %>
82
82
  <% end %>
83
83
  EOF
@@ -113,6 +113,6 @@ describe RailsBestPractices::Reviews::UseSayWithTimeInMigrationsReview do
113
113
  end
114
114
  EOF
115
115
  runner.review('db/migrate/20101010080658_create_users.rb', content)
116
- runner.should have(0).errors
116
+ runner.should have(3).errors
117
117
  end
118
118
  end
@@ -20,7 +20,7 @@ describe RailsBestPractices::Reviews::UseScopeAccessReview do
20
20
  EOF
21
21
  runner.review('app/controllers/posts_controller.rb', content)
22
22
  runner.should have(1).errors
23
- runner.errors[0].to_s.should == "app/controllers/posts_controller.rb:7 - use scope access"
23
+ runner.errors[0].to_s.should == "app/controllers/posts_controller.rb:6 - use scope access"
24
24
  end
25
25
 
26
26
  it "shoud use scope access by comparing with id" do
@@ -39,7 +39,7 @@ describe RailsBestPractices::Reviews::UseScopeAccessReview do
39
39
  EOF
40
40
  runner.review('app/controllers/posts_controller.rb', content)
41
41
  runner.should have(1).errors
42
- runner.errors[0].to_s.should == "app/controllers/posts_controller.rb:7 - use scope access"
42
+ runner.errors[0].to_s.should == "app/controllers/posts_controller.rb:6 - use scope access"
43
43
  end
44
44
 
45
45
  it "shoud use scope access with current_user ==" do
@@ -58,7 +58,7 @@ describe RailsBestPractices::Reviews::UseScopeAccessReview do
58
58
  EOF
59
59
  runner.review('app/controllers/posts_controller.rb', content)
60
60
  runner.should have(1).errors
61
- runner.errors[0].to_s.should == "app/controllers/posts_controller.rb:7 - use scope access"
61
+ runner.errors[0].to_s.should == "app/controllers/posts_controller.rb:6 - use scope access"
62
62
  end
63
63
 
64
64
  it "shoud use scope access by current_user.id ==" do
@@ -77,7 +77,7 @@ describe RailsBestPractices::Reviews::UseScopeAccessReview do
77
77
  EOF
78
78
  runner.review('app/controllers/posts_controller.rb', content)
79
79
  runner.should have(1).errors
80
- runner.errors[0].to_s.should == "app/controllers/posts_controller.rb:7 - use scope access"
80
+ runner.errors[0].to_s.should == "app/controllers/posts_controller.rb:6 - use scope access"
81
81
  end
82
82
  end
83
83
 
@@ -7,8 +7,6 @@ describe RailsBestPractices do
7
7
  it "should expand all files in spec directory" do
8
8
  dir = File.dirname(__FILE__)
9
9
  RailsBestPractices.expand_dirs_to_files(dir).should be_include(dir + '/rails_best_practices_spec.rb')
10
- RailsBestPractices.expand_dirs_to_files(dir).should be_include(dir + '/rails_best_practices/core/visitable_sexp_spec.rb')
11
- RailsBestPractices.expand_dirs_to_files(dir).should be_include(dir + '/rails_best_practices/reviews/review_spec.rb')
12
10
  end
13
11
  end
14
12
 
@@ -40,6 +38,6 @@ describe RailsBestPractices do
40
38
  RailsBestPractices.output_terminal_errors
41
39
  result = $stdout.string
42
40
  $stdout = $origin_stdout
43
- result.should == ["app/models/user.rb:10 - law of demeter".red, "app/models/post.rb:100 - use query attribute".red, "\nPlease go to http://rails-bestpractices.com to see more useful Rails Best Practices.".green, "\nFound 2 errors.".red].join("\n") + "\n"
41
+ result.should == ["app/models/user.rb:10 - law of demeter".red, "app/models/post.rb:100 - use query attribute".red, "\nPlease go to http://rails-bestpractices.com to see more useful Rails Best Practices.".green, "\nFound 2 warnings.".red].join("\n") + "\n"
44
42
  end
45
43
  end
data/spec/spec_helper.rb CHANGED
@@ -3,3 +3,7 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
3
3
 
4
4
  require 'rspec/expectations'
5
5
  require 'rails_best_practices'
6
+
7
+ def parse_content(content)
8
+ Sexp.from_array(Ripper::SexpBuilder.new(content).parse)[1]
9
+ end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: rails_best_practices
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.10.1
5
+ version: 1.0.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Richard Huang
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-07-16 00:00:00 +09:00
13
+ date: 2011-09-24 00:00:00 +08:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -170,8 +170,8 @@ files:
170
170
  - lib/rails_best_practices/core/models.rb
171
171
  - lib/rails_best_practices/core/nil.rb
172
172
  - lib/rails_best_practices/core/runner.rb
173
- - lib/rails_best_practices/core/visitable_sexp.rb
174
173
  - lib/rails_best_practices/core_ext/enumerable.rb
174
+ - lib/rails_best_practices/core_ext/sexp.rb
175
175
  - lib/rails_best_practices/lexicals.rb
176
176
  - lib/rails_best_practices/lexicals/remove_tab_check.rb
177
177
  - lib/rails_best_practices/lexicals/remove_trailing_whitespace_check.rb
@@ -218,8 +218,8 @@ files:
218
218
  - spec/rails_best_practices/core/model_attributes_spec.rb
219
219
  - spec/rails_best_practices/core/models_spec.rb
220
220
  - spec/rails_best_practices/core/nil_spec.rb
221
- - spec/rails_best_practices/core/visitable_sexp_spec.rb
222
221
  - spec/rails_best_practices/core_ext/enumerable_spec.rb
222
+ - spec/rails_best_practices/core_ext/sexp_spec.rb
223
223
  - spec/rails_best_practices/lexicals/remove_tab_check_spec.rb
224
224
  - spec/rails_best_practices/lexicals/remove_trailing_whitespace_check_spec.rb
225
225
  - spec/rails_best_practices/prepares/mailer_prepare_spec.rb
@@ -242,7 +242,6 @@ files:
242
242
  - spec/rails_best_practices/reviews/remove_empty_helpers_review_spec.rb
243
243
  - spec/rails_best_practices/reviews/replace_complex_creation_with_factory_method_review_spec.rb
244
244
  - spec/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review_spec.rb
245
- - spec/rails_best_practices/reviews/review_spec.rb
246
245
  - spec/rails_best_practices/reviews/simplify_render_in_controllers_review_spec.rb
247
246
  - spec/rails_best_practices/reviews/simplify_render_in_views_review_spec.rb
248
247
  - spec/rails_best_practices/reviews/use_before_filter_review_spec.rb
@@ -282,7 +281,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
282
281
  requirements:
283
282
  - - ">="
284
283
  - !ruby/object:Gem::Version
285
- hash: -1121248838931870428
284
+ hash: 3845996389708993408
286
285
  segments:
287
286
  - 0
288
287
  version: "0"
@@ -307,8 +306,8 @@ test_files:
307
306
  - spec/rails_best_practices/core/model_attributes_spec.rb
308
307
  - spec/rails_best_practices/core/models_spec.rb
309
308
  - spec/rails_best_practices/core/nil_spec.rb
310
- - spec/rails_best_practices/core/visitable_sexp_spec.rb
311
309
  - spec/rails_best_practices/core_ext/enumerable_spec.rb
310
+ - spec/rails_best_practices/core_ext/sexp_spec.rb
312
311
  - spec/rails_best_practices/lexicals/remove_tab_check_spec.rb
313
312
  - spec/rails_best_practices/lexicals/remove_trailing_whitespace_check_spec.rb
314
313
  - spec/rails_best_practices/prepares/mailer_prepare_spec.rb
@@ -331,7 +330,6 @@ test_files:
331
330
  - spec/rails_best_practices/reviews/remove_empty_helpers_review_spec.rb
332
331
  - spec/rails_best_practices/reviews/replace_complex_creation_with_factory_method_review_spec.rb
333
332
  - spec/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review_spec.rb
334
- - spec/rails_best_practices/reviews/review_spec.rb
335
333
  - spec/rails_best_practices/reviews/simplify_render_in_controllers_review_spec.rb
336
334
  - spec/rails_best_practices/reviews/simplify_render_in_views_review_spec.rb
337
335
  - spec/rails_best_practices/reviews/use_before_filter_review_spec.rb
@@ -1,444 +0,0 @@
1
- # encoding: utf-8
2
- require 'sexp'
3
-
4
- class Sexp
5
- # prepare current node.
6
- #
7
- # @param [RailsBestPractices::Core::CheckingVisitor] visitor the visitor to prepare current node
8
- def prepare(visitor)
9
- visitor.prepare(self)
10
- end
11
-
12
- # prepare current node.
13
- #
14
- # @param [RailsBestPractices::Core::CheckingVisitor] visitor the visitor to review current node
15
- def review(visitor)
16
- visitor.review(self)
17
- end
18
-
19
- # return child nodes of a sexp node.
20
- #
21
- # s(:call, nil, :puts,
22
- # s(:arglist, s(:str, "hello "), s(:str, "world"))
23
- # )
24
- # => [s(:arglist, s(:str, "hello "), s(:str, "world"))]
25
- #
26
- # @return [Array] child nodes.
27
- def children
28
- find_all { | sexp | Sexp === sexp }
29
- end
30
-
31
- # recursively find all child nodes, and yeild each child node.
32
- def recursive_children
33
- children.each do |child|
34
- yield child
35
- child.recursive_children { |c| yield c }
36
- end
37
- end
38
-
39
- # grep all the recursive child nodes with conditions, and yield each match node.
40
- #
41
- # @param [Hash] options grep conditions
42
- #
43
- # options is the grep conditions, like
44
- #
45
- # :node_type => :call,
46
- # :subject => s(:const, Post),
47
- # :message => [:find, :new],
48
- # :arguments => s(:arglist)
49
- #
50
- # the condition key is one of :node_type, :subject, :message or :arguments,
51
- # the condition value can be Symbol, Array or Sexp.
52
- def grep_nodes(options)
53
- node_type = options[:node_type]
54
- subject = options[:subject]
55
- message = options[:message]
56
- arguments = options[:arguments]
57
- self.recursive_children do |child|
58
- if (!node_type || (node_type.is_a?(Array) ? node_type.include?(child.node_type) : node_type == child.node_type)) &&
59
- (!subject || (subject.is_a?(Array) ? subject.include?(child.subject) : subject == child.subject)) &&
60
- (!message || (message.is_a?(Array) ? message.include?(child.message) : message == child.message)) &&
61
- (!arguments || (arguments.is_?(Array) ? arguments.include?(child.arguments) : arguments == child.arguments))
62
- yield child
63
- end
64
- end
65
- end
66
-
67
- # grep all the recursive child nodes with conditions, and yield the first match node.
68
- #
69
- # @param [Hash] options grep conditions
70
- #
71
- # options is the grep conditions, like
72
- #
73
- # :node_type => :call,
74
- # :subject => s(:const, Post),
75
- # :message => [:find, :new],
76
- # :arguments => s(:arglist)
77
- #
78
- # the condition key is one of :node_type, :subject, :message or :arguments,
79
- # the condition value can be Symbol, Array or Sexp.
80
- def grep_node(options)
81
- grep_nodes(options) { |node| return node }
82
- end
83
-
84
- # grep all the recursive child nodes with conditions, and get the count of match nodes.
85
- #
86
- # @param [Hash] options grep conditions
87
- # @return [Integer] the count of metch nodes
88
- def grep_nodes_count(options)
89
- count = 0
90
- grep_nodes(options) { |node| count += 1 }
91
- count
92
- end
93
-
94
- # Get subject of attrasgan, call and iter node.
95
- #
96
- # s(:attrasgn,
97
- # s(:call, nil, :user, s(:arglist)),
98
- # :name=,
99
- # s(:arglist,
100
- # s(:call,
101
- # s(:call, nil, :params, s(:arglist)),
102
- # :[],
103
- # s(:arglist, s(:lit, :name))
104
- # )
105
- # )
106
- # )
107
- # => s(:call, nil, :user, s(:arglist))
108
- #
109
- # s(:call,
110
- # s(:call, nil, :user, s(:arglist)),
111
- # :name,
112
- # s(:arglist)
113
- # )
114
- # => s(:call, nil, :user, s(:arglist))
115
- #
116
- # s(:iter,
117
- # s(:call, s(:ivar, :@users), :each, s(:arglist)),
118
- # s(:lasgn, :user),
119
- # s(:call, nil, :p,
120
- # s(:arglist, s(:lvar, :user))
121
- # )
122
- # )
123
- # => s(:call, :s(:ivar, ;@users), :each, s(:arglist))
124
- #
125
- # @return [Sexp] subject of attrasgn, call or iter node
126
- def subject
127
- if [:attrasgn, :call, :iter].include? node_type
128
- self[1]
129
- end
130
- end
131
-
132
- # Get the class name of the class node.
133
- #
134
- # s(:class, :User, nil, s(:scope))
135
- # => :User
136
- #
137
- # @return [Symbol] class name of class node
138
- def class_name
139
- if :class == node_type
140
- self[1]
141
- end
142
- end
143
-
144
- # Get the base class of the class node.
145
- #
146
- # s(:class, :User, s(:colon2, s(:const, :ActiveRecord), :Base), s(:scope))
147
- # => s(:colon2, s(:const, :ActiveRecord), :Base)
148
- #
149
- # @return [Sexp] base class of class node
150
- def base_class
151
- if :class == node_type
152
- self[2]
153
- end
154
- end
155
-
156
- # Get the left value of the lasgn or iasgn node.
157
- #
158
- # s(:lasgn,
159
- # :user,
160
- # s(:call,
161
- # s(:call, nil, :params, s(:arglist)),
162
- # :[],
163
- # s(:arglist, s(:lit, :user))
164
- # )
165
- # )
166
- # => :user
167
- #
168
- # s(:iasgn,
169
- # :@user,
170
- # s(:call,
171
- # s(:call, nil, :params, s(:arglist)),
172
- # :[],
173
- # s(:arglist, s(:lit, :user))
174
- # )
175
- # )
176
- # => :@user
177
- #
178
- # @return [Symbol] left value of lasgn or iasgn node
179
- def left_value
180
- if [:lasgn, :iasgn].include? node_type
181
- self[1]
182
- end
183
- end
184
-
185
- # Get the right value of lasgn and iasgn node.
186
- #
187
- # s(:lasgn,
188
- # :user,
189
- # s(:call, nil, :current_user, s(:arglist))
190
- # )
191
- # => s(:call, nil, :current_user, s(:arglist))
192
- #
193
- # s(:iasgn,
194
- # :@user,
195
- # s(:call, nil, :current_user, s(:arglist))
196
- # )
197
- # => s(:call, nil, :current_user, s(:arglist))
198
- #
199
- # @return [Sexp] right value of lasgn or iasgn node
200
- def right_value
201
- if [:lasgn, :iasgn].include? node_type
202
- self[2]
203
- end
204
- end
205
-
206
- # Get the message of attrasgn and call node.
207
- #
208
- # s(:attrasgn,
209
- # s(:call, nil, :user, s(:arglist)),
210
- # :name=,
211
- # s(:arglist,
212
- # s(:call,
213
- # s(:call, nil, :params, s(:arglist)),
214
- # :[],
215
- # s(:arglist, s(:lit, :name))
216
- # )
217
- # )
218
- # )
219
- # => :name=
220
- #
221
- # s(:call, nil, :has_many, s(:arglist, s(:lit, :projects)))
222
- # => :has_many
223
- #
224
- # @return [Symbol] message of attrasgn or call node
225
- def message
226
- if [:attrasgn, :call].include? node_type
227
- self[2]
228
- end
229
- end
230
-
231
- # Get arguments of call node.
232
- #
233
- # s(:attrasgn,
234
- # s(:call, nil, :post, s(:arglist)),
235
- # :user=,
236
- # s(:arglist,
237
- # s(:call, nil, :current_user, s(:arglist))
238
- # )
239
- # )
240
- # => s(:arglist, s(:call, nil, :current_user, s(:arglist)))
241
- #
242
- # s(:call,
243
- # s(:call, nil, :username, s(:arglist)),
244
- # :==,
245
- # s(:arglist, s(:str, ""))
246
- # )
247
- # => s(:arglist, s(:str, ""))
248
- #
249
- # @return [Sexp] arguments of attrasgn or call node
250
- def arguments
251
- if [:attrasgn, :call].include? node_type
252
- self[3]
253
- end
254
- end
255
-
256
- # Get the conditional statement of if node.
257
- #
258
- # s(:if,
259
- # s(:call,
260
- # s(:call, nil, :current_user, s(:arglist)),
261
- # :present?,
262
- # s(:arglist)
263
- # ),
264
- # s(:call, nil, :puts,
265
- # s(:arglist,
266
- # s(:call,
267
- # s(:call, nil, :current_user, s(:arglist)),
268
- # :login,
269
- # s(:arglist)
270
- # )
271
- # )
272
- # ),
273
- # nil
274
- # )
275
- # => s(:call, s(:call, nil, :current_user, s(:arglist)), :present?, s(:arglist))
276
- #
277
- # @return [Sexp] conditional statement of if node
278
- def conditional_statement
279
- if :if == node_type
280
- self[1]
281
- end
282
- end
283
-
284
- # Get the body node when conditional statement is true.
285
- #
286
- # s(:if,
287
- # s(:call, s(:call, nil, :current_user, s(:arglist)), :login?, s(:arglist)),
288
- # s(:call, s(:call, nil, :current_user, s(:arglist)), :login, s(:arglist)),
289
- # s(:call, s(:call, nil, :current_user, s(:arglist)), :email, s(:arglist))
290
- # )
291
- # => s(:call, s(:call, nil, :current_user, s(:arglist)), :login, s(:arglist))
292
- #
293
- # @return [Sexp] the body node when conditional statement is true
294
- def true_node
295
- if :if == node_type
296
- self[2]
297
- end
298
- end
299
-
300
- # Get the body node when conditional statement is false.
301
- #
302
- # s(:if,
303
- # s(:call, s(:call, nil, :current_user, s(:arglist)), :login?, s(:arglist)),
304
- # s(:call, s(:call, nil, :current_user, s(:arglist)), :login, s(:arglist)),
305
- # s(:call, s(:call, nil, :current_user, s(:arglist)), :email, s(:arglist))
306
- # )
307
- # => s(:call, s(:call, nil, :current_user, s(:arglist)), :email, s(:arglist))
308
- #
309
- # @return [Sexp] the body node when conditional statement is false
310
- def false_node
311
- if :if == node_type
312
- self[3]
313
- end
314
- end
315
-
316
- # Get the method name of defn node.
317
- #
318
- # s(:defn, :show, s(:args), s(:scope, s(:block, s(:nil))))
319
- # => :show
320
- #
321
- # @return [Symbol] method name of defn node
322
- def method_name
323
- if :defn == node_type
324
- self[1]
325
- end
326
- end
327
-
328
- # Get body of iter, class and defn node.
329
- #
330
- # s(:iter,
331
- # s(:call, nil, :resources, s(:arglist, s(:lit, :posts))),
332
- # nil,
333
- # s(:call, nil, :resources, s(:arglist, s(:lit, :comments)))
334
- # )
335
- # => s(:call, nil, :resources, s(:arglist, s(:lit, :comments)))
336
- #
337
- # s(:class, :User, nil,
338
- # s(:scope,
339
- # s(:block,
340
- # s(:defn, :login, s(:args), s(:scope, s(:block, s(:nil)))),
341
- # s(:defn, :email, s(:args), s(:scope, s(:block, s(:nil))))
342
- # )
343
- # )
344
- # )
345
- # => s(:block,
346
- # s(:defn, :login, s(:args), s(:scope, s(:block, s(:nil)))),
347
- # s(:defn, :email, s(:args), s(:scope, s(:block, s(:nil))))
348
- # )
349
- #
350
- # s(:defn, :fullname, s(:args),
351
- # s(:scope,
352
- # s(:block,
353
- # s(:call,
354
- # s(:call,
355
- # s(:call, nil, :first_name, s(:arglist)),
356
- # :+,
357
- # s(:arglist,
358
- # s(:call, nil, :last, s(:arglist))
359
- # )
360
- # ),
361
- # :+,
362
- # s(:arglist,
363
- # s(:call, nil, :name, s(:arglist))
364
- # )
365
- # )
366
- # )
367
- # )
368
- # )
369
- # => s(:block,
370
- # s(:call,
371
- # s(:call,
372
- # s(:call, nil, :first_name, s(:arglist)),
373
- # :+,
374
- # s(:arglist,
375
- # s(:call, nil, :last, s(:arglist))
376
- # )
377
- # ),
378
- # :+,
379
- # s(:arglist,
380
- # s(:call, nil, :name, s(:arglist))
381
- # )
382
- # )
383
- # )
384
- #
385
- # @return [Sexp] body of iter, class or defn node
386
- def body
387
- if :iter == node_type
388
- self[3]
389
- elsif :class == node_type
390
- self[3][1]
391
- elsif :module == node_type
392
- self[2][1]
393
- elsif :defn == node_type
394
- self[3][1]
395
- end
396
- end
397
-
398
- # to_s for lvar, ivar, lit, const, array, hash, and colon2 node.
399
- #
400
- # @param [Hash] options
401
- # :remove_at remove the @ symbol for ivar.
402
- # @return [String] to_s
403
- def to_s(options={})
404
- case node_type
405
- when :true, :false, :nil
406
- self[0].to_s
407
- when :ivar
408
- options[:remove_at] ? self[1].to_s[1..-1] : self[1].to_s
409
- when :lvar, :str, :lit, :const
410
- self[1].to_s
411
- when :array
412
- "[\"#{self.children.collect(&:to_s).join('", "')}\"]"
413
- when :hash
414
- key_value = false # false is key, true is value
415
- result = ['{']
416
- children.each do |child|
417
- if [:true, :false, :nil, :array, :hash].include? child.node_type
418
- result << "#{child}"
419
- else
420
- result << "\"#{child}\""
421
- end
422
- result << (key_value ? ", " : " => ")
423
- key_value = !key_value
424
- end
425
- result.join("").sub(/, $/, '') + '}'
426
- when :colon2
427
- "#{self[1]}::#{self[2]}"
428
- else
429
- ""
430
- end
431
- end
432
-
433
- # if the return value of these methods is nil, then return RailsBestPractices::Core::Nil.new instead
434
- [:node_type, :subject, :message, :arguments, :class_name, :base_class, :method_name, :body, :conditional_statement, :true_node, :false_node, :left_value, :right_value].each do |method|
435
- class_eval <<-EOS
436
- alias_method :origin_#{method}, :#{method}
437
-
438
- def #{method}
439
- ret = origin_#{method}
440
- ret.nil? ? RailsBestPractices::Core::Nil.new : ret
441
- end
442
- EOS
443
- end
444
- end