rails_best_practices 0.6.7 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemtest +0 -0
- data/README.md +32 -22
- data/Rakefile +1 -0
- data/lib/rails_best_practices.rb +7 -5
- data/lib/rails_best_practices/core/check.rb +22 -1
- data/lib/rails_best_practices/core/checking_visitor.rb +16 -7
- data/lib/rails_best_practices/core/runner.rb +50 -11
- data/lib/rails_best_practices/core/visitable_sexp.rb +10 -3
- data/lib/rails_best_practices/lexicals.rb +2 -0
- data/lib/rails_best_practices/lexicals/remove_trailing_whitespace_check.rb +26 -0
- data/lib/rails_best_practices/reviews.rb +1 -0
- data/lib/rails_best_practices/reviews/law_of_demeter_review.rb +0 -3
- data/lib/rails_best_practices/reviews/needless_deep_nesting_review.rb +3 -3
- data/lib/rails_best_practices/reviews/review.rb +0 -15
- data/lib/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review.rb +80 -0
- data/lib/rails_best_practices/reviews/use_observer_review.rb +0 -4
- data/lib/rails_best_practices/reviews/use_query_attribute_review.rb +0 -5
- data/lib/rails_best_practices/version.rb +1 -1
- data/rails_best_practices.yml +24 -22
- data/spec/rails_best_practices/core/checking_visitor_spec.rb +21 -1
- data/spec/rails_best_practices/core/visitable_sexp_spec.rb +10 -0
- data/spec/rails_best_practices/lexicals/remove_trailing_whitespace_check_spec.rb +39 -0
- data/spec/rails_best_practices/reviews/needless_deep_nesting_review_spec.rb +24 -0
- data/spec/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review_spec.rb +196 -0
- metadata +12 -4
data/.gemtest
ADDED
File without changes
|
data/README.md
CHANGED
@@ -83,28 +83,30 @@ to generate `rails_best_practices.yml` file.
|
|
83
83
|
|
84
84
|
Now you can customize this configuration file, the default configuration is as follows:
|
85
85
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
86
|
+
MoveFinderToNamedScopeCheck: { }
|
87
|
+
UseModelAssociationCheck: { }
|
88
|
+
UseScopeAccessCheck: { }
|
89
|
+
AddModelVirtualAttributeCheck: { }
|
90
|
+
ReplaceComplexCreationWithFactoryMethodCheck: { attribute_assignment_count: 2 }
|
91
|
+
MoveModelLogicIntoModelCheck: { use_count: 4 }
|
92
|
+
OveruseRouteCustomizationsCheck: { customize_count: 3 }
|
93
|
+
NeedlessDeepNestingCheck: { nested_count: 2 }
|
94
|
+
NotUseDefaultRouteCheck: { }
|
95
|
+
KeepFindersOnTheirOwnModelCheck: { }
|
96
|
+
LawOfDemeterCheck: { }
|
97
|
+
UseObserverCheck: { }
|
98
|
+
IsolateSeedDataCheck: { }
|
99
|
+
AlwaysAddDbIndexCheck: { }
|
100
|
+
UseBeforeFilterCheck: { }
|
101
|
+
MoveCodeIntoControllerCheck: { }
|
102
|
+
MoveCodeIntoModelCheck: { use_count: 2 }
|
103
|
+
MoveCodeIntoHelperCheck: { array_count: 3 }
|
104
|
+
ReplaceInstanceVariableWithLocalVariableCheck: { }
|
105
|
+
DryBundlerInCapistranoCheck: { }
|
106
|
+
UseSayWithTimeInMigrationsCheck: { }
|
107
|
+
UseQueryAttributeCheck: { }
|
108
|
+
RemoveTrailingWhitespaceCheck: { }
|
109
|
+
UseMultipartAlternativeAsContentTypeOfEmailCheck: {}
|
108
110
|
|
109
111
|
You can remove or comment one review to disable it, and you can change the options.
|
110
112
|
|
@@ -133,6 +135,10 @@ Model
|
|
133
135
|
3. Use Observer
|
134
136
|
4. Use Query Attribute
|
135
137
|
|
138
|
+
Mailer
|
139
|
+
|
140
|
+
1. Use multipart/alternative as content_type of email
|
141
|
+
|
136
142
|
Migration
|
137
143
|
|
138
144
|
1. Isolating Seed Data
|
@@ -154,6 +160,10 @@ Deployment
|
|
154
160
|
|
155
161
|
1. Dry bundler in capistrano
|
156
162
|
|
163
|
+
Other
|
164
|
+
|
165
|
+
1. Remove Trailing Whitespace
|
166
|
+
|
157
167
|
Contribute
|
158
168
|
----------
|
159
169
|
|
data/Rakefile
CHANGED
data/lib/rails_best_practices.rb
CHANGED
@@ -26,6 +26,7 @@ require 'rubygems'
|
|
26
26
|
require 'progressbar'
|
27
27
|
require 'colored'
|
28
28
|
require 'haml'
|
29
|
+
require 'rails_best_practices/lexicals'
|
29
30
|
require 'rails_best_practices/prepares'
|
30
31
|
require 'rails_best_practices/reviews'
|
31
32
|
require 'rails_best_practices/core'
|
@@ -79,9 +80,8 @@ module RailsBestPractices
|
|
79
80
|
plain_output("AlwaysAddDbIndexReview is disabled as there is no db/schema.rb file in your rails project.", 'blue')
|
80
81
|
end
|
81
82
|
|
82
|
-
@bar = ProgressBar.new('Analyzing', prepare_files.size + review_files.size)
|
83
|
-
|
84
|
-
process("review")
|
83
|
+
@bar = ProgressBar.new('Analyzing', lexical_files.size + prepare_files.size + review_files.size)
|
84
|
+
["lexical", "prepare", "review"].each { |process| send(:process, process) }
|
85
85
|
@bar.finish
|
86
86
|
|
87
87
|
if @options['format'] == 'html'
|
@@ -92,12 +92,12 @@ module RailsBestPractices
|
|
92
92
|
exit @runner.errors.size
|
93
93
|
end
|
94
94
|
|
95
|
-
# process prepare or reivew.
|
95
|
+
# process lexical, prepare or reivew.
|
96
96
|
#
|
97
97
|
# get all files for the process, analyze each file,
|
98
98
|
# and increment progress bar unless debug.
|
99
99
|
#
|
100
|
-
# @param [String] process the process name, prepare or review.
|
100
|
+
# @param [String] process the process name, lexical, prepare or review.
|
101
101
|
def process(process)
|
102
102
|
files = send("#{process}_files")
|
103
103
|
files.each do |file|
|
@@ -137,6 +137,8 @@ module RailsBestPractices
|
|
137
137
|
end
|
138
138
|
end
|
139
139
|
|
140
|
+
alias :lexical_files :review_files
|
141
|
+
|
140
142
|
# expand all files with extenstion rb, erb, haml and builder under the dirs
|
141
143
|
#
|
142
144
|
# @param [Array] dirs what directories to expand
|
@@ -9,11 +9,17 @@ module RailsBestPractices
|
|
9
9
|
CONTROLLER_FILES = /_controller\.rb$/
|
10
10
|
MIGRATION_FILES = /db\/migrate\/.*\.rb$/
|
11
11
|
MODEL_FILES = /models\/.*\.rb$/
|
12
|
-
MAILER_FILES = /models
|
12
|
+
MAILER_FILES = /models\/.*mailer\.rb$|mailers\/.*mailer\.rb/
|
13
13
|
VIEW_FILES = /views\/.*\.(erb|haml)$/
|
14
14
|
PARTIAL_VIEW_FILES = /views\/.*\/_.*\.(erb|haml)$/
|
15
15
|
ROUTE_FILE = /config\/routes.rb/
|
16
16
|
|
17
|
+
attr_reader :errors
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@errors = []
|
21
|
+
end
|
22
|
+
|
17
23
|
# default interesting nodes.
|
18
24
|
def interesting_nodes
|
19
25
|
[]
|
@@ -46,6 +52,21 @@ module RailsBestPractices
|
|
46
52
|
self.send("end_#{node.node_type}", node)
|
47
53
|
end
|
48
54
|
|
55
|
+
# add error if source code violates rails best practice.
|
56
|
+
# error is the string message for violation of the rails best practice
|
57
|
+
# file is the filename of source code
|
58
|
+
# line is the line number of the source code which is reviewing
|
59
|
+
def add_error(error, file = @node.file, line = @node.line)
|
60
|
+
@errors << RailsBestPractices::Core::Error.new("#{file}", "#{line}", error, url)
|
61
|
+
end
|
62
|
+
|
63
|
+
# default url is empty.
|
64
|
+
#
|
65
|
+
# @return [String] the url of rails best practice
|
66
|
+
def url
|
67
|
+
""
|
68
|
+
end
|
69
|
+
|
49
70
|
# method_missing to catch all start and end process for each node type, like
|
50
71
|
#
|
51
72
|
# start_defn
|
@@ -3,25 +3,26 @@ module RailsBestPractices
|
|
3
3
|
module Core
|
4
4
|
# CheckingVisitor is a visitor class.
|
5
5
|
#
|
6
|
-
# it remembers all the checks for prepare and review processes according to
|
6
|
+
# it remembers all the checks for prepare and review processes according to interesting_nodes and interesting_nodes,
|
7
7
|
# then recursively iterate all sexp nodes,
|
8
8
|
#
|
9
9
|
# for prepare process
|
10
|
-
# if the node_type and the node filename match the interesting_prepare_nodes and
|
10
|
+
# if the node_type and the node filename match the interesting_prepare_nodes and interesting_files,
|
11
11
|
# then run the prepare for that node.
|
12
12
|
#
|
13
13
|
# for review process
|
14
|
-
# if the node_type and the node filename match the interesting_review_nodes and
|
14
|
+
# if the node_type and the node filename match the interesting_review_nodes and interesting_files,
|
15
15
|
# then run the reivew for that node.
|
16
16
|
class CheckingVisitor
|
17
17
|
# remember all the checks for prepare and review processes according to interesting_nodes.
|
18
18
|
#
|
19
|
-
# @param [
|
20
|
-
#
|
21
|
-
def initialize(
|
19
|
+
# @param [Hash] options
|
20
|
+
# {:lexicals => [], :prepares => [], :reviews => []}
|
21
|
+
def initialize(options={})
|
22
|
+
@lexicals = options[:lexicals]
|
22
23
|
[:prepare, :review].each do |process|
|
23
24
|
instance_variable_set("@#{process}_checks", {}) # @review_checks = {}
|
24
|
-
|
25
|
+
options["#{process}s".to_sym].each do |check| # options[:reviews].each do |check|
|
25
26
|
check.send("interesting_nodes").each do |node| # check.interesting_nodes.each do |node|
|
26
27
|
instance_variable_get("@#{process}_checks")[node] ||= [] # @review_checks[node] ||= []
|
27
28
|
instance_variable_get("@#{process}_checks")[node] << check # @review_checks[node] << check
|
@@ -31,6 +32,14 @@ module RailsBestPractices
|
|
31
32
|
end
|
32
33
|
end
|
33
34
|
|
35
|
+
# for lexical process
|
36
|
+
# check the content of files one by one.
|
37
|
+
def lexical(filename, content)
|
38
|
+
@lexicals.each do |lexical|
|
39
|
+
lexical.check(filename, content)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
34
43
|
# for prepare process
|
35
44
|
# if the node_type and the node filename match the interesting_nodes and interesting_files,
|
36
45
|
# then run the prepare for that node.
|
@@ -40,13 +40,30 @@ module RailsBestPractices
|
|
40
40
|
|
41
41
|
prepares = Array(options[:prepares])
|
42
42
|
reviews = Array(options[:reviews])
|
43
|
+
@lexicals = load_lexicals
|
43
44
|
@prepares = prepares.empty? ? load_prepares : prepares
|
44
45
|
@reviews = reviews.empty? ? load_reviews : reviews
|
45
46
|
|
46
|
-
@checker ||= CheckingVisitor.new(@prepares, @reviews)
|
47
|
+
@checker ||= CheckingVisitor.new(:prepares => @prepares, :reviews => @reviews, :lexicals => @lexicals)
|
47
48
|
@debug = false
|
48
49
|
end
|
49
50
|
|
51
|
+
# lexical analysis the file.
|
52
|
+
#
|
53
|
+
# @param [String] filename name of the file
|
54
|
+
# @param [String] content content of the file
|
55
|
+
def lexical(filename, content)
|
56
|
+
puts filename if @debug
|
57
|
+
@checker.lexical(filename, content)
|
58
|
+
end
|
59
|
+
|
60
|
+
# lexical analysis the file.
|
61
|
+
#
|
62
|
+
# @param [String] filename
|
63
|
+
def lexical_file(filename)
|
64
|
+
lexical(filename, File.read(filename))
|
65
|
+
end
|
66
|
+
|
50
67
|
# prepare and review a file's content with filename.
|
51
68
|
# the file may be a ruby, erb or haml file.
|
52
69
|
#
|
@@ -67,11 +84,11 @@ module RailsBestPractices
|
|
67
84
|
EOS
|
68
85
|
end
|
69
86
|
|
70
|
-
# get all errors from reviews.
|
87
|
+
# get all errors from lexicals and reviews.
|
71
88
|
#
|
72
|
-
# @return [Array] all errors from reviews
|
89
|
+
# @return [Array] all errors from lexicals and reviews
|
73
90
|
def errors
|
74
|
-
@reviews.collect {|
|
91
|
+
(@reviews + @lexicals).collect {|check| check.errors}.flatten
|
75
92
|
end
|
76
93
|
|
77
94
|
private
|
@@ -111,6 +128,20 @@ module RailsBestPractices
|
|
111
128
|
content
|
112
129
|
end
|
113
130
|
|
131
|
+
# load all lexical checks.
|
132
|
+
def load_lexicals
|
133
|
+
checks_from_config.inject([]) { |active_checks, check|
|
134
|
+
begin
|
135
|
+
check_name, options = *check
|
136
|
+
klass = RailsBestPractices::Lexicals.const_get(check_name)
|
137
|
+
active_checks << (options.empty? ? klass.new : klass.new(options))
|
138
|
+
rescue
|
139
|
+
# the check does not exist in the Lexicals namepace.
|
140
|
+
end
|
141
|
+
active_checks
|
142
|
+
}
|
143
|
+
end
|
144
|
+
|
114
145
|
# load all prepares.
|
115
146
|
def load_prepares
|
116
147
|
[RailsBestPractices::Prepares::ModelPrepare.new, RailsBestPractices::Prepares::MailerPrepare.new]
|
@@ -118,13 +149,21 @@ module RailsBestPractices
|
|
118
149
|
|
119
150
|
# load all reviews according to configuration.
|
120
151
|
def load_reviews
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
152
|
+
checks_from_config.inject([]) { |active_checks, check|
|
153
|
+
begin
|
154
|
+
check_name, options = *check
|
155
|
+
klass = RailsBestPractices::Reviews.const_get(check_name.gsub(/Check/, 'Review'))
|
156
|
+
active_checks << (options.empty? ? klass.new : klass.new(options))
|
157
|
+
rescue
|
158
|
+
# the check does not exist in the Reviews namepace.
|
159
|
+
end
|
160
|
+
active_checks
|
161
|
+
}
|
162
|
+
end
|
163
|
+
|
164
|
+
# read the checks from yaml config.
|
165
|
+
def checks_from_config
|
166
|
+
@checks ||= YAML.load_file @config
|
128
167
|
end
|
129
168
|
end
|
130
169
|
end
|
@@ -400,6 +400,8 @@ class Sexp
|
|
400
400
|
# @return [String] to_s
|
401
401
|
def to_s(options={})
|
402
402
|
case node_type
|
403
|
+
when :true, :false, :nil
|
404
|
+
self[0].to_s
|
403
405
|
when :ivar
|
404
406
|
options[:remove_at] ? self[1].to_s[1..-1] : self[1].to_s
|
405
407
|
when :lvar, :str, :lit, :const
|
@@ -408,12 +410,17 @@ class Sexp
|
|
408
410
|
"[\"#{self.children.collect(&:to_s).join('", "')}\"]"
|
409
411
|
when :hash
|
410
412
|
key_value = false # false is key, true is value
|
411
|
-
result = ['{
|
413
|
+
result = ['{']
|
412
414
|
children.each do |child|
|
413
|
-
|
415
|
+
if [:true, :false, :nil, :array, :hash].include? child.node_type
|
416
|
+
result << "#{child}"
|
417
|
+
else
|
418
|
+
result << "\"#{child}\""
|
419
|
+
end
|
420
|
+
result << (key_value ? ", " : " => ")
|
414
421
|
key_value = !key_value
|
415
422
|
end
|
416
|
-
result.join("").sub(/,
|
423
|
+
result.join("").sub(/, $/, '') + '}'
|
417
424
|
when :colon2
|
418
425
|
"#{self[1]}::#{self[2]}"
|
419
426
|
else
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rails_best_practices/core/check'
|
3
|
+
|
4
|
+
module RailsBestPractices
|
5
|
+
module Lexicals
|
6
|
+
# Make sure there are no trailing whitespace in codes.
|
7
|
+
#
|
8
|
+
# See the best practice details here http://rails-bestpractices.com/posts/60-remove-trailing-whitespace
|
9
|
+
class RemoveTrailingWhitespaceCheck < Core::Check
|
10
|
+
def url
|
11
|
+
"http://rails-bestpractices.com/posts/60-remove-trailing-whitespace"
|
12
|
+
end
|
13
|
+
|
14
|
+
# check if the content of file contain a trailing whitespace.
|
15
|
+
#
|
16
|
+
# @param [String] filename name of the file
|
17
|
+
# @param [String] content content of the file
|
18
|
+
def check(filename, content)
|
19
|
+
if content =~ / +\n/m
|
20
|
+
line_no = $`.count("\n") + 1
|
21
|
+
add_error("remove trailing whitespace", filename, line_no)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -21,3 +21,4 @@ require 'rails_best_practices/reviews/replace_instance_variable_with_local_varia
|
|
21
21
|
require 'rails_best_practices/reviews/dry_bundler_in_capistrano_review'
|
22
22
|
require 'rails_best_practices/reviews/use_say_with_time_in_migrations_review'
|
23
23
|
require 'rails_best_practices/reviews/use_query_attribute_review'
|
24
|
+
require 'rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review'
|
@@ -9,9 +9,6 @@ module RailsBestPractices
|
|
9
9
|
#
|
10
10
|
# Implementation:
|
11
11
|
#
|
12
|
-
# Prepare process:
|
13
|
-
# only review all model files to save model names and association names.
|
14
|
-
#
|
15
12
|
# Review process:
|
16
13
|
# check all method calls to see if there is method call to the association object.
|
17
14
|
# if there is a call node whose subject is an object of model (compare by name),
|
@@ -113,13 +113,13 @@ module RailsBestPractices
|
|
113
113
|
# if so, it is the needless deep nesting.
|
114
114
|
def recursively_check(node)
|
115
115
|
if :iter == node.node_type && :resources == node.subject.message
|
116
|
+
options = eval(node.subject.arguments[2].to_s)
|
117
|
+
return if options["shallow"] == true
|
116
118
|
@counter += 1
|
117
119
|
recursively_check(node.body)
|
118
120
|
@counter -= 1
|
119
121
|
elsif :block == node.node_type
|
120
|
-
node.children.each
|
121
|
-
recursively_check(child_node)
|
122
|
-
end
|
122
|
+
node.children.each { |child_node| recursively_check(child_node) }
|
123
123
|
elsif :call == node.node_type && [:resources, :resource].include?(node.message)
|
124
124
|
add_error "needless deep nesting (nested_count > #{@nested_count})", node.file, node.line if @counter >= @nested_count
|
125
125
|
end
|
@@ -6,21 +6,6 @@ module RailsBestPractices
|
|
6
6
|
module Reviews
|
7
7
|
# A Review class that takes charge of reviewing one rails best practice.
|
8
8
|
class Review < Core::Check
|
9
|
-
attr_reader :errors
|
10
|
-
|
11
|
-
def initialize
|
12
|
-
super
|
13
|
-
@errors = []
|
14
|
-
end
|
15
|
-
|
16
|
-
# add error if source code violates rails best practice.
|
17
|
-
# error is the string message for violation of the rails best practice
|
18
|
-
# file is the filename of source code
|
19
|
-
# line is the line number of the source code which is reviewing
|
20
|
-
def add_error(error, file = @node.file, line = @node.line)
|
21
|
-
@errors << RailsBestPractices::Core::Error.new("#{file}", "#{line}", error, url)
|
22
|
-
end
|
23
|
-
|
24
9
|
# remember use count for the local or instance variable in the call or attrasgn node.
|
25
10
|
#
|
26
11
|
# find the local variable or instance variable in the call or attrasgn node,
|
data/lib/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rails_best_practices/core/runner'
|
3
|
+
require 'rails_best_practices/reviews/review'
|
4
|
+
|
5
|
+
module RailsBestPractices
|
6
|
+
module Reviews
|
7
|
+
# Make sure to use multipart/alternative as content_type of email.
|
8
|
+
#
|
9
|
+
# See the best practice details here http://rails-bestpractices.com/posts/41-use-multipart-alternative-as-content_type-of-email.
|
10
|
+
#
|
11
|
+
# Implementation:
|
12
|
+
#
|
13
|
+
# Review process:
|
14
|
+
# check class node to remember the class name,
|
15
|
+
# and check the method definition nodes to see if the corresponding mailer views exist or not.
|
16
|
+
class UseMultipartAlternativeAsContentTypeOfEmailReview < Review
|
17
|
+
def url
|
18
|
+
"http://rails-bestpractices.com/posts/41-use-multipart-alternative-as-content_type-of-email"
|
19
|
+
end
|
20
|
+
|
21
|
+
def interesting_nodes
|
22
|
+
[:class, :defn]
|
23
|
+
end
|
24
|
+
|
25
|
+
def interesting_files
|
26
|
+
MAILER_FILES
|
27
|
+
end
|
28
|
+
|
29
|
+
# check class node to remember the ActionMailer class name.
|
30
|
+
def start_class(node)
|
31
|
+
@klazz_name = node.class_name
|
32
|
+
end
|
33
|
+
|
34
|
+
# check defn node and find if the corresponding views exist or not?
|
35
|
+
def start_defn(node)
|
36
|
+
name = node.method_name
|
37
|
+
return unless deliver_method?(name)
|
38
|
+
if !rails2_mailer_views_exist?(name) && !rails3_mailer_views_exist?(name)
|
39
|
+
add_error("use multipart/alternative as content_type of email")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
# check if rails2's syntax mailer views exist or not according to the method name.
|
45
|
+
# @param [String] name method name in action_mailer
|
46
|
+
def rails2_mailer_views_exist?(name)
|
47
|
+
(exist?("#{name}.text.plain.erb") && exist?("#{name}.text.html.erb")) ||
|
48
|
+
(exist?("#{name}.text.plain.haml") && exist?("#{name}.text.html.haml")) ||
|
49
|
+
(exist?("#{name}.text.plain.rhtml") && exist?("#{name}.text.html.rhtml"))
|
50
|
+
end
|
51
|
+
|
52
|
+
# check if rails3's syntax mailer views exist or not according to the method name.
|
53
|
+
#
|
54
|
+
# @param [String] name method name in action_mailer
|
55
|
+
def rails3_mailer_views_exist?(name)
|
56
|
+
(exist?("#{name}.text.erb") && exist?("#{name}.html.erb")) ||
|
57
|
+
(exist?("#{name}.text.haml") && exist?("#{name}.html.haml"))
|
58
|
+
end
|
59
|
+
|
60
|
+
# check if the filename existed in the mailer directory.
|
61
|
+
def exist?(filename)
|
62
|
+
File.exist? File.join(mailer_directory, filename)
|
63
|
+
end
|
64
|
+
|
65
|
+
# check if the method is a deliver_method.
|
66
|
+
#
|
67
|
+
# @param [String] name the name of the method
|
68
|
+
def deliver_method?(name)
|
69
|
+
Dir.entries(mailer_directory).find { |filename| filename.index name.to_s }
|
70
|
+
rescue
|
71
|
+
false
|
72
|
+
end
|
73
|
+
|
74
|
+
# the view directory of mailer.
|
75
|
+
def mailer_directory
|
76
|
+
File.join(Core::Runner.base_path, "app/views/#{@klazz_name.to_s.underscore}")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -11,10 +11,6 @@ module RailsBestPractices
|
|
11
11
|
#
|
12
12
|
# Implementation:
|
13
13
|
#
|
14
|
-
# Prepare process:
|
15
|
-
# check all class nodes to see if they are the subclass of ActionMailer::Base,
|
16
|
-
# if so, remember the class name.
|
17
|
-
#
|
18
14
|
# Review process:
|
19
15
|
# check all call nodes to see if they are callback definitions, like after_create, before_destroy,
|
20
16
|
# if so, remember the callback methods.
|
@@ -9,11 +9,6 @@ module RailsBestPractices
|
|
9
9
|
#
|
10
10
|
# Implementation:
|
11
11
|
#
|
12
|
-
# Prepare process:
|
13
|
-
# only check all model files to save model names and association names,
|
14
|
-
# model names are saved as only when subject of call method is equal to one of the model name, then the call method may use query attribute instead,
|
15
|
-
# association names are saved as association attributes should not be detected as query attributes.
|
16
|
-
#
|
17
12
|
# Review process:
|
18
13
|
# check all method calls within conditional statements, like @user.login.nil?
|
19
14
|
# if their subjects are one of the model names
|
data/rails_best_practices.yml
CHANGED
@@ -1,22 +1,24 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
1
|
+
MoveFinderToNamedScopeCheck: { }
|
2
|
+
UseModelAssociationCheck: { }
|
3
|
+
UseScopeAccessCheck: { }
|
4
|
+
AddModelVirtualAttributeCheck: { }
|
5
|
+
ReplaceComplexCreationWithFactoryMethodCheck: { attribute_assignment_count: 2 }
|
6
|
+
MoveModelLogicIntoModelCheck: { use_count: 4 }
|
7
|
+
OveruseRouteCustomizationsCheck: { customize_count: 3 }
|
8
|
+
NeedlessDeepNestingCheck: { nested_count: 2 }
|
9
|
+
NotUseDefaultRouteCheck: { }
|
10
|
+
KeepFindersOnTheirOwnModelCheck: { }
|
11
|
+
LawOfDemeterCheck: { }
|
12
|
+
UseObserverCheck: { }
|
13
|
+
IsolateSeedDataCheck: { }
|
14
|
+
AlwaysAddDbIndexCheck: { }
|
15
|
+
UseBeforeFilterCheck: { }
|
16
|
+
MoveCodeIntoControllerCheck: { }
|
17
|
+
MoveCodeIntoModelCheck: { use_count: 2 }
|
18
|
+
MoveCodeIntoHelperCheck: { array_count: 3 }
|
19
|
+
ReplaceInstanceVariableWithLocalVariableCheck: { }
|
20
|
+
DryBundlerInCapistranoCheck: { }
|
21
|
+
UseSayWithTimeInMigrationsCheck: { }
|
22
|
+
UseQueryAttributeCheck: { }
|
23
|
+
RemoveTrailingWhitespaceCheck: { }
|
24
|
+
UseMultipartAlternativeAsContentTypeOfEmailCheck: {}
|
@@ -1,6 +1,10 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require 'spec_helper'
|
3
3
|
|
4
|
+
class TestLexical1
|
5
|
+
end
|
6
|
+
class TestLexical2
|
7
|
+
end
|
4
8
|
class TestPrepare1
|
5
9
|
def interesting_nodes
|
6
10
|
[:call]
|
@@ -42,11 +46,27 @@ class TestReview2
|
|
42
46
|
end
|
43
47
|
|
44
48
|
describe RailsBestPractices::Core::CheckingVisitor do
|
49
|
+
let(:lexical1) { TestLexical1.new }
|
50
|
+
let(:lexical2) { TestLexical2.new }
|
45
51
|
let(:prepare1) { TestPrepare1.new }
|
46
52
|
let(:prepare2) { TestPrepare2.new }
|
47
53
|
let(:review1) { TestReview1.new }
|
48
54
|
let(:review2) { TestReview2.new }
|
49
|
-
let(:visitor) {
|
55
|
+
let(:visitor) {
|
56
|
+
RailsBestPractices::Core::CheckingVisitor.new(
|
57
|
+
:lexicals => [lexical1, lexical2],
|
58
|
+
:prepares => [prepare1, prepare2],
|
59
|
+
:reviews => [review1, review2]
|
60
|
+
)
|
61
|
+
}
|
62
|
+
|
63
|
+
it "should lexical check" do
|
64
|
+
filename = "app/models/user.rb"
|
65
|
+
content = "class User; end"
|
66
|
+
lexical1.should_receive(:check).with(filename, content)
|
67
|
+
lexical2.should_receive(:check).with(filename, content)
|
68
|
+
visitor.lexical(filename, content)
|
69
|
+
end
|
50
70
|
|
51
71
|
it "should prepare model associations" do
|
52
72
|
node = stub(:node_type => :call, :children => [], :file => "app/models/user.rb")
|
@@ -254,6 +254,16 @@ describe Sexp do
|
|
254
254
|
node.to_s.should == '{"first_name" => "Richard", "last_name" => "Huang"}'
|
255
255
|
end
|
256
256
|
|
257
|
+
it "should get to_s for hash with true/false" do
|
258
|
+
node = parser.parse("{:shallow => true, :index => false}")
|
259
|
+
node.to_s.should == '{"shallow" => true, "index" => false}'
|
260
|
+
end
|
261
|
+
|
262
|
+
it "should get to_s for array and hash mixed" do
|
263
|
+
node = parser.parse("{:only => [:show, :index]}")
|
264
|
+
node.to_s.should == '{"only" => ["show", "index"]}'
|
265
|
+
end
|
266
|
+
|
257
267
|
it "should get to_s for colon2" do
|
258
268
|
node = parser.parse("RailsBestPractices::Core")
|
259
269
|
node.to_s.should == "RailsBestPractices::Core"
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RailsBestPractices::Lexicals::RemoveTrailingWhitespaceCheck do
|
4
|
+
let(:runner) { RailsBestPractices::Core::Runner.new(:lexicals => RailsBestPractices::Lexicals::RemoveTrailingWhitespaceCheck.new) }
|
5
|
+
|
6
|
+
it "should remove trailing whitespace" do
|
7
|
+
content =<<-EOF
|
8
|
+
class User < ActiveRecord::Base
|
9
|
+
has_many :projects
|
10
|
+
end
|
11
|
+
EOF
|
12
|
+
content.gsub!("\n", " \n")
|
13
|
+
runner.lexical('app/models/user.rb', content)
|
14
|
+
runner.should have(1).errors
|
15
|
+
runner.errors[0].to_s.should == "app/models/user.rb:1 - remove trailing whitespace"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should remove whitespace with third line" do
|
19
|
+
content =<<-EOF
|
20
|
+
class User < ActiveRecord::Base
|
21
|
+
has_many :projects
|
22
|
+
end
|
23
|
+
EOF
|
24
|
+
content.gsub!("d\n", "d \n")
|
25
|
+
runner.lexical('app/models/user.rb', content)
|
26
|
+
runner.should have(1).errors
|
27
|
+
runner.errors[0].to_s.should == "app/models/user.rb:3 - remove trailing whitespace"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should not remove trailing whitespace" do
|
31
|
+
content =<<-EOF
|
32
|
+
class User < ActiveRecord::Base
|
33
|
+
has_many :projects
|
34
|
+
end
|
35
|
+
EOF
|
36
|
+
runner.lexical('app/models/user.rb', content)
|
37
|
+
runner.should have(0).errors
|
38
|
+
end
|
39
|
+
end
|
@@ -17,6 +17,18 @@ describe RailsBestPractices::Reviews::NeedlessDeepNestingReview do
|
|
17
17
|
runner.errors[0].to_s.should == "config/routes.rb:3 - needless deep nesting (nested_count > 2)"
|
18
18
|
end
|
19
19
|
|
20
|
+
it "should not needless deep nesting for shallow" do
|
21
|
+
content = <<-EOF
|
22
|
+
map.resources :posts, :shallow => true do |post|
|
23
|
+
post.resources :comments do |comment|
|
24
|
+
comment.resources :favorites
|
25
|
+
end
|
26
|
+
end
|
27
|
+
EOF
|
28
|
+
runner.review('config/routes.rb', content)
|
29
|
+
runner.should have(0).errors
|
30
|
+
end
|
31
|
+
|
20
32
|
it "should needless deep nesting with resource" do
|
21
33
|
content = <<-EOF
|
22
34
|
map.resources :posts do |post|
|
@@ -84,6 +96,18 @@ describe RailsBestPractices::Reviews::NeedlessDeepNestingReview do
|
|
84
96
|
runner.errors[0].to_s.should == "config/routes.rb:4 - needless deep nesting (nested_count > 2)"
|
85
97
|
end
|
86
98
|
|
99
|
+
it "should not needless deep nesting for shallow" do
|
100
|
+
content = <<-EOF
|
101
|
+
resources :posts, :shallow => true do
|
102
|
+
resources :comments do
|
103
|
+
resources :favorites
|
104
|
+
end
|
105
|
+
end
|
106
|
+
EOF
|
107
|
+
runner.review('config/routes.rb', content)
|
108
|
+
runner.should have(0).errors
|
109
|
+
end
|
110
|
+
|
87
111
|
it "should needless deep nesting with resource" do
|
88
112
|
content = <<-EOF
|
89
113
|
resources :posts do
|
@@ -0,0 +1,196 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RailsBestPractices::Reviews::UseMultipartAlternativeAsContentTypeOfEmailReview do
|
4
|
+
let(:runner) { RailsBestPractices::Core::Runner.new(:reviews => RailsBestPractices::Reviews::UseMultipartAlternativeAsContentTypeOfEmailReview.new) }
|
5
|
+
|
6
|
+
context "rails2" do
|
7
|
+
before :each do
|
8
|
+
RailsBestPractices::Core::Runner.stub!(:base_path).and_return(".")
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should use mulipart/alternative as content_type of email" do
|
12
|
+
content =<<-EOF
|
13
|
+
class ProjectMailer < ActionMailer::Base
|
14
|
+
def send_email(email)
|
15
|
+
subject email.subject
|
16
|
+
from email.from
|
17
|
+
recipients email.recipients
|
18
|
+
sent_on Time.now
|
19
|
+
body :email => email
|
20
|
+
end
|
21
|
+
end
|
22
|
+
EOF
|
23
|
+
Dir.stub!(:entries).with("./app/views/project_mailer").and_return(["send_email.html.erb"])
|
24
|
+
runner.review('app/mailers/project_mailer.rb', content)
|
25
|
+
runner.should have(1).errors
|
26
|
+
runner.errors[0].to_s.should == "app/mailers/project_mailer.rb:2 - use multipart/alternative as content_type of email"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should not use mulipart/alternative as content_type of email by erb" do
|
30
|
+
content =<<-EOF
|
31
|
+
class ProjectMailer < ActionMailer::Base
|
32
|
+
def send_email(email)
|
33
|
+
subject email.subject
|
34
|
+
from email.from
|
35
|
+
recipients email.recipients
|
36
|
+
sent_on Time.now
|
37
|
+
body :email => email
|
38
|
+
end
|
39
|
+
end
|
40
|
+
EOF
|
41
|
+
Dir.stub!(:entries).with("./app/views/project_mailer").and_return(["send_email.html.erb"])
|
42
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.plain.erb").and_return(true)
|
43
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.html.erb").and_return(true)
|
44
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.erb").and_return(false)
|
45
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.html.erb").and_return(false)
|
46
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.plain.haml").and_return(false)
|
47
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.html.haml").and_return(false)
|
48
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.haml").and_return(false)
|
49
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.html.haml").and_return(false)
|
50
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.plain.rhtml").and_return(false)
|
51
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.html.rhtml").and_return(false)
|
52
|
+
runner.review('app/mailers/project_mailer.rb', content)
|
53
|
+
runner.should have(0).errors
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should not use mulipart/alternative as content_type of email by haml" do
|
57
|
+
content =<<-EOF
|
58
|
+
class ProjectMailer < ActionMailer::Base
|
59
|
+
def send_email(email)
|
60
|
+
subject email.subject
|
61
|
+
from email.from
|
62
|
+
recipients email.recipients
|
63
|
+
sent_on Time.now
|
64
|
+
body :email => email
|
65
|
+
end
|
66
|
+
end
|
67
|
+
EOF
|
68
|
+
Dir.stub!(:entries).with("./app/views/project_mailer").and_return(["send_email.html.erb"])
|
69
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.plain.erb").and_return(false)
|
70
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.html.erb").and_return(false)
|
71
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.erb").and_return(false)
|
72
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.html.erb").and_return(false)
|
73
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.plain.haml").and_return(true)
|
74
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.html.haml").and_return(true)
|
75
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.haml").and_return(false)
|
76
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.html.haml").and_return(false)
|
77
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.plain.rhtml").and_return(false)
|
78
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.html.rhtml").and_return(false)
|
79
|
+
runner.review('app/mailers/project_mailer.rb', content)
|
80
|
+
runner.should have(0).errors
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should not use mulipart/alternative as content_type of email by rhtml" do
|
84
|
+
content =<<-EOF
|
85
|
+
class ProjectMailer < ActionMailer::Base
|
86
|
+
def send_email(email)
|
87
|
+
subject email.subject
|
88
|
+
from email.from
|
89
|
+
recipients email.recipients
|
90
|
+
sent_on Time.now
|
91
|
+
body :email => email
|
92
|
+
end
|
93
|
+
end
|
94
|
+
EOF
|
95
|
+
Dir.stub!(:entries).with("./app/views/project_mailer").and_return(["send_email.html.erb"])
|
96
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.plain.erb").and_return(false)
|
97
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.html.erb").and_return(false)
|
98
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.erb").and_return(false)
|
99
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.html.erb").and_return(false)
|
100
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.plain.haml").and_return(false)
|
101
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.html.haml").and_return(false)
|
102
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.haml").and_return(false)
|
103
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.html.haml").and_return(false)
|
104
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.plain.rhtml").and_return(true)
|
105
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.html.rhtml").and_return(true)
|
106
|
+
runner.review('app/mailers/project_mailer.rb', content)
|
107
|
+
runner.should have(0).errors
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should not use mulipart/alternative as content_type of email for non deliver method" do
|
111
|
+
content =<<-EOF
|
112
|
+
class ProjectMailer < ActionMailer::Base
|
113
|
+
def no_deliver
|
114
|
+
end
|
115
|
+
end
|
116
|
+
EOF
|
117
|
+
Dir.stub!(:entries).with("./app/views/project_mailer").and_return(["send_email.html.erb"])
|
118
|
+
runner.review('app/mailers/project_mailer.rb', content)
|
119
|
+
runner.should have(0).errors
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context "rails3" do
|
124
|
+
it "should use mulipart/alternative as content_type of email" do
|
125
|
+
content =<<-EOF
|
126
|
+
class ProjectMailer < ActionMailer::Base
|
127
|
+
def send_email(email)
|
128
|
+
subject email.subject
|
129
|
+
from email.from
|
130
|
+
recipients email.recipients
|
131
|
+
sent_on Time.now
|
132
|
+
body :email => email
|
133
|
+
end
|
134
|
+
end
|
135
|
+
EOF
|
136
|
+
Dir.stub!(:entries).with("./app/views/project_mailer").and_return(["send_email.html.erb"])
|
137
|
+
runner.review('app/mailers/project_mailer.rb', content)
|
138
|
+
runner.should have(1).errors
|
139
|
+
runner.errors[0].to_s.should == "app/mailers/project_mailer.rb:2 - use multipart/alternative as content_type of email"
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should not use mulipart/alternative as content_type of email by erb" do
|
143
|
+
content =<<-EOF
|
144
|
+
class ProjectMailer < ActionMailer::Base
|
145
|
+
def send_email(email)
|
146
|
+
subject email.subject
|
147
|
+
from email.from
|
148
|
+
recipients email.recipients
|
149
|
+
sent_on Time.now
|
150
|
+
body :email => email
|
151
|
+
end
|
152
|
+
end
|
153
|
+
EOF
|
154
|
+
Dir.stub!(:entries).with("./app/views/project_mailer").and_return(["send_email.html.erb"])
|
155
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.plain.erb").and_return(false)
|
156
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.html.erb").and_return(false)
|
157
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.erb").and_return(true)
|
158
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.html.erb").and_return(true)
|
159
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.plain.haml").and_return(false)
|
160
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.html.haml").and_return(false)
|
161
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.haml").and_return(false)
|
162
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.html.haml").and_return(false)
|
163
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.plain.rhtml").and_return(false)
|
164
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.html.rhtml").and_return(false)
|
165
|
+
runner.review('app/mailers/project_mailer.rb', content)
|
166
|
+
runner.should have(0).errors
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should not use mulipart/alternative as content_type of email by haml" do
|
170
|
+
content =<<-EOF
|
171
|
+
class ProjectMailer < ActionMailer::Base
|
172
|
+
def send_email(email)
|
173
|
+
subject email.subject
|
174
|
+
from email.from
|
175
|
+
recipients email.recipients
|
176
|
+
sent_on Time.now
|
177
|
+
body :email => email
|
178
|
+
end
|
179
|
+
end
|
180
|
+
EOF
|
181
|
+
Dir.stub!(:entries).with("./app/views/project_mailer").and_return(["send_email.html.erb"])
|
182
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.plain.erb").and_return(false)
|
183
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.html.erb").and_return(false)
|
184
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.erb").and_return(false)
|
185
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.html.erb").and_return(false)
|
186
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.plain.haml").and_return(false)
|
187
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.html.haml").and_return(false)
|
188
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.haml").and_return(true)
|
189
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.html.haml").and_return(true)
|
190
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.plain.rhtml").and_return(false)
|
191
|
+
File.stub!(:exist?).with("./app/views/project_mailer/send_email.text.html.rhtml").and_return(false)
|
192
|
+
runner.review('app/mailers/project_mailer.rb', content)
|
193
|
+
runner.should have(0).errors
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_best_practices
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 3
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
- 6
|
9
8
|
- 7
|
10
|
-
|
9
|
+
- 0
|
10
|
+
version: 0.7.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Richard Huang
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-02-
|
18
|
+
date: 2011-02-15 00:00:00 +08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -196,6 +196,7 @@ extensions: []
|
|
196
196
|
extra_rdoc_files: []
|
197
197
|
|
198
198
|
files:
|
199
|
+
- .gemtest
|
199
200
|
- .gitignore
|
200
201
|
- .rspec.example
|
201
202
|
- .rvmrc.example
|
@@ -219,6 +220,8 @@ files:
|
|
219
220
|
- lib/rails_best_practices/core/visitable_sexp.rb
|
220
221
|
- lib/rails_best_practices/core_ext/enumerable.rb
|
221
222
|
- lib/rails_best_practices/core_ext/nil_class.rb
|
223
|
+
- lib/rails_best_practices/lexicals.rb
|
224
|
+
- lib/rails_best_practices/lexicals/remove_trailing_whitespace_check.rb
|
222
225
|
- lib/rails_best_practices/prepares.rb
|
223
226
|
- lib/rails_best_practices/prepares/mailer_prepare.rb
|
224
227
|
- lib/rails_best_practices/prepares/model_prepare.rb
|
@@ -242,6 +245,7 @@ files:
|
|
242
245
|
- lib/rails_best_practices/reviews/review.rb
|
243
246
|
- lib/rails_best_practices/reviews/use_before_filter_review.rb
|
244
247
|
- lib/rails_best_practices/reviews/use_model_association_review.rb
|
248
|
+
- lib/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review.rb
|
245
249
|
- lib/rails_best_practices/reviews/use_observer_review.rb
|
246
250
|
- lib/rails_best_practices/reviews/use_query_attribute_review.rb
|
247
251
|
- lib/rails_best_practices/reviews/use_say_with_time_in_migrations_review.rb
|
@@ -256,6 +260,7 @@ files:
|
|
256
260
|
- spec/rails_best_practices/core/visitable_sexp_spec.rb
|
257
261
|
- spec/rails_best_practices/core_ext/enumerable_spec.rb
|
258
262
|
- spec/rails_best_practices/core_ext/nil_class_spec.rb
|
263
|
+
- spec/rails_best_practices/lexicals/remove_trailing_whitespace_check_spec.rb
|
259
264
|
- spec/rails_best_practices/prepares/mailer_prepare_spec.rb
|
260
265
|
- spec/rails_best_practices/prepares/model_prepare_spec.rb
|
261
266
|
- spec/rails_best_practices/reviews/add_model_virtual_attribute_review_spec.rb
|
@@ -277,6 +282,7 @@ files:
|
|
277
282
|
- spec/rails_best_practices/reviews/review_spec.rb
|
278
283
|
- spec/rails_best_practices/reviews/use_before_filter_review_spec.rb
|
279
284
|
- spec/rails_best_practices/reviews/use_model_association_review_spec.rb
|
285
|
+
- spec/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review_spec.rb
|
280
286
|
- spec/rails_best_practices/reviews/use_observer_review_spec.rb
|
281
287
|
- spec/rails_best_practices/reviews/use_query_attribute_review_spec.rb
|
282
288
|
- spec/rails_best_practices/reviews/use_say_with_time_in_migrations_review_spec.rb
|
@@ -340,6 +346,7 @@ test_files:
|
|
340
346
|
- spec/rails_best_practices/core/visitable_sexp_spec.rb
|
341
347
|
- spec/rails_best_practices/core_ext/enumerable_spec.rb
|
342
348
|
- spec/rails_best_practices/core_ext/nil_class_spec.rb
|
349
|
+
- spec/rails_best_practices/lexicals/remove_trailing_whitespace_check_spec.rb
|
343
350
|
- spec/rails_best_practices/prepares/mailer_prepare_spec.rb
|
344
351
|
- spec/rails_best_practices/prepares/model_prepare_spec.rb
|
345
352
|
- spec/rails_best_practices/reviews/add_model_virtual_attribute_review_spec.rb
|
@@ -361,6 +368,7 @@ test_files:
|
|
361
368
|
- spec/rails_best_practices/reviews/review_spec.rb
|
362
369
|
- spec/rails_best_practices/reviews/use_before_filter_review_spec.rb
|
363
370
|
- spec/rails_best_practices/reviews/use_model_association_review_spec.rb
|
371
|
+
- spec/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review_spec.rb
|
364
372
|
- spec/rails_best_practices/reviews/use_observer_review_spec.rb
|
365
373
|
- spec/rails_best_practices/reviews/use_query_attribute_review_spec.rb
|
366
374
|
- spec/rails_best_practices/reviews/use_say_with_time_in_migrations_review_spec.rb
|