rails_best_practices 0.6.1 → 0.6.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.gitignore +12 -0
  2. data/.rspec.example +2 -0
  3. data/.rvmrc.example +2 -0
  4. data/.watchr +65 -0
  5. data/.watchr.example +65 -0
  6. data/Gemfile +3 -0
  7. data/README.md +6 -0
  8. data/Rakefile +45 -0
  9. data/assets/result.html.haml +53 -0
  10. data/lib/rails_best_practices.rb +30 -11
  11. data/lib/rails_best_practices/checks/check.rb +10 -10
  12. data/lib/rails_best_practices/command.rb +9 -0
  13. data/lib/rails_best_practices/core/visitable_sexp.rb +9 -10
  14. data/lib/rails_best_practices/version.rb +1 -1
  15. data/rails_best_practices.gemspec +32 -0
  16. data/rubies_test.sh +10 -0
  17. data/spec/rails_best_practices/checks/add_model_virtual_attribute_check_spec.rb +113 -0
  18. data/spec/rails_best_practices/checks/always_add_db_index_check_spec.rb +172 -0
  19. data/spec/rails_best_practices/checks/check_spec.rb +57 -0
  20. data/spec/rails_best_practices/checks/dry_bundler_in_capistrano_check_spec.rb +39 -0
  21. data/spec/rails_best_practices/checks/isolate_seed_data_check_spec.rb +105 -0
  22. data/spec/rails_best_practices/checks/keep_finders_on_their_own_model_check_spec.rb +103 -0
  23. data/spec/rails_best_practices/checks/law_of_demeter_check_spec.rb +101 -0
  24. data/spec/rails_best_practices/checks/move_code_into_controller_check_spec.rb +33 -0
  25. data/spec/rails_best_practices/checks/move_code_into_helper_check_spec.rb +28 -0
  26. data/spec/rails_best_practices/checks/move_code_into_model_check_spec.rb +55 -0
  27. data/spec/rails_best_practices/checks/move_finder_to_named_scope_check_spec.rb +82 -0
  28. data/spec/rails_best_practices/checks/move_model_logic_into_model_check_spec.rb +49 -0
  29. data/spec/rails_best_practices/checks/needless_deep_nesting_check_spec.rb +140 -0
  30. data/spec/rails_best_practices/checks/not_use_default_route_check_spec.rb +63 -0
  31. data/spec/rails_best_practices/checks/overuse_route_customizations_check_spec.rb +159 -0
  32. data/spec/rails_best_practices/checks/replace_complex_creation_with_factory_method_check_spec.rb +76 -0
  33. data/spec/rails_best_practices/checks/replace_instance_variable_with_local_variable_check_spec.rb +36 -0
  34. data/spec/rails_best_practices/checks/use_before_filter_check_spec.rb +85 -0
  35. data/spec/rails_best_practices/checks/use_model_association_check_spec.rb +71 -0
  36. data/spec/rails_best_practices/checks/use_observer_check_spec.rb +155 -0
  37. data/spec/rails_best_practices/checks/use_query_attribute_check_spec.rb +192 -0
  38. data/spec/rails_best_practices/checks/use_say_with_time_in_migrations_check_spec.rb +113 -0
  39. data/spec/rails_best_practices/checks/use_scope_access_check_spec.rb +193 -0
  40. data/spec/rails_best_practices/core/error_spec.rb +7 -0
  41. data/spec/rails_best_practices/core/visitable_sexp_spec.rb +259 -0
  42. data/spec/rails_best_practices/core_ext/enumerable_spec.rb +7 -0
  43. data/spec/rails_best_practices/core_ext/nil_class_spec.rb +11 -0
  44. data/spec/rails_best_practices_spec.rb +44 -0
  45. data/spec/spec_helper.rb +4 -0
  46. metadata +114 -32
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ .DS_STORE
2
+ .*.swp
3
+ .rvmrc
4
+ .rspec
5
+ .watchr
6
+ pkg/**
7
+ *.gem
8
+ .bundle
9
+ Gemfile.lock
10
+ rdoc/**
11
+ doc/**
12
+ .yardoc/**
data/.rspec.example ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --format nested
data/.rvmrc.example ADDED
@@ -0,0 +1,2 @@
1
+ rvm_gemset_create_on_use_flag=1
2
+ rvm gemset use rails_best_practices
data/.watchr ADDED
@@ -0,0 +1,65 @@
1
+ # vim:set filetype=ruby:
2
+ def growl
3
+ title = "Watchr Test Results"
4
+ image = $?.success? ? "~/.watchr/images/passed.png" : "~/.watchr/images/failed.png"
5
+ message = $?.success? ? "success" : "failed"
6
+ growlnotify = `which growlnotify`.chomp
7
+ options = "-w -n Watchr --image '#{File.expand_path(image)}' -m '#{message}' '#{title}'"
8
+ system %(#{growlnotify} #{options} &)
9
+ end
10
+
11
+ def run(cmd)
12
+ puts cmd
13
+ system(cmd)
14
+ end
15
+
16
+ def spec(file)
17
+ if File.exists?(file)
18
+ run("rspec #{file}")
19
+ growl
20
+ else
21
+ puts("Spec: #{file} does not exist.")
22
+ end
23
+ end
24
+
25
+
26
+ def run_all_specs
27
+ run "rake spec"
28
+ growl
29
+ end
30
+
31
+ def run_suite
32
+ system "clear"
33
+ run_all_specs
34
+ end
35
+
36
+ watch("spec/.*/*_spec\.rb") do |match|
37
+ puts(match[0])
38
+ spec(match[0])
39
+ end
40
+
41
+ watch("lib/(.*/.*)\.rb") do |match|
42
+ puts(match[1])
43
+ spec("spec/#{match[1]}_spec.rb")
44
+ end
45
+
46
+
47
+ # Ctrl-\
48
+ Signal.trap 'QUIT' do
49
+ puts " --- Running all tests ---\n\n"
50
+ run_suite
51
+ end
52
+
53
+ # Ctrl-C
54
+ Signal.trap 'INT' do
55
+ if @interrupted then
56
+ abort("\n")
57
+ else
58
+ puts "Interrupt a second time to quit"
59
+ @interrupted = true
60
+ Kernel.sleep 1.5
61
+ # raise Interrupt, nil # let the run loop catch it
62
+ run_suite
63
+ @interrupted = false
64
+ end
65
+ end
data/.watchr.example ADDED
@@ -0,0 +1,65 @@
1
+ # vim:set filetype=ruby:
2
+ def growl
3
+ title = "Watchr Test Results"
4
+ image = $?.success? ? "~/.watchr/images/passed.png" : "~/.watchr/images/failed.png"
5
+ message = $?.success? ? "success" : "failed"
6
+ growlnotify = `which growlnotify`.chomp
7
+ options = "-w -n Watchr --image '#{File.expand_path(image)}' -m '#{message}' '#{title}'"
8
+ system %(#{growlnotify} #{options} &)
9
+ end
10
+
11
+ def run(cmd)
12
+ puts cmd
13
+ system(cmd)
14
+ end
15
+
16
+ def spec(file)
17
+ if File.exists?(file)
18
+ run("rspec #{file}")
19
+ growl
20
+ else
21
+ puts("Spec: #{file} does not exist.")
22
+ end
23
+ end
24
+
25
+
26
+ def run_all_specs
27
+ run "rake spec"
28
+ growl
29
+ end
30
+
31
+ def run_suite
32
+ system "clear"
33
+ run_all_specs
34
+ end
35
+
36
+ watch("spec/.*/*_spec\.rb") do |match|
37
+ puts(match[0])
38
+ spec(match[0])
39
+ end
40
+
41
+ watch("lib/(.*/.*)\.rb") do |match|
42
+ puts(match[1])
43
+ spec("spec/#{match[1]}_spec.rb")
44
+ end
45
+
46
+
47
+ # Ctrl-\
48
+ Signal.trap 'QUIT' do
49
+ puts " --- Running all tests ---\n\n"
50
+ run_suite
51
+ end
52
+
53
+ # Ctrl-C
54
+ Signal.trap 'INT' do
55
+ if @interrupted then
56
+ abort("\n")
57
+ else
58
+ puts "Interrupt a second time to quit"
59
+ @interrupted = true
60
+ Kernel.sleep 1.5
61
+ # raise Interrupt, nil # let the run loop catch it
62
+ run_suite
63
+ @interrupted = false
64
+ end
65
+ end
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+ gem 'rake'
3
+ gemspec
data/README.md CHANGED
@@ -15,11 +15,17 @@ At the root directory of rails app
15
15
 
16
16
  rails_best_practices .
17
17
 
18
+ or html output
19
+
20
+ rails_best_practices -f html .
21
+
18
22
  By default rails_best_practices will do parse codes in vendor, spec, test and features directories. If you need, see the command options:
19
23
 
20
24
  $ rails_best_practices -h
21
25
  Usage: rails_best_practices [options]
22
26
  -d, --debug Debug mode
27
+ -f, --format FORMAT output format
28
+ --without-color only output plain text without color
23
29
  --vendor include vendor files
24
30
  --spec include spec files
25
31
  --test include test files
data/Rakefile ADDED
@@ -0,0 +1,45 @@
1
+ require "bundler"
2
+ Bundler.setup
3
+
4
+ require "rake"
5
+ require "rake/rdoctask"
6
+ require "rspec"
7
+ require "rspec/core/rake_task"
8
+
9
+ $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
10
+ require "rails_best_practices/version"
11
+
12
+ task :build do
13
+ system "gem build rails_best_practices.gemspec"
14
+ end
15
+
16
+ task :install => :build do
17
+ system "sudo gem install rails_best_practices-#{RailsBestPractices::VERSION}.gem"
18
+ end
19
+
20
+ task :release => :build do
21
+ puts "Tagging #{RailsBestPractices::VERSION}..."
22
+ system "git tag -a #{RailsBestPractices::VERSION} -m 'Tagging #{RailsBestPractices::VERSION}'"
23
+ puts "Pushing to Github..."
24
+ system "git push --tags"
25
+ puts "Pushing to rubygems.org..."
26
+ system "gem push rails_best_practices-#{RailsBestPractices::VERSION}.gem"
27
+ end
28
+
29
+ Rspec::Core::RakeTask.new(:spec) do |spec|
30
+ spec.pattern = "spec/**/*_spec.rb"
31
+ end
32
+
33
+ Rspec::Core::RakeTask.new('spec:progress') do |spec|
34
+ spec.rspec_opts = %w(--format progress)
35
+ spec.pattern = "spec/**/*_spec.rb"
36
+ end
37
+
38
+ Rake::RDocTask.new do |rdoc|
39
+ rdoc.rdoc_dir = "rdoc"
40
+ rdoc.title = "rails_best_practices #{RailsBestPractices::VERSION}"
41
+ rdoc.rdoc_files.include("README*")
42
+ rdoc.rdoc_files.include("lib/**/*.rb")
43
+ end
44
+
45
+ task :default => :spec
@@ -0,0 +1,53 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %meta{:charset => "UTF-8"}
5
+ %title Output of rails_best_practices
6
+ :css
7
+ body {
8
+ color: #333;
9
+ background: #eee;
10
+ padding: 0 20px;
11
+ }
12
+ h1 {
13
+ color: ##4E4E4E;
14
+ }
15
+ table {
16
+ background: white;
17
+ border: 1px solid #666;
18
+ border-collapse: collapse;
19
+ margin: 20px 0;
20
+ font-size: 14px;
21
+ }
22
+ table th, table td {
23
+ padding: 4px;
24
+ border: 1px solid #D0D0D0;
25
+ }
26
+ table th {
27
+ background-color: #DFC;
28
+ color: #337022;
29
+ }
30
+ table td.filename {
31
+ color: #ED1556;
32
+ }
33
+ table tr:hover {
34
+ background-color: #FFFFC0;
35
+ }
36
+ %body
37
+ %h1 rails_best_practices output
38
+ %h2 Please go to <a href="http://rails-bestpractices.com">http://rails-bestpractices.com</a> to see more useful Rails Best Practices.
39
+ %h2
40
+ - if errors.empty?
41
+ No error found. Cool!
42
+ - else
43
+ Found #{errors.size} errors.
44
+ %table
45
+ %tr
46
+ %th Filename
47
+ %th Line Number
48
+ %th Error Message
49
+ - errors.each do |error|
50
+ %tr
51
+ %td.filename= error.filename
52
+ %td.line-number= error.line_number
53
+ %td.message= error.message
@@ -25,6 +25,7 @@
25
25
  require 'rubygems'
26
26
  require 'progressbar'
27
27
  require 'colored'
28
+ require 'haml'
28
29
  require 'rails_best_practices/checks'
29
30
  require 'rails_best_practices/core'
30
31
 
@@ -80,7 +81,11 @@ module RailsBestPractices
80
81
  process("review")
81
82
  @bar.finish
82
83
 
83
- output_errors
84
+ if @options['format'] == 'html'
85
+ output_html_errors
86
+ else
87
+ output_terminal_errors
88
+ end
84
89
  exit @runner.errors.size
85
90
  end
86
91
 
@@ -103,11 +108,9 @@ module RailsBestPractices
103
108
  # @return [Array] all files for prepare process
104
109
  def prepare_files
105
110
  @prepare_files ||= begin
106
- files = []
107
- ['models', 'mailers'].each do |name|
111
+ ['models', 'mailers'].inject([]) { |files, name|
108
112
  files += expand_dirs_to_files(File.join(@path, 'app', name))
109
- end
110
- files.compact
113
+ }.compact
111
114
  end
112
115
  end
113
116
 
@@ -123,7 +126,7 @@ module RailsBestPractices
123
126
  end
124
127
 
125
128
  # Exclude files based on exclude regexes if the option is set.
126
- for pattern in @options[:exclude]
129
+ @options[:exclude].each do |pattern|
127
130
  files = file_ignore(files, pattern)
128
131
  end
129
132
 
@@ -181,13 +184,29 @@ module RailsBestPractices
181
184
  end
182
185
 
183
186
  # output errors if exist.
184
- def output_errors
185
- @runner.errors.each { |error| puts error.to_s.red }
186
- puts "\nPlease go to http://rails-bestpractices.com to see more useful Rails Best Practices.".green
187
+ def output_terminal_errors
188
+ @runner.errors.each { |error| plain_output(error.to_s, 'red') }
189
+ plain_output("\nPlease go to http://rails-bestpractices.com to see more useful Rails Best Practices.", 'green')
187
190
  if @runner.errors.empty?
188
- puts "\nNo error found. Cool!".green
191
+ plain_output("\nNo error found. Cool!", 'green')
192
+ else
193
+ plain_output("\nFound #{@runner.errors.size} errors.", 'red')
194
+ end
195
+ end
196
+
197
+ def plain_output(message, color)
198
+ if @options["without-color"]
199
+ puts message
189
200
  else
190
- puts "\nFound #{@runner.errors.size} errors.".red
201
+ puts message.send(color)
202
+ end
203
+ end
204
+
205
+ def output_html_errors
206
+ template = File.read(File.join(File.dirname(__FILE__), "..", "assets", "result.html.haml"))
207
+
208
+ File.open("rails_best_practices_output.html", "w+") do |file|
209
+ file.puts Haml::Engine.new(template).render(Object.new, :errors => @runner.errors)
191
210
  end
192
211
  end
193
212
  end
@@ -62,21 +62,21 @@ module RailsBestPractices
62
62
  EOS
63
63
  end
64
64
 
65
- # define all start and end process for each node type, like
65
+ # method_missing to catch all start and end process for each node type, like
66
66
  #
67
67
  # prepare_start_defn
68
68
  # prepare_end_defn
69
69
  # review_start_call
70
70
  # review_end_call
71
- [:prepare, :review].each do |process|
72
- NODE_TYPES.each do |node|
73
- class_eval <<-EOS
74
- def #{process}_start_#{node}(node) # def review_start_defn(node)
75
- end # end
76
- #
77
- def #{process}_end_#{node}(node) # def review_end_defn(node)
78
- end # end
79
- EOS
71
+ #
72
+ # if there is a ""debug"" method defined in check, each node will be output.
73
+ def method_missing(method_name, *args)
74
+ if method_name.to_s =~ /^(prepare|review)_start_/
75
+ p args if respond_to?(:debug)
76
+ elsif method_name.to_s =~ /^(prepare|review)_end_/
77
+ # nothing to do
78
+ else
79
+ super
80
80
  end
81
81
  end
82
82
 
@@ -3,6 +3,7 @@ require 'optparse'
3
3
 
4
4
  # Usage: rails_best_practices [options] path
5
5
  # -d, --debug Debug mode
6
+ # -f, --format FORMAT output format
6
7
  # --vendor include vendor files
7
8
  # --spec include spec files
8
9
  # --test include test files
@@ -20,6 +21,14 @@ OptionParser.new do |opts|
20
21
  options['debug'] = true
21
22
  end
22
23
 
24
+ opts.on("-f", "--format FORMAT", "output format") do |format|
25
+ options['format'] = format
26
+ end
27
+
28
+ opts.on("--without-color", "only output plain text without color") do
29
+ options["without-color"] = true
30
+ end
31
+
23
32
  ['vendor', 'spec', 'test', 'features'].each do |pattern|
24
33
  opts.on("--#{pattern}", "include #{pattern} files") do
25
34
  options[pattern] = true
@@ -393,21 +393,16 @@ class Sexp
393
393
  end
394
394
  end
395
395
 
396
- # to_s for lvar, ivar, lit, const, array and hash node.
396
+ # to_s for lvar, ivar, lit, const, array, hash, and colon2 node.
397
397
  #
398
398
  # @return [String] to_s
399
399
  def to_s
400
- if [:lvar, :ivar].include? node_type
400
+ case node_type
401
+ when :lvar, :ivar, :str, :lit, :const
401
402
  self[1].to_s
402
- elsif :str == node_type
403
- self[1]
404
- elsif :lit == node_type
405
- self[1].to_s
406
- elsif :const == node_type
407
- self[1].to_s
408
- elsif :array == node_type
403
+ when :array
409
404
  "[\"#{self.children.collect(&:to_s).join('", "')}\"]"
410
- elsif :hash == node_type
405
+ when :hash
411
406
  key_value = false # false is key, true is value
412
407
  result = ['{"']
413
408
  children.each do |child|
@@ -415,6 +410,10 @@ class Sexp
415
410
  key_value = !key_value
416
411
  end
417
412
  result.join("").sub(/, "$/, '') + '}'
413
+ when :colon2
414
+ "#{self[1]}::#{self[2]}"
415
+ else
416
+ ""
418
417
  end
419
418
  end
420
419
  end