rails_best_practices 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,11 +5,11 @@ module RailsBestPractices
5
5
  module Checks
6
6
  # Check db/schema.rb file to make sure every reference key has a database index.
7
7
  #
8
- # Implementation: read all add_index method calls to get the indexed columns in table, then read integer method call in create_table block to get the reference columns in tables, compare with indexed columns, if not in the indexed columns, then it violates always_add_db_index_check.
8
+ # Implementation: read all add_index method calls to get the indexed columns in table, then read integer method call in create_table block to get the reference columns in tables (or polymorphic index like [commentable_id, commentable_type]), compare with indexed columns, if not in the indexed columns, then it violates always_add_db_index_check.
9
9
  class AlwaysAddDbIndexCheck < Check
10
10
 
11
11
  def interesting_nodes
12
- [:block, :call]
12
+ [:block, :call, :iter]
13
13
  end
14
14
 
15
15
  def interesting_files
@@ -18,7 +18,9 @@ module RailsBestPractices
18
18
 
19
19
  def initialize
20
20
  super
21
- @index_columns = []
21
+ @index_columns = {}
22
+ @foreign_keys = {}
23
+ @table_nodes = {}
22
24
  end
23
25
 
24
26
  def evaluate_start(node)
@@ -28,27 +30,48 @@ module RailsBestPractices
28
30
  case node.message
29
31
  when :create_table
30
32
  @table_name = node.arguments[1].to_s
31
- when :integer
33
+ @table_nodes[@table_name] = node
34
+ when :integer, :string
32
35
  column_name = node.arguments[1].to_s
33
- if column_name =~ /_id$/ and !indexed?(@table_name, column_name)
34
- add_error "always add db index (#@table_name => #{column_name})", node.file, node.line
36
+ add_foreign_key_column(@table_name, column_name)
37
+ end
38
+ end
39
+ end
40
+
41
+ def evaluate_end(node)
42
+ if :iter == node.node_type && :call == node.subject.node_type && s(:colon2, s(:const, :ActiveRecord), :Schema) == node.subject.subject
43
+ @foreign_keys.each do |table, foreign_key|
44
+ table_node = @table_nodes[table]
45
+ foreign_key.each do |column|
46
+ unless @index_columns[table] && @index_columns[table].include?(column)
47
+ add_error "always add db index (#{table} => [#{Array(column).join(', ')}])", table_node.file, table_node.line
48
+ end
35
49
  end
36
50
  end
37
51
  end
38
52
  end
39
-
53
+
40
54
  private
41
55
  def find_index_columns(node)
42
56
  node.grep_nodes({:node_type => :call, :message => :add_index}).each do |index_node|
43
57
  table_name = index_node.arguments[1].to_s
44
- reference_column = eval(index_node.arguments[2].to_s)
45
- @index_columns << [table_name, reference_column]
58
+ index_column = eval(index_node.arguments[2].to_s)
59
+ add_index_column(table_name, index_column)
46
60
  end
47
61
  end
48
-
49
- def indexed?(table_name, column_name)
50
- !!@index_columns.find do |reference|
51
- reference[0] == table_name and reference[1].class == String ? reference[1] == column_name : reference[1].include?(column_name)
62
+
63
+ def add_index_column(table_name, index_column)
64
+ @index_columns[table_name] ||= []
65
+ @index_columns[table_name] << (index_column.size == 1 ? index_column[0] : index_column)
66
+ end
67
+
68
+ def add_foreign_key_column(table_name, foreign_key_column)
69
+ if foreign_key_column =~ /_id$/
70
+ @foreign_keys[table_name] ||= []
71
+ @foreign_keys[table_name] << foreign_key_column
72
+ elsif foreign_key_column =~ /(.*?)_type$/
73
+ @foreign_keys[table_name].delete("#{$1}_id")
74
+ @foreign_keys[table_name] << ["#{$1}_id", foreign_key_column]
52
75
  end
53
76
  end
54
77
  end
@@ -6,7 +6,7 @@ require 'colored'
6
6
  options = {}
7
7
  OptionParser.new do |opts|
8
8
  opts.banner = "Usage: rails_best_practices [options]"
9
-
9
+
10
10
  opts.on("-d", "--debug", "Debug mode") do
11
11
  options['debug'] = true
12
12
  end
@@ -16,7 +16,7 @@ OptionParser.new do |opts|
16
16
  options[pattern] = true
17
17
  end
18
18
  end
19
-
19
+
20
20
  opts.on_tail('-v', '--version', 'Show this version') do
21
21
  require 'rails_best_practices/version'
22
22
  puts RailsBestPractices::VERSION
@@ -27,7 +27,7 @@ OptionParser.new do |opts|
27
27
  puts opts
28
28
  exit
29
29
  end
30
-
30
+
31
31
  opts.on("-x", "--exclude PATTERNS", "Don't analyze files matching a pattern", "(comma-separated regexp list)") do |list|
32
32
  begin
33
33
  options[:exclude] = list.split(/,/).map{|x| Regexp.new x}
@@ -43,6 +43,12 @@ runner = RailsBestPractices::Core::Runner.new
43
43
  runner.set_debug if options['debug']
44
44
 
45
45
  files = RailsBestPractices::analyze_files(ARGV, options)
46
+
47
+ if runner.checks.find { |check| check.is_a? RailsBestPractices::Checks::AlwaysAddDbIndexCheck } &&
48
+ !files.find { |file| file.index "db\/schema.rb" }
49
+ puts "AlwaysAddDbIndexCheck is disabled as there is no db/schema.rb file in your rails project.".blue
50
+ end
51
+
46
52
  bar = ProgressBar.new('Analyzing', files.size)
47
53
  files.each do |file|
48
54
  runner.check_file(file)
@@ -50,9 +56,11 @@ files.each do |file|
50
56
  end
51
57
  bar.finish
52
58
 
53
- runner.errors.each {|error| puts error.to_s.red}
59
+ runner.errors.each { |error| puts error.to_s.red }
54
60
  puts "\nPlease go to http://rails-bestpractices.com to see more useful Rails Best Practices.".green
55
- if runner.errors.size > 0
61
+ if runner.errors.empty?
62
+ puts "\nNo error found. Cool!".green
63
+ else
56
64
  puts "\nFound #{runner.errors.size} errors.".red
57
65
  end
58
66
 
@@ -8,9 +8,11 @@ require 'active_support/inflector'
8
8
  module RailsBestPractices
9
9
  module Core
10
10
  class Runner
11
+ attr_reader :checks
12
+
11
13
  DEFAULT_CONFIG = File.join(File.dirname(__FILE__), "..", "..", "..", "rails_best_practices.yml")
12
14
  CUSTOM_CONFIG = File.join('config', 'rails_best_practices.yml')
13
-
15
+
14
16
  def initialize(*checks)
15
17
  @config = File.exists?(CUSTOM_CONFIG) ? CUSTOM_CONFIG : DEFAULT_CONFIG
16
18
  @checks = checks unless checks.empty?
@@ -18,7 +20,7 @@ module RailsBestPractices
18
20
  @checker ||= CheckingVisitor.new(@checks)
19
21
  @debug = false
20
22
  end
21
-
23
+
22
24
  def set_debug
23
25
  @debug = true
24
26
  end
@@ -67,11 +69,11 @@ module RailsBestPractices
67
69
  nil
68
70
  end
69
71
  end
70
-
72
+
71
73
  def load_checks
72
74
  check_objects = []
73
75
  checks = YAML.load_file @config
74
- checks.each do |check|
76
+ checks.each do |check|
75
77
  klass = eval("RailsBestPractices::Checks::#{check[0]}")
76
78
  check_objects << (check[1].empty? ? klass.new : klass.new(check[1]))
77
79
  end
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
  module RailsBestPractices
3
- VERSION = "0.5.0"
3
+ VERSION = "0.5.1"
4
4
  end
5
5
 
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: 11
4
+ hash: 9
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 5
9
- - 0
10
- version: 0.5.0
9
+ - 1
10
+ version: 0.5.1
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: 2010-11-06 00:00:00 +08:00
18
+ date: 2010-12-01 00:00:00 +08:00
19
19
  default_executable: rails_best_practices
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -75,12 +75,26 @@ dependencies:
75
75
  segments:
76
76
  - 0
77
77
  version: "0"
78
- name: activesupport
78
+ name: i18n
79
79
  prerelease: false
80
80
  type: :runtime
81
81
  version_requirements: *id004
82
82
  - !ruby/object:Gem::Dependency
83
83
  requirement: &id005 !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ hash: 3
89
+ segments:
90
+ - 0
91
+ version: "0"
92
+ name: activesupport
93
+ prerelease: false
94
+ type: :runtime
95
+ version_requirements: *id005
96
+ - !ruby/object:Gem::Dependency
97
+ requirement: &id006 !ruby/object:Gem::Requirement
84
98
  none: false
85
99
  requirements:
86
100
  - - ~>
@@ -94,9 +108,9 @@ dependencies:
94
108
  name: rspec
95
109
  prerelease: false
96
110
  type: :development
97
- version_requirements: *id005
111
+ version_requirements: *id006
98
112
  - !ruby/object:Gem::Dependency
99
- requirement: &id006 !ruby/object:Gem::Requirement
113
+ requirement: &id007 !ruby/object:Gem::Requirement
100
114
  none: false
101
115
  requirements:
102
116
  - - ~>
@@ -110,9 +124,9 @@ dependencies:
110
124
  name: haml
111
125
  prerelease: false
112
126
  type: :development
113
- version_requirements: *id006
127
+ version_requirements: *id007
114
128
  - !ruby/object:Gem::Dependency
115
- requirement: &id007 !ruby/object:Gem::Requirement
129
+ requirement: &id008 !ruby/object:Gem::Requirement
116
130
  none: false
117
131
  requirements:
118
132
  - - ~>
@@ -125,7 +139,7 @@ dependencies:
125
139
  name: watchr
126
140
  prerelease: false
127
141
  type: :development
128
- version_requirements: *id007
142
+ version_requirements: *id008
129
143
  description: a code metric tool for rails codes, written in Ruby.
130
144
  email:
131
145
  - flyerhzm@gmail.com
@@ -137,39 +151,39 @@ extra_rdoc_files:
137
151
  - MIT_LICENSE
138
152
  - README.textile
139
153
  files:
140
- - lib/rails_best_practices.rb
141
- - lib/rails_best_practices/version.rb
142
- - lib/rails_best_practices/checks/move_finder_to_named_scope_check.rb
143
- - lib/rails_best_practices/checks/use_model_association_check.rb
144
- - lib/rails_best_practices/checks/keep_finders_on_their_own_model_check.rb
145
154
  - lib/rails_best_practices/checks/add_model_virtual_attribute_check.rb
146
- - lib/rails_best_practices/checks/use_say_with_time_in_migrations_check.rb
155
+ - lib/rails_best_practices/checks/always_add_db_index_check.rb
156
+ - lib/rails_best_practices/checks/check.rb
157
+ - lib/rails_best_practices/checks/dry_bundler_in_capistrano_check.rb
158
+ - lib/rails_best_practices/checks/isolate_seed_data_check.rb
159
+ - lib/rails_best_practices/checks/keep_finders_on_their_own_model_check.rb
147
160
  - lib/rails_best_practices/checks/law_of_demeter_check.rb
148
- - lib/rails_best_practices/checks/use_scope_access_check.rb
149
161
  - lib/rails_best_practices/checks/move_code_into_controller_check.rb
162
+ - lib/rails_best_practices/checks/move_code_into_helper_check.rb
163
+ - lib/rails_best_practices/checks/move_code_into_model_check.rb
164
+ - lib/rails_best_practices/checks/move_finder_to_named_scope_check.rb
150
165
  - lib/rails_best_practices/checks/move_model_logic_into_model_check.rb
166
+ - lib/rails_best_practices/checks/needless_deep_nesting_check.rb
151
167
  - lib/rails_best_practices/checks/not_use_default_route_check.rb
168
+ - lib/rails_best_practices/checks/overuse_route_customizations_check.rb
152
169
  - lib/rails_best_practices/checks/replace_complex_creation_with_factory_method_check.rb
153
- - lib/rails_best_practices/checks/dry_bundler_in_capistrano_check.rb
154
- - lib/rails_best_practices/checks/isolate_seed_data_check.rb
155
- - lib/rails_best_practices/checks/always_add_db_index_check.rb
156
170
  - lib/rails_best_practices/checks/replace_instance_variable_with_local_variable_check.rb
157
- - lib/rails_best_practices/checks/needless_deep_nesting_check.rb
158
- - lib/rails_best_practices/checks/move_code_into_helper_check.rb
171
+ - lib/rails_best_practices/checks/use_before_filter_check.rb
172
+ - lib/rails_best_practices/checks/use_model_association_check.rb
159
173
  - lib/rails_best_practices/checks/use_observer_check.rb
160
- - lib/rails_best_practices/checks/check.rb
161
- - lib/rails_best_practices/checks/overuse_route_customizations_check.rb
162
174
  - lib/rails_best_practices/checks/use_query_attribute_check.rb
163
- - lib/rails_best_practices/checks/use_before_filter_check.rb
164
- - lib/rails_best_practices/checks/move_code_into_model_check.rb
165
- - lib/rails_best_practices/core.rb
175
+ - lib/rails_best_practices/checks/use_say_with_time_in_migrations_check.rb
176
+ - lib/rails_best_practices/checks/use_scope_access_check.rb
166
177
  - lib/rails_best_practices/checks.rb
178
+ - lib/rails_best_practices/command.rb
167
179
  - lib/rails_best_practices/core/checking_visitor.rb
168
180
  - lib/rails_best_practices/core/core_ext.rb
169
181
  - lib/rails_best_practices/core/error.rb
170
- - lib/rails_best_practices/core/visitable_sexp.rb
171
182
  - lib/rails_best_practices/core/runner.rb
172
- - lib/rails_best_practices/command.rb
183
+ - lib/rails_best_practices/core/visitable_sexp.rb
184
+ - lib/rails_best_practices/core.rb
185
+ - lib/rails_best_practices/version.rb
186
+ - lib/rails_best_practices.rb
173
187
  - rails_best_practices.yml
174
188
  - MIT_LICENSE
175
189
  - README.textile