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.
Files changed (46) hide show
  1. data/.gitignore +12 -0
  2. data/.rspec.example +2 -0
  3. data/.rvmrc.example +2 -0
  4. data/.watchr +65 -0
  5. data/.watchr.example +65 -0
  6. data/Gemfile +3 -0
  7. data/README.md +6 -0
  8. data/Rakefile +45 -0
  9. data/assets/result.html.haml +53 -0
  10. data/lib/rails_best_practices.rb +30 -11
  11. data/lib/rails_best_practices/checks/check.rb +10 -10
  12. data/lib/rails_best_practices/command.rb +9 -0
  13. data/lib/rails_best_practices/core/visitable_sexp.rb +9 -10
  14. data/lib/rails_best_practices/version.rb +1 -1
  15. data/rails_best_practices.gemspec +32 -0
  16. data/rubies_test.sh +10 -0
  17. data/spec/rails_best_practices/checks/add_model_virtual_attribute_check_spec.rb +113 -0
  18. data/spec/rails_best_practices/checks/always_add_db_index_check_spec.rb +172 -0
  19. data/spec/rails_best_practices/checks/check_spec.rb +57 -0
  20. data/spec/rails_best_practices/checks/dry_bundler_in_capistrano_check_spec.rb +39 -0
  21. data/spec/rails_best_practices/checks/isolate_seed_data_check_spec.rb +105 -0
  22. data/spec/rails_best_practices/checks/keep_finders_on_their_own_model_check_spec.rb +103 -0
  23. data/spec/rails_best_practices/checks/law_of_demeter_check_spec.rb +101 -0
  24. data/spec/rails_best_practices/checks/move_code_into_controller_check_spec.rb +33 -0
  25. data/spec/rails_best_practices/checks/move_code_into_helper_check_spec.rb +28 -0
  26. data/spec/rails_best_practices/checks/move_code_into_model_check_spec.rb +55 -0
  27. data/spec/rails_best_practices/checks/move_finder_to_named_scope_check_spec.rb +82 -0
  28. data/spec/rails_best_practices/checks/move_model_logic_into_model_check_spec.rb +49 -0
  29. data/spec/rails_best_practices/checks/needless_deep_nesting_check_spec.rb +140 -0
  30. data/spec/rails_best_practices/checks/not_use_default_route_check_spec.rb +63 -0
  31. data/spec/rails_best_practices/checks/overuse_route_customizations_check_spec.rb +159 -0
  32. data/spec/rails_best_practices/checks/replace_complex_creation_with_factory_method_check_spec.rb +76 -0
  33. data/spec/rails_best_practices/checks/replace_instance_variable_with_local_variable_check_spec.rb +36 -0
  34. data/spec/rails_best_practices/checks/use_before_filter_check_spec.rb +85 -0
  35. data/spec/rails_best_practices/checks/use_model_association_check_spec.rb +71 -0
  36. data/spec/rails_best_practices/checks/use_observer_check_spec.rb +155 -0
  37. data/spec/rails_best_practices/checks/use_query_attribute_check_spec.rb +192 -0
  38. data/spec/rails_best_practices/checks/use_say_with_time_in_migrations_check_spec.rb +113 -0
  39. data/spec/rails_best_practices/checks/use_scope_access_check_spec.rb +193 -0
  40. data/spec/rails_best_practices/core/error_spec.rb +7 -0
  41. data/spec/rails_best_practices/core/visitable_sexp_spec.rb +259 -0
  42. data/spec/rails_best_practices/core_ext/enumerable_spec.rb +7 -0
  43. data/spec/rails_best_practices/core_ext/nil_class_spec.rb +11 -0
  44. data/spec/rails_best_practices_spec.rb +44 -0
  45. data/spec/spec_helper.rb +4 -0
  46. metadata +114 -32
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
  module RailsBestPractices
3
- VERSION = "0.6.1"
3
+ VERSION = "0.6.5"
4
4
  end
5
5
 
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path("../lib/rails_best_practices/version", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "rails_best_practices"
6
+ s.version = RailsBestPractices::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ["Richard Huang"]
9
+ s.email = ["flyerhzm@gmail.com"]
10
+ s.homepage = "http://rails-bestpractices.com"
11
+ s.summary = "a code metric tool for rails codes."
12
+ s.description = "a code metric tool for rails codes, written in Ruby."
13
+
14
+ s.required_rubygems_version = ">= 1.3.6"
15
+
16
+ s.add_dependency("ruby_parser", "~> 2.0.4")
17
+ s.add_dependency("ruby-progressbar", "~> 0.0.9")
18
+ s.add_dependency("colored", "~> 1.2")
19
+ s.add_dependency("erubis", "~> 2.6.6")
20
+ s.add_dependency("haml", "~> 3.0.18")
21
+ s.add_dependency("i18n")
22
+ s.add_dependency("activesupport")
23
+
24
+ s.add_development_dependency("rspec", "~> 2.0.1")
25
+ s.add_development_dependency("watchr", "~> 0.6")
26
+ s.add_development_dependency("bundler", ">= 1.0.0")
27
+
28
+ s.files = `git ls-files`.split("\n")
29
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
30
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
31
+ s.require_paths = ["lib"]
32
+ end
data/rubies_test.sh ADDED
@@ -0,0 +1,10 @@
1
+ #!/bin/bash
2
+ rvm ruby-1.8.7@rails_best_practices ruby -S bundle install || exit $?
3
+ rvm ruby-1.9.2@rails_best_practices ruby -S bundle install || exit $?
4
+ rvm ree@rails_best_practices ruby -S bundle install || exit $?
5
+ rvm 1.8.7@rails_best_practices
6
+ rake spec:progress
7
+ rvm 1.9.2@rails_best_practices
8
+ rake spec:progress
9
+ rvm ree@rails_best_practices
10
+ rake spec:progress
@@ -0,0 +1,113 @@
1
+ require 'spec_helper'
2
+
3
+ describe RailsBestPractices::Checks::AddModelVirtualAttributeCheck do
4
+ before(:each) do
5
+ @runner = RailsBestPractices::Core::Runner.new(RailsBestPractices::Checks::AddModelVirtualAttributeCheck.new)
6
+ end
7
+
8
+ it "should add model virtual attribute" do
9
+ content = <<-EOF
10
+ class UsersController < ApplicationController
11
+
12
+ def create
13
+ @user = User.new(params[:user])
14
+ @user.first_name = params[:full_name].split(' ', 2).first
15
+ @user.last_name = params[:full_name].split(' ', 2).last
16
+ @user.save
17
+ end
18
+ end
19
+ EOF
20
+ @runner.review('app/controllers/users_controller.rb', content)
21
+ errors = @runner.errors
22
+ errors.should_not be_empty
23
+ errors[0].to_s.should == "app/controllers/users_controller.rb:3 - add model virtual attribute (for @user)"
24
+ end
25
+
26
+ it "should add model virtual attribute with local assignment" do
27
+ content = <<-EOF
28
+ class UsersController < ApplicationController
29
+
30
+ def create
31
+ user = User.new(params[:user])
32
+ user.first_name = params[:full_name].split(' ', 2).first
33
+ user.last_name = params[:full_name].split(' ', 2).last
34
+ user.save
35
+ end
36
+ end
37
+ EOF
38
+ @runner.review('app/controllers/users_controller.rb', content)
39
+ errors = @runner.errors
40
+ errors.should_not be_empty
41
+ errors[0].to_s.should == "app/controllers/users_controller.rb:3 - add model virtual attribute (for user)"
42
+ end
43
+
44
+ it "should not add model virtual attribute with differen param" do
45
+ content = <<-EOF
46
+ class UsersController < ApplicationController
47
+
48
+ def create
49
+ @user = User.new(params[:user])
50
+ @user.first_name = params[:first_name]
51
+ @user.last_name = params[:last_name]
52
+ @user.save
53
+ end
54
+ end
55
+ EOF
56
+ @runner.review('app/controllers/users_controller.rb', content)
57
+ errors = @runner.errors
58
+ errors.should be_empty
59
+ end
60
+
61
+ it "should not add model virtual attribute with read" do
62
+ content = <<-EOF
63
+ class UsersController < ApplicationController
64
+
65
+ def show
66
+ if params[:id]
67
+ @user = User.find(params[:id])
68
+ else
69
+ @user = current_user
70
+ end
71
+ end
72
+ end
73
+ EOF
74
+ @runner.review('app/controllers/users_controller.rb', content)
75
+ errors = @runner.errors
76
+ errors.should be_empty
77
+ end
78
+
79
+ it "should add model virtual attribute with two dimension params" do
80
+ content = <<-EOF
81
+ class UsersController < ApplicationController
82
+
83
+ def create
84
+ @user = User.new(params[:user])
85
+ @user.first_name = params[:user][:full_name].split(' ', 2).first
86
+ @user.last_name = params[:user][:full_name].split(' ', 2).last
87
+ @user.save
88
+ end
89
+ end
90
+ EOF
91
+ @runner.review('app/controllers/users_controller.rb', content)
92
+ errors = @runner.errors
93
+ errors.should_not be_empty
94
+ errors[0].to_s.should == "app/controllers/users_controller.rb:3 - add model virtual attribute (for @user)"
95
+ end
96
+
97
+ it "should no add model virtual attribute with two dimension params" do
98
+ content = <<-EOF
99
+ class UsersController < ApplicationController
100
+
101
+ def create
102
+ @user = User.new(params[:user])
103
+ @user.first_name = params[:user][:first_name]
104
+ @user.last_name = params[:user][:last_name]
105
+ @user.save
106
+ end
107
+ end
108
+ EOF
109
+ @runner.review('app/controllers/users_controller.rb', content)
110
+ errors = @runner.errors
111
+ errors.should be_empty
112
+ end
113
+ end
@@ -0,0 +1,172 @@
1
+ require 'spec_helper'
2
+
3
+ describe RailsBestPractices::Checks::AlwaysAddDbIndexCheck do
4
+ before(:each) do
5
+ @runner = RailsBestPractices::Core::Runner.new(RailsBestPractices::Checks::AlwaysAddDbIndexCheck.new)
6
+ end
7
+
8
+ it "should always add db index" do
9
+ content = <<-EOF
10
+ ActiveRecord::Schema.define(:version => 20100603080629) do
11
+ create_table "comments", :force => true do |t|
12
+ t.string "content"
13
+ t.integer "post_id"
14
+ t.integer "user_id"
15
+ end
16
+ end
17
+ EOF
18
+ @runner.review('db/schema.rb', content)
19
+ errors = @runner.errors
20
+ errors.should_not be_empty
21
+ errors[0].to_s.should == "db/schema.rb:2 - always add db index (comments => [post_id])"
22
+ errors[1].to_s.should == "db/schema.rb:2 - always add db index (comments => [user_id])"
23
+ end
24
+
25
+ it "should always add db index with polymorphic foreign key" do
26
+ content = <<-EOF
27
+ ActiveRecord::Schema.define(:version => 20100603080629) do
28
+ create_table "versions", :force => true do |t|
29
+ t.integer "versioned_id"
30
+ t.string "versioned_type"
31
+ t.string "tag"
32
+ end
33
+ end
34
+ EOF
35
+ @runner.review('db/schema.rb', content)
36
+ errors = @runner.errors
37
+ errors.should_not be_empty
38
+ errors[0].to_s.should == "db/schema.rb:2 - always add db index (versions => [versioned_id, versioned_type])"
39
+ end
40
+
41
+ it "should always add db index with polymorphic foreign key and _type is defined before _id" do
42
+ content = <<-EOF
43
+ ActiveRecord::Schema.define(:version => 20100603080629) do
44
+ create_table "versions", :force => true do |t|
45
+ t.string "versioned_type"
46
+ t.integer "versioned_id"
47
+ t.string "tag"
48
+ end
49
+ end
50
+ EOF
51
+ @runner.review('db/schema.rb', content)
52
+ errors = @runner.errors
53
+ errors.should_not be_empty
54
+ errors.size.should == 1
55
+ errors[0].to_s.should == "db/schema.rb:2 - always add db index (versions => [versioned_id, versioned_type])"
56
+ end
57
+
58
+ it "should always add db index with single index, but without polymorphic foreign key" do
59
+ content = <<-EOF
60
+ ActiveRecord::Schema.define(:version => 20100603080629) do
61
+ create_table "taggings", :force => true do |t|
62
+ t.integer "tag_id"
63
+ t.integer "taggable_id"
64
+ t.string "taggable_type"
65
+ end
66
+
67
+ add_index "taggings", ["tag_id"], :name => "index_taggings_on_tag_id"
68
+ end
69
+ EOF
70
+ @runner.review('db/schema.rb', content)
71
+ errors = @runner.errors
72
+ errors.should_not be_empty
73
+ errors[0].to_s.should == "db/schema.rb:2 - always add db index (taggings => [taggable_id, taggable_type])"
74
+ end
75
+
76
+ it "should always add db index with polymorphic foreign key, but without single index" do
77
+ content = <<-EOF
78
+ ActiveRecord::Schema.define(:version => 20100603080629) do
79
+ create_table "taggings", :force => true do |t|
80
+ t.integer "tag_id"
81
+ t.integer "taggable_id"
82
+ t.string "taggable_type"
83
+ end
84
+
85
+ add_index "taggings", ["taggable_id", "taggable_type"], :name => "index_taggings_on_taggable_id_and_taggable_type"
86
+ end
87
+ EOF
88
+ @runner.review('db/schema.rb', content)
89
+ errors = @runner.errors
90
+ errors.should_not be_empty
91
+ errors[0].to_s.should == "db/schema.rb:2 - always add db index (taggings => [tag_id])"
92
+ end
93
+
94
+ it "should not always add db index with column has no id" do
95
+ content = <<-EOF
96
+ ActiveRecord::Schema.define(:version => 20100603080629) do
97
+ create_table "comments", :force => true do |t|
98
+ t.string "content"
99
+ t.integer "position"
100
+ end
101
+ end
102
+ EOF
103
+ @runner.review('db/schema.rb', content)
104
+ errors = @runner.errors
105
+ errors.should be_empty
106
+ end
107
+
108
+ it "should not always add db index with add_index" do
109
+ content = <<-EOF
110
+ ActiveRecord::Schema.define(:version => 20100603080629) do
111
+ create_table "comments", :force => true do |t|
112
+ t.string "content"
113
+ t.integer "post_id"
114
+ t.integer "user_id"
115
+ end
116
+
117
+ add_index "comments", ["post_id"], :name => "index_comments_on_post_id"
118
+ add_index "comments", ["user_id"], :name => "index_comments_on_user_id"
119
+ end
120
+ EOF
121
+ @runner.review('db/schema.rb', content)
122
+ errors = @runner.errors
123
+ errors.should be_empty
124
+ end
125
+
126
+ it "should not always add db index with only _type column" do
127
+ content = <<-EOF
128
+ ActiveRecord::Schema.define(:version => 20100603080629) do
129
+ create_table "versions", :force => true do |t|
130
+ t.string "versioned_type"
131
+ end
132
+ end
133
+ EOF
134
+ @runner.review('db/schema.rb', content)
135
+ errors = @runner.errors
136
+ errors.should be_empty
137
+ end
138
+
139
+ it "should not always add db index with multi-column index" do
140
+ content = <<-EOF
141
+ ActiveRecord::Schema.define(:version => 20100603080629) do
142
+ create_table "versions", :force => true do |t|
143
+ t.integer "versioned_id"
144
+ t.string "versioned_type"
145
+ t.string "tag"
146
+ end
147
+
148
+ add_index "versions", ["versioned_id", "versioned_type"], :name => "index_versions_on_versioned_id_and_versioned_type"
149
+ end
150
+ EOF
151
+ @runner.review('db/schema.rb', content)
152
+ errors = @runner.errors
153
+ errors.should be_empty
154
+ end
155
+
156
+ it "should not always add db index if there is an index contains more columns" do
157
+ content = <<-EOF
158
+ ActiveRecord::Schema.define(:version => 20100603080629) do
159
+ create_table "taggings", :force => true do |t|
160
+ t.integer "taggable_id"
161
+ t.string "taggable_type"
162
+ t.string "context"
163
+ end
164
+
165
+ add_index "taggings", ["taggable_id", "taggable_type", "context"], :name => "index_taggings_on_taggable_id_and_taggable_type_and_context"
166
+ end
167
+ EOF
168
+ @runner.review('db/schema.rb', content)
169
+ errors = @runner.errors
170
+ errors.should be_empty
171
+ end
172
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ describe RailsBestPractices::Checks::Check do
4
+ before :each do
5
+ @check = RailsBestPractices::Checks::Check.new
6
+ end
7
+
8
+ it "should get empty interesting prepare nodes" do
9
+ @check.interesting_prepare_nodes.should == []
10
+ end
11
+
12
+ it "should get empty interesting review nodes" do
13
+ @check.interesting_review_nodes.should == []
14
+ end
15
+
16
+ it "should match all files of interesting prepare files" do
17
+ @check.interesting_prepare_files.should == /.*/
18
+ end
19
+
20
+ it "should match all files of interesting review files" do
21
+ @check.interesting_review_files.should == /.*/
22
+ end
23
+
24
+ context "review_node_start" do
25
+ it "should call review_start_if" do
26
+ node = stub(:node_type => :if)
27
+ @check.should_receive(:send).with("review_start_if", node)
28
+ @check.review_node_start(node)
29
+ end
30
+
31
+ it "should call review_start_call" do
32
+ node = stub(:node_type => :call)
33
+ @check.should_receive(:send).with("review_start_call", node)
34
+ @check.review_node_start(node)
35
+ end
36
+ end
37
+
38
+ context "review_node_end" do
39
+ it "should call review_end_if" do
40
+ node = stub(:node_type => :if)
41
+ @check.should_receive(:send).with("review_end_if", node)
42
+ @check.review_node_end(node)
43
+ end
44
+
45
+ it "should call review_end_call" do
46
+ node = stub(:node_type => :call)
47
+ @check.should_receive(:send).with("review_end_call", node)
48
+ @check.review_node_end(node)
49
+ end
50
+ end
51
+
52
+ context "equal?" do
53
+ it "should be true when compare symbol string with symbol" do
54
+ @check.equal?(":test", :test).should be_true
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe RailsBestPractices::Checks::DryBundlerInCapistranoCheck do
4
+ before(:each) do
5
+ @runner = RailsBestPractices::Core::Runner.new(RailsBestPractices::Checks::DryBundlerInCapistranoCheck.new)
6
+ end
7
+
8
+ it "should dry bundler in capistrno" do
9
+ content = <<-EOF
10
+ namespace :bundler do
11
+ task :create_symlink, :roles => :app do
12
+ shared_dir = File.join(shared_path, 'bundle')
13
+ release_dir = File.join(current_release, '.bundle')
14
+ run("mkdir -p \#{shared_dir} && ln -s \#{shared_dir} \#{release_dir}")
15
+ end
16
+
17
+ task :bundle_new_release, :roles => :app do
18
+ bundler.create_symlink
19
+ run "cd \#{release_path} && bundle install --without development test"
20
+ end
21
+ end
22
+
23
+ after 'deploy:update_code', 'bundler:bundle_new_release'
24
+ EOF
25
+ @runner.review('config/deploy.rb', content)
26
+ errors = @runner.errors
27
+ errors.should_not be_empty
28
+ errors[0].to_s.should == "config/deploy.rb:1 - dry bundler in capistrano"
29
+ end
30
+
31
+ it "should not dry bundler in capistrano" do
32
+ content = <<-EOF
33
+ require 'bundler/capistrano'
34
+ EOF
35
+ @runner.review('config/deploy.rb', content)
36
+ errors = @runner.errors
37
+ errors.should be_empty
38
+ end
39
+ end
@@ -0,0 +1,105 @@
1
+ require 'spec_helper'
2
+
3
+ describe RailsBestPractices::Checks::IsolateSeedDataCheck do
4
+ before(:each) do
5
+ @runner = RailsBestPractices::Core::Runner.new(RailsBestPractices::Checks::IsolateSeedDataCheck.new)
6
+ end
7
+
8
+ context "create" do
9
+ it "should isolate seed data" do
10
+ content = <<-EOF
11
+ class CreateRoles < ActiveRecord::Migration
12
+ def self.up
13
+ create_table "roles", :force => true do |t|
14
+ t.string :name
15
+ end
16
+
17
+ ["admin", "author", "editor", "account"].each do |name|
18
+ Role.create!(:name => name)
19
+ end
20
+ end
21
+
22
+ def self.down
23
+ drop_table "roles"
24
+ end
25
+ end
26
+ EOF
27
+ @runner.review('db/migrate/20090818130258_create_roles.rb', content)
28
+ errors = @runner.errors
29
+ errors.should_not be_empty
30
+ errors[0].to_s.should == "db/migrate/20090818130258_create_roles.rb:8 - isolate seed data"
31
+ errors.size.should == 1
32
+ end
33
+ end
34
+
35
+ context "new and save" do
36
+ it "should isolate seed data for local variable" do
37
+ content = <<-EOF
38
+ class CreateRoles < ActiveRecord::Migration
39
+ def self.up
40
+ create_table "roles", :force => true do |t|
41
+ t.string :name
42
+ end
43
+
44
+ ["admin", "author", "editor", "account"].each do |name|
45
+ role = Role.new(:name => name)
46
+ role.save!
47
+ end
48
+ end
49
+
50
+ def self.down
51
+ drop_table "roles"
52
+ end
53
+ end
54
+ EOF
55
+ @runner.review('db/migrate/20090818130258_create_roles.rb', content)
56
+ errors = @runner.errors
57
+ errors.should_not be_empty
58
+ errors[0].to_s.should == "db/migrate/20090818130258_create_roles.rb:9 - isolate seed data"
59
+ end
60
+
61
+ it "should isolate seed data for instance variable" do
62
+ content = <<-EOF
63
+ class CreateRoles < ActiveRecord::Migration
64
+ def self.up
65
+ create_table "roles", :force => true do |t|
66
+ t.string :name
67
+ end
68
+
69
+ ["admin", "author", "editor", "account"].each do |name|
70
+ @role = Role.new(:name => name)
71
+ @role.save!
72
+ end
73
+ end
74
+
75
+ def self.down
76
+ drop_table "roles"
77
+ end
78
+ end
79
+ EOF
80
+ @runner.review('db/migrate/20090818130258_create_roles.rb', content)
81
+ errors = @runner.errors
82
+ errors.should_not be_empty
83
+ errors[0].to_s.should == "db/migrate/20090818130258_create_roles.rb:9 - isolate seed data"
84
+ end
85
+ end
86
+
87
+ it "should not isolate seed data without data insert" do
88
+ content = <<-EOF
89
+ class CreateRoles < ActiveRecord::Migration
90
+ def self.up
91
+ create_table "roles", :force => true do |t|
92
+ t.string :name
93
+ end
94
+ end
95
+
96
+ def self.down
97
+ drop_table "roles"
98
+ end
99
+ end
100
+ EOF
101
+ @runner.review('db/migrate/20090818130258_create_roles.rb', content)
102
+ errors = @runner.errors
103
+ errors.should be_empty
104
+ end
105
+ end