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
@@ -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