rails_best_practices 0.6.1 → 0.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +12 -0
- data/.rspec.example +2 -0
- data/.rvmrc.example +2 -0
- data/.watchr +65 -0
- data/.watchr.example +65 -0
- data/Gemfile +3 -0
- data/README.md +6 -0
- data/Rakefile +45 -0
- data/assets/result.html.haml +53 -0
- data/lib/rails_best_practices.rb +30 -11
- data/lib/rails_best_practices/checks/check.rb +10 -10
- data/lib/rails_best_practices/command.rb +9 -0
- data/lib/rails_best_practices/core/visitable_sexp.rb +9 -10
- data/lib/rails_best_practices/version.rb +1 -1
- data/rails_best_practices.gemspec +32 -0
- data/rubies_test.sh +10 -0
- data/spec/rails_best_practices/checks/add_model_virtual_attribute_check_spec.rb +113 -0
- data/spec/rails_best_practices/checks/always_add_db_index_check_spec.rb +172 -0
- data/spec/rails_best_practices/checks/check_spec.rb +57 -0
- data/spec/rails_best_practices/checks/dry_bundler_in_capistrano_check_spec.rb +39 -0
- data/spec/rails_best_practices/checks/isolate_seed_data_check_spec.rb +105 -0
- data/spec/rails_best_practices/checks/keep_finders_on_their_own_model_check_spec.rb +103 -0
- data/spec/rails_best_practices/checks/law_of_demeter_check_spec.rb +101 -0
- data/spec/rails_best_practices/checks/move_code_into_controller_check_spec.rb +33 -0
- data/spec/rails_best_practices/checks/move_code_into_helper_check_spec.rb +28 -0
- data/spec/rails_best_practices/checks/move_code_into_model_check_spec.rb +55 -0
- data/spec/rails_best_practices/checks/move_finder_to_named_scope_check_spec.rb +82 -0
- data/spec/rails_best_practices/checks/move_model_logic_into_model_check_spec.rb +49 -0
- data/spec/rails_best_practices/checks/needless_deep_nesting_check_spec.rb +140 -0
- data/spec/rails_best_practices/checks/not_use_default_route_check_spec.rb +63 -0
- data/spec/rails_best_practices/checks/overuse_route_customizations_check_spec.rb +159 -0
- data/spec/rails_best_practices/checks/replace_complex_creation_with_factory_method_check_spec.rb +76 -0
- data/spec/rails_best_practices/checks/replace_instance_variable_with_local_variable_check_spec.rb +36 -0
- data/spec/rails_best_practices/checks/use_before_filter_check_spec.rb +85 -0
- data/spec/rails_best_practices/checks/use_model_association_check_spec.rb +71 -0
- data/spec/rails_best_practices/checks/use_observer_check_spec.rb +155 -0
- data/spec/rails_best_practices/checks/use_query_attribute_check_spec.rb +192 -0
- data/spec/rails_best_practices/checks/use_say_with_time_in_migrations_check_spec.rb +113 -0
- data/spec/rails_best_practices/checks/use_scope_access_check_spec.rb +193 -0
- data/spec/rails_best_practices/core/error_spec.rb +7 -0
- data/spec/rails_best_practices/core/visitable_sexp_spec.rb +259 -0
- data/spec/rails_best_practices/core_ext/enumerable_spec.rb +7 -0
- data/spec/rails_best_practices/core_ext/nil_class_spec.rb +11 -0
- data/spec/rails_best_practices_spec.rb +44 -0
- data/spec/spec_helper.rb +4 -0
- metadata +114 -32
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RailsBestPractices::Checks::KeepFindersOnTheirOwnModelCheck do
|
4
|
+
before(:each) do
|
5
|
+
@runner = RailsBestPractices::Core::Runner.new(RailsBestPractices::Checks::KeepFindersOnTheirOwnModelCheck.new)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should keep finders on thier own model" do
|
9
|
+
content = <<-EOF
|
10
|
+
class Post < ActiveRecord::Base
|
11
|
+
has_many :comments
|
12
|
+
|
13
|
+
def find_valid_comments
|
14
|
+
self.comment.find(:all, :conditions => { :is_spam => false },
|
15
|
+
:limit => 10)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
EOF
|
19
|
+
@runner.review('app/models/post.rb', content)
|
20
|
+
errors = @runner.errors
|
21
|
+
errors.should_not be_empty
|
22
|
+
errors[0].to_s.should == "app/models/post.rb:5 - keep finders on their own model"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should keep finders on thier own model with all method" do
|
26
|
+
content = <<-EOF
|
27
|
+
class Post < ActiveRecord::Base
|
28
|
+
has_many :comments
|
29
|
+
|
30
|
+
def find_valid_comments
|
31
|
+
self.comment.all(:conditions => { :is_spam => false },
|
32
|
+
:limit => 10)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
EOF
|
36
|
+
@runner.review('app/models/post.rb', content)
|
37
|
+
errors = @runner.errors
|
38
|
+
errors.should_not be_empty
|
39
|
+
errors[0].to_s.should == "app/models/post.rb:5 - keep finders on their own model"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should not keep finders on thier own model with self finder" do
|
43
|
+
content = <<-EOF
|
44
|
+
class Post < ActiveRecord::Base
|
45
|
+
has_many :comments
|
46
|
+
|
47
|
+
def find_valid_comments
|
48
|
+
self.find(:all, :conditions => { :is_spam => false },
|
49
|
+
:limit => 10)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
EOF
|
53
|
+
@runner.review('app/models/post.rb', content)
|
54
|
+
errors = @runner.errors
|
55
|
+
errors.should be_empty
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should not keep finders on thier own model with own finder" do
|
59
|
+
content = <<-EOF
|
60
|
+
class Post < ActiveRecord::Base
|
61
|
+
has_many :comments
|
62
|
+
|
63
|
+
def find_valid_comments
|
64
|
+
Post.find(:all, :conditions => { :is_spam => false },
|
65
|
+
:limit => 10)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
EOF
|
69
|
+
@runner.review('app/models/post.rb', content)
|
70
|
+
errors = @runner.errors
|
71
|
+
errors.should be_empty
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should not keep finders on their own model without finder" do
|
75
|
+
content = <<-EOF
|
76
|
+
class Post < ActiveRecord::Base
|
77
|
+
has_many :comments
|
78
|
+
|
79
|
+
def find_valid_comments
|
80
|
+
self.comments.destroy_all
|
81
|
+
end
|
82
|
+
end
|
83
|
+
EOF
|
84
|
+
@runner.review('app/models/post.rb', content)
|
85
|
+
errors = @runner.errors
|
86
|
+
errors.should be_empty
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should not keep finders on their own model with ruby Array#find" do
|
90
|
+
content = <<-EOF
|
91
|
+
class Post < ActiveRecord::Base
|
92
|
+
has_many :comments
|
93
|
+
|
94
|
+
def active_comments
|
95
|
+
self.comments.find {|comment| comment.status == 'active'}
|
96
|
+
end
|
97
|
+
end
|
98
|
+
EOF
|
99
|
+
@runner.review('app/models/post.rb', content)
|
100
|
+
errors = @runner.errors
|
101
|
+
errors.should be_empty
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RailsBestPractices::Checks::LawOfDemeterCheck do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
@runner = RailsBestPractices::Core::Runner.new(RailsBestPractices::Checks::LawOfDemeterCheck.new)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "belongs_to" do
|
10
|
+
before(:each) do
|
11
|
+
content = <<-EOF
|
12
|
+
class Invoice < ActiveRecord::Base
|
13
|
+
belongs_to :user
|
14
|
+
end
|
15
|
+
EOF
|
16
|
+
@runner.prepare('app/models/invoice.rb', content)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should law of demeter" do
|
20
|
+
content = <<-EOF
|
21
|
+
<%= @invoice.user.name %>
|
22
|
+
<%= @invoice.user.address %>
|
23
|
+
<%= @invoice.user.cellphone %>
|
24
|
+
EOF
|
25
|
+
@runner.review('app/views/invoices/show.html.erb', content)
|
26
|
+
errors = @runner.errors
|
27
|
+
errors.should_not be_empty
|
28
|
+
errors[0].to_s.should == "app/views/invoices/show.html.erb:1 - law of demeter"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should law of demeter" do
|
32
|
+
content = <<-EOF
|
33
|
+
= @invoice.user.name
|
34
|
+
= @invoice.user.address
|
35
|
+
= @invoice.user.cellphone
|
36
|
+
EOF
|
37
|
+
@runner.review('app/views/invoices/show.html.haml', content)
|
38
|
+
errors = @runner.errors
|
39
|
+
errors.should_not be_empty
|
40
|
+
errors[0].to_s.should == "app/views/invoices/show.html.haml:1 - law of demeter"
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should no law of demeter" do
|
44
|
+
content = <<-EOF
|
45
|
+
<%= @invoice.user_name %>
|
46
|
+
<%= @invoice.user_address %>
|
47
|
+
<%= @invoice.user_cellphone %>
|
48
|
+
EOF
|
49
|
+
@runner.review('app/views/invoices/show.html.erb', content)
|
50
|
+
errors = @runner.errors
|
51
|
+
errors.should be_empty
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "has_one" do
|
56
|
+
before(:each) do
|
57
|
+
content = <<-EOF
|
58
|
+
class Invoice < ActiveRecord::Base
|
59
|
+
has_one :price
|
60
|
+
end
|
61
|
+
EOF
|
62
|
+
@runner.prepare('app/models/invoice.rb', content)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should law of demeter" do
|
66
|
+
content = <<-EOF
|
67
|
+
<%= @invoice.price.currency %>
|
68
|
+
<%= @invoice.price.number %>
|
69
|
+
EOF
|
70
|
+
@runner.review('app/views/invoices/show.html.erb', content)
|
71
|
+
errors = @runner.errors
|
72
|
+
errors.should_not be_empty
|
73
|
+
errors[0].to_s.should == "app/views/invoices/show.html.erb:1 - law of demeter"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should no law of demeter with method call" do
|
78
|
+
content = <<-EOF
|
79
|
+
class Question < ActiveRecord::Base
|
80
|
+
has_many :answers, :dependent => :destroy
|
81
|
+
end
|
82
|
+
EOF
|
83
|
+
@runner.prepare('app/models/question.rb', content)
|
84
|
+
content = <<-EOF
|
85
|
+
class Answer < ActiveRecord::Base
|
86
|
+
belongs_to :question, :counter_cache => true, :touch => true
|
87
|
+
end
|
88
|
+
EOF
|
89
|
+
@runner.prepare('app/models/answer.rb', content)
|
90
|
+
content = <<-EOF
|
91
|
+
class CommentsController < ApplicationController
|
92
|
+
def comment_url
|
93
|
+
question_path(@answer.question)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
EOF
|
97
|
+
@runner.review('app/controllers/comments_controller.rb', content)
|
98
|
+
errors = @runner.errors
|
99
|
+
errors.should be_empty
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RailsBestPractices::Checks::MoveCodeIntoControllerCheck do
|
4
|
+
before(:each) do
|
5
|
+
@runner = RailsBestPractices::Core::Runner.new(RailsBestPractices::Checks::MoveCodeIntoControllerCheck.new)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should move code into controller" do
|
9
|
+
content = <<-EOF
|
10
|
+
<% @posts = Post.find(:all) %>
|
11
|
+
<% @posts.each do |post| %>
|
12
|
+
<%=h post.title %>
|
13
|
+
<%=h post.content %>
|
14
|
+
<% end %>
|
15
|
+
EOF
|
16
|
+
@runner.review('app/views/posts/index.html.erb', content)
|
17
|
+
errors = @runner.errors
|
18
|
+
errors.should_not be_empty
|
19
|
+
errors[0].to_s.should == "app/views/posts/index.html.erb:1 - move code into controller"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should not move code into controller" do
|
23
|
+
content = <<-EOF
|
24
|
+
<% @posts.each do |post| %>
|
25
|
+
<%=h post.title %>
|
26
|
+
<%=h post.content %>
|
27
|
+
<% end %>
|
28
|
+
EOF
|
29
|
+
@runner.review('app/views/posts/index.html.erb', content)
|
30
|
+
errors = @runner.errors
|
31
|
+
errors.should be_empty
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RailsBestPractices::Checks::MoveCodeIntoHelperCheck do
|
4
|
+
before(:each) do
|
5
|
+
@runner = RailsBestPractices::Core::Runner.new(RailsBestPractices::Checks::MoveCodeIntoHelperCheck.new('array_count' => 2))
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should move code into helper" do
|
9
|
+
content = <<-EOF
|
10
|
+
<%= select_tag :state, options_for_select( [[t(:draft), "draft"],
|
11
|
+
[t(:published), "published"]],
|
12
|
+
params[:default_state] ) %>
|
13
|
+
EOF
|
14
|
+
@runner.review('app/views/posts/show.html.erb', content)
|
15
|
+
errors = @runner.errors
|
16
|
+
errors.should_not be_empty
|
17
|
+
errors[0].to_s.should == "app/views/posts/show.html.erb:3 - move code into helper (array_count >= 2)"
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should not move code into helper with simple arguments" do
|
21
|
+
content = <<-EOF
|
22
|
+
<%= select_tag :state, options_for_select( Post.STATES ) %>
|
23
|
+
EOF
|
24
|
+
@runner.review('app/views/posts/show.html.erb', content)
|
25
|
+
errors = @runner.errors
|
26
|
+
errors.should be_empty
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RailsBestPractices::Checks::MoveCodeIntoModelCheck do
|
4
|
+
before(:each) do
|
5
|
+
@runner = RailsBestPractices::Core::Runner.new(RailsBestPractices::Checks::MoveCodeIntoModelCheck.new)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should move code into model" do
|
9
|
+
content =<<-EOF
|
10
|
+
<% if current_user && (current_user == @post.user || @post.editors.include?(current_user)) %>
|
11
|
+
<%= link_to 'Edit this post', edit_post_url(@post) %>
|
12
|
+
<% end %>
|
13
|
+
EOF
|
14
|
+
@runner.review('app/views/posts/show.html.erb', content)
|
15
|
+
errors = @runner.errors
|
16
|
+
errors.should_not be_empty
|
17
|
+
errors[0].to_s.should == "app/views/posts/show.html.erb:1 - move code into model (@post use_count > 2)"
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should move code into model with haml" do
|
21
|
+
content =<<-EOF
|
22
|
+
- if current_user && (current_user == @post.user || @post.editors.include?(current_user))
|
23
|
+
= link_to 'Edit this post', edit_post_url(@post)
|
24
|
+
EOF
|
25
|
+
@runner.review('app/views/posts/show.html.haml', content)
|
26
|
+
errors = @runner.errors
|
27
|
+
errors.should_not be_empty
|
28
|
+
errors[0].to_s.should == "app/views/posts/show.html.haml:1 - move code into model (@post use_count > 2)"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should move code into model only review for current if conditional statement" do
|
32
|
+
content =<<-EOF
|
33
|
+
<% if @post.title %>
|
34
|
+
<% if @post.user %>
|
35
|
+
<% if @post.description %>
|
36
|
+
<% end %>
|
37
|
+
<% end %>
|
38
|
+
<% end %>
|
39
|
+
EOF
|
40
|
+
@runner.review('app/views/posts/show.html.erb', content)
|
41
|
+
errors = @runner.errors
|
42
|
+
errors.should be_empty
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should not move code into model" do
|
46
|
+
content =<<-EOF
|
47
|
+
<% if @post.editable_by?(current_user) %>
|
48
|
+
<%= link_to 'Edit this post', edit_post_url(@post) %>
|
49
|
+
<% end %>
|
50
|
+
EOF
|
51
|
+
@runner.review('app/views/posts/show.html.erb', content)
|
52
|
+
errors = @runner.errors
|
53
|
+
errors.should be_empty
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RailsBestPractices::Checks::MoveFinderToNamedScopeCheck do
|
4
|
+
before(:each) do
|
5
|
+
@runner = RailsBestPractices::Core::Runner.new(RailsBestPractices::Checks::MoveFinderToNamedScopeCheck.new)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should move finder to named_scope" do
|
9
|
+
content = <<-EOF
|
10
|
+
class PostsController < ActionController::Base
|
11
|
+
|
12
|
+
def index
|
13
|
+
@public_posts = Post.find(:all, :conditions => { :state => 'public' },
|
14
|
+
:limit => 10,
|
15
|
+
:order => 'created_at desc')
|
16
|
+
|
17
|
+
@draft_posts = Post.find(:all, :conditions => { :state => 'draft' },
|
18
|
+
:limit => 10,
|
19
|
+
:order => 'created_at desc')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
EOF
|
23
|
+
@runner.review('app/controllers/posts_controller.rb', content)
|
24
|
+
errors = @runner.errors
|
25
|
+
errors.size.should == 2
|
26
|
+
errors[0].to_s.should == "app/controllers/posts_controller.rb:4 - move finder to named_scope"
|
27
|
+
errors[1].to_s.should == "app/controllers/posts_controller.rb:8 - move finder to named_scope"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should not move simple finder" do
|
31
|
+
content = <<-EOF
|
32
|
+
class PostsController < ActionController::Base
|
33
|
+
|
34
|
+
def index
|
35
|
+
@all_posts = Post.find(:all)
|
36
|
+
@another_all_posts = Post.all
|
37
|
+
@first_post = Post.find(:first)
|
38
|
+
@another_first_post = Post.first
|
39
|
+
@last_post = Post.find(:last)
|
40
|
+
@another_last_post = Post.last
|
41
|
+
end
|
42
|
+
end
|
43
|
+
EOF
|
44
|
+
@runner.review('app/controllers/posts_controller.rb', content)
|
45
|
+
@runner.errors.should be_empty
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should not move namd_scope" do
|
49
|
+
content = <<-EOF
|
50
|
+
class PostsController < ActionController::Base
|
51
|
+
|
52
|
+
def index
|
53
|
+
@public_posts = Post.published
|
54
|
+
@draft_posts = Post.draft
|
55
|
+
end
|
56
|
+
end
|
57
|
+
EOF
|
58
|
+
@runner.review('app/controllers/posts_controller.rb', content)
|
59
|
+
@runner.errors.should be_empty
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should not review model file" do
|
63
|
+
content = <<-EOF
|
64
|
+
class Post < ActiveRecord::Base
|
65
|
+
|
66
|
+
def published
|
67
|
+
Post.find(:all, :conditions => { :state => 'public' },
|
68
|
+
:limit => 10, :order => 'created_at desc')
|
69
|
+
end
|
70
|
+
|
71
|
+
def published
|
72
|
+
Post.find(:all, :conditions => { :state => 'draft' },
|
73
|
+
:limit => 10, :order => 'created_at desc')
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
EOF
|
78
|
+
@runner.review('app/model/post.rb', content)
|
79
|
+
@runner.errors.should be_empty
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RailsBestPractices::Checks::MoveModelLogicIntoModelCheck do
|
4
|
+
before(:each) do
|
5
|
+
@runner = RailsBestPractices::Core::Runner.new(RailsBestPractices::Checks::MoveModelLogicIntoModelCheck.new)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should move model logic into model" do
|
9
|
+
content = <<-EOF
|
10
|
+
class PostsController < ApplicationController
|
11
|
+
|
12
|
+
def publish
|
13
|
+
@post = Post.find(params[:id])
|
14
|
+
@post.update_attributes(:is_published, true)
|
15
|
+
@post.approved_by = current_user
|
16
|
+
if @post.created_at > Time.now - 7.days
|
17
|
+
@post.popular = 100
|
18
|
+
else
|
19
|
+
@post.popular = 0
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
redirect_to post_url(@post)
|
24
|
+
end
|
25
|
+
EOF
|
26
|
+
@runner.review('app/controllers/posts_controller.rb', content)
|
27
|
+
errors = @runner.errors
|
28
|
+
errors.should_not be_empty
|
29
|
+
errors[0].to_s.should == "app/controllers/posts_controller.rb:3 - move model logic into model (@post use_count > 4)"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should not move model logic into model with simple model calling" do
|
33
|
+
content = <<-EOF
|
34
|
+
class PostsController < ApplicationController
|
35
|
+
|
36
|
+
def publish
|
37
|
+
@post = Post.find(params[:id])
|
38
|
+
@post.update_attributes(:is_published, true)
|
39
|
+
@post.approved_by = current_user
|
40
|
+
end
|
41
|
+
|
42
|
+
redirect_to post_url(@post)
|
43
|
+
end
|
44
|
+
EOF
|
45
|
+
@runner.review('app/controllers/posts_controller.rb', content)
|
46
|
+
errors = @runner.errors
|
47
|
+
errors.should be_empty
|
48
|
+
end
|
49
|
+
end
|