rails_best_practices 1.5.3 → 1.6.0

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 (34) hide show
  1. data/Gemfile.lock +1 -1
  2. data/README.md +11 -7
  3. data/assets/result.html.erb +6 -4
  4. data/lib/rails_best_practices/analyzer.rb +45 -42
  5. data/lib/rails_best_practices/command.rb +36 -9
  6. data/lib/rails_best_practices/core.rb +2 -0
  7. data/lib/rails_best_practices/core/check.rb +52 -18
  8. data/lib/rails_best_practices/core/error.rb +8 -0
  9. data/lib/rails_best_practices/core/helpers.rb +8 -0
  10. data/lib/rails_best_practices/core/modules.rb +39 -0
  11. data/lib/rails_best_practices/core/runner.rb +14 -3
  12. data/lib/rails_best_practices/prepares.rb +9 -0
  13. data/lib/rails_best_practices/prepares/controller_prepare.rb +15 -3
  14. data/lib/rails_best_practices/prepares/helper_prepare.rb +41 -0
  15. data/lib/rails_best_practices/prepares/mailer_prepare.rb +1 -1
  16. data/lib/rails_best_practices/prepares/model_prepare.rb +1 -1
  17. data/lib/rails_best_practices/reviews.rb +1 -0
  18. data/lib/rails_best_practices/reviews/always_add_db_index_review.rb +2 -2
  19. data/lib/rails_best_practices/reviews/remove_unused_methods_in_controllers_review.rb +13 -3
  20. data/lib/rails_best_practices/reviews/remove_unused_methods_in_helpers_review.rb +47 -0
  21. data/lib/rails_best_practices/reviews/remove_unused_methods_in_models_review.rb +3 -3
  22. data/lib/rails_best_practices/version.rb +1 -1
  23. data/rails_best_practices.yml +1 -0
  24. data/spec/rails_best_practices/analyzer_spec.rb +3 -3
  25. data/spec/rails_best_practices/core/error_spec.rb +10 -1
  26. data/spec/rails_best_practices/core/helpers_spec.rb +5 -0
  27. data/spec/rails_best_practices/core/modules_spec.rb +26 -0
  28. data/spec/rails_best_practices/prepares/controller_prepare_spec.rb +32 -1
  29. data/spec/rails_best_practices/prepares/helper_prepare_spec.rb +41 -0
  30. data/spec/rails_best_practices/reviews/always_add_db_index_review_spec.rb +11 -11
  31. data/spec/rails_best_practices/reviews/remove_unused_methods_in_controllers_review_spec.rb +15 -15
  32. data/spec/rails_best_practices/reviews/remove_unused_methods_in_helpers_review_spec.rb +84 -0
  33. data/spec/rails_best_practices/reviews/remove_unused_methods_in_models_review_spec.rb +31 -31
  34. metadata +35 -23
@@ -16,6 +16,14 @@ module RailsBestPractices
16
16
  @url = url
17
17
  end
18
18
 
19
+ def short_filename
20
+ File.expand_path(filename)[File.expand_path(Core::Runner.base_path).size..-1].sub(/^\//, '')
21
+ end
22
+
23
+ def first_line_number
24
+ line_number.split(',').first
25
+ end
26
+
19
27
  def to_s
20
28
  "#{@filename}:#{@line_number} - #{@message}"
21
29
  end
@@ -0,0 +1,8 @@
1
+ # encoding: utf-8
2
+ module RailsBestPractices
3
+ module Core
4
+ # Helper moduels.
5
+ class Helpers < Modules
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+ module RailsBestPractices
3
+ module Core
4
+ # Module container
5
+ class Modules < Array
6
+ # add module decendant.
7
+ #
8
+ # @param [String] module name
9
+ # @param [String] decendant name
10
+ def add_module_decendant(module_name, decendant)
11
+ mod = find { |mod| mod.to_s == module_name }
12
+ mod.add_decendant(decendant) if mod
13
+ end
14
+ end
15
+
16
+ # Module info include module name and module spaces.
17
+ class Mod
18
+ attr_reader :decendants
19
+
20
+ def initialize(module_name, modules)
21
+ @module_name = module_name
22
+ @modules = modules
23
+ @decendants = []
24
+ end
25
+
26
+ def add_decendant(decendant)
27
+ @decendants << decendant
28
+ end
29
+
30
+ def to_s
31
+ if @modules.empty?
32
+ @module_name
33
+ else
34
+ @modules.map { |modu| "#{modu}::" }.join("") + @module_name
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -115,10 +115,21 @@ module RailsBestPractices
115
115
  (@reviews + @lexicals).collect {|check| check.errors}.flatten
116
116
  end
117
117
 
118
+ def after_lexical; end
119
+
120
+ # provide a handler after all files reviewed.
121
+ def after_prepare
122
+ filename = "rails_best_practices.after_prepare"
123
+ content = "class RailsBestPractices::AfterPrepare; end"
124
+ node = parse_ruby(filename, content)
125
+ node.file = filename
126
+ node.prepare(@checker)
127
+ end
128
+
118
129
  # provide a handler after all files reviewed.
119
- def on_complete
120
- filename = "rails_best_practices.complete"
121
- content = "class RailsBestPractices::Complete; end"
130
+ def after_review
131
+ filename = "rails_best_practices.after_review"
132
+ content = "class RailsBestPractices::AfterReview; end"
122
133
  node = parse_ruby(filename, content)
123
134
  node.file = filename
124
135
  node.review(@checker)
@@ -4,6 +4,7 @@ require 'rails_best_practices/prepares/mailer_prepare'
4
4
  require 'rails_best_practices/prepares/schema_prepare'
5
5
  require 'rails_best_practices/prepares/controller_prepare'
6
6
  require 'rails_best_practices/prepares/route_prepare'
7
+ require 'rails_best_practices/prepares/helper_prepare'
7
8
 
8
9
  module RailsBestPractices
9
10
  module Prepares
@@ -40,6 +41,14 @@ module RailsBestPractices
40
41
  @controller_methods ||= Core::Methods.new
41
42
  end
42
43
 
44
+ def helpers
45
+ @helpers ||= Core::Helpers.new
46
+ end
47
+
48
+ def helper_methods
49
+ @helper_methods ||= Core::Methods.new
50
+ end
51
+
43
52
  def routes
44
53
  @routes ||= Core::Routes.new
45
54
  end
@@ -5,9 +5,10 @@ module RailsBestPractices
5
5
  module Prepares
6
6
  # Remember controllers and controller methods
7
7
  class ControllerPrepare < Core::Check
8
- include Core::Check::Klassable
8
+ include Core::Check::Classable
9
9
  include Core::Check::InheritedResourcesable
10
10
  include Core::Check::Accessable
11
+ include Core::Check::Afterable
11
12
 
12
13
  interesting_nodes :class, :var_ref, :command, :def
13
14
  interesting_files CONTROLLER_FILES
@@ -17,6 +18,7 @@ module RailsBestPractices
17
18
  def initialize
18
19
  @controllers = Prepares.controllers
19
20
  @methods = Prepares.controller_methods
21
+ @helpers = Prepares.helpers
20
22
  @inherited_resources = false
21
23
  end
22
24
 
@@ -47,11 +49,13 @@ module RailsBestPractices
47
49
 
48
50
  # restrict actions for inherited_resources
49
51
  def start_command(node)
50
- if @inherited_resources && "actions" == node.message.to_s
52
+ if "include" == node.message.to_s
53
+ @helpers.add_module_decendant(node.arguments.all.first.to_s, current_class_name)
54
+ elsif @inherited_resources && "actions" == node.message.to_s
51
55
  if "all" == node.arguments.all.first.to_s
52
56
  @actions = DEFAULT_ACTIONS
53
57
  option_argument = node.arguments.all[1]
54
- if :bare_assoc_hash == option_argument.sexp_type && option_argument.hash_value("except")
58
+ if option_argument && :bare_assoc_hash == option_argument.sexp_type && option_argument.hash_value("except")
55
59
  @actions -= option_argument.hash_value("except").to_object
56
60
  end
57
61
  else
@@ -76,6 +80,14 @@ module RailsBestPractices
76
80
  method_name = node.method_name.to_s
77
81
  @methods.add_method(current_class_name, method_name, {"file" => node.file, "line" => node.line}, current_access_control)
78
82
  end
83
+
84
+ # ask Reviews::RemoveUnusedMoethodsInHelperReview to check the controllers who include helpers.
85
+ def after_prepare
86
+ decendants = @helpers.map(&:decendants).flatten
87
+ if decendants.present?
88
+ Reviews::RemoveUnusedMethodsInHelpersReview.interesting_files *decendants.map { |decendant| %r|#{decendant.underscore}| }
89
+ end
90
+ end
79
91
  end
80
92
  end
81
93
  end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+ require 'rails_best_practices/core/check'
3
+
4
+ module RailsBestPractices
5
+ module Prepares
6
+ # Remember helper methods.
7
+ class HelperPrepare < Core::Check
8
+ include Core::Check::Moduleable
9
+ include Core::Check::Accessable
10
+
11
+ interesting_nodes :def, :command
12
+ interesting_files HELPER_FILES, CONTROLLER_FILES
13
+
14
+ def initialize
15
+ @helpers = Prepares.helpers
16
+ @methods = Prepares.helper_methods
17
+ end
18
+
19
+ # check module node to remember the module name.
20
+ def start_module(node)
21
+ @helpers << Core::Mod.new(current_module_name, [])
22
+ end
23
+
24
+ # check def node to remember all methods.
25
+ #
26
+ # the remembered methods (@methods) are like
27
+ # {
28
+ # "PostsHelper" => {
29
+ # "create_time" => {"file" => "app/helpers/posts_helper.rb", "line" => 10, "unused" => false},
30
+ # "update_time" => {"file" => "app/helpers/posts_helper.rb", "line" => 10, "unused" => false}
31
+ # }
32
+ # }
33
+ def start_def(node)
34
+ if node.file =~ HELPER_FILES
35
+ method_name = node.method_name.to_s
36
+ @methods.add_method(current_module_name, method_name, {"file" => node.file, "line" => node.line}, current_access_control)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -5,7 +5,7 @@ module RailsBestPractices
5
5
  module Prepares
6
6
  # Remember the mailer names.
7
7
  class MailerPrepare < Core::Check
8
- include Core::Check::Klassable
8
+ include Core::Check::Classable
9
9
 
10
10
  interesting_nodes :class
11
11
  interesting_files MAILER_FILES, MODEL_FILES
@@ -5,7 +5,7 @@ module RailsBestPractices
5
5
  module Prepares
6
6
  # Remember models and model associations.
7
7
  class ModelPrepare < Core::Check
8
- include Core::Check::Klassable
8
+ include Core::Check::Classable
9
9
  include Core::Check::Accessable
10
10
 
11
11
  interesting_nodes :class, :def, :command, :var_ref, :alias
@@ -28,3 +28,4 @@ require 'rails_best_practices/reviews/remove_empty_helpers_review'
28
28
  require 'rails_best_practices/reviews/restrict_auto_generated_routes_review'
29
29
  require 'rails_best_practices/reviews/remove_unused_methods_in_models_review'
30
30
  require 'rails_best_practices/reviews/remove_unused_methods_in_controllers_review'
31
+ require 'rails_best_practices/reviews/remove_unused_methods_in_helpers_review'
@@ -24,7 +24,7 @@ module RailsBestPractices
24
24
  # if there are any foreign keys not existed in index columns,
25
25
  # then the foreign keys should add db index.
26
26
  class AlwaysAddDbIndexReview < Review
27
- include Completeable
27
+ include Afterable
28
28
 
29
29
  interesting_nodes :command, :command_call
30
30
  interesting_files SCHEMA_FILE
@@ -73,7 +73,7 @@ module RailsBestPractices
73
73
  # compare foreign keys and index columns,
74
74
  # if there are any foreign keys not existed in index columns,
75
75
  # then we should add db index for that foreign keys.
76
- def on_complete
76
+ def after_review
77
77
  remove_only_type_foreign_keys
78
78
  @foreign_keys.each do |table, foreign_key|
79
79
  table_node = @table_nodes[table]
@@ -3,9 +3,19 @@ require 'rails_best_practices/reviews/review'
3
3
 
4
4
  module RailsBestPractices
5
5
  module Reviews
6
+ # Find out unused methods in controllers.
7
+ #
8
+ # Implementation:
9
+ #
10
+ # Review process:
11
+ # remember all method calls in controllers,
12
+ # if they are not defined in routes,
13
+ # and they are not called in controllers,
14
+ # then they are the unused methods in controllers.
6
15
  class RemoveUnusedMethodsInControllersReview < Review
7
- include Klassable
8
- include Completeable
16
+ include Classable
17
+ include Moduleable
18
+ include Afterable
9
19
  include Callable
10
20
  include Exceptable
11
21
  include InheritedResourcesable
@@ -66,7 +76,7 @@ module RailsBestPractices
66
76
  alias :start_method_add_arg :start_command
67
77
 
68
78
  # get all unused methods at the end of review process.
69
- def on_complete
79
+ def after_review
70
80
  @routes.each do |route|
71
81
  if "*" == route.action_name
72
82
  action_names = @controller_methods.get_methods(route.controller_name_with_namespaces).map(&:method_name)
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+ require 'rails_best_practices/reviews/review'
3
+
4
+ module RailsBestPractices
5
+ module Reviews
6
+ # Find out unused methods in helpers.
7
+ #
8
+ # Implementation:
9
+ #
10
+ # Review process:
11
+ # remember all method calls in helpers.
12
+ # if they are not called in views or helpers,
13
+ # then they are unused methods in helpers.
14
+ class RemoveUnusedMethodsInHelpersReview < Review
15
+ include Moduleable
16
+ include Afterable
17
+ include Callable
18
+ include Exceptable
19
+
20
+ interesting_files HELPER_FILES, VIEW_FILES
21
+
22
+ def initialize(options={})
23
+ super
24
+ @helper_methods = Prepares.helper_methods
25
+ self.class.interesting_files Prepares.helpers.map(&:decendants)
26
+ end
27
+
28
+ # get all unused methods at the end of review process
29
+ def after_review
30
+ @helper_methods.get_all_unused_methods.each do |method|
31
+ if !excepted?(method)
32
+ add_error "remove unused methods (#{method.class_name}##{method.method_name})", method.file, method.line
33
+ end
34
+ end
35
+ end
36
+
37
+ protected
38
+ def methods
39
+ @helper_methods
40
+ end
41
+
42
+ def internal_except_methods
43
+ []
44
+ end
45
+ end
46
+ end
47
+ end
@@ -12,8 +12,8 @@ module RailsBestPractices
12
12
  # at end, check if all defined methods are called,
13
13
  # if not, non called methods are unused.
14
14
  class RemoveUnusedMethodsInModelsReview < Review
15
- include Klassable
16
- include Completeable
15
+ include Classable
16
+ include Afterable
17
17
  include Callable
18
18
  include Exceptable
19
19
 
@@ -41,7 +41,7 @@ module RailsBestPractices
41
41
  end
42
42
 
43
43
  # get all unused methods at the end of review process.
44
- def on_complete
44
+ def after_review
45
45
  @model_methods.get_all_unused_methods.each do |method|
46
46
  if !excepted?(method) && method.method_name !~ /=$/
47
47
  add_error "remove unused methods (#{method.class_name}##{method.method_name})", method.file, method.line
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module RailsBestPractices
3
- VERSION = "1.5.3"
3
+ VERSION = "1.6.0"
4
4
  end
@@ -29,3 +29,4 @@ RemoveTabCheck: { }
29
29
  RestrictAutoGeneratedRoutesCheck: { }
30
30
  RemoveUnusedMethodsInModelsCheck: { except_methods: [] }
31
31
  RemoveUnusedMethodsInControllersCheck: { except_methods: [] }
32
+ RemoveUnusedMethodsInHelpersCheck: { except_methods: [] }
@@ -11,9 +11,9 @@ describe RailsBestPractices::Analyzer do
11
11
  end
12
12
 
13
13
  describe "file_sort" do
14
- it "should get models first, then mailers" do
15
- files = ["app/controllers/users_controller.rb", "app/mailers/user_mailer.rb", "app/models/user.rb", "app/views/users/index.html.haml", "lib/user.rb"]
16
- subject.file_sort(files).should == ["app/models/user.rb", "app/mailers/user_mailer.rb", "app/controllers/users_controller.rb", "app/views/users/index.html.haml", "lib/user.rb"]
14
+ it "should get models first, mailers, helpers and then others" do
15
+ files = ["app/controllers/users_controller.rb", "app/mailers/user_mailer.rb", "app/helpers/users_helper.rb", "app/models/user.rb", "app/views/users/index.html.haml", "lib/user.rb"]
16
+ subject.file_sort(files).should == ["app/models/user.rb", "app/mailers/user_mailer.rb", "app/helpers/users_helper.rb", "app/controllers/users_controller.rb", "app/views/users/index.html.haml", "lib/user.rb"]
17
17
  end
18
18
  end
19
19
 
@@ -2,6 +2,15 @@ require 'spec_helper'
2
2
 
3
3
  describe RailsBestPractices::Core::Error do
4
4
  it "should return error with filename, line number and message" do
5
- RailsBestPractices::Core::Error.new("app/models/user.rb", 100, "not good", "BogusReview").to_s.should == "app/models/user.rb:100 - not good"
5
+ RailsBestPractices::Core::Error.new("app/models/user.rb", "100", "not good", "BogusReview").to_s.should == "app/models/user.rb:100 - not good"
6
+ end
7
+
8
+ it "should return short filename" do
9
+ RailsBestPractices::Core::Runner.base_path = "../rails-bestpractices.com"
10
+ RailsBestPractices::Core::Error.new("../rails-bestpractices.com/app/models/user.rb", "100", "not good", "BogusReview").short_filename.should == "app/models/user.rb"
11
+ end
12
+
13
+ it "should return first line number" do
14
+ RailsBestPractices::Core::Error.new("app/models/user.rb", "50,70,100", "not good", "BogusReview").first_line_number.should == "50"
6
15
  end
7
16
  end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe RailsBestPractices::Core::Helpers do
4
+ it { should be_a_kind_of RailsBestPractices::Core::Modules }
5
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe RailsBestPractices::Core::Modules do
4
+ it { should be_a_kind_of Array }
5
+
6
+ context "Modules" do
7
+ before do
8
+ @mod = RailsBestPractices::Core::Mod.new("PostsHelper", [])
9
+ end
10
+ subject { RailsBestPractices::Core::Modules.new.tap { |modules| modules << @mod } }
11
+ it "should add decendant to the corresponding module" do
12
+ @mod.should_receive(:add_decendant).with("PostsController")
13
+ subject.add_module_decendant("PostsHelper", "PostsController")
14
+ end
15
+ end
16
+
17
+ context "Mod" do
18
+ subject {
19
+ RailsBestPractices::Core::Mod.new("UsersHelper", ["Admin"]).tap do |mod|
20
+ mod.add_decendant("Admin::UsersController")
21
+ end
22
+ }
23
+ its(:to_s) { should == "Admin::UsersHelper" }
24
+ its(:decendants) { should == ["Admin::UsersController"] }
25
+ end
26
+ end
@@ -1,7 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe RailsBestPractices::Prepares::ControllerPrepare do
4
- let(:runner) { RailsBestPractices::Core::Runner.new(:prepares => RailsBestPractices::Prepares::ControllerPrepare.new) }
4
+ let(:runner) { RailsBestPractices::Core::Runner.new(
5
+ :prepares => [RailsBestPractices::Prepares::ControllerPrepare.new, RailsBestPractices::Prepares::HelperPrepare.new]
6
+ ) }
5
7
 
6
8
  before :each do
7
9
  runner.whiny = true
@@ -100,6 +102,17 @@ describe RailsBestPractices::Prepares::ControllerPrepare do
100
102
  methods.get_methods("PostsController").map(&:method_name).should == ["index", "new", "create", "edit", "update", "destroy"]
101
103
  end
102
104
 
105
+ it "extend inherited_resources with all actions with no arguments" do
106
+ content =<<-EOF
107
+ class PostsController < InheritedResources::Base
108
+ actions :all
109
+ end
110
+ EOF
111
+ runner.prepare('app/controllers/posts_controller.rb', content)
112
+ methods = RailsBestPractices::Prepares.controller_methods
113
+ methods.get_methods("PostsController").map(&:method_name).should == ["index", "show", "new", "create", "edit", "update", "destroy"]
114
+ end
115
+
103
116
  it "DSL inherit_resources" do
104
117
  content =<<-EOF
105
118
  class PostsController
@@ -112,4 +125,22 @@ describe RailsBestPractices::Prepares::ControllerPrepare do
112
125
  end
113
126
  end
114
127
  end
128
+
129
+ context "helpers" do
130
+ it "should add helper decendant" do
131
+ content =<<-EOF
132
+ module PostsHelper
133
+ end
134
+ EOF
135
+ runner.prepare('app/helpers/posts_helper.rb', content)
136
+ content =<<-EOF
137
+ class PostsController
138
+ include PostsHelper
139
+ end
140
+ EOF
141
+ runner.prepare('app/controllers/posts_controller.rb', content)
142
+ helpers = RailsBestPractices::Prepares.helpers
143
+ helpers.first.decendants.should == ["PostsController"]
144
+ end
145
+ end
115
146
  end