rails_best_practices 0.6.6 → 0.6.7
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +0 -1
- data/README.md +28 -24
- data/Rakefile +0 -8
- data/install_supported_rubies.sh +2 -3
- data/lib/rails_best_practices.rb +8 -7
- data/lib/rails_best_practices/core.rb +1 -0
- data/lib/rails_best_practices/core/check.rb +68 -0
- data/lib/rails_best_practices/core/checking_visitor.rb +18 -15
- data/lib/rails_best_practices/core/runner.rb +22 -12
- data/lib/rails_best_practices/core/visitable_sexp.rb +6 -2
- data/lib/rails_best_practices/prepares.rb +11 -0
- data/lib/rails_best_practices/prepares/mailer_prepare.rb +33 -0
- data/lib/rails_best_practices/prepares/model_prepare.rb +60 -0
- data/lib/rails_best_practices/reviews.rb +23 -0
- data/lib/rails_best_practices/{checks/add_model_virtual_attribute_check.rb → reviews/add_model_virtual_attribute_review.rb} +6 -9
- data/lib/rails_best_practices/{checks/always_add_db_index_check.rb → reviews/always_add_db_index_review.rb} +9 -12
- data/lib/rails_best_practices/{checks/dry_bundler_in_capistrano_check.rb → reviews/dry_bundler_in_capistrano_review.rb} +8 -11
- data/lib/rails_best_practices/{checks/isolate_seed_data_check.rb → reviews/isolate_seed_data_review.rb} +11 -14
- data/lib/rails_best_practices/{checks/keep_finders_on_their_own_model_check.rb → reviews/keep_finders_on_their_own_model_review.rb} +7 -10
- data/lib/rails_best_practices/{checks/law_of_demeter_check.rb → reviews/law_of_demeter_review.rb} +10 -14
- data/lib/rails_best_practices/{checks/move_code_into_controller_check.rb → reviews/move_code_into_controller_review.rb} +8 -11
- data/lib/rails_best_practices/{checks/move_code_into_helper_check.rb → reviews/move_code_into_helper_review.rb} +7 -10
- data/lib/rails_best_practices/{checks/move_code_into_model_check.rb → reviews/move_code_into_model_review.rb} +7 -10
- data/lib/rails_best_practices/{checks/move_finder_to_named_scope_check.rb → reviews/move_finder_to_named_scope_review.rb} +7 -10
- data/lib/rails_best_practices/{checks/move_model_logic_into_model_check.rb → reviews/move_model_logic_into_model_review.rb} +8 -11
- data/lib/rails_best_practices/{checks/needless_deep_nesting_check.rb → reviews/needless_deep_nesting_review.rb} +8 -11
- data/lib/rails_best_practices/{checks/not_use_default_route_check.rb → reviews/not_use_default_route_review.rb} +7 -10
- data/lib/rails_best_practices/{checks/overuse_route_customizations_check.rb → reviews/overuse_route_customizations_review.rb} +10 -13
- data/lib/rails_best_practices/{checks/replace_complex_creation_with_factory_method_check.rb → reviews/replace_complex_creation_with_factory_method_review.rb} +8 -11
- data/lib/rails_best_practices/{checks/replace_instance_variable_with_local_variable_check.rb → reviews/replace_instance_variable_with_local_variable_review.rb} +7 -10
- data/lib/rails_best_practices/reviews/review.rb +92 -0
- data/lib/rails_best_practices/{checks/use_before_filter_check.rb → reviews/use_before_filter_review.rb} +8 -11
- data/lib/rails_best_practices/{checks/use_model_association_check.rb → reviews/use_model_association_review.rb} +8 -11
- data/lib/rails_best_practices/{checks/use_observer_check.rb → reviews/use_observer_review.rb} +14 -41
- data/lib/rails_best_practices/{checks/use_query_attribute_check.rb → reviews/use_query_attribute_review.rb} +20 -16
- data/lib/rails_best_practices/{checks/use_say_with_time_in_migrations_check.rb → reviews/use_say_with_time_in_migrations_review.rb} +8 -11
- data/lib/rails_best_practices/{checks/use_scope_access_check.rb → reviews/use_scope_access_review.rb} +8 -11
- data/lib/rails_best_practices/version.rb +1 -1
- data/rails_best_practices.gemspec +3 -2
- data/rails_best_practices.yml +22 -22
- data/rake_rubies.sh +3 -2
- data/spec/rails_best_practices/core/check_spec.rb +41 -0
- data/spec/rails_best_practices/core/checking_visitor_spec.rb +78 -0
- data/spec/rails_best_practices/core/visitable_sexp_spec.rb +39 -36
- data/spec/rails_best_practices/prepares/mailer_prepare_spec.rb +14 -0
- data/spec/rails_best_practices/prepares/model_prepare_spec.rb +22 -0
- data/spec/rails_best_practices/{checks/add_model_virtual_attribute_check_spec.rb → reviews/add_model_virtual_attribute_review_spec.rb} +17 -25
- data/spec/rails_best_practices/{checks/always_add_db_index_check_spec.rb → reviews/always_add_db_index_review_spec.rb} +28 -41
- data/spec/rails_best_practices/{checks/dry_bundler_in_capistrano_check_spec.rb → reviews/dry_bundler_in_capistrano_review_spec.rb} +7 -11
- data/spec/rails_best_practices/{checks/isolate_seed_data_check_spec.rb → reviews/isolate_seed_data_review_spec.rb} +13 -20
- data/spec/rails_best_practices/{checks/keep_finders_on_their_own_model_check_spec.rb → reviews/keep_finders_on_their_own_model_review_spec.rb} +16 -24
- data/spec/rails_best_practices/{checks/law_of_demeter_check_spec.rb → reviews/law_of_demeter_review_spec.rb} +24 -26
- data/spec/rails_best_practices/reviews/move_code_into_controller_review_spec.rb +29 -0
- data/spec/rails_best_practices/reviews/move_code_into_helper_review_spec.rb +24 -0
- data/spec/rails_best_practices/{checks/move_code_into_model_check_spec.rb → reviews/move_code_into_model_review_spec.rb} +12 -18
- data/spec/rails_best_practices/{checks/move_finder_to_named_scope_check_spec.rb → reviews/move_finder_to_named_scope_review_spec.rb} +12 -16
- data/spec/rails_best_practices/{checks/move_model_logic_into_model_check_spec.rb → reviews/move_model_logic_into_model_review_spec.rb} +7 -11
- data/spec/rails_best_practices/{checks/needless_deep_nesting_check_spec.rb → reviews/needless_deep_nesting_review_spec.rb} +26 -37
- data/spec/rails_best_practices/{checks/not_use_default_route_check_spec.rb → reviews/not_use_default_route_review_spec.rb} +13 -19
- data/spec/rails_best_practices/{checks/overuse_route_customizations_check_spec.rb → reviews/overuse_route_customizations_review_spec.rb} +27 -39
- data/spec/rails_best_practices/{checks/replace_complex_creation_with_factory_method_check_spec.rb → reviews/replace_complex_creation_with_factory_method_review_spec.rb} +10 -15
- data/spec/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review_spec.rb +31 -0
- data/spec/rails_best_practices/reviews/review_spec.rb +11 -0
- data/spec/rails_best_practices/{checks/use_before_filter_check_spec.rb → reviews/use_before_filter_review_spec.rb} +11 -17
- data/spec/rails_best_practices/{checks/use_model_association_check_spec.rb → reviews/use_model_association_review_spec.rb} +12 -18
- data/spec/rails_best_practices/{checks/use_observer_check_spec.rb → reviews/use_observer_review_spec.rb} +28 -29
- data/spec/rails_best_practices/reviews/use_query_attribute_review_spec.rb +190 -0
- data/spec/rails_best_practices/{checks/use_say_with_time_in_migrations_check_spec.rb → reviews/use_say_with_time_in_migrations_review_spec.rb} +14 -23
- data/spec/rails_best_practices/{checks/use_scope_access_check_spec.rb → reviews/use_scope_access_review_spec.rb} +28 -37
- data/spec/rails_best_practices_spec.rb +4 -4
- data/spec/spec_helper.rb +1 -0
- metadata +128 -102
- data/lib/rails_best_practices/checks.rb +0 -23
- data/lib/rails_best_practices/checks/check.rb +0 -203
- data/spec/rails_best_practices/checks/check_spec.rb +0 -57
- data/spec/rails_best_practices/checks/move_code_into_controller_check_spec.rb +0 -33
- data/spec/rails_best_practices/checks/move_code_into_helper_check_spec.rb +0 -28
- data/spec/rails_best_practices/checks/replace_instance_variable_with_local_variable_check_spec.rb +0 -36
- data/spec/rails_best_practices/checks/use_query_attribute_check_spec.rb +0 -192
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -62,6 +62,10 @@ Install
|
|
62
62
|
Issue
|
63
63
|
-----
|
64
64
|
|
65
|
+
If you install the rails_best_practices with bundler-installed github-sourced gem, please use the following command instead.
|
66
|
+
|
67
|
+
bundle exec rails_best_practices .
|
68
|
+
|
65
69
|
If you got NoMethodError or any syntax error, you should use debug mode to detect which file rails_best_practices is parsing and getting the error.
|
66
70
|
|
67
71
|
rails_best_practices -d .
|
@@ -79,30 +83,30 @@ to generate `rails_best_practices.yml` file.
|
|
79
83
|
|
80
84
|
Now you can customize this configuration file, the default configuration is as follows:
|
81
85
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
You can remove or comment one
|
86
|
+
MoveFinderToNamedScopeReview: { }
|
87
|
+
UseModelAssociationReview: { }
|
88
|
+
UseScopeAccessReview: { }
|
89
|
+
AddModelVirtualAttributeReview: { }
|
90
|
+
ReplaceComplexCreationWithFactoryMethodReview: { attribute_assignment_count: 2 }
|
91
|
+
MoveModelLogicIntoModelReview: { use_count: 4 }
|
92
|
+
OveruseRouteCustomizationsReview: { customize_count: 3 }
|
93
|
+
NeedlessDeepNestingReview: { nested_count: 2 }
|
94
|
+
NotUseDefaultRouteReview: { }
|
95
|
+
KeepFindersOnTheirOwnModelReview: { }
|
96
|
+
LawOfDemeterReview: { }
|
97
|
+
UseObserverReview: { }
|
98
|
+
IsolateSeedDataReview: { }
|
99
|
+
AlwaysAddDbIndexReview: { }
|
100
|
+
UseBeforeFilterReview: { }
|
101
|
+
MoveCodeIntoControllerReview: { }
|
102
|
+
MoveCodeIntoModelReview: { use_count: 2 }
|
103
|
+
MoveCodeIntoHelperReview: { array_count: 3 }
|
104
|
+
ReplaceInstanceVariableWithLocalVariableReview: { }
|
105
|
+
DryBundlerInCapistranoReview: { }
|
106
|
+
UseSayWithTimeInMigrationsReview: { }
|
107
|
+
UseQueryAttributeReview: { }
|
108
|
+
|
109
|
+
You can remove or comment one review to disable it, and you can change the options.
|
106
110
|
|
107
111
|
Implementation
|
108
112
|
--------------
|
data/Rakefile
CHANGED
@@ -2,7 +2,6 @@ require "bundler"
|
|
2
2
|
Bundler.setup
|
3
3
|
|
4
4
|
require "rake"
|
5
|
-
require "rake/rdoctask"
|
6
5
|
require "rspec"
|
7
6
|
require "rspec/core/rake_task"
|
8
7
|
|
@@ -35,11 +34,4 @@ Rspec::Core::RakeTask.new('spec:progress') do |spec|
|
|
35
34
|
spec.pattern = "spec/**/*_spec.rb"
|
36
35
|
end
|
37
36
|
|
38
|
-
Rake::RDocTask.new do |rdoc|
|
39
|
-
rdoc.rdoc_dir = "rdoc"
|
40
|
-
rdoc.title = "rails_best_practices #{RailsBestPractices::VERSION}"
|
41
|
-
rdoc.rdoc_files.include("README*")
|
42
|
-
rdoc.rdoc_files.include("lib/**/*.rb")
|
43
|
-
end
|
44
|
-
|
45
37
|
task :default => :spec
|
data/install_supported_rubies.sh
CHANGED
data/lib/rails_best_practices.rb
CHANGED
@@ -26,7 +26,8 @@ require 'rubygems'
|
|
26
26
|
require 'progressbar'
|
27
27
|
require 'colored'
|
28
28
|
require 'haml'
|
29
|
-
require 'rails_best_practices/
|
29
|
+
require 'rails_best_practices/prepares'
|
30
|
+
require 'rails_best_practices/reviews'
|
30
31
|
require 'rails_best_practices/core'
|
31
32
|
require 'fileutils'
|
32
33
|
|
@@ -73,9 +74,9 @@ module RailsBestPractices
|
|
73
74
|
@runner.debug = true if @options['debug']
|
74
75
|
@runner.color = !options['without-color']
|
75
76
|
|
76
|
-
if @runner.checks.find { |check| check.is_a?
|
77
|
+
if @runner.checks.find { |check| check.is_a? Reviews::AlwaysAddDbIndexReview } &&
|
77
78
|
!review_files.find { |file| file.index "db\/schema.rb" }
|
78
|
-
plain_output("
|
79
|
+
plain_output("AlwaysAddDbIndexReview is disabled as there is no db/schema.rb file in your rails project.", 'blue')
|
79
80
|
end
|
80
81
|
|
81
82
|
@bar = ProgressBar.new('Analyzing', prepare_files.size + review_files.size)
|
@@ -162,13 +163,13 @@ module RailsBestPractices
|
|
162
163
|
# @return [Array] sorted files
|
163
164
|
def file_sort files
|
164
165
|
files.sort { |a, b|
|
165
|
-
if a =~
|
166
|
+
if a =~ Core::Check::MODEL_FILES
|
166
167
|
-1
|
167
|
-
elsif b =~
|
168
|
+
elsif b =~ Core::Check::MODEL_FILES
|
168
169
|
1
|
169
|
-
elsif a =~
|
170
|
+
elsif a =~ Core::Check::MAILER_FILES
|
170
171
|
-1
|
171
|
-
elsif b =~
|
172
|
+
elsif b =~ Core::Check::MAILER_FILES
|
172
173
|
1
|
173
174
|
else
|
174
175
|
a <=> b
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module RailsBestPractices
|
3
|
+
module Core
|
4
|
+
# A Check class that takes charge of checking the sexp.
|
5
|
+
class Check
|
6
|
+
# only nodes whose node_type is in NODE_TYPE will be reviewed.
|
7
|
+
NODE_TYPES = [:call, :defn, :defs, :if, :class, :lasgn, :iasgn, :ivar, :lvar, :block, :iter, :const]
|
8
|
+
|
9
|
+
CONTROLLER_FILES = /_controller\.rb$/
|
10
|
+
MIGRATION_FILES = /db\/migrate\/.*\.rb$/
|
11
|
+
MODEL_FILES = /models\/.*\.rb$/
|
12
|
+
MAILER_FILES = /models\/.*\.rb$|mailers\/.*\.rb/
|
13
|
+
VIEW_FILES = /views\/.*\.(erb|haml)$/
|
14
|
+
PARTIAL_VIEW_FILES = /views\/.*\/_.*\.(erb|haml)$/
|
15
|
+
ROUTE_FILE = /config\/routes.rb/
|
16
|
+
|
17
|
+
# default interesting nodes.
|
18
|
+
def interesting_nodes
|
19
|
+
[]
|
20
|
+
end
|
21
|
+
|
22
|
+
# default interesting files.
|
23
|
+
def interesting_files
|
24
|
+
/.*/
|
25
|
+
end
|
26
|
+
|
27
|
+
# delegate to start_### according to the node_type, like
|
28
|
+
#
|
29
|
+
# start_call
|
30
|
+
# start_defn
|
31
|
+
#
|
32
|
+
# @param [Sexp] node
|
33
|
+
def node_start(node)
|
34
|
+
@node = node
|
35
|
+
self.send("start_#{node.node_type}", node)
|
36
|
+
end
|
37
|
+
|
38
|
+
# delegate to end_### according to the node_type, like
|
39
|
+
#
|
40
|
+
# end_call
|
41
|
+
# end_defn
|
42
|
+
#
|
43
|
+
# @param [Sexp] node
|
44
|
+
def node_end(node)
|
45
|
+
@node = node
|
46
|
+
self.send("end_#{node.node_type}", node)
|
47
|
+
end
|
48
|
+
|
49
|
+
# method_missing to catch all start and end process for each node type, like
|
50
|
+
#
|
51
|
+
# start_defn
|
52
|
+
# end_defn
|
53
|
+
# start_call
|
54
|
+
# end_call
|
55
|
+
#
|
56
|
+
# if there is a "debug" method defined in check, each node will be output.
|
57
|
+
def method_missing(method_name, *args)
|
58
|
+
if method_name.to_s =~ /^start_/
|
59
|
+
p args if respond_to?(:debug)
|
60
|
+
elsif method_name.to_s =~ /^end_/
|
61
|
+
# nothing to do
|
62
|
+
else
|
63
|
+
super
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -14,26 +14,29 @@ module RailsBestPractices
|
|
14
14
|
# if the node_type and the node filename match the interesting_review_nodes and interesting_review_files,
|
15
15
|
# then run the reivew for that node.
|
16
16
|
class CheckingVisitor
|
17
|
-
# remember all the checks for prepare and review processes according to
|
18
|
-
|
17
|
+
# remember all the checks for prepare and review processes according to interesting_nodes.
|
18
|
+
#
|
19
|
+
# @param [Array] prepares
|
20
|
+
# @param [Array] reviews
|
21
|
+
def initialize(prepares, reviews)
|
19
22
|
[:prepare, :review].each do |process|
|
20
23
|
instance_variable_set("@#{process}_checks", {}) # @review_checks = {}
|
21
|
-
|
22
|
-
check.send("
|
23
|
-
instance_variable_get("@#{process}_checks")[node] ||= [] #
|
24
|
-
instance_variable_get("@#{process}_checks")[node] << check #
|
25
|
-
instance_variable_get("@#{process}_checks")[node].uniq! #
|
26
|
-
end #
|
27
|
-
end
|
24
|
+
eval("#{process}s").each do |check| # reviews.each do |check|
|
25
|
+
check.send("interesting_nodes").each do |node| # check.interesting_nodes.each do |node|
|
26
|
+
instance_variable_get("@#{process}_checks")[node] ||= [] # @review_checks[node] ||= []
|
27
|
+
instance_variable_get("@#{process}_checks")[node] << check # @review_checks[node] << check
|
28
|
+
instance_variable_get("@#{process}_checks")[node].uniq! # @review_checks[node].uniq!
|
29
|
+
end # end
|
30
|
+
end # end
|
28
31
|
end
|
29
32
|
end
|
30
33
|
|
31
34
|
# for prepare process
|
32
|
-
# if the node_type and the node filename match the
|
35
|
+
# if the node_type and the node filename match the interesting_nodes and interesting_files,
|
33
36
|
# then run the prepare for that node.
|
34
37
|
#
|
35
38
|
# for review process
|
36
|
-
# if the node_type and the node filename match the
|
39
|
+
# if the node_type and the node filename match the interesting_nodes and interesting_files,
|
37
40
|
# then run the reivew for that node.
|
38
41
|
[:prepare, :review].each do |process|
|
39
42
|
class_eval <<-EOS
|
@@ -41,16 +44,16 @@ module RailsBestPractices
|
|
41
44
|
checks = @#{process}_checks[node.node_type] # checks = @review_checks[node.node_type]
|
42
45
|
if checks # if checks
|
43
46
|
checks.each { |check| # checks.each { |check|
|
44
|
-
if node.file =~ check.
|
45
|
-
check
|
47
|
+
if node.file =~ check.interesting_files # if node.file =~ check.interesting_files
|
48
|
+
check.node_start(node) # check.node_start(node)
|
46
49
|
end # end
|
47
50
|
} # }
|
48
51
|
end # end
|
49
52
|
node.children.each {|sexp| sexp.#{process}(self)} # node.children.each {|sexp| sexp.review(self)}
|
50
53
|
if checks # if checks
|
51
54
|
checks.each { |check| # checks.each { |check|
|
52
|
-
if node.file =~ check.
|
53
|
-
check
|
55
|
+
if node.file =~ check.interesting_files # if node.file =~ check.interesting_files
|
56
|
+
check.node_end(node) # check.node_end(node)
|
54
57
|
end # end
|
55
58
|
} # }
|
56
59
|
end # end
|
@@ -31,12 +31,19 @@ module RailsBestPractices
|
|
31
31
|
@base_path || "."
|
32
32
|
end
|
33
33
|
|
34
|
-
|
34
|
+
# initialize the runner.
|
35
|
+
#
|
36
|
+
# @param [Hash] options pass the prepares and reviews.
|
37
|
+
def initialize(options={})
|
35
38
|
custom_config = File.join(Runner.base_path, 'config/rails_best_practices.yml')
|
36
39
|
@config = File.exists?(custom_config) ? custom_config : RailsBestPractices::DEFAULT_CONFIG
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
+
|
41
|
+
prepares = Array(options[:prepares])
|
42
|
+
reviews = Array(options[:reviews])
|
43
|
+
@prepares = prepares.empty? ? load_prepares : prepares
|
44
|
+
@reviews = reviews.empty? ? load_reviews : reviews
|
45
|
+
|
46
|
+
@checker ||= CheckingVisitor.new(@prepares, @reviews)
|
40
47
|
@debug = false
|
41
48
|
end
|
42
49
|
|
@@ -60,13 +67,11 @@ module RailsBestPractices
|
|
60
67
|
EOS
|
61
68
|
end
|
62
69
|
|
63
|
-
# get all errors from
|
70
|
+
# get all errors from reviews.
|
64
71
|
#
|
65
|
-
# @return [Array] all errors from
|
72
|
+
# @return [Array] all errors from reviews
|
66
73
|
def errors
|
67
|
-
@
|
68
|
-
all_errors = @checks.collect {|check| check.errors}
|
69
|
-
all_errors.flatten
|
74
|
+
@reviews.collect {|review| review.errors}.flatten
|
70
75
|
end
|
71
76
|
|
72
77
|
private
|
@@ -106,12 +111,17 @@ module RailsBestPractices
|
|
106
111
|
content
|
107
112
|
end
|
108
113
|
|
109
|
-
# load all
|
110
|
-
def
|
114
|
+
# load all prepares.
|
115
|
+
def load_prepares
|
116
|
+
[RailsBestPractices::Prepares::ModelPrepare.new, RailsBestPractices::Prepares::MailerPrepare.new]
|
117
|
+
end
|
118
|
+
|
119
|
+
# load all reviews according to configuration.
|
120
|
+
def load_reviews
|
111
121
|
check_objects = []
|
112
122
|
checks = YAML.load_file @config
|
113
123
|
checks.each do |check|
|
114
|
-
klass = RailsBestPractices::
|
124
|
+
klass = RailsBestPractices::Reviews.const_get(check[0].gsub(/Check/, 'Review'))
|
115
125
|
check_objects << (check[1].empty? ? klass.new : klass.new(check[1]))
|
116
126
|
end
|
117
127
|
check_objects
|
@@ -395,10 +395,14 @@ class Sexp
|
|
395
395
|
|
396
396
|
# to_s for lvar, ivar, lit, const, array, hash, and colon2 node.
|
397
397
|
#
|
398
|
+
# @param [Hash] options
|
399
|
+
# :remove_at remove the @ symbol for ivar.
|
398
400
|
# @return [String] to_s
|
399
|
-
def to_s
|
401
|
+
def to_s(options={})
|
400
402
|
case node_type
|
401
|
-
when :
|
403
|
+
when :ivar
|
404
|
+
options[:remove_at] ? self[1].to_s[1..-1] : self[1].to_s
|
405
|
+
when :lvar, :str, :lit, :const
|
402
406
|
self[1].to_s
|
403
407
|
when :array
|
404
408
|
"[\"#{self.children.collect(&:to_s).join('", "')}\"]"
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rails_best_practices/prepares/model_prepare'
|
3
|
+
require 'rails_best_practices/prepares/mailer_prepare'
|
4
|
+
|
5
|
+
module RailsBestPractices
|
6
|
+
module Prepares
|
7
|
+
class <<self
|
8
|
+
attr_accessor :model_associations, :mailer_names
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rails_best_practices/core/check'
|
3
|
+
|
4
|
+
module RailsBestPractices
|
5
|
+
module Prepares
|
6
|
+
# Remember the mailer names.
|
7
|
+
class MailerPrepare < Core::Check
|
8
|
+
|
9
|
+
def interesting_nodes
|
10
|
+
[:class]
|
11
|
+
end
|
12
|
+
|
13
|
+
def interesting_files
|
14
|
+
/#{MAILER_FILES}|#{MODEL_FILES}/
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@mailer_names = []
|
19
|
+
end
|
20
|
+
|
21
|
+
# check class node.
|
22
|
+
#
|
23
|
+
# if it is a subclass of ActionMailer::Base,
|
24
|
+
# then remember its class name.
|
25
|
+
def start_class(class_node)
|
26
|
+
if s(:colon2, s(:const, :ActionMailer), :Base) == class_node.base_class
|
27
|
+
@mailer_names << class_node.class_name
|
28
|
+
Prepares.mailer_names = @mailer_names
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rails_best_practices/core/check'
|
3
|
+
|
4
|
+
module RailsBestPractices
|
5
|
+
module Prepares
|
6
|
+
# Remember the model associations.
|
7
|
+
class ModelPrepare < Core::Check
|
8
|
+
|
9
|
+
def interesting_nodes
|
10
|
+
[:class, :call]
|
11
|
+
end
|
12
|
+
|
13
|
+
def interesting_files
|
14
|
+
MODEL_FILES
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@associations = {}
|
19
|
+
end
|
20
|
+
|
21
|
+
# check class node to remember the last class name.
|
22
|
+
def start_class(class_node)
|
23
|
+
@last_klazz = class_node.class_name.to_s
|
24
|
+
end
|
25
|
+
|
26
|
+
# assign @associations to Prepare.model_associations.
|
27
|
+
def end_class(class_node)
|
28
|
+
Prepares.model_associations = @associations
|
29
|
+
end
|
30
|
+
|
31
|
+
# check call node to remember all assoications.
|
32
|
+
#
|
33
|
+
# the remembered association names (@associations) are like
|
34
|
+
# {
|
35
|
+
# :Project=>{
|
36
|
+
# "categories"=>:has_and_belongs_to_many,
|
37
|
+
# "project_manager"=>:has_one,
|
38
|
+
# "portfolio"=>:belongs_to,
|
39
|
+
# "milestones=>:has_many"
|
40
|
+
# }
|
41
|
+
# }
|
42
|
+
def start_call(node)
|
43
|
+
remember_association(node) if association_methods.include? node.message
|
44
|
+
end
|
45
|
+
|
46
|
+
# remember associations, with class to association names.
|
47
|
+
def remember_association(association_node)
|
48
|
+
association_meta = association_node.message
|
49
|
+
association_name = association_node.arguments[1].to_s
|
50
|
+
@associations[@last_klazz] ||= {}
|
51
|
+
@associations[@last_klazz][association_name] = association_meta
|
52
|
+
end
|
53
|
+
|
54
|
+
# default rails association methods.
|
55
|
+
def association_methods
|
56
|
+
[:belongs_to, :has_one, :has_many, :has_and_belongs_to_many]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|