rails_best_practices 0.10.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +20 -0
- data/assets/result.html.haml +1 -1
- data/lib/rails_best_practices.rb +5 -3
- data/lib/rails_best_practices/core.rb +1 -1
- data/lib/rails_best_practices/core/check.rb +9 -12
- data/lib/rails_best_practices/core/checking_visitor.rb +9 -6
- data/lib/rails_best_practices/core/model_associations.rb +1 -1
- data/lib/rails_best_practices/core/nil.rb +5 -1
- data/lib/rails_best_practices/core/runner.rb +5 -5
- data/lib/rails_best_practices/core_ext/sexp.rb +688 -0
- data/lib/rails_best_practices/prepares/mailer_prepare.rb +4 -5
- data/lib/rails_best_practices/prepares/model_prepare.rb +16 -26
- data/lib/rails_best_practices/prepares/schema_prepare.rb +11 -17
- data/lib/rails_best_practices/reviews/add_model_virtual_attribute_review.rb +24 -75
- data/lib/rails_best_practices/reviews/always_add_db_index_review.rb +39 -113
- data/lib/rails_best_practices/reviews/dry_bundler_in_capistrano_review.rb +6 -16
- data/lib/rails_best_practices/reviews/isolate_seed_data_review.rb +16 -32
- data/lib/rails_best_practices/reviews/keep_finders_on_their_own_model_review.rb +11 -20
- data/lib/rails_best_practices/reviews/law_of_demeter_review.rb +7 -28
- data/lib/rails_best_practices/reviews/move_code_into_controller_review.rb +16 -14
- data/lib/rails_best_practices/reviews/move_code_into_helper_review.rb +10 -28
- data/lib/rails_best_practices/reviews/move_code_into_model_review.rb +12 -11
- data/lib/rails_best_practices/reviews/move_finder_to_named_scope_review.rb +13 -24
- data/lib/rails_best_practices/reviews/move_model_logic_into_model_review.rb +9 -9
- data/lib/rails_best_practices/reviews/needless_deep_nesting_review.rb +24 -68
- data/lib/rails_best_practices/reviews/not_use_default_route_review.rb +15 -22
- data/lib/rails_best_practices/reviews/overuse_route_customizations_review.rb +31 -91
- data/lib/rails_best_practices/reviews/remove_empty_helpers_review.rb +4 -2
- data/lib/rails_best_practices/reviews/replace_complex_creation_with_factory_method_review.rb +20 -18
- data/lib/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review.rb +5 -3
- data/lib/rails_best_practices/reviews/review.rb +8 -37
- data/lib/rails_best_practices/reviews/simplify_render_in_controllers_review.rb +10 -6
- data/lib/rails_best_practices/reviews/simplify_render_in_views_review.rb +9 -6
- data/lib/rails_best_practices/reviews/use_before_filter_review.rb +14 -72
- data/lib/rails_best_practices/reviews/use_model_association_review.rb +19 -31
- data/lib/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review.rb +5 -5
- data/lib/rails_best_practices/reviews/use_observer_review.rb +22 -40
- data/lib/rails_best_practices/reviews/use_query_attribute_review.rb +34 -39
- data/lib/rails_best_practices/reviews/use_say_with_time_in_migrations_review.rb +14 -38
- data/lib/rails_best_practices/reviews/use_scope_access_review.rb +13 -44
- data/lib/rails_best_practices/version.rb +1 -1
- data/spec/rails_best_practices/core/check_spec.rb +5 -5
- data/spec/rails_best_practices/core/checking_visitor_spec.rb +4 -4
- data/spec/rails_best_practices/core/model_associations_spec.rb +4 -4
- data/spec/rails_best_practices/core/nil_spec.rb +7 -1
- data/spec/rails_best_practices/core_ext/sexp_spec.rb +430 -0
- data/spec/rails_best_practices/prepares/model_prepare_spec.rb +12 -12
- data/spec/rails_best_practices/prepares/schema_prepare_spec.rb +6 -6
- data/spec/rails_best_practices/reviews/move_code_into_controller_review_spec.rb +14 -2
- data/spec/rails_best_practices/reviews/move_code_into_helper_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/needless_deep_nesting_review_spec.rb +3 -3
- data/spec/rails_best_practices/reviews/not_use_default_route_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/overuse_route_customizations_review_spec.rb +15 -1
- data/spec/rails_best_practices/reviews/simplify_render_in_controllers_review_spec.rb +3 -3
- data/spec/rails_best_practices/reviews/use_query_attribute_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/use_say_with_time_in_migrations_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/use_scope_access_review_spec.rb +4 -4
- data/spec/rails_best_practices_spec.rb +1 -3
- data/spec/spec_helper.rb +4 -0
- metadata +6 -8
- data/lib/rails_best_practices/core/visitable_sexp.rb +0 -444
- data/spec/rails_best_practices/core/visitable_sexp_spec.rb +0 -272
- 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 == {
|
22
|
-
model_associations.get_association("Project", "project_manager").should == {
|
23
|
-
model_associations.get_association("Project", "milestones").should == {
|
24
|
-
model_associations.get_association("Project", "categories").should == {
|
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,
|
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 == {
|
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,
|
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 == {
|
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,
|
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 == {
|
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,
|
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 == {
|
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 ==
|
22
|
-
model_attributes.get_attribute_type("Post", "body").should ==
|
23
|
-
model_attributes.get_attribute_type("Post", "created_at").should ==
|
24
|
-
model_attributes.get_attribute_type("Post", "user_id").should ==
|
25
|
-
model_attributes.get_attribute_type("Post", "comments_count").should ==
|
26
|
-
model_attributes.get_attribute_type("Post", "published").should ==
|
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
|
-
<%
|
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:
|
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:
|
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:
|
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:
|
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:
|
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
|
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:
|
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:
|
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:
|
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?
|
80
|
+
<% if @user.active? && @user.login.present? %>
|
81
81
|
<%= @user.login %>
|
82
82
|
<% end %>
|
83
83
|
EOF
|
@@ -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:
|
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:
|
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:
|
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:
|
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
|
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
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.
|
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-
|
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:
|
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
|