rails_best_practices 1.15.7 → 1.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +1 -1
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +382 -0
- data/.travis.yml +1 -0
- data/CHANGELOG.md +88 -0
- data/README.md +31 -33
- data/Rakefile +4 -1
- data/lib/rails_best_practices.rb +1 -0
- data/lib/rails_best_practices/analyzer.rb +2 -3
- data/lib/rails_best_practices/colorize.rb +11 -0
- data/lib/rails_best_practices/core/modules.rb +8 -8
- data/lib/rails_best_practices/prepares/controller_prepare.rb +4 -4
- data/lib/rails_best_practices/reviews/check_destroy_return_value_review.rb +60 -0
- data/lib/rails_best_practices/reviews/check_save_return_value_review.rb +3 -3
- data/lib/rails_best_practices/reviews/remove_unused_methods_in_helpers_review.rb +3 -3
- data/lib/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review.rb +2 -0
- data/lib/rails_best_practices/version.rb +1 -1
- data/rails_best_practices.gemspec +1 -1
- data/rails_best_practices.yml +1 -0
- data/spec/rails_best_practices/analyzer_spec.rb +5 -1
- data/spec/rails_best_practices/core/modules_spec.rb +5 -5
- data/spec/rails_best_practices/prepares/controller_prepare_spec.rb +2 -2
- data/spec/rails_best_practices/reviews/check_destroy_return_value_spec.rb +151 -0
- data/spec/rails_best_practices/reviews/remove_unused_methods_in_helpers_review_spec.rb +30 -0
- data/spec/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review_spec.rb +12 -18
- metadata +24 -17
data/README.md
CHANGED
@@ -7,22 +7,22 @@
|
|
7
7
|
[![Coderwall Endorse](http://api.coderwall.com/flyerhzm/endorsecount.png)](http://coderwall.com/flyerhzm)
|
8
8
|
[![Click here to lend your support to: rails best practices and make a donation at www.pledgie.com !](https://pledgie.com/campaigns/12057.png?skin_name=chrome)](https://pledgie.com/campaigns/12057)
|
9
9
|
|
10
|
-
rails_best_practices is a code metric tool to check the quality of
|
10
|
+
rails_best_practices is a code metric tool to check the quality of Rails code.
|
11
11
|
|
12
|
-
|
12
|
+
It supports the following ORM/ODMs:
|
13
13
|
|
14
14
|
* activerecord
|
15
15
|
* mongoid
|
16
16
|
* mongomapper
|
17
17
|
|
18
|
-
following template engines:
|
18
|
+
And the following template engines:
|
19
19
|
|
20
20
|
* erb
|
21
21
|
* haml
|
22
22
|
* slim
|
23
23
|
* rabl
|
24
24
|
|
25
|
-
rails_best_practices
|
25
|
+
rails_best_practices supports Ruby 1.9.3 or newer.
|
26
26
|
|
27
27
|
## External Introduction
|
28
28
|
|
@@ -32,29 +32,29 @@ rails_best_practices works well only in ruby 1.9.3, 2.0.0, and 2.1.0 so far. It
|
|
32
32
|
|
33
33
|
## Usage
|
34
34
|
|
35
|
-
At the root directory of
|
35
|
+
At the root directory of a Rails app, run:
|
36
36
|
|
37
37
|
rails_best_practices .
|
38
38
|
|
39
|
-
|
39
|
+
Or for HTML output:
|
40
40
|
|
41
41
|
rails_best_practices -f html .
|
42
42
|
|
43
|
-
By default rails_best_practices will
|
43
|
+
By default rails_best_practices will parse code in the `vendor`, `spec`, `test` and `features` directories.
|
44
44
|
|
45
|
-
### Excluding
|
45
|
+
### Excluding directories
|
46
46
|
|
47
|
-
To exclude
|
47
|
+
To exclude a directory simply call it with `-e` or `--exclude`:
|
48
48
|
|
49
49
|
rails_best_practices -e "db/migrate" .
|
50
50
|
|
51
|
-
To exclude multiple
|
51
|
+
To exclude multiple directories, separate them with comma:
|
52
52
|
|
53
53
|
rails_best_practices -e "db/migrate,vendor" .
|
54
54
|
|
55
|
-
### Other command
|
55
|
+
### Other command-line options
|
56
56
|
|
57
|
-
To see full list of
|
57
|
+
To see the full list of command-line options, run:
|
58
58
|
|
59
59
|
$ rails_best_practices -h
|
60
60
|
|
@@ -89,7 +89,7 @@ Homepage: <http://rails-bestpractices.com>
|
|
89
89
|
|
90
90
|
Online Service: <http://railsbp.com>
|
91
91
|
|
92
|
-
|
92
|
+
GitHub: <http://github.com/railsbp/rails_best_practices>
|
93
93
|
|
94
94
|
RDoc: <http://rdoc.rails-bestpractices.com>
|
95
95
|
|
@@ -103,11 +103,9 @@ Issue Tracker: <http://github.com/railsbp/rails_best_practices/issues>
|
|
103
103
|
|
104
104
|
## Install
|
105
105
|
|
106
|
-
rails_best_practices gem is rewritten based on ripper instead of ruby_parser to support ruby 1.9 new syntax.
|
107
|
-
|
108
106
|
gem install rails_best_practices
|
109
107
|
|
110
|
-
or add
|
108
|
+
or add it to the Gemfile
|
111
109
|
|
112
110
|
gem "rails_best_practices"
|
113
111
|
|
@@ -115,27 +113,27 @@ or add in Gemfile
|
|
115
113
|
|
116
114
|
Install <https://github.com/asuth/subl-handler>
|
117
115
|
|
118
|
-
##
|
116
|
+
## Issues
|
119
117
|
|
120
|
-
If you install the rails_best_practices with bundler-installed
|
118
|
+
If you install the rails_best_practices with bundler-installed GitHub-sourced gem, please use the following command instead.
|
121
119
|
|
122
120
|
bundle exec rails_best_practices .
|
123
121
|
|
124
|
-
If you
|
122
|
+
If you encounter a NoMethodError exception, or a syntax error, you can use debug mode to discover which file is to blame:
|
125
123
|
|
126
124
|
rails_best_practices -d .
|
127
125
|
|
128
|
-
|
126
|
+
That will provide the error's stack trace and the source code of the file which is causing the error.
|
129
127
|
|
130
|
-
##
|
128
|
+
## Custom Configuration
|
131
129
|
|
132
|
-
First run
|
130
|
+
First run:
|
133
131
|
|
134
132
|
rails_best_practices -g
|
135
133
|
|
136
134
|
to generate `rails_best_practices.yml` file.
|
137
135
|
|
138
|
-
Now you can customize this configuration file
|
136
|
+
Now you can customize this configuration file. The default configuration is as follows:
|
139
137
|
|
140
138
|
AddModelVirtualAttributeCheck: { }
|
141
139
|
AlwaysAddDbIndexCheck: { }
|
@@ -179,7 +177,7 @@ Now you can customize this configuration file, the default configuration is as f
|
|
179
177
|
UseScopeAccessCheck: { }
|
180
178
|
UseTurboSprocketsRails3Check: { }
|
181
179
|
|
182
|
-
You can remove or comment
|
180
|
+
You can remove or comment a review to disable it, and you can change the options.
|
183
181
|
|
184
182
|
You can apply the `ignored_files` option on any rule by giving a regexp or array of regexps describing the path of the files you don't want to be checked:
|
185
183
|
|
@@ -208,7 +206,7 @@ RESTful Conventions
|
|
208
206
|
Model
|
209
207
|
|
210
208
|
1. Keep finders on their own model (rails2 only)
|
211
|
-
2.
|
209
|
+
2. The law of demeter
|
212
210
|
3. Use observer
|
213
211
|
4. Use query attribute
|
214
212
|
5. Remove unused methods in models
|
@@ -221,12 +219,12 @@ Mailer
|
|
221
219
|
Migration
|
222
220
|
|
223
221
|
1. Isolating seed data
|
224
|
-
2. Always add
|
222
|
+
2. Always add database index
|
225
223
|
3. Use say with time in migrations
|
226
224
|
|
227
225
|
Controller
|
228
226
|
|
229
|
-
1. Use before_filter (disabled by default)
|
227
|
+
1. Use `before_filter` (disabled by default)
|
230
228
|
2. Simplify render in controllers
|
231
229
|
3. Remove unused methods in controllers
|
232
230
|
|
@@ -246,21 +244,21 @@ View
|
|
246
244
|
|
247
245
|
Deployment
|
248
246
|
|
249
|
-
1. Dry bundler in
|
250
|
-
2. Speed up assets
|
247
|
+
1. Dry bundler in Capistrano
|
248
|
+
2. Speed up assets precompilation with turbo-sprockets-rails3
|
251
249
|
|
252
250
|
Other
|
253
251
|
|
254
252
|
1. Remove trailing whitespace
|
255
253
|
2. Remove tab (disabled by default)
|
256
254
|
3. Hash syntax (disabled by default)
|
257
|
-
4. Use parentheses in method
|
255
|
+
4. Use parentheses in method definition (disabled by default)
|
258
256
|
5. Long line (disabled by default)
|
259
257
|
6. Not rescue exception
|
260
258
|
|
261
|
-
## Write Your Own
|
259
|
+
## Write Your Own Checklist
|
262
260
|
|
263
|
-
If you want to write your own
|
261
|
+
If you want to write your own checklist (some checklist only for your Rails projects), please read this first, [How to write your own check list?][1]
|
264
262
|
|
265
263
|
## Contribute
|
266
264
|
|
@@ -268,7 +266,7 @@ If you want to add your rails best practices into the gem, please post your best
|
|
268
266
|
|
269
267
|
## Contact Us
|
270
268
|
|
271
|
-
We provide
|
269
|
+
We provide Rails consulting services, you can contact us by Twitter or email.
|
272
270
|
|
273
271
|
Follow us on twitter: <http://twitter.com/railsbp>
|
274
272
|
|
data/Rakefile
CHANGED
@@ -6,6 +6,7 @@ Bundler.setup
|
|
6
6
|
require "rake"
|
7
7
|
require "rspec"
|
8
8
|
require "rspec/core/rake_task"
|
9
|
+
require 'rubocop/rake_task'
|
9
10
|
|
10
11
|
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
11
12
|
require "rails_best_practices/version"
|
@@ -14,5 +15,7 @@ RSpec::Core::RakeTask.new(:spec) do |spec|
|
|
14
15
|
spec.pattern = "spec/**/*_spec.rb"
|
15
16
|
end
|
16
17
|
|
17
|
-
|
18
|
+
RuboCop::RakeTask.new
|
19
|
+
|
20
|
+
task :default => [:spec, :rubocop]
|
18
21
|
task :test => :spec
|
data/lib/rails_best_practices.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require 'colored'
|
3
2
|
require 'fileutils'
|
4
3
|
require 'json'
|
5
4
|
require 'ruby-progressbar'
|
@@ -308,13 +307,13 @@ module RailsBestPractices
|
|
308
307
|
if @options["without-color"]
|
309
308
|
puts message
|
310
309
|
else
|
311
|
-
puts
|
310
|
+
puts Colorize.send(color, message)
|
312
311
|
end
|
313
312
|
end
|
314
313
|
|
315
314
|
# analyze source codes.
|
316
315
|
def analyze_source_codes
|
317
|
-
@bar = ProgressBar.create(:title => 'Source
|
316
|
+
@bar = ProgressBar.create(:title => 'Source Code', :total => parse_files.size * 3) if display_bar?
|
318
317
|
["lexical", "prepare", "review"].each { |process| send(:process, process) }
|
319
318
|
@bar.finish if display_bar?
|
320
319
|
end
|
@@ -3,28 +3,28 @@ module RailsBestPractices
|
|
3
3
|
module Core
|
4
4
|
# Module container
|
5
5
|
class Modules < Array
|
6
|
-
# add module
|
6
|
+
# add module descendant.
|
7
7
|
#
|
8
8
|
# @param [String] module name
|
9
|
-
# @param [String]
|
10
|
-
def
|
9
|
+
# @param [String] descendant name
|
10
|
+
def add_module_descendant(module_name, descendant)
|
11
11
|
mod = find { |mod| mod.to_s == module_name }
|
12
|
-
mod.
|
12
|
+
mod.add_descendant(descendant) if mod
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
16
|
# Module info include module name and module spaces.
|
17
17
|
class Mod
|
18
|
-
attr_reader :
|
18
|
+
attr_reader :descendants
|
19
19
|
|
20
20
|
def initialize(module_name, modules)
|
21
21
|
@module_name = module_name
|
22
22
|
@modules = modules
|
23
|
-
@
|
23
|
+
@descendants = []
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
27
|
-
@
|
26
|
+
def add_descendant(descendant)
|
27
|
+
@descendants << descendant
|
28
28
|
end
|
29
29
|
|
30
30
|
def to_s
|
@@ -54,7 +54,7 @@ module RailsBestPractices
|
|
54
54
|
# restrict actions for inherited_resources
|
55
55
|
add_callback :start_command do |node|
|
56
56
|
if "include" == node.message.to_s
|
57
|
-
@helpers.
|
57
|
+
@helpers.add_module_descendant(node.arguments.all.first.to_s, current_class_name)
|
58
58
|
elsif @inherited_resources && "actions" == node.message.to_s
|
59
59
|
if "all" == node.arguments.all.first.to_s
|
60
60
|
@actions = DEFAULT_ACTIONS
|
@@ -87,9 +87,9 @@ module RailsBestPractices
|
|
87
87
|
|
88
88
|
# ask Reviews::RemoveUnusedMoethodsInHelperReview to check the controllers who include helpers.
|
89
89
|
add_callback :after_check do
|
90
|
-
|
91
|
-
if
|
92
|
-
Reviews::RemoveUnusedMethodsInHelpersReview.interesting_files *
|
90
|
+
descendants = @helpers.map(&:descendants).flatten
|
91
|
+
if descendants.present?
|
92
|
+
Reviews::RemoveUnusedMethodsInHelpersReview.interesting_files *descendants.map { |descendant| %r|#{descendant.underscore}| }
|
93
93
|
end
|
94
94
|
end
|
95
95
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module RailsBestPractices
|
3
|
+
module Reviews
|
4
|
+
# Review all code to make sure we either check the return value of "destroy"
|
5
|
+
# or use "destroy!"
|
6
|
+
#
|
7
|
+
# Review process:
|
8
|
+
# Track which nodes are used by 'if', 'unless', '&&' nodes etc. as we pass them by.
|
9
|
+
# Check all "save" calls to check the return value is used by a node we have visited.
|
10
|
+
class CheckDestroyReturnValueReview < Review
|
11
|
+
include Classable
|
12
|
+
interesting_nodes :call, :command_call, :method_add_arg, :if, :ifop, :elsif, :unless, :if_mod, :unless_mod, :assign, :binary
|
13
|
+
interesting_files ALL_FILES
|
14
|
+
|
15
|
+
add_callback :start_if, :start_ifop, :start_elsif, :start_unless, :start_if_mod, :start_unless_mod do |node|
|
16
|
+
@used_return_value_of = node.conditional_statement.all_conditions
|
17
|
+
end
|
18
|
+
|
19
|
+
add_callback :start_assign do |node|
|
20
|
+
@used_return_value_of = node.right_value
|
21
|
+
end
|
22
|
+
|
23
|
+
add_callback :start_binary do |node|
|
24
|
+
# Consider anything used in an expression like "A or B" as used
|
25
|
+
if %w(&& || and or).include?(node[2].to_s)
|
26
|
+
all_conditions = node.all_conditions
|
27
|
+
# if our current binary is a subset of the @used_return_value_of
|
28
|
+
# then don't overwrite it
|
29
|
+
already_included = @used_return_value_of &&
|
30
|
+
(all_conditions - @used_return_value_of).empty?
|
31
|
+
|
32
|
+
@used_return_value_of = node.all_conditions unless already_included
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def return_value_is_used? node
|
37
|
+
return false unless @used_return_value_of
|
38
|
+
node == @used_return_value_of or @used_return_value_of.include?(node)
|
39
|
+
end
|
40
|
+
|
41
|
+
def model_classnames
|
42
|
+
@model_classnames ||= models.map(&:to_s)
|
43
|
+
end
|
44
|
+
|
45
|
+
add_callback :start_call, :start_command_call, :start_method_add_arg do |node|
|
46
|
+
unless @already_checked == node
|
47
|
+
message = node.message.to_s
|
48
|
+
if message.eql? 'destroy'
|
49
|
+
unless return_value_is_used? node
|
50
|
+
add_error "check '#{message}' return value or use '#{message}!'"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
if node.sexp_type == :method_add_arg
|
54
|
+
@already_checked = node[1]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module RailsBestPractices
|
3
3
|
module Reviews
|
4
|
-
# Review all code to make sure we either check the return value of "save"
|
5
|
-
# or use "save!"
|
4
|
+
# Review all code to make sure we either check the return value of "save", "update_attributes"
|
5
|
+
# and "create" or use "save!", "update_attributes!", or "create!", respectively.
|
6
6
|
#
|
7
7
|
# See the best practice details here http://rails-bestpractices.com/posts/2012/11/02/check-the-return-value-of-save-otherwise-use-save/
|
8
8
|
#
|
@@ -57,7 +57,7 @@ module RailsBestPractices
|
|
57
57
|
elsif message == 'create'
|
58
58
|
# We're only interested in 'create' calls on model classes:
|
59
59
|
possible_receiver_classes = [node.receiver.to_s] + classable_modules.map do |mod|
|
60
|
-
"#{mod}::#{node.receiver
|
60
|
+
"#{mod}::#{node.receiver}"
|
61
61
|
end
|
62
62
|
unless (possible_receiver_classes & model_classnames).empty?
|
63
63
|
add_error "use 'create!' instead of 'create' as the latter may not always save"
|
@@ -7,19 +7,19 @@ module RailsBestPractices
|
|
7
7
|
#
|
8
8
|
# Review process:
|
9
9
|
# remember all method calls in helpers.
|
10
|
-
# if they are not called in views or
|
10
|
+
# if they are not called in views, helpers, or controllers
|
11
11
|
# then they are unused methods in helpers.
|
12
12
|
class RemoveUnusedMethodsInHelpersReview < Review
|
13
13
|
include Moduleable
|
14
14
|
include Callable
|
15
15
|
include Exceptable
|
16
16
|
|
17
|
-
interesting_files HELPER_FILES, VIEW_FILES
|
17
|
+
interesting_files HELPER_FILES, VIEW_FILES, CONTROLLER_FILES
|
18
18
|
|
19
19
|
def initialize(options={})
|
20
20
|
super
|
21
21
|
@helper_methods = Prepares.helper_methods
|
22
|
-
self.class.interesting_files Prepares.helpers.map(&:
|
22
|
+
self.class.interesting_files Prepares.helpers.map(&:descendants)
|
23
23
|
end
|
24
24
|
|
25
25
|
# get all unused methods at the end of review process
|
data/lib/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review.rb
CHANGED
@@ -45,6 +45,7 @@ module RailsBestPractices
|
|
45
45
|
# @param [String] name method name in action_mailer
|
46
46
|
def rails2_canonical_mailer_views?(name)
|
47
47
|
return true if mailer_files(name).length == 0
|
48
|
+
return true if mailer_files(name).none? { |filename| filename.index 'text.html' }
|
48
49
|
mailer_files(name).any? { |filename| filename.index 'text.html' } &&
|
49
50
|
mailer_files(name).any? { |filename| filename.index 'text.plain' }
|
50
51
|
end
|
@@ -54,6 +55,7 @@ module RailsBestPractices
|
|
54
55
|
# @param [String] name method name in action_mailer
|
55
56
|
def rails3_canonical_mailer_views?(name)
|
56
57
|
return true if mailer_files(name).length == 0
|
58
|
+
return true if mailer_files(name).none? { |filename| filename.index 'html' }
|
57
59
|
mailer_files(name).any? { |filename| filename.index 'html' } &&
|
58
60
|
mailer_files(name).any? { |filename| filename.index 'text' }
|
59
61
|
end
|
@@ -17,7 +17,6 @@ Gem::Specification.new do |s|
|
|
17
17
|
|
18
18
|
s.add_dependency("activesupport")
|
19
19
|
s.add_dependency("code_analyzer", ">= 0.4.3")
|
20
|
-
s.add_dependency("colored")
|
21
20
|
s.add_dependency("erubis")
|
22
21
|
s.add_dependency("i18n")
|
23
22
|
s.add_dependency("require_all")
|
@@ -30,6 +29,7 @@ Gem::Specification.new do |s|
|
|
30
29
|
s.add_development_dependency("slim")
|
31
30
|
s.add_development_dependency("bundler")
|
32
31
|
s.add_development_dependency("awesome_print")
|
32
|
+
s.add_development_dependency("rubocop", "= 0.30.1")
|
33
33
|
|
34
34
|
s.files = `git ls-files`.split("\n")
|
35
35
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|