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.
- data/.gitignore +12 -0
- data/.rspec.example +2 -0
- data/.rvmrc.example +2 -0
- data/.watchr +65 -0
- data/.watchr.example +65 -0
- data/Gemfile +3 -0
- data/README.md +6 -0
- data/Rakefile +45 -0
- data/assets/result.html.haml +53 -0
- data/lib/rails_best_practices.rb +30 -11
- data/lib/rails_best_practices/checks/check.rb +10 -10
- data/lib/rails_best_practices/command.rb +9 -0
- data/lib/rails_best_practices/core/visitable_sexp.rb +9 -10
- data/lib/rails_best_practices/version.rb +1 -1
- data/rails_best_practices.gemspec +32 -0
- data/rubies_test.sh +10 -0
- data/spec/rails_best_practices/checks/add_model_virtual_attribute_check_spec.rb +113 -0
- data/spec/rails_best_practices/checks/always_add_db_index_check_spec.rb +172 -0
- data/spec/rails_best_practices/checks/check_spec.rb +57 -0
- data/spec/rails_best_practices/checks/dry_bundler_in_capistrano_check_spec.rb +39 -0
- data/spec/rails_best_practices/checks/isolate_seed_data_check_spec.rb +105 -0
- data/spec/rails_best_practices/checks/keep_finders_on_their_own_model_check_spec.rb +103 -0
- data/spec/rails_best_practices/checks/law_of_demeter_check_spec.rb +101 -0
- data/spec/rails_best_practices/checks/move_code_into_controller_check_spec.rb +33 -0
- data/spec/rails_best_practices/checks/move_code_into_helper_check_spec.rb +28 -0
- data/spec/rails_best_practices/checks/move_code_into_model_check_spec.rb +55 -0
- data/spec/rails_best_practices/checks/move_finder_to_named_scope_check_spec.rb +82 -0
- data/spec/rails_best_practices/checks/move_model_logic_into_model_check_spec.rb +49 -0
- data/spec/rails_best_practices/checks/needless_deep_nesting_check_spec.rb +140 -0
- data/spec/rails_best_practices/checks/not_use_default_route_check_spec.rb +63 -0
- data/spec/rails_best_practices/checks/overuse_route_customizations_check_spec.rb +159 -0
- data/spec/rails_best_practices/checks/replace_complex_creation_with_factory_method_check_spec.rb +76 -0
- data/spec/rails_best_practices/checks/replace_instance_variable_with_local_variable_check_spec.rb +36 -0
- data/spec/rails_best_practices/checks/use_before_filter_check_spec.rb +85 -0
- data/spec/rails_best_practices/checks/use_model_association_check_spec.rb +71 -0
- data/spec/rails_best_practices/checks/use_observer_check_spec.rb +155 -0
- data/spec/rails_best_practices/checks/use_query_attribute_check_spec.rb +192 -0
- data/spec/rails_best_practices/checks/use_say_with_time_in_migrations_check_spec.rb +113 -0
- data/spec/rails_best_practices/checks/use_scope_access_check_spec.rb +193 -0
- data/spec/rails_best_practices/core/error_spec.rb +7 -0
- data/spec/rails_best_practices/core/visitable_sexp_spec.rb +259 -0
- data/spec/rails_best_practices/core_ext/enumerable_spec.rb +7 -0
- data/spec/rails_best_practices/core_ext/nil_class_spec.rb +11 -0
- data/spec/rails_best_practices_spec.rb +44 -0
- data/spec/spec_helper.rb +4 -0
- metadata +114 -32
data/.gitignore
ADDED
data/.rspec.example
ADDED
data/.rvmrc.example
ADDED
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
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
|
data/lib/rails_best_practices.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
185
|
-
@runner.errors.each { |error|
|
186
|
-
|
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
|
-
|
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
|
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
|
-
#
|
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
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
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
|
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
|
-
|
400
|
+
case node_type
|
401
|
+
when :lvar, :ivar, :str, :lit, :const
|
401
402
|
self[1].to_s
|
402
|
-
|
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
|
-
|
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
|