rails_best_practices 0.6.1 → 0.6.5

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,113 @@
1
+ require 'spec_helper'
2
+
3
+ describe RailsBestPractices::Checks::UseSayWithTimeInMigrationsCheck do
4
+ before :each do
5
+ @runner = RailsBestPractices::Core::Runner.new(RailsBestPractices::Checks::UseSayWithTimeInMigrationsCheck.new)
6
+ end
7
+
8
+ it "should use say with time in migrations" do
9
+ content =<<-EOF
10
+ def self.up
11
+ User.find_each do |user|
12
+ user.first_name, user.last_name = user.full_name.split(' ')
13
+ user.save
14
+ end
15
+ end
16
+ EOF
17
+ @runner.review('db/migrate/20101010080658_update_users.rb', content)
18
+ errors = @runner.errors
19
+ errors.should_not be_empty
20
+ errors.size.should == 1
21
+ errors[0].to_s.should == "db/migrate/20101010080658_update_users.rb:2 - use say with time in migrations"
22
+ end
23
+
24
+ it "should use say with time in migrations with create_table" do
25
+ content =<<-EOF
26
+ def self.up
27
+ create_table :users do |t|
28
+ t.string :login
29
+ t.timestamps
30
+ end
31
+
32
+ User.find_each do |user|
33
+ user.first_name, user.last_name = user.full_name.split(' ')
34
+ user.save
35
+ end
36
+ end
37
+ EOF
38
+ @runner.review('db/migrate/20101010080658_update_users.rb', content)
39
+ errors = @runner.errors
40
+ errors.should_not be_empty
41
+ errors.size.should == 1
42
+ errors[0].to_s.should == "db/migrate/20101010080658_update_users.rb:7 - use say with time in migrations"
43
+ end
44
+
45
+ it "should not use say with time in migrations" do
46
+ content =<<-EOF
47
+ def self.up
48
+ say_with_time("Initialize first_name and last_name for users") do
49
+ User.find_each do |user|
50
+ user.first_name, user.last_name = user.full_name.split(' ')
51
+ user.save
52
+ say(user.id + " was updated.")
53
+ end
54
+ end
55
+ end
56
+ EOF
57
+ @runner.review('db/migrate/20101010080658_update_users.rb', content)
58
+ errors = @runner.errors
59
+ errors.should be_empty
60
+ end
61
+
62
+ it "should not use say with time when default migration message" do
63
+ content =<<-EOF
64
+ def self.up
65
+ create_table :users do |t|
66
+ t.string :login
67
+ t.string :email
68
+ t.timestamps
69
+ end
70
+ end
71
+ EOF
72
+ @runner.review('db/migrate/20101010080658_create_users.rb', content)
73
+ errors = @runner.errors
74
+ errors.should be_empty
75
+ end
76
+
77
+ it "should not raise an error" do
78
+ content =<<-EOF
79
+ class AddAdmin < ActiveRecord::Migration
80
+
81
+ class Person < ActiveRecord::Base
82
+ end
83
+
84
+ class Blog < ActiveRecord::Base
85
+ end
86
+
87
+ def self.up
88
+ add_column :people, :admin, :boolean, :default => false, :null => false
89
+ add_column :people, :deactivated, :boolean,
90
+ :default => false, :null => false
91
+
92
+ key = Crypto::Key.from_file("\#{RAILS_ROOT}/rsa_key.pub")
93
+ person = Person.new(:email => "admin@example.com",
94
+ :name => "admin",
95
+ :crypted_password => key.encrypt("admin"),
96
+ :description => "")
97
+ person.admin = true
98
+ person.save!
99
+ Blog.create(:person_id => person.id)
100
+ end
101
+
102
+ def self.down
103
+ remove_column :people, :deactivated
104
+ Person.delete(Person.find_by_name("admin"))
105
+ remove_column :people, :admin
106
+ end
107
+ end
108
+ EOF
109
+ @runner.review('db/migrate/20101010080658_create_users.rb', content)
110
+ errors = @runner.errors
111
+ errors.should be_empty
112
+ end
113
+ end
@@ -0,0 +1,193 @@
1
+ require 'spec_helper'
2
+
3
+ describe RailsBestPractices::Checks::UseScopeAccessCheck do
4
+ before(:each) do
5
+ @runner = RailsBestPractices::Core::Runner.new(RailsBestPractices::Checks::UseScopeAccessCheck.new)
6
+ end
7
+
8
+ context "if" do
9
+ it "shoud use scope access" do
10
+ content = <<-EOF
11
+ class PostsController < ApplicationController
12
+
13
+ def edit
14
+ @post = Post.find(params[:id])
15
+
16
+ if @post.user != current_user
17
+ flash[:warning] = 'Access Denied'
18
+ redirect_to posts_url
19
+ end
20
+ end
21
+ end
22
+ EOF
23
+ @runner.review('app/controllers/posts_controller.rb', content)
24
+ errors = @runner.errors
25
+ errors.should_not be_empty
26
+ errors[0].to_s.should == "app/controllers/posts_controller.rb:7 - use scope access"
27
+ end
28
+
29
+ it "shoud use scope access by comparing with id" do
30
+ content = <<-EOF
31
+ class PostsController < ApplicationController
32
+
33
+ def edit
34
+ @post = Post.find(params[:id])
35
+
36
+ if @post.user_id != current_user.id
37
+ flash[:warning] = 'Access Denied'
38
+ redirect_to posts_url
39
+ end
40
+ end
41
+ end
42
+ EOF
43
+ @runner.review('app/controllers/posts_controller.rb', content)
44
+ errors = @runner.errors
45
+ errors.should_not be_empty
46
+ errors[0].to_s.should == "app/controllers/posts_controller.rb:7 - use scope access"
47
+ end
48
+
49
+ it "shoud use scope access with current_user ==" do
50
+ content = <<-EOF
51
+ class PostsController < ApplicationController
52
+
53
+ def edit
54
+ @post = Post.find(params[:id])
55
+
56
+ if current_user != @post.user
57
+ flash[:warning] = 'Access Denied'
58
+ redirect_to posts_url
59
+ end
60
+ end
61
+ end
62
+ EOF
63
+ @runner.review('app/controllers/posts_controller.rb', content)
64
+ errors = @runner.errors
65
+ errors.should_not be_empty
66
+ errors[0].to_s.should == "app/controllers/posts_controller.rb:7 - use scope access"
67
+ end
68
+
69
+ it "shoud use scope access by current_user.id ==" do
70
+ content = <<-EOF
71
+ class PostsController < ApplicationController
72
+
73
+ def edit
74
+ @post = Post.find(params[:id])
75
+
76
+ if current_user.id != @post.user_id
77
+ flash[:warning] = 'Access Denied'
78
+ redirect_to posts_url
79
+ end
80
+ end
81
+ end
82
+ EOF
83
+ @runner.review('app/controllers/posts_controller.rb', content)
84
+ errors = @runner.errors
85
+ errors.should_not be_empty
86
+ errors[0].to_s.should == "app/controllers/posts_controller.rb:7 - use scope access"
87
+ end
88
+ end
89
+
90
+ context "unless" do
91
+ it "shoud use scope access" do
92
+ content = <<-EOF
93
+ class PostsController < ApplicationController
94
+
95
+ def edit
96
+ @post = Post.find(params[:id])
97
+
98
+ unless @post.user == current_user
99
+ flash[:warning] = 'Access Denied'
100
+ redirect_to posts_url
101
+ end
102
+ end
103
+ end
104
+ EOF
105
+ @runner.review('app/controllers/posts_controller.rb', content)
106
+ errors = @runner.errors
107
+ errors.should_not be_empty
108
+ errors[0].to_s.should == "app/controllers/posts_controller.rb:6 - use scope access"
109
+ end
110
+
111
+ it "shoud use scope access by comparing with id" do
112
+ content = <<-EOF
113
+ class PostsController < ApplicationController
114
+
115
+ def edit
116
+ @post = Post.find(params[:id])
117
+
118
+ unless @post.user_id == current_user.id
119
+ flash[:warning] = 'Access Denied'
120
+ redirect_to posts_url
121
+ end
122
+ end
123
+ end
124
+ EOF
125
+ @runner.review('app/controllers/posts_controller.rb', content)
126
+ errors = @runner.errors
127
+ errors.should_not be_empty
128
+ errors[0].to_s.should == "app/controllers/posts_controller.rb:6 - use scope access"
129
+ end
130
+
131
+ it "shoud use scope access with current_user ==" do
132
+ content = <<-EOF
133
+ class PostsController < ApplicationController
134
+
135
+ def edit
136
+ @post = Post.find(params[:id])
137
+
138
+ unless current_user == @post.user
139
+ flash[:warning] = 'Access Denied'
140
+ redirect_to posts_url
141
+ end
142
+ end
143
+ end
144
+ EOF
145
+ @runner.review('app/controllers/posts_controller.rb', content)
146
+ errors = @runner.errors
147
+ errors.should_not be_empty
148
+ errors[0].to_s.should == "app/controllers/posts_controller.rb:6 - use scope access"
149
+ end
150
+
151
+ it "shoud use scope access by current_user.id ==" do
152
+ content = <<-EOF
153
+ class PostsController < ApplicationController
154
+
155
+ def edit
156
+ @post = Post.find(params[:id])
157
+
158
+ unless current_user.id == @post.user_id
159
+ flash[:warning] = 'Access Denied'
160
+ redirect_to posts_url
161
+ end
162
+ end
163
+ end
164
+ EOF
165
+ @runner.review('app/controllers/posts_controller.rb', content)
166
+ errors = @runner.errors
167
+ errors.should_not be_empty
168
+ errors[0].to_s.should == "app/controllers/posts_controller.rb:6 - use scope access"
169
+ end
170
+
171
+ it "should no error in use_scope_access_review" do
172
+ content = <<-EOF
173
+ class CommentsController < ApplicationController
174
+
175
+ def add_comment
176
+ @current_user = User.find_by_id(session[:user_id])
177
+ @id = params[:post_id]
178
+ @error = ""
179
+ if (@text = params[:text]) == ""
180
+ @error = "Please enter a comment!"
181
+ else
182
+ @comment = Comment.create_object(@text, @id, @current_user.id)
183
+ end
184
+ unless @comment
185
+ @error = "Comment could not be saved."
186
+ end
187
+ end
188
+ end
189
+ EOF
190
+ @runner.review('app/controllers/comments_controller.rb', content)
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe RailsBestPractices::Core::Error do
4
+ it "should return error with filename, line number and message" do
5
+ RailsBestPractices::Core::Error.new("app/models/user.rb", 100, "not good").to_s.should == "app/models/user.rb:100 - not good"
6
+ end
7
+ end
@@ -0,0 +1,259 @@
1
+ require 'spec_helper'
2
+
3
+ describe Sexp do
4
+ before :each do
5
+ @parser = RubyParser.new
6
+ end
7
+
8
+ describe "children" do
9
+ it "should get all child nodes" do
10
+ node = @parser.parse("puts 'hello ', 'world'")
11
+ node.children.should == [s(:arglist, s(:str, "hello "), s(:str, "world"))]
12
+ end
13
+ end
14
+
15
+ describe "recursive_children" do
16
+ it "should get all recursive child nodes" do
17
+ node = @parser.parse("puts 'hello', dynamic_output")
18
+ children = []
19
+ node.recursive_children { |child| children << child }
20
+ children.should == [s(:arglist, s(:str, "hello"), s(:call, nil, :dynamic_output, s(:arglist))), s(:str, "hello"), s(:call, nil, :dynamic_output, s(:arglist)), s(:arglist)]
21
+ end
22
+ end
23
+
24
+ describe "grep_nodes" do
25
+ before :each do
26
+ content = <<-EOF
27
+ def show
28
+ current_user.posts.find(params[:id])
29
+ end
30
+ EOF
31
+ @node = @parser.parse(content)
32
+ end
33
+
34
+ it "should get the call nodes with empty arguments" do
35
+ nodes = []
36
+ @node.grep_nodes(:node_type => :call, :arguments => s(:arglist)) { |node| nodes << node }
37
+ nodes.should == [s(:call, s(:call, nil, :current_user, s(:arglist)), :posts, s(:arglist)), s(:call, nil, :current_user, s(:arglist)), s(:call, nil, :params, s(:arglist))]
38
+ end
39
+
40
+ it "should get the call nodes with different messages" do
41
+ nodes = []
42
+ @node.grep_nodes(:node_type => :call, :message => [:current_user, :params]) { |node| nodes << node }
43
+ nodes.should == [s(:call, nil, :current_user, s(:arglist)), s(:call, nil, :params, s(:arglist))]
44
+ end
45
+ end
46
+
47
+ describe "grep_node" do
48
+ before :each do
49
+ content = <<-EOF
50
+ def show
51
+ current_user.posts.find(params[:id])
52
+ end
53
+ EOF
54
+ @node = @parser.parse(content)
55
+ end
56
+
57
+ it "should get first node with empty argument" do
58
+ node = @node.grep_node(:node_type => :call, :arguments => s(:arglist))
59
+ node.should == s(:call, s(:call, nil, :current_user, s(:arglist)), :posts, s(:arglist))
60
+ end
61
+ end
62
+
63
+ describe "grep_nodes_count" do
64
+ before :each do
65
+ content = <<-EOF
66
+ def show
67
+ current_user.posts.find(params[:id])
68
+ end
69
+ EOF
70
+ @node = @parser.parse(content)
71
+ end
72
+
73
+ it "should get the count of call nodes" do
74
+ @node.grep_nodes_count(:node_type => :call).should == 5
75
+ end
76
+ end
77
+
78
+ describe "subject" do
79
+ it "should get subject of attrasgn node" do
80
+ node = @parser.parse("user.name = params[:name]")
81
+ node.subject.should == s(:call, nil, :user, s(:arglist))
82
+ end
83
+
84
+ it "should get subject of call node" do
85
+ node = @parser.parse("user.name")
86
+ node.subject.should == s(:call, nil, :user, s(:arglist))
87
+ end
88
+
89
+ it "should get subject of iter node" do
90
+ node = @parser.parse("@users.each { |user| p user }")
91
+ node.subject.should == s(:call, s(:ivar, :@users), :each, s(:arglist))
92
+ end
93
+ end
94
+
95
+ describe "class_name" do
96
+ it "should get class name of class node" do
97
+ node = @parser.parse("class User; end")
98
+ node.class_name.should == :User
99
+ end
100
+ end
101
+
102
+ describe "base_class" do
103
+ it "should get base class of class node" do
104
+ node = @parser.parse("class User < ActiveRecord::Base; end")
105
+ node.base_class.should == s(:colon2, s(:const, :ActiveRecord), :Base)
106
+ end
107
+ end
108
+
109
+ describe "left_value" do
110
+ it "should get the left value of lasgn" do
111
+ node = @parser.parse("user = params[:user]")
112
+ node.left_value.should == :user
113
+ end
114
+
115
+ it "should get the left value of iasgn" do
116
+ node = @parser.parse("@user = params[:user]")
117
+ node.left_value.should == :@user
118
+ end
119
+ end
120
+
121
+ describe "right_value" do
122
+ it "should get the right value of lasgn" do
123
+ node = @parser.parse("user = current_user")
124
+ node.right_value.should == s(:call, nil, :current_user, s(:arglist))
125
+ end
126
+
127
+ it "should get the right value of iasgn" do
128
+ node = @parser.parse("@user = current_user")
129
+ node.right_value.should == s(:call, nil, :current_user, s(:arglist))
130
+ end
131
+ end
132
+
133
+ describe "message" do
134
+ it "should get the message of attrasgn" do
135
+ node = @parser.parse("user.name = params[:name]")
136
+ node.message.should == :name=
137
+ end
138
+
139
+ it "should get the message of call" do
140
+ node = @parser.parse("has_many :projects")
141
+ node.message.should == :has_many
142
+ end
143
+ end
144
+
145
+ describe "arguments" do
146
+ it "should get the arguments of attrasgn" do
147
+ node = @parser.parse("post.user = current_user")
148
+ node.arguments.should == s(:arglist, s(:call, nil, :current_user, s(:arglist)))
149
+ end
150
+
151
+ it "should get the arguments of call" do
152
+ node = @parser.parse("username == ''")
153
+ node.arguments.should == s(:arglist, s(:str, ""))
154
+ end
155
+ end
156
+
157
+ describe "conditional_statement" do
158
+ it "should get conditional statement of if" do
159
+ node = @parser.parse("if current_user.present?; puts current_user.login; end")
160
+ node.conditional_statement.should == s(:call, s(:call, nil, :current_user, s(:arglist)), :present?, s(:arglist))
161
+ end
162
+ end
163
+
164
+ describe "true_node" do
165
+ it "should get the true node of if" do
166
+ content = <<-EOF
167
+ if current_user.login?
168
+ current_user.login
169
+ else
170
+ current_user.email
171
+ end
172
+ EOF
173
+ node = @parser.parse(content)
174
+ node.true_node.should == s(:call, s(:call, nil, :current_user, s(:arglist)), :login, s(:arglist))
175
+ end
176
+ end
177
+
178
+ describe "false_node" do
179
+ it "should get the false node of if" do
180
+ content = <<-EOF
181
+ if current_user.login?
182
+ current_user.login
183
+ else
184
+ current_user.email
185
+ end
186
+ EOF
187
+ node = @parser.parse(content)
188
+ node.false_node.should == s(:call, s(:call, nil, :current_user, s(:arglist)), :email, s(:arglist))
189
+ end
190
+ end
191
+
192
+ describe "method_name" do
193
+ it "should get the method name of defn" do
194
+ node = @parser.parse("def show; end")
195
+ node.method_name.should == :show
196
+ end
197
+ end
198
+
199
+ describe "body" do
200
+ it "should get body of iter" do
201
+ node = @parser.parse("resources :posts do; resources :comments; end")
202
+ node.body.should == s(:call, nil, :resources, s(:arglist, s(:lit, :comments)))
203
+ end
204
+
205
+ it "should get body of class" do
206
+ node = @parser.parse("class User; def login; end; def email; end; end")
207
+ node.body.should == s(:block, s(:defn, :login, s(:args), s(:scope, s(:block, s(:nil)))), s(:defn, :email, s(:args), s(:scope, s(:block, s(:nil)))))
208
+ end
209
+
210
+ it "should get body of defn" do
211
+ node = @parser.parse("def fullname; first_name + last+name; end")
212
+ node.body.should == s(:block, s(:call, s(:call, s(:call, nil, :first_name, s(:arglist)), :+, s(:arglist, s(:call, nil, :last, s(:arglist)))), :+, s(:arglist, s(:call, nil, :name, s(:arglist)))))
213
+ end
214
+ end
215
+
216
+ describe "to_s" do
217
+ it "should get to_s for lvar" do
218
+ node = @parser.parse("user = current_user; user")
219
+ node.children[1].node_type.should == :lvar
220
+ node.children[1].to_s.should == "user"
221
+ end
222
+
223
+ it "should get to_s for ivar" do
224
+ node = @parser.parse("@user")
225
+ node.to_s.should == "@user"
226
+ end
227
+
228
+ it "should get to_s for str" do
229
+ node = @parser.parse("'user'")
230
+ node.to_s.should == "user"
231
+ end
232
+
233
+ it "should get to_s for lit" do
234
+ node = @parser.parse("{:user => 'Richard'}")
235
+ node[1].to_s.should == "user"
236
+ end
237
+
238
+
239
+ it "should get to_s for const" do
240
+ node = @parser.parse("User")
241
+ node.to_s.should == "User"
242
+ end
243
+
244
+ it "should get to_s for array" do
245
+ node = @parser.parse("[@user1, @user2]")
246
+ node.to_s.should == '["@user1", "@user2"]'
247
+ end
248
+
249
+ it "should get to_s for hash" do
250
+ node = @parser.parse("{:first_name => 'Richard', :last_name => 'Huang'}")
251
+ node.to_s.should == '{"first_name" => "Richard", "last_name" => "Huang"}'
252
+ end
253
+
254
+ it "should get to_s for colon2" do
255
+ node = @parser.parse("RailsBestPractices::Core")
256
+ node.to_s.should == "RailsBestPractices::Core"
257
+ end
258
+ end
259
+ end