rails_best_practices 0.2.0 → 0.2.6
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/README.textile +11 -6
- data/VERSION +1 -1
- data/lib/rails_best_practices/checks/always_add_db_index_check.rb +83 -0
- data/lib/rails_best_practices/checks/check.rb +1 -1
- data/lib/rails_best_practices/checks/isolate_seed_data_check.rb +46 -0
- data/lib/rails_best_practices/checks/keep_finders_on_their_own_model_check.rb +29 -0
- data/lib/rails_best_practices/checks/law_of_demeter_check.rb +47 -0
- data/lib/rails_best_practices/checks/use_observer_check.rb +49 -0
- data/lib/rails_best_practices/checks/use_scope_access_check.rb +2 -2
- data/lib/rails_best_practices/checks.rb +6 -1
- data/lib/rails_best_practices/command.rb +24 -4
- data/lib/rails_best_practices/core/core_ext.rb +12 -1
- data/lib/rails_best_practices/core/runner.rb +5 -1
- data/lib/rails_best_practices/core/visitable_sexp.rb +14 -5
- data/rails_best_practices.gemspec +17 -2
- data/rails_best_practices.yml +5 -0
- data/spec/rails_best_practices/checks/add_model_virtual_attribute_check_spec.rb +22 -4
- data/spec/rails_best_practices/checks/always_add_db_index_check_spec.rb +153 -0
- data/spec/rails_best_practices/checks/isolate_seed_data_check_spec.rb +75 -0
- data/spec/rails_best_practices/checks/keep_finders_on_their_own_model_check_spec.rb +71 -0
- data/spec/rails_best_practices/checks/law_of_demeter_check_spec.rb +37 -0
- data/spec/rails_best_practices/checks/move_finder_to_named_scope_check_spec.rb +6 -6
- data/spec/rails_best_practices/checks/move_model_logic_into_model_check_spec.rb +4 -4
- data/spec/rails_best_practices/checks/replace_complex_creation_with_factory_method_check_spec.rb +5 -5
- data/spec/rails_best_practices/checks/use_model_association_check_spec.rb +6 -6
- data/spec/rails_best_practices/checks/use_observer_check_spec.rb +67 -0
- data/spec/rails_best_practices/checks/use_scope_access_check_spec.rb +17 -17
- metadata +17 -2
data/README.textile
CHANGED
|
@@ -41,6 +41,11 @@ MoveModelLogicIntoModelCheck: { called_count: 4 }
|
|
|
41
41
|
OveruseRouteCustomizationsCheck: { customize_count: 3 }
|
|
42
42
|
NeedlessDeepNestingCheck: { nested_count: 2 }
|
|
43
43
|
NotUseDefaultRouteCheck: { }
|
|
44
|
+
KeepFindersOnTheirOwnModelCheck: { }
|
|
45
|
+
LawOfDemeterCheck: { }
|
|
46
|
+
UseObserverCheck: { }
|
|
47
|
+
IsolateSeedDataCheck: { }
|
|
48
|
+
AlwaysAddDbIndexCheck: { }
|
|
44
49
|
</code></pre>
|
|
45
50
|
|
|
46
51
|
*************************************************
|
|
@@ -65,17 +70,17 @@ h2. Progress
|
|
|
65
70
|
## [-Not use default route-]
|
|
66
71
|
|
|
67
72
|
* Lesson 3. Model
|
|
68
|
-
## Keep Finders on Their Own Model
|
|
69
|
-
## Love named_scope
|
|
70
|
-
## the Law of Demeter
|
|
73
|
+
## [-Keep Finders on Their Own Model-]
|
|
74
|
+
## [-Love named_scope-] # same as Move finder to named_scope
|
|
75
|
+
## [-the Law of Demeter-]
|
|
71
76
|
## DRY: metaprogramming
|
|
72
77
|
## Extract into Module
|
|
73
78
|
## Extract to composed class
|
|
74
|
-
## Use Observer
|
|
79
|
+
## [-Use Observer-]
|
|
75
80
|
|
|
76
81
|
* Lesson 4. Migration
|
|
77
|
-
## Isolating Seed Data
|
|
78
|
-
## Always add DB index
|
|
82
|
+
## [-Isolating Seed Data-]
|
|
83
|
+
## [-Always add DB index-]
|
|
79
84
|
|
|
80
85
|
* Lesson 5. Controller
|
|
81
86
|
## Use before_filter
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.2.
|
|
1
|
+
0.2.6
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
require 'rails_best_practices/checks/check'
|
|
2
|
+
|
|
3
|
+
module RailsBestPractices
|
|
4
|
+
module Checks
|
|
5
|
+
class AlwaysAddDbIndexCheck < Check
|
|
6
|
+
|
|
7
|
+
def interesting_nodes
|
|
8
|
+
[:defs]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def interesting_files
|
|
12
|
+
/db\/migrate\/.*rb/
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def initialize
|
|
16
|
+
super
|
|
17
|
+
@files = []
|
|
18
|
+
@references = {}
|
|
19
|
+
@indexes = {}
|
|
20
|
+
@parse = false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def evaluate_start(node)
|
|
24
|
+
if @files.include? node.file
|
|
25
|
+
@parse = true if :up == node.message
|
|
26
|
+
else
|
|
27
|
+
@files << node.file
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
if @parse and :up == node.message
|
|
31
|
+
@references.each do |table_name, column_names|
|
|
32
|
+
differences = column_names - (@indexes[table_name] || [])
|
|
33
|
+
hint = differences.collect {|column_name| "#{table_name} => #{column_name}"}.join(', ')
|
|
34
|
+
add_error "always add db index (#{hint})" unless differences.empty?
|
|
35
|
+
end
|
|
36
|
+
else
|
|
37
|
+
remember_references(node.body)
|
|
38
|
+
remember_indexes(node.body)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def remember_references(node)
|
|
45
|
+
create_table_node = node.grep_nodes({:node_type => :call, :message => :create_table}).first
|
|
46
|
+
if create_table_node
|
|
47
|
+
table_name = eval(create_table_node.arguments[1].to_ruby).to_s
|
|
48
|
+
node.grep_nodes({:node_type => :call, :message => :integer}).each do |integer_node|
|
|
49
|
+
column_name = eval(integer_node.arguments[1].to_ruby).to_s
|
|
50
|
+
if column_name =~ /_id$/
|
|
51
|
+
@references[table_name] ||= []
|
|
52
|
+
@references[table_name] << column_name
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
node.grep_nodes({:node_type => :call, :message => :references}).each do |references_node|
|
|
56
|
+
column_name = eval(references_node.arguments[1].to_ruby).to_s + "_id"
|
|
57
|
+
@references[table_name] ||= []
|
|
58
|
+
@references[table_name] << column_name
|
|
59
|
+
end
|
|
60
|
+
node.grep_nodes({:node_type => :call, :message => :column}).each do |column_node|
|
|
61
|
+
if 'integer' == eval(column_node.arguments[2].to_ruby).to_s
|
|
62
|
+
column_name = eval(column_node.arguments[1].to_ruby).to_s
|
|
63
|
+
if column_name =~ /_id$/
|
|
64
|
+
@references[table_name] ||= []
|
|
65
|
+
@references[table_name] << column_name
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def remember_indexes(node)
|
|
73
|
+
add_index_nodes = node.grep_nodes({:node_type => :call, :message => :add_index})
|
|
74
|
+
add_index_nodes.each do |add_index_node|
|
|
75
|
+
table_name = eval(add_index_node.arguments[1].to_ruby).to_s
|
|
76
|
+
column_name = eval(add_index_node.arguments[2].to_ruby).to_s
|
|
77
|
+
@indexes[table_name] ||= []
|
|
78
|
+
@indexes[table_name] << column_name
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'rails_best_practices/checks/check'
|
|
2
|
+
|
|
3
|
+
module RailsBestPractices
|
|
4
|
+
module Checks
|
|
5
|
+
# Check a migration file to make sure not to insert data in migration, move them to seed file.
|
|
6
|
+
#
|
|
7
|
+
# Implementation: check if there are :create, :create!, and :new with :save or :save! exist, the migration file needs isolate seed data.
|
|
8
|
+
class IsolateSeedDataCheck < Check
|
|
9
|
+
|
|
10
|
+
def interesting_nodes
|
|
11
|
+
[:call, :lasgn]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def interesting_files
|
|
15
|
+
/db\/migrate\/.*rb/
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def initialize
|
|
19
|
+
super
|
|
20
|
+
@new_variables = []
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def evaluate_start(node)
|
|
24
|
+
if [:create, :create!].include? node.message
|
|
25
|
+
add_error("isolate seed data")
|
|
26
|
+
elsif :lasgn == node.node_type
|
|
27
|
+
remember_new_variable(node)
|
|
28
|
+
elsif [:save, :save!].include? node.message
|
|
29
|
+
add_error("isolate seed data") if new_record?(node)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def remember_new_variable(node)
|
|
36
|
+
unless node.grep_nodes({:node_type => :call, :message => :new}).empty?
|
|
37
|
+
@new_variables << node.subject.to_s
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def new_record?(node)
|
|
42
|
+
@new_variables.include? node.subject.to_ruby
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'rails_best_practices/checks/check'
|
|
2
|
+
|
|
3
|
+
module RailsBestPractices
|
|
4
|
+
module Checks
|
|
5
|
+
# Check a model to make sure finders are on their own model.
|
|
6
|
+
#
|
|
7
|
+
# Implementation: check if :find is called by other model.
|
|
8
|
+
class KeepFindersOnTheirOwnModelCheck < Check
|
|
9
|
+
|
|
10
|
+
def interesting_nodes
|
|
11
|
+
[:call]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def interesting_files
|
|
15
|
+
/models\/.*rb/
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def evaluate_start(node)
|
|
19
|
+
add_error "keep finders on their own model" if others_finder?(node)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def others_finder?(node)
|
|
25
|
+
node.message == :find and node.subject.node_type == :call
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require 'rails_best_practices/checks/check'
|
|
2
|
+
|
|
3
|
+
module RailsBestPractices
|
|
4
|
+
module Checks
|
|
5
|
+
# Check to make sure not avoid the law of demeter.
|
|
6
|
+
#
|
|
7
|
+
# Implementation:
|
|
8
|
+
# 1. check all models to record belongs_to associations
|
|
9
|
+
# 2. check if calling belongs_to association's method or attribute
|
|
10
|
+
class LawOfDemeterCheck < Check
|
|
11
|
+
|
|
12
|
+
def interesting_nodes
|
|
13
|
+
[:call, :class]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def initialize
|
|
17
|
+
super
|
|
18
|
+
@associations = {}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def evaluate_start(node)
|
|
22
|
+
if node.node_type == :class
|
|
23
|
+
remember_belongs_to(node)
|
|
24
|
+
elsif [:lvar, :ivar].include?(node.subject.node_type) and node.subject != s(:lvar, :_erbout)
|
|
25
|
+
add_error "law of demeter" if need_delegate?(node)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def remember_belongs_to(node)
|
|
32
|
+
node.body.grep_nodes(:message => :belongs_to).collect do |body_node|
|
|
33
|
+
class_name = node.subject.to_s.underscore
|
|
34
|
+
@associations[class_name] ||= []
|
|
35
|
+
@associations[class_name] << eval(body_node.arguments[1].to_ruby).to_s
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def need_delegate?(node)
|
|
40
|
+
@associations.each do |class_name, associations|
|
|
41
|
+
return true if node.subject.to_ruby =~ /#{class_name}$/ and associations.include? node.message.to_s
|
|
42
|
+
end
|
|
43
|
+
false
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require 'rails_best_practices/checks/check'
|
|
2
|
+
|
|
3
|
+
module RailsBestPractices
|
|
4
|
+
module Checks
|
|
5
|
+
# Check a model file to make sure mail deliver method is in observer not callback.
|
|
6
|
+
#
|
|
7
|
+
# Implementation:
|
|
8
|
+
# Record :after_create callback
|
|
9
|
+
# Check method define, if it is a callback and call deliver_xxx message in method body, then it should use observer.
|
|
10
|
+
class UseObserverCheck < Check
|
|
11
|
+
|
|
12
|
+
def interesting_nodes
|
|
13
|
+
[:defn, :call]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def interesting_files
|
|
17
|
+
/models\/.*rb/
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def initialize
|
|
21
|
+
super
|
|
22
|
+
@callbacks = []
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def evaluate_start(node)
|
|
26
|
+
if :after_create == node.message
|
|
27
|
+
remember_callbacks(node)
|
|
28
|
+
elsif :defn == node.node_type and @callbacks.include?(node.message_name.to_s)
|
|
29
|
+
add_error "use observer" if use_observer?(node)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def remember_callbacks(node)
|
|
36
|
+
node.arguments[1..-1].each do |argument|
|
|
37
|
+
@callbacks << eval(argument.to_ruby).to_s
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def use_observer?(node)
|
|
42
|
+
node.recursive_children do |child|
|
|
43
|
+
return true if :call == child.node_type and :const == child.subject.node_type and child.message.to_s =~ /^deliver_/
|
|
44
|
+
end
|
|
45
|
+
false
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -26,7 +26,7 @@ module RailsBestPractices
|
|
|
26
26
|
|
|
27
27
|
condition_node.message == :== and
|
|
28
28
|
(current_user?(condition_node.arguments.call) or current_user?(condition_node.subject)) and
|
|
29
|
-
(node.false_node.
|
|
29
|
+
(node.false_node.body.any? {|n| n.message == :redirect_to} or node.true_node.method_body.any? {|n| n.message == :redirect_to})
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
def current_user?(call_node)
|
|
@@ -35,4 +35,4 @@ module RailsBestPractices
|
|
|
35
35
|
|
|
36
36
|
end
|
|
37
37
|
end
|
|
38
|
-
end
|
|
38
|
+
end
|
|
@@ -9,4 +9,9 @@ require 'rails_best_practices/checks/many_to_many_collection_check'
|
|
|
9
9
|
require 'rails_best_practices/checks/nested_model_forms_check'
|
|
10
10
|
require 'rails_best_practices/checks/overuse_route_customizations_check'
|
|
11
11
|
require 'rails_best_practices/checks/needless_deep_nesting_check'
|
|
12
|
-
require 'rails_best_practices/checks/not_use_default_route_check'
|
|
12
|
+
require 'rails_best_practices/checks/not_use_default_route_check'
|
|
13
|
+
require 'rails_best_practices/checks/keep_finders_on_their_own_model_check'
|
|
14
|
+
require 'rails_best_practices/checks/law_of_demeter_check'
|
|
15
|
+
require 'rails_best_practices/checks/use_observer_check'
|
|
16
|
+
require 'rails_best_practices/checks/isolate_seed_data_check'
|
|
17
|
+
require 'rails_best_practices/checks/always_add_db_index_check'
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
require 'optparse'
|
|
2
2
|
|
|
3
3
|
def expand_dirs_to_files *dirs
|
|
4
|
-
extensions = ['rb']
|
|
4
|
+
# extensions = ['rb', 'erb', 'builder']
|
|
5
|
+
extensions = ['rb', 'builder']
|
|
5
6
|
|
|
6
7
|
dirs.flatten.map { |p|
|
|
7
8
|
if File.directory? p
|
|
@@ -9,7 +10,26 @@ def expand_dirs_to_files *dirs
|
|
|
9
10
|
else
|
|
10
11
|
p
|
|
11
12
|
end
|
|
12
|
-
}.flatten.sort
|
|
13
|
+
}.flatten.sort { |a, b|
|
|
14
|
+
# for law_of_demeter_check
|
|
15
|
+
if a =~ /models\/.*rb/
|
|
16
|
+
-1
|
|
17
|
+
elsif b =~ /models\/.*rb/
|
|
18
|
+
1
|
|
19
|
+
else
|
|
20
|
+
a <=> b
|
|
21
|
+
end
|
|
22
|
+
}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# for always_add_db_index_check
|
|
26
|
+
def add_duplicate_migration_files files
|
|
27
|
+
migration_files = files.select { |file| file.index("db/migrate") }
|
|
28
|
+
(files << migration_files).flatten
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def ignore_vendor_directories files
|
|
32
|
+
files.reject { |file| file.index("vendor/") }
|
|
13
33
|
end
|
|
14
34
|
|
|
15
35
|
options = {}
|
|
@@ -25,8 +45,8 @@ OptionParser.new do |opts|
|
|
|
25
45
|
end
|
|
26
46
|
|
|
27
47
|
runner = RailsBestPractices::Core::Runner.new
|
|
28
|
-
expand_dirs_to_files(ARGV).each
|
|
48
|
+
ignore_vendor_directories(add_duplicate_migration_files(expand_dirs_to_files(ARGV))).each { |file| runner.check_file(file) }
|
|
29
49
|
runner.errors.each {|error| puts error}
|
|
30
50
|
puts "\nFound #{runner.errors.size} errors."
|
|
31
51
|
|
|
32
|
-
exit runner.errors.size
|
|
52
|
+
exit runner.errors.size
|
|
@@ -4,8 +4,19 @@ module Enumerable
|
|
|
4
4
|
end
|
|
5
5
|
end
|
|
6
6
|
|
|
7
|
+
class String
|
|
8
|
+
# copy from rails
|
|
9
|
+
def underscore
|
|
10
|
+
self.gsub(/::/, '/').
|
|
11
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
|
12
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
|
13
|
+
tr("-", "_").
|
|
14
|
+
downcase
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
7
18
|
class NilClass
|
|
8
19
|
def method_missing(method_sym, *arguments, &block)
|
|
9
20
|
return nil
|
|
10
21
|
end
|
|
11
|
-
end
|
|
22
|
+
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require 'rubygems'
|
|
2
2
|
require 'ruby_parser'
|
|
3
|
+
require 'erb'
|
|
3
4
|
require 'yaml'
|
|
4
5
|
|
|
5
6
|
module RailsBestPractices
|
|
@@ -21,6 +22,9 @@ module RailsBestPractices
|
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
def check(filename, content)
|
|
25
|
+
if filename =~ /.*erb/
|
|
26
|
+
content = ERB.new(content).src
|
|
27
|
+
end
|
|
24
28
|
node = parse(filename, content)
|
|
25
29
|
node.accept(@checker) if node
|
|
26
30
|
end
|
|
@@ -45,7 +49,7 @@ module RailsBestPractices
|
|
|
45
49
|
begin
|
|
46
50
|
@parser.parse(content, filename)
|
|
47
51
|
rescue Exception => e
|
|
48
|
-
puts "#{filename} looks like it's not a valid Ruby file. Skipping..."
|
|
52
|
+
puts "#{filename} looks like it's not a valid Ruby file. Skipping..."
|
|
49
53
|
nil
|
|
50
54
|
end
|
|
51
55
|
end
|
|
@@ -47,13 +47,13 @@ class Sexp
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
def subject
|
|
50
|
-
if [:attrasgn, :call, :iasgn, :lasgn].include? node_type
|
|
50
|
+
if [:attrasgn, :call, :iasgn, :lasgn, :class].include? node_type
|
|
51
51
|
self[1]
|
|
52
52
|
end
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def message
|
|
56
|
-
if [:attrasgn, :call].include? node_type
|
|
56
|
+
if [:attrasgn, :call, :defs].include? node_type
|
|
57
57
|
self[2]
|
|
58
58
|
end
|
|
59
59
|
end
|
|
@@ -81,15 +81,24 @@ class Sexp
|
|
|
81
81
|
self[3]
|
|
82
82
|
end
|
|
83
83
|
end
|
|
84
|
+
|
|
85
|
+
def message_name
|
|
86
|
+
if :defn == node_type
|
|
87
|
+
self[1]
|
|
88
|
+
end
|
|
89
|
+
end
|
|
84
90
|
|
|
85
|
-
def
|
|
91
|
+
def body
|
|
86
92
|
if :block == node_type
|
|
87
93
|
self[1..-1]
|
|
88
|
-
|
|
94
|
+
elsif :class == node_type
|
|
95
|
+
self[3]
|
|
96
|
+
elsif :defs == node_type
|
|
97
|
+
self[4]
|
|
89
98
|
end
|
|
90
99
|
end
|
|
91
100
|
|
|
92
101
|
def to_ruby
|
|
93
|
-
Ruby2Ruby.new.process(self)
|
|
102
|
+
Ruby2Ruby.new.process(self) unless self.empty?
|
|
94
103
|
end
|
|
95
104
|
end
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
Gem::Specification.new do |s|
|
|
7
7
|
s.name = %q{rails_best_practices}
|
|
8
|
-
s.version = "0.2.
|
|
8
|
+
s.version = "0.2.6"
|
|
9
9
|
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
11
11
|
s.authors = ["Richard Huang"]
|
|
12
|
-
s.date = %q{2009-11-
|
|
12
|
+
s.date = %q{2009-11-08}
|
|
13
13
|
s.default_executable = %q{rails_best_practices}
|
|
14
14
|
s.description = %q{check rails files according to ihower's presentation 'rails best practices'}
|
|
15
15
|
s.email = %q{flyerhzm@gmail.com}
|
|
@@ -28,7 +28,11 @@ Gem::Specification.new do |s|
|
|
|
28
28
|
"lib/rails_best_practices.rb",
|
|
29
29
|
"lib/rails_best_practices/checks.rb",
|
|
30
30
|
"lib/rails_best_practices/checks/add_model_virtual_attribute_check.rb",
|
|
31
|
+
"lib/rails_best_practices/checks/always_add_db_index_check.rb",
|
|
31
32
|
"lib/rails_best_practices/checks/check.rb",
|
|
33
|
+
"lib/rails_best_practices/checks/isolate_seed_data_check.rb",
|
|
34
|
+
"lib/rails_best_practices/checks/keep_finders_on_their_own_model_check.rb",
|
|
35
|
+
"lib/rails_best_practices/checks/law_of_demeter_check.rb",
|
|
32
36
|
"lib/rails_best_practices/checks/many_to_many_collection_check.rb",
|
|
33
37
|
"lib/rails_best_practices/checks/move_finder_to_named_scope_check.rb",
|
|
34
38
|
"lib/rails_best_practices/checks/move_model_logic_into_model_check.rb",
|
|
@@ -39,6 +43,7 @@ Gem::Specification.new do |s|
|
|
|
39
43
|
"lib/rails_best_practices/checks/replace_complex_creation_with_factory_method_check.rb",
|
|
40
44
|
"lib/rails_best_practices/checks/use_model_association_check.rb",
|
|
41
45
|
"lib/rails_best_practices/checks/use_model_callback_check.rb",
|
|
46
|
+
"lib/rails_best_practices/checks/use_observer_check.rb",
|
|
42
47
|
"lib/rails_best_practices/checks/use_scope_access_check.rb",
|
|
43
48
|
"lib/rails_best_practices/command.rb",
|
|
44
49
|
"lib/rails_best_practices/core.rb",
|
|
@@ -50,6 +55,10 @@ Gem::Specification.new do |s|
|
|
|
50
55
|
"rails_best_practices.gemspec",
|
|
51
56
|
"rails_best_practices.yml",
|
|
52
57
|
"spec/rails_best_practices/checks/add_model_virtual_attribute_check_spec.rb",
|
|
58
|
+
"spec/rails_best_practices/checks/always_add_db_index_check_spec.rb",
|
|
59
|
+
"spec/rails_best_practices/checks/isolate_seed_data_check_spec.rb",
|
|
60
|
+
"spec/rails_best_practices/checks/keep_finders_on_their_own_model_check_spec.rb",
|
|
61
|
+
"spec/rails_best_practices/checks/law_of_demeter_check_spec.rb",
|
|
53
62
|
"spec/rails_best_practices/checks/many_to_many_collection_check_spec.rb",
|
|
54
63
|
"spec/rails_best_practices/checks/move_finder_to_named_scope_check_spec.rb",
|
|
55
64
|
"spec/rails_best_practices/checks/move_model_logic_into_model_check_spec.rb",
|
|
@@ -60,6 +69,7 @@ Gem::Specification.new do |s|
|
|
|
60
69
|
"spec/rails_best_practices/checks/replace_complex_creation_with_factory_method_check_spec.rb",
|
|
61
70
|
"spec/rails_best_practices/checks/use_model_association_check_spec.rb",
|
|
62
71
|
"spec/rails_best_practices/checks/use_model_callback_check_spec.rb",
|
|
72
|
+
"spec/rails_best_practices/checks/use_observer_check_spec.rb",
|
|
63
73
|
"spec/rails_best_practices/checks/use_scope_access_check_spec.rb",
|
|
64
74
|
"spec/spec.opts",
|
|
65
75
|
"spec/spec_helper.rb"
|
|
@@ -73,15 +83,20 @@ Gem::Specification.new do |s|
|
|
|
73
83
|
"spec/rails_best_practices/checks/use_scope_access_check_spec.rb",
|
|
74
84
|
"spec/rails_best_practices/checks/not_use_default_route_check_spec.rb",
|
|
75
85
|
"spec/rails_best_practices/checks/add_model_virtual_attribute_check_spec.rb",
|
|
86
|
+
"spec/rails_best_practices/checks/keep_finders_on_their_own_model_check_spec.rb",
|
|
76
87
|
"spec/rails_best_practices/checks/use_model_callback_check_spec.rb",
|
|
88
|
+
"spec/rails_best_practices/checks/isolate_seed_data_check_spec.rb",
|
|
77
89
|
"spec/rails_best_practices/checks/many_to_many_collection_check_spec.rb",
|
|
78
90
|
"spec/rails_best_practices/checks/use_model_association_check_spec.rb",
|
|
79
91
|
"spec/rails_best_practices/checks/move_model_logic_into_model_check_spec.rb",
|
|
92
|
+
"spec/rails_best_practices/checks/law_of_demeter_check_spec.rb",
|
|
80
93
|
"spec/rails_best_practices/checks/replace_complex_creation_with_factory_method_check_spec.rb",
|
|
81
94
|
"spec/rails_best_practices/checks/nested_model_forms_check_spec.rb",
|
|
95
|
+
"spec/rails_best_practices/checks/use_observer_check_spec.rb",
|
|
82
96
|
"spec/rails_best_practices/checks/move_finder_to_named_scope_check_spec.rb",
|
|
83
97
|
"spec/rails_best_practices/checks/needless_deep_nesting_check_spec.rb",
|
|
84
98
|
"spec/rails_best_practices/checks/overuse_route_customizations_check_spec.rb",
|
|
99
|
+
"spec/rails_best_practices/checks/always_add_db_index_check_spec.rb",
|
|
85
100
|
"spec/spec_helper.rb"
|
|
86
101
|
]
|
|
87
102
|
|
data/rails_best_practices.yml
CHANGED
|
@@ -10,3 +10,8 @@ MoveModelLogicIntoModelCheck: { called_count: 4 }
|
|
|
10
10
|
OveruseRouteCustomizationsCheck: { customize_count: 3 }
|
|
11
11
|
NeedlessDeepNestingCheck: { nested_count: 2 }
|
|
12
12
|
NotUseDefaultRouteCheck: { }
|
|
13
|
+
KeepFindersOnTheirOwnModelCheck: { }
|
|
14
|
+
LawOfDemeterCheck: { }
|
|
15
|
+
UseObserverCheck: { }
|
|
16
|
+
IsolateSeedDataCheck: { }
|
|
17
|
+
AlwaysAddDbIndexCheck: { }
|
|
@@ -17,10 +17,28 @@ describe RailsBestPractices::Checks::AddModelVirtualAttributeCheck do
|
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
EOF
|
|
20
|
-
@runner.check('app/
|
|
20
|
+
@runner.check('app/controllers/users_controller.rb', content)
|
|
21
21
|
errors = @runner.errors
|
|
22
22
|
errors.should_not be_empty
|
|
23
|
-
errors[0].to_s.should == "app/
|
|
23
|
+
errors[0].to_s.should == "app/controllers/users_controller.rb:3 - add model virtual attribute (for @user)"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "should add model virtual attribute with local assignment" do
|
|
27
|
+
content = <<-EOF
|
|
28
|
+
class UsersController < ApplicationController
|
|
29
|
+
|
|
30
|
+
def create
|
|
31
|
+
user = User.new(params[:user])
|
|
32
|
+
user.first_name = params[:full_name].split(' ', 2).first
|
|
33
|
+
user.last_name = params[:full_name].split(' ', 2).last
|
|
34
|
+
user.save
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
EOF
|
|
38
|
+
@runner.check('app/controllers/users_controller.rb', content)
|
|
39
|
+
errors = @runner.errors
|
|
40
|
+
errors.should_not be_empty
|
|
41
|
+
errors[0].to_s.should == "app/controllers/users_controller.rb:3 - add model virtual attribute (for user)"
|
|
24
42
|
end
|
|
25
43
|
|
|
26
44
|
it "should not add model virtual attribute with differen param" do
|
|
@@ -35,7 +53,7 @@ describe RailsBestPractices::Checks::AddModelVirtualAttributeCheck do
|
|
|
35
53
|
end
|
|
36
54
|
end
|
|
37
55
|
EOF
|
|
38
|
-
@runner.check('app/
|
|
56
|
+
@runner.check('app/controllers/users_controller.rb', content)
|
|
39
57
|
errors = @runner.errors
|
|
40
58
|
errors.should be_empty
|
|
41
59
|
end
|
|
@@ -53,7 +71,7 @@ describe RailsBestPractices::Checks::AddModelVirtualAttributeCheck do
|
|
|
53
71
|
end
|
|
54
72
|
end
|
|
55
73
|
EOF
|
|
56
|
-
@runner.check('app/
|
|
74
|
+
@runner.check('app/controllers/users_controller.rb', content)
|
|
57
75
|
errors = @runner.errors
|
|
58
76
|
errors.should be_empty
|
|
59
77
|
end
|