rails_best_practices 0.6.1 → 0.6.5

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