rails_best_practices 0.5.0 → 0.5.1

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.
@@ -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