rails_best_practices 0.6.7 → 0.7.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.
- 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
|