rails_best_practices 1.7.2 → 1.8.0
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/Gemfile.lock +1 -1
- data/README.md +5 -1
- data/lib/rails_best_practices/analyzer.rb +15 -1
- data/lib/rails_best_practices/command.rb +11 -1
- data/lib/rails_best_practices/core/check.rb +12 -5
- data/lib/rails_best_practices/core/error.rb +10 -6
- data/lib/rails_best_practices/core/model_associations.rb +16 -1
- data/lib/rails_best_practices/core/runner.rb +1 -0
- data/lib/rails_best_practices/core.rb +1 -0
- data/lib/rails_best_practices/core_ext/sexp.rb +6 -2
- data/lib/rails_best_practices/core_ext/string.rb +5 -0
- data/lib/rails_best_practices/prepares/model_prepare.rb +37 -2
- data/lib/rails_best_practices/prepares/route_prepare.rb +19 -3
- data/lib/rails_best_practices/reviews/always_add_db_index_review.rb +30 -0
- data/lib/rails_best_practices/reviews/not_use_time_ago_in_words_review.rb +30 -0
- data/lib/rails_best_practices/reviews/remove_unused_methods_in_controllers_review.rb +2 -1
- data/lib/rails_best_practices/reviews/remove_unused_methods_in_helpers_review.rb +1 -1
- data/lib/rails_best_practices/reviews/remove_unused_methods_in_models_review.rb +47 -5
- data/lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb +2 -2
- data/lib/rails_best_practices/reviews.rb +1 -0
- data/lib/rails_best_practices/version.rb +1 -1
- data/rails_best_practices.gemspec +4 -0
- data/rails_best_practices.yml +1 -0
- data/spec/rails_best_practices/core/error_spec.rb +15 -3
- data/spec/rails_best_practices/core_ext/sexp_spec.rb +6 -1
- data/spec/rails_best_practices/prepares/helper_prepare_spec.rb +1 -1
- data/spec/rails_best_practices/prepares/model_prepare_spec.rb +40 -0
- data/spec/rails_best_practices/prepares/route_prepare_spec.rb +50 -0
- data/spec/rails_best_practices/reviews/always_add_db_index_review_spec.rb +72 -0
- data/spec/rails_best_practices/reviews/not_use_times_ago_in_words_review_spec.rb +49 -0
- data/spec/rails_best_practices/reviews/remove_unused_methods_in_models_review_spec.rb +64 -0
- metadata +32 -27
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -3,7 +3,7 @@ rails_best_practices
|
|
3
3
|
|
4
4
|
[](http://travis-ci.org/railsbp/rails_best_practices)
|
5
5
|
|
6
|
-
[](http://www.pledgie.com/campaigns/12057)
|
7
7
|
|
8
8
|
rails_best_practices is a code metric tool to check the quality of rails codes.
|
9
9
|
|
@@ -50,6 +50,8 @@ By default rails_best_practices will do parse codes in vendor, spec, test and fe
|
|
50
50
|
--features include features files
|
51
51
|
-x, --exclude PATTERNS Don't analyze files matching a pattern
|
52
52
|
(comma-separated regexp list)
|
53
|
+
-o, --only PATTERNS analyze files only matching a pattern
|
54
|
+
(comma-separated regexp list)
|
53
55
|
-g, --generate Generate configuration yaml
|
54
56
|
-v, --version Show this version
|
55
57
|
-h, --help Show this message
|
@@ -140,6 +142,7 @@ Now you can customize this configuration file, the default configuration is as f
|
|
140
142
|
RemoveUnusedMethodsInModelsCheck: { except_methods: [] }
|
141
143
|
RemoveUnusedMethodsInControllersCheck: { except_methods: [] }
|
142
144
|
RemoveUnusedMethodsInHelpersCheck: { except_methods: [] }
|
145
|
+
NotUseTimeAgoInWordsCheck: {}
|
143
146
|
|
144
147
|
You can remove or comment one review to disable it, and you can change the options.
|
145
148
|
|
@@ -198,6 +201,7 @@ View
|
|
198
201
|
3. Move code into helper
|
199
202
|
4. Replace instance variable with local variable
|
200
203
|
5. Simplify render in views
|
204
|
+
6. Not use time_ago_in_words
|
201
205
|
|
202
206
|
Deployment
|
203
207
|
|
@@ -46,6 +46,7 @@ module RailsBestPractices
|
|
46
46
|
# @param [Hash] options
|
47
47
|
def analyze
|
48
48
|
@options["exclude"] ||= []
|
49
|
+
@options["only"] ||= []
|
49
50
|
@options["output-file"] ||= "rails_best_practices_output.html"
|
50
51
|
|
51
52
|
Core::Runner.base_path = @path
|
@@ -98,6 +99,10 @@ module RailsBestPractices
|
|
98
99
|
files = expand_dirs_to_files(@path)
|
99
100
|
files = file_sort(files)
|
100
101
|
|
102
|
+
if @options["only"].present?
|
103
|
+
files = file_accept(files, @options["only"])
|
104
|
+
end
|
105
|
+
|
101
106
|
# By default, tmp, vender, spec, test, features are ignored.
|
102
107
|
["vendor", "spec", "test", "features", "tmp"].each do |pattern|
|
103
108
|
files = file_ignore(files, "#{pattern}/") unless @options[pattern]
|
@@ -157,6 +162,14 @@ module RailsBestPractices
|
|
157
162
|
files.reject { |file| file.index(pattern) }
|
158
163
|
end
|
159
164
|
|
165
|
+
# accept specific files.
|
166
|
+
#
|
167
|
+
# @param [Array] files
|
168
|
+
# @param [Regexp] patterns, files match any pattern will be accepted
|
169
|
+
def file_accept files, patterns
|
170
|
+
files.reject { |file| !patterns.any? { |pattern| file =~ pattern } }
|
171
|
+
end
|
172
|
+
|
160
173
|
# output errors on terminal.
|
161
174
|
def output_terminal_errors
|
162
175
|
@runner.errors.each { |error| plain_output(error.to_s, 'red') }
|
@@ -186,8 +199,9 @@ module RailsBestPractices
|
|
186
199
|
# load git commit and git username info.
|
187
200
|
def load_git_info
|
188
201
|
git_progressbar = ProgressBar.new('Git Info', @runner.errors.size) if display_bar?
|
202
|
+
start = @runner.class.base_path =~ /\/$/ ? @runner.class.base_path.size : @runner.class.base_path.size + 1
|
189
203
|
@runner.errors.each do |error|
|
190
|
-
git_info = `cd #{@runner.class.base_path}; git blame
|
204
|
+
git_info = `cd #{@runner.class.base_path}; git blame -L #{error.line_number.split(',').first},+1 #{error.filename[start..-1]}`
|
191
205
|
unless git_info == ""
|
192
206
|
git_commit, git_username = git_info.split(/\d{4}-\d{2}-\d{2}/).first.split("(")
|
193
207
|
error.git_commit = git_commit.split(" ").first.strip
|
@@ -19,6 +19,8 @@ require 'optparse'
|
|
19
19
|
# --features include features files
|
20
20
|
# -x, --exclude PATTERNS don't analyze files matching a pattern
|
21
21
|
# (comma-separated regexp list)
|
22
|
+
# -o, --only PATTERNS analyze files only matching a pattern
|
23
|
+
# (comma-separated regexp list)
|
22
24
|
# -g, --generate generate configuration yaml
|
23
25
|
# -v, --version show this version
|
24
26
|
# -h, --help show this message
|
@@ -94,12 +96,20 @@ OptionParser.new do |opts|
|
|
94
96
|
|
95
97
|
opts.on("-x", "--exclude PATTERNS", "Don't analyze files matching a pattern", "(comma-separated regexp list)") do |list|
|
96
98
|
begin
|
97
|
-
options["exclude"] = list.split(
|
99
|
+
options["exclude"] = list.split(",").map{|x| Regexp.new x}
|
98
100
|
rescue RegexpError => e
|
99
101
|
raise OptionParser::InvalidArgument, e.message
|
100
102
|
end
|
101
103
|
end
|
102
104
|
|
105
|
+
opts.on("-o", "--only PATTERNS", "Analyze files only matching a pattern", "(comma-separated regexp list)") do |list|
|
106
|
+
begin
|
107
|
+
options["only"] = list.split(",").map { |x| Regexp.new x }
|
108
|
+
rescue RegexpError => e
|
109
|
+
raise OptionParser::InvalidArgument e.message
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
103
113
|
opts.on("-g", "--generate", "Generate configuration yaml") do
|
104
114
|
options["generate"] = true
|
105
115
|
end
|
@@ -73,10 +73,16 @@ module RailsBestPractices
|
|
73
73
|
# add error if source code violates rails best practice.
|
74
74
|
#
|
75
75
|
# @param [String] message, is the string message for violation of the rails best practice
|
76
|
-
# @param [String]
|
77
|
-
# @param [Integer]
|
78
|
-
def add_error(message,
|
79
|
-
errors << RailsBestPractices::Core::Error.new(
|
76
|
+
# @param [String] filename, is the filename of source code
|
77
|
+
# @param [Integer] line_number, is the line number of the source code which is reviewing
|
78
|
+
def add_error(message, filename = @node.file, line_number = @node.line)
|
79
|
+
errors << RailsBestPractices::Core::Error.new(
|
80
|
+
:filename => filename,
|
81
|
+
:line_number => line_number,
|
82
|
+
:message => message,
|
83
|
+
:type => self.class.to_s,
|
84
|
+
:url => url
|
85
|
+
)
|
80
86
|
end
|
81
87
|
|
82
88
|
# errors that vialote the rails best practices.
|
@@ -265,7 +271,7 @@ module RailsBestPractices
|
|
265
271
|
when "alias_method_chain"
|
266
272
|
method, feature = *node.arguments.all.map(&:to_s)
|
267
273
|
call_method("#{method}_with_#{feature}")
|
268
|
-
when
|
274
|
+
when /^(before|after)_/
|
269
275
|
node.arguments.all.each { |argument| mark_used(argument) }
|
270
276
|
else
|
271
277
|
mark_used(node.message)
|
@@ -374,6 +380,7 @@ module RailsBestPractices
|
|
374
380
|
class_name, method_name = except_method.split('#')
|
375
381
|
(class_name == '*' && method_name == method.method_name) ||
|
376
382
|
(method_name == '*' && class_name == method.class_name) ||
|
383
|
+
(method_name == '*' && class_name == Prepares.klasses.find { |klass| klass.class_name == method.class_name }.try(:extend_class_name)) ||
|
377
384
|
(class_name == method.class_name && method_name == method.method_name)
|
378
385
|
end
|
379
386
|
end
|
@@ -8,12 +8,16 @@ module RailsBestPractices
|
|
8
8
|
attr_reader :filename, :line_number, :message, :type, :url
|
9
9
|
attr_accessor :git_commit, :git_username, :hg_commit, :hg_username
|
10
10
|
|
11
|
-
def initialize(
|
12
|
-
@filename = filename
|
13
|
-
@line_number = line_number
|
14
|
-
@message = message
|
15
|
-
@type = type
|
16
|
-
@url = url
|
11
|
+
def initialize(options={})
|
12
|
+
@filename = options[:filename]
|
13
|
+
@line_number = options[:line_number].to_s
|
14
|
+
@message = options[:message]
|
15
|
+
@type = options[:type]
|
16
|
+
@url = options[:url]
|
17
|
+
@git_commit = options[:git_commit]
|
18
|
+
@git_username = options[:git_username]
|
19
|
+
@hg_commit = options[:hg_commit]
|
20
|
+
@hg_username = options[:hg_username]
|
17
21
|
end
|
18
22
|
|
19
23
|
def short_filename
|
@@ -7,7 +7,6 @@ module RailsBestPractices
|
|
7
7
|
@associations = {}
|
8
8
|
end
|
9
9
|
|
10
|
-
# Add a model association.
|
11
10
|
#
|
12
11
|
# @param [String] model name
|
13
12
|
# @param [String] association name
|
@@ -37,6 +36,22 @@ module RailsBestPractices
|
|
37
36
|
associations = @associations[model_name]
|
38
37
|
associations && associations[association_name]
|
39
38
|
end
|
39
|
+
|
40
|
+
# delegate each to @associations.
|
41
|
+
def each(&block)
|
42
|
+
@associations.each { |model, model_associations| yield model, model_associations }
|
43
|
+
end
|
44
|
+
|
45
|
+
# Get association's class name
|
46
|
+
#
|
47
|
+
# @param [String] table name
|
48
|
+
# @param [String] association_name
|
49
|
+
# @return [String] association's class name
|
50
|
+
def get_association_class_name(table_name, association_name)
|
51
|
+
associations = @associations.select { |model, model_associations| model.table_name == table_name }.values.first and
|
52
|
+
association_meta = associations.select { |name, meta| name == association_name }.values.first and
|
53
|
+
association_meta["class_name"]
|
54
|
+
end
|
40
55
|
end
|
41
56
|
end
|
42
57
|
end
|
@@ -15,6 +15,7 @@ require 'rails_best_practices/core/controllers'
|
|
15
15
|
require 'rails_best_practices/core/helpers'
|
16
16
|
require 'rails_best_practices/core/routes'
|
17
17
|
|
18
|
+
require 'rails_best_practices/core_ext/string'
|
18
19
|
require 'rails_best_practices/core_ext/sexp'
|
19
20
|
require 'rails_best_practices/core_ext/enumerable'
|
20
21
|
require 'rails_best_practices/core_ext/erubis'
|
@@ -21,7 +21,7 @@ class Sexp
|
|
21
21
|
# s(:@ident, "test", s(2, 12)
|
22
22
|
# => 2
|
23
23
|
def line
|
24
|
-
if [:def, :command, :command_call, :call, :fcall, :method_add_arg, :method_add_block,
|
24
|
+
if [:def, :defs, :command, :command_call, :call, :fcall, :method_add_arg, :method_add_block,
|
25
25
|
:var_ref, :const_ref, :const_path_ref, :class, :module, :if, :unless, :elsif, :binary,
|
26
26
|
:alias, :symbol_literal, :symbol, :aref].include? sexp_type
|
27
27
|
self[1].line
|
@@ -382,8 +382,12 @@ class Sexp
|
|
382
382
|
#
|
383
383
|
# @return [Sexp] method name node
|
384
384
|
def method_name
|
385
|
-
|
385
|
+
case sexp_type
|
386
|
+
when :def
|
386
387
|
self[1]
|
388
|
+
when :defs
|
389
|
+
self[3]
|
390
|
+
else
|
387
391
|
end
|
388
392
|
end
|
389
393
|
|
@@ -7,8 +7,9 @@ module RailsBestPractices
|
|
7
7
|
class ModelPrepare < Core::Check
|
8
8
|
include Core::Check::Classable
|
9
9
|
include Core::Check::Accessable
|
10
|
+
include Core::Check::Afterable
|
10
11
|
|
11
|
-
interesting_nodes :class, :def, :command, :var_ref, :alias
|
12
|
+
interesting_nodes :class, :def, :defs, :command, :var_ref, :alias
|
12
13
|
interesting_files MODEL_FILES
|
13
14
|
|
14
15
|
ASSOCIATION_METHODS = %w(belongs_to has_one has_many has_and_belongs_to_many embeds_many embeds_one embedded_in many one)
|
@@ -27,7 +28,7 @@ module RailsBestPractices
|
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
30
|
-
# check
|
31
|
+
# check def node to remember all methods.
|
31
32
|
#
|
32
33
|
# the remembered methods (@methods) are like
|
33
34
|
# {
|
@@ -46,6 +47,25 @@ module RailsBestPractices
|
|
46
47
|
end
|
47
48
|
end
|
48
49
|
|
50
|
+
# check defs node to remember all static methods.
|
51
|
+
#
|
52
|
+
# the remembered methods (@methods) are like
|
53
|
+
# {
|
54
|
+
# "Post" => {
|
55
|
+
# "save" => {"file" => "app/models/post.rb", "line" => 10, "unused" => false, "unused" => false},
|
56
|
+
# "find" => {"file" => "app/models/post.rb", "line" => 10, "unused" => false, "unused" => false}
|
57
|
+
# },
|
58
|
+
# "Comment" => {
|
59
|
+
# "create" => {"file" => "app/models/comment.rb", "line" => 10, "unused" => false, "unused" => false},
|
60
|
+
# }
|
61
|
+
# }
|
62
|
+
def start_defs(node)
|
63
|
+
if @klass && "ActionMailer::Base" != current_extend_class_name
|
64
|
+
method_name = node.method_name.to_s
|
65
|
+
@methods.add_method(current_class_name, method_name, {"file" => node.file, "line" => node.line}, current_access_control)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
49
69
|
# check command node to remember all assoications or named_scope/scope methods.
|
50
70
|
#
|
51
71
|
# the remembered association names (@associations) are like
|
@@ -86,6 +106,21 @@ module RailsBestPractices
|
|
86
106
|
@methods.add_method(current_class_name, method_name, {"file" => node.file, "line" => node.line}, current_access_control)
|
87
107
|
end
|
88
108
|
|
109
|
+
# after prepare process, fix incorrect associations' class_name.
|
110
|
+
def after_prepare
|
111
|
+
@model_associations.each do |model, model_associations|
|
112
|
+
model_associations.each do |association_name, association_meta|
|
113
|
+
unless @models.include?(association_meta["class_name"])
|
114
|
+
if @models.include?("#{model}::#{association_meta['class_name']}")
|
115
|
+
association_meta["class_name"] = "#{model}::#{association_meta['class_name']}"
|
116
|
+
elsif @models.include?(model.gsub(/::\w+$/, ""))
|
117
|
+
association_meta["class_name"] = model.gsub(/::\w+$/, "")
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
89
124
|
private
|
90
125
|
# remember associations, with class to association names.
|
91
126
|
def remember_association(node)
|
@@ -5,7 +5,7 @@ module RailsBestPractices
|
|
5
5
|
module Prepares
|
6
6
|
# Remembber routes.
|
7
7
|
class RoutePrepare < Core::Check
|
8
|
-
interesting_nodes :command, :command_call, :method_add_block
|
8
|
+
interesting_nodes :command, :command_call, :method_add_block, :do_block
|
9
9
|
interesting_files ROUTE_FILES
|
10
10
|
|
11
11
|
RESOURCES_ACTIONS = %w(index show new create edit update destroy)
|
@@ -14,6 +14,7 @@ module RailsBestPractices
|
|
14
14
|
def initialize
|
15
15
|
@routes = Prepares.routes
|
16
16
|
@namespaces = []
|
17
|
+
@controller_names = []
|
17
18
|
end
|
18
19
|
|
19
20
|
# remember route for rails3.
|
@@ -25,7 +26,8 @@ module RailsBestPractices
|
|
25
26
|
add_resource_routes(node)
|
26
27
|
when "get", "post", "put", "delete"
|
27
28
|
first_argument = node.arguments.all.first
|
28
|
-
|
29
|
+
second_argument = node.arguments.all[1]
|
30
|
+
if @controller_names.last
|
29
31
|
action_name = first_argument.to_s
|
30
32
|
@routes.add_route(current_namespaces, current_controller_name, action_name)
|
31
33
|
else
|
@@ -34,6 +36,8 @@ module RailsBestPractices
|
|
34
36
|
# do not parse redirect block
|
35
37
|
return if :method_add_arg == route_node.sexp_type
|
36
38
|
controller_name, action_name = route_node.to_s.split('#')
|
39
|
+
elsif :bare_assoc_hash == second_argument.try(:sexp_type) && second_argument.hash_value("to")
|
40
|
+
controller_name, action_name = second_argument.hash_value("to").to_s.split('#')
|
37
41
|
else
|
38
42
|
controller_name, action_name = first_argument.to_s.split('/')
|
39
43
|
end
|
@@ -91,10 +95,12 @@ module RailsBestPractices
|
|
91
95
|
case node.message.to_s
|
92
96
|
when "namespace"
|
93
97
|
@namespaces << node.arguments.all.first.to_s
|
98
|
+
@controller_name = nil
|
94
99
|
when "scope"
|
95
100
|
if node.arguments.all.last.hash_value("module").present?
|
96
101
|
@namespaces << node.arguments.all.last.hash_value("module").to_s
|
97
102
|
end
|
103
|
+
@controller_name = nil
|
98
104
|
when "with_options"
|
99
105
|
argument = node.arguments.all.last
|
100
106
|
if :bare_assoc_hash == argument.sexp_type && argument.hash_value("controller").present?
|
@@ -119,6 +125,16 @@ module RailsBestPractices
|
|
119
125
|
end
|
120
126
|
end
|
121
127
|
|
128
|
+
# remember current controller name, used for nested resources.
|
129
|
+
def start_do_block(node)
|
130
|
+
@controller_names << @controller_name
|
131
|
+
end
|
132
|
+
|
133
|
+
# remove current controller name, and use upper lever resource name.
|
134
|
+
def end_do_block(node)
|
135
|
+
@controller_names.pop
|
136
|
+
end
|
137
|
+
|
122
138
|
[:resources, :resource].each do |route_name|
|
123
139
|
class_eval <<-EOF
|
124
140
|
def add_#{route_name}_routes(node)
|
@@ -185,7 +201,7 @@ module RailsBestPractices
|
|
185
201
|
end
|
186
202
|
|
187
203
|
def current_controller_name
|
188
|
-
@controller_name
|
204
|
+
@controller_names.last || @controller_name
|
189
205
|
end
|
190
206
|
end
|
191
207
|
end
|
@@ -74,7 +74,9 @@ module RailsBestPractices
|
|
74
74
|
# if there are any foreign keys not existed in index columns,
|
75
75
|
# then we should add db index for that foreign keys.
|
76
76
|
def after_review
|
77
|
+
remove_table_not_exist_foreign_keys
|
77
78
|
remove_only_type_foreign_keys
|
79
|
+
combine_polymorphic_foreign_keys
|
78
80
|
@foreign_keys.each do |table, foreign_key|
|
79
81
|
table_node = @table_nodes[table]
|
80
82
|
foreign_key.each do |column|
|
@@ -122,6 +124,18 @@ module RailsBestPractices
|
|
122
124
|
end
|
123
125
|
end
|
124
126
|
|
127
|
+
# remove the non foreign keys without corresponding tables.
|
128
|
+
def remove_table_not_exist_foreign_keys
|
129
|
+
@foreign_keys.each do |table, foreign_keys|
|
130
|
+
foreign_keys.delete_if do |key|
|
131
|
+
if key =~ /_id$/
|
132
|
+
class_name = Prepares.model_associations.get_association_class_name(table, key[0..-4])
|
133
|
+
class_name ? !@table_nodes[class_name.table_name] : !@table_nodes[key[0..-4].pluralize]
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
125
139
|
# remove the non foreign keys with only _type column.
|
126
140
|
def remove_only_type_foreign_keys
|
127
141
|
@foreign_keys.each { |table, foreign_keys|
|
@@ -129,6 +143,22 @@ module RailsBestPractices
|
|
129
143
|
}
|
130
144
|
end
|
131
145
|
|
146
|
+
# combine polymorphic foreign keys, e.g.
|
147
|
+
# [tagger_id], [tagger_type] => [tagger_id, tagger_type]
|
148
|
+
def combine_polymorphic_foreign_keys
|
149
|
+
@index_columns.each { |table, foreign_keys|
|
150
|
+
foreign_id_keys = foreign_keys.select { |key| key.size == 1 && key.first =~ /_id/ }
|
151
|
+
foreign_type_keys = foreign_keys.select { |key| key.size == 1 && key.first =~ /_type/ }
|
152
|
+
foreign_id_keys.each do |id_key|
|
153
|
+
if type_key = foreign_type_keys.detect { |type_key| type_key.first == id_key.first.sub(/_id/, '') + "_type" }
|
154
|
+
foreign_keys.delete(id_key)
|
155
|
+
foreign_keys.delete(type_key)
|
156
|
+
foreign_keys << id_key + type_key
|
157
|
+
end
|
158
|
+
end
|
159
|
+
}
|
160
|
+
end
|
161
|
+
|
132
162
|
# check if the table's column is indexed.
|
133
163
|
def indexed?(table, column)
|
134
164
|
index_columns = @index_columns[table]
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rails_best_practices/reviews/review'
|
3
|
+
|
4
|
+
module RailsBestPractices
|
5
|
+
module Reviews
|
6
|
+
# Review view and helper files to make sure not use time_ago_in_words or distance_of_time_in_words_to_now.
|
7
|
+
#
|
8
|
+
# See the best practice details here http://rails-bestpractices.com/posts/105-not-use-time_ago_in_words.
|
9
|
+
#
|
10
|
+
# Implementation:
|
11
|
+
#
|
12
|
+
# Review process:
|
13
|
+
# check all fcall node to see if its message is time_ago_in_words and distance_of_time_in_words_to_now
|
14
|
+
class NotUseTimeAgoInWordsReview < Review
|
15
|
+
interesting_nodes :fcall
|
16
|
+
interesting_files VIEW_FILES, HELPER_FILES
|
17
|
+
|
18
|
+
def url
|
19
|
+
"http://rails-bestpractices.com/posts/105-not-use-time_ago_in_words"
|
20
|
+
end
|
21
|
+
|
22
|
+
# check fcall node to see if its message is time_ago_in_words or distance_of_time_in_words_to_now
|
23
|
+
def start_fcall(node)
|
24
|
+
if "time_ago_in_words" == node.message.to_s || "distance_of_time_in_words_to_now" == node.message.to_s
|
25
|
+
add_error "not use time_ago_in_words"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -98,7 +98,8 @@ module RailsBestPractices
|
|
98
98
|
end
|
99
99
|
|
100
100
|
def internal_except_methods
|
101
|
-
%w(rescue_action).map { |method_name| "*\##{method_name}" }
|
101
|
+
%w(rescue_action).map { |method_name| "*\##{method_name}" } +
|
102
|
+
%w(Devise::OmniauthCallbacksController).map { |controller_name| "#{controller_name}#*" }
|
102
103
|
end
|
103
104
|
|
104
105
|
def mark_publicize(method_name, class_name=current_class_name)
|
@@ -17,7 +17,7 @@ module RailsBestPractices
|
|
17
17
|
include Callable
|
18
18
|
include Exceptable
|
19
19
|
|
20
|
-
interesting_nodes :command
|
20
|
+
interesting_nodes :command, :command_call, :method_add_arg
|
21
21
|
interesting_files ALL_FILES
|
22
22
|
|
23
23
|
def initialize(options={})
|
@@ -31,12 +31,50 @@ module RailsBestPractices
|
|
31
31
|
end
|
32
32
|
|
33
33
|
# mark validate methods as used.
|
34
|
+
# mark key method and value method for collection_select and grouped_collection_select.
|
34
35
|
def start_command(node)
|
36
|
+
arguments = node.arguments.all
|
35
37
|
case node.message.to_s
|
36
38
|
when "validate", "validate_on_create", "validate_on_update"
|
37
|
-
|
38
|
-
|
39
|
-
|
39
|
+
arguments.each { |argument| mark_used(argument) }
|
40
|
+
when "collection_select"
|
41
|
+
mark_used(arguments[3])
|
42
|
+
mark_used(arguments[4])
|
43
|
+
when "grouped_collection_select"
|
44
|
+
mark_used(arguments[3])
|
45
|
+
mark_used(arguments[4])
|
46
|
+
mark_used(arguments[5])
|
47
|
+
mark_used(arguments[6])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# mark key method and value method for collection_select and grouped_collection_select.
|
52
|
+
def start_command_call(node)
|
53
|
+
arguments = node.arguments.all
|
54
|
+
case node.message.to_s
|
55
|
+
when "collection_select"
|
56
|
+
mark_used(arguments[2])
|
57
|
+
mark_used(arguments[3])
|
58
|
+
when "grouped_collection_select"
|
59
|
+
mark_used(arguments[2])
|
60
|
+
mark_used(arguments[3])
|
61
|
+
mark_used(arguments[4])
|
62
|
+
mark_used(arguments[5])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# mark key method and value method for options_from_collection_for_select and option_groups_from_collection_for_select.
|
67
|
+
def start_method_add_arg(node)
|
68
|
+
arguments = node.arguments.all
|
69
|
+
case node.message.to_s
|
70
|
+
when "options_from_collection_for_select"
|
71
|
+
mark_used(arguments[1])
|
72
|
+
mark_used(arguments[2])
|
73
|
+
when "option_groups_from_collection_for_select"
|
74
|
+
mark_used(arguments[1])
|
75
|
+
mark_used(arguments[2])
|
76
|
+
mark_used(arguments[3])
|
77
|
+
mark_used(arguments[4])
|
40
78
|
end
|
41
79
|
end
|
42
80
|
|
@@ -55,7 +93,11 @@ module RailsBestPractices
|
|
55
93
|
end
|
56
94
|
|
57
95
|
def internal_except_methods
|
58
|
-
%w(
|
96
|
+
%w(
|
97
|
+
initialize validate validate_each to_xml to_json assign_attributes after_find after_initialize
|
98
|
+
before_save before_create before_update before_destroy after_save after_create after_update after_destroy
|
99
|
+
to_param method_missing
|
100
|
+
).map { |method_name| "*\##{method_name}" }
|
59
101
|
end
|
60
102
|
end
|
61
103
|
end
|
@@ -86,10 +86,10 @@ module RailsBestPractices
|
|
86
86
|
if hash_key_exist?(option_node,"controller")
|
87
87
|
name = option_node.hash_value("controller").to_s
|
88
88
|
else
|
89
|
-
name = node.arguments.all.first.to_s.
|
89
|
+
name = node.arguments.all.first.to_s.table_name
|
90
90
|
end
|
91
91
|
else
|
92
|
-
name = node.arguments.all.first.to_s.
|
92
|
+
name = node.arguments.all.first.to_s.table_name
|
93
93
|
end
|
94
94
|
namespaced_class_name(name)
|
95
95
|
end
|
@@ -29,3 +29,4 @@ require 'rails_best_practices/reviews/restrict_auto_generated_routes_review'
|
|
29
29
|
require 'rails_best_practices/reviews/remove_unused_methods_in_models_review'
|
30
30
|
require 'rails_best_practices/reviews/remove_unused_methods_in_controllers_review'
|
31
31
|
require 'rails_best_practices/reviews/remove_unused_methods_in_helpers_review'
|
32
|
+
require 'rails_best_practices/reviews/not_use_time_ago_in_words_review'
|
data/rails_best_practices.yml
CHANGED
@@ -2,15 +2,27 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe RailsBestPractices::Core::Error do
|
4
4
|
it "should return error with filename, line number and message" do
|
5
|
-
RailsBestPractices::Core::Error.new(
|
5
|
+
RailsBestPractices::Core::Error.new(
|
6
|
+
:filename => "app/models/user.rb",
|
7
|
+
:line_number => "100",
|
8
|
+
:message => "not good",
|
9
|
+
:type => "BogusReview").to_s.should == "app/models/user.rb:100 - not good"
|
6
10
|
end
|
7
11
|
|
8
12
|
it "should return short filename" do
|
9
13
|
RailsBestPractices::Core::Runner.base_path = "../rails-bestpractices.com"
|
10
|
-
RailsBestPractices::Core::Error.new(
|
14
|
+
RailsBestPractices::Core::Error.new(
|
15
|
+
:filename => "../rails-bestpractices.com/app/models/user.rb",
|
16
|
+
:line_number => "100",
|
17
|
+
:message => "not good",
|
18
|
+
:type => "BogusReview").short_filename.should == "app/models/user.rb"
|
11
19
|
end
|
12
20
|
|
13
21
|
it "should return first line number" do
|
14
|
-
RailsBestPractices::Core::Error.new(
|
22
|
+
RailsBestPractices::Core::Error.new(
|
23
|
+
:filename => "app/models/user.rb",
|
24
|
+
:line_number => "50,70,100",
|
25
|
+
:message => "not good",
|
26
|
+
:type => "BogusReview").first_line_number.should == "50"
|
15
27
|
end
|
16
28
|
end
|
@@ -281,10 +281,15 @@ describe Sexp do
|
|
281
281
|
end
|
282
282
|
|
283
283
|
describe "method_name" do
|
284
|
-
it "should get the method name of
|
284
|
+
it "should get the method name of def" do
|
285
285
|
node = parse_content("def show; end").grep_node(:sexp_type => :def)
|
286
286
|
node.method_name.to_s.should == "show"
|
287
287
|
end
|
288
|
+
|
289
|
+
it "should get the method name of defs" do
|
290
|
+
node = parse_content("def self.find; end").grep_node(:sexp_type => :defs)
|
291
|
+
node.method_name.to_s.should == "find"
|
292
|
+
end
|
288
293
|
end
|
289
294
|
|
290
295
|
describe "body" do
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe RailsBestPractices::Prepares::HelperPrepare do
|
4
|
-
let(:runner) { RailsBestPractices::Core::Runner.new(:
|
4
|
+
let(:runner) { RailsBestPractices::Core::Runner.new(:prepares => RailsBestPractices::Prepares::HelperPrepare.new) }
|
5
5
|
|
6
6
|
context "methods" do
|
7
7
|
it "should parse helper methods" do
|
@@ -93,6 +93,46 @@ describe RailsBestPractices::Prepares::ModelPrepare do
|
|
93
93
|
model_associations = RailsBestPractices::Prepares.model_associations
|
94
94
|
model_associations.get_association("Citizen", "nations").should == {"meta" => "has_and_belongs_to_many", "class_name" => "Country"}
|
95
95
|
end
|
96
|
+
|
97
|
+
context "namespace" do
|
98
|
+
it "should parse with namespace" do
|
99
|
+
content =<<-EOF
|
100
|
+
class Community < ActiveRecord::Base
|
101
|
+
has_many :members
|
102
|
+
end
|
103
|
+
EOF
|
104
|
+
runner.prepare("app/models/community.rb", content)
|
105
|
+
content =<<-EOF
|
106
|
+
class Community::Member < ActiveRecord::Base
|
107
|
+
belongs_to :community
|
108
|
+
end
|
109
|
+
EOF
|
110
|
+
runner.prepare("app/models/community/member.rb", content)
|
111
|
+
runner.after_prepare
|
112
|
+
model_associations = RailsBestPractices::Prepares.model_associations
|
113
|
+
model_associations.get_association("Community", "members").should == {"meta" => "has_many", "class_name" => "Community::Member"}
|
114
|
+
model_associations.get_association("Community::Member", "community").should == {"meta" => "belongs_to", "class_name" => "Community"}
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should parse without namespace" do
|
118
|
+
content =<<-EOF
|
119
|
+
class Community::Member::Rating < ActiveRecord::Base
|
120
|
+
belongs_to :member
|
121
|
+
end
|
122
|
+
EOF
|
123
|
+
runner.prepare("app/models/community/member/rating.rb", content)
|
124
|
+
content =<<-EOF
|
125
|
+
class Community::Member < ActiveRecord::Base
|
126
|
+
has_many :ratings
|
127
|
+
end
|
128
|
+
EOF
|
129
|
+
runner.prepare("app/models/community/member.rb", content)
|
130
|
+
runner.after_prepare
|
131
|
+
model_associations = RailsBestPractices::Prepares.model_associations
|
132
|
+
model_associations.get_association("Community::Member::Rating", "member").should == {"meta" => "belongs_to", "class_name" => "Community::Member"}
|
133
|
+
model_associations.get_association("Community::Member", "ratings").should == {"meta" => "has_many", "class_name" => "Community::Member::Rating"}
|
134
|
+
end
|
135
|
+
end
|
96
136
|
end
|
97
137
|
|
98
138
|
context "mongoid embeds" do
|
@@ -255,6 +255,18 @@ describe RailsBestPractices::Prepares::RoutePrepare do
|
|
255
255
|
routes = RailsBestPractices::Prepares.routes
|
256
256
|
routes.map(&:to_s).should == ["AdminSessionController#new"]
|
257
257
|
end
|
258
|
+
|
259
|
+
it "should not take former resources for direct get/post" do
|
260
|
+
content =<<-EOF
|
261
|
+
ActionController::Routing::Routes.draw do |map|
|
262
|
+
map.resources :posts
|
263
|
+
map.stop 'sprints/stop', :controller => 'sprints', :action => 'stop'
|
264
|
+
end
|
265
|
+
EOF
|
266
|
+
runner.prepare('config/routes.rb', content)
|
267
|
+
routes = RailsBestPractices::Prepares.routes
|
268
|
+
routes.last.to_s.should == "SprintsController#stop"
|
269
|
+
end
|
258
270
|
end
|
259
271
|
|
260
272
|
context "rails3" do
|
@@ -517,6 +529,18 @@ describe RailsBestPractices::Prepares::RoutePrepare do
|
|
517
529
|
routes.map(&:to_s).should == ["PostsController#show", "PostsController#create", "PostsController#update", "PostsController#destroy", "HighVoltage::PagesController#show"]
|
518
530
|
end
|
519
531
|
|
532
|
+
it "should add routes for another get/post" do
|
533
|
+
content =<<-EOF
|
534
|
+
RailsBestPracticesCom::Application.routes.draw do
|
535
|
+
get "/login", to: 'sessions#new', as: :login
|
536
|
+
end
|
537
|
+
EOF
|
538
|
+
runner.prepare('config/routes.rb', content)
|
539
|
+
routes = RailsBestPractices::Prepares.routes
|
540
|
+
routes.size.should == 1
|
541
|
+
routes.first.to_s.should == "SessionsController#new"
|
542
|
+
end
|
543
|
+
|
520
544
|
it "should add match route" do
|
521
545
|
content =<<-EOF
|
522
546
|
RailsBestPracticesCom::Application.routes.draw do
|
@@ -572,5 +596,31 @@ describe RailsBestPractices::Prepares::RoutePrepare do
|
|
572
596
|
routes = RailsBestPractices::Prepares.routes
|
573
597
|
routes.size.should == 0
|
574
598
|
end
|
599
|
+
|
600
|
+
it "should parse customize route in nested resources" do
|
601
|
+
content =<<-EOF
|
602
|
+
RailsBestPracticesCom::Application.routes.draw do
|
603
|
+
resources :posts do
|
604
|
+
resources :comments
|
605
|
+
post :stop
|
606
|
+
end
|
607
|
+
end
|
608
|
+
EOF
|
609
|
+
runner.prepare('config/routes.rb', content)
|
610
|
+
routes = RailsBestPractices::Prepares.routes
|
611
|
+
routes.last.to_s.should == "PostsController#stop"
|
612
|
+
end
|
613
|
+
|
614
|
+
it "should not take former resources for direct get/post" do
|
615
|
+
content =<<-EOF
|
616
|
+
RailsBestPracticesCom::Application.routes.draw do
|
617
|
+
resources :posts
|
618
|
+
post "sprints/stop"
|
619
|
+
end
|
620
|
+
EOF
|
621
|
+
runner.prepare('config/routes.rb', content)
|
622
|
+
routes = RailsBestPractices::Prepares.routes
|
623
|
+
routes.last.to_s.should == "SprintsController#stop"
|
624
|
+
end
|
575
625
|
end
|
576
626
|
end
|
@@ -13,6 +13,10 @@ describe RailsBestPractices::Reviews::AlwaysAddDbIndexReview do
|
|
13
13
|
t.integer "post_id"
|
14
14
|
t.integer "user_id"
|
15
15
|
end
|
16
|
+
create_table "posts", :force => true do |t|
|
17
|
+
end
|
18
|
+
create_table "users", :force => true do |t|
|
19
|
+
end
|
16
20
|
end
|
17
21
|
EOF
|
18
22
|
runner.review('db/schema.rb', content)
|
@@ -62,6 +66,8 @@ describe RailsBestPractices::Reviews::AlwaysAddDbIndexReview do
|
|
62
66
|
t.integer "taggable_id"
|
63
67
|
t.string "taggable_type"
|
64
68
|
end
|
69
|
+
create_table "tags", :force => true do |t|
|
70
|
+
end
|
65
71
|
|
66
72
|
add_index "taggings", ["tag_id"], :name => "index_taggings_on_tag_id"
|
67
73
|
end
|
@@ -80,6 +86,8 @@ describe RailsBestPractices::Reviews::AlwaysAddDbIndexReview do
|
|
80
86
|
t.integer "taggable_id"
|
81
87
|
t.string "taggable_type"
|
82
88
|
end
|
89
|
+
create_table "tags", :force => true do |t|
|
90
|
+
end
|
83
91
|
|
84
92
|
add_index "taggings", ["taggable_id", "taggable_type"], :name => "index_taggings_on_taggable_id_and_taggable_type"
|
85
93
|
end
|
@@ -99,6 +107,8 @@ describe RailsBestPractices::Reviews::AlwaysAddDbIndexReview do
|
|
99
107
|
t.integer "icon_file_size"
|
100
108
|
t.string "icon_content_type"
|
101
109
|
end
|
110
|
+
create_table "users", :force => true do |t|
|
111
|
+
end
|
102
112
|
end
|
103
113
|
EOF
|
104
114
|
runner.review('db/schema.rb', content)
|
@@ -129,6 +139,10 @@ describe RailsBestPractices::Reviews::AlwaysAddDbIndexReview do
|
|
129
139
|
t.integer "post_id"
|
130
140
|
t.integer "user_id"
|
131
141
|
end
|
142
|
+
create_table "posts", :force => true do |t|
|
143
|
+
end
|
144
|
+
create_table "users", :force => true do |t|
|
145
|
+
end
|
132
146
|
|
133
147
|
add_index "comments", ["post_id"], :name => "index_comments_on_post_id"
|
134
148
|
add_index "comments", ["user_id"], :name => "index_comments_on_user_id"
|
@@ -185,4 +199,62 @@ describe RailsBestPractices::Reviews::AlwaysAddDbIndexReview do
|
|
185
199
|
runner.after_review
|
186
200
|
runner.should have(0).errors
|
187
201
|
end
|
202
|
+
|
203
|
+
it "should not always add db index if two indexes for polymorphic association" do
|
204
|
+
content =<<-EOF
|
205
|
+
ActiveRecord::Schema.define(:version => 20100603080629) do
|
206
|
+
create_table "taggings", :force => true do |t|
|
207
|
+
t.integer "tagger_id"
|
208
|
+
t.string "tagger_type"
|
209
|
+
t.datetime "created_at"
|
210
|
+
end
|
211
|
+
|
212
|
+
add_index "taggings", ["tagger_id"], :name => "index_taggings_on_tagger_id"
|
213
|
+
add_index "taggings", ["tagger_type"], :name => "index_taggings_on_tagger_type"
|
214
|
+
end
|
215
|
+
EOF
|
216
|
+
runner.review('db/schema.rb', content)
|
217
|
+
runner.after_review
|
218
|
+
runner.should have(0).errors
|
219
|
+
end
|
220
|
+
|
221
|
+
it "should not always add db index if table does not exist" do
|
222
|
+
content =<<-EOF
|
223
|
+
ActiveRecord::Schema.define(:version => 20100603080629) do
|
224
|
+
create_table "comments", :force => true do |t|
|
225
|
+
t.integer "post_id"
|
226
|
+
end
|
227
|
+
end
|
228
|
+
EOF
|
229
|
+
runner.review('db/schema.rb', content)
|
230
|
+
runner.after_review
|
231
|
+
runner.should have(0).errors
|
232
|
+
end
|
233
|
+
|
234
|
+
it "should always add db index if association_name is different to foreign_key" do
|
235
|
+
content =<<-EOF
|
236
|
+
class Comment < ActiveRecord::Base
|
237
|
+
belongs_to :commentor, :class_name => "User"
|
238
|
+
end
|
239
|
+
EOF
|
240
|
+
runner.prepare('app/models/comment.rb', content)
|
241
|
+
content =<<-EOF
|
242
|
+
class User < ActiveRecord::Base
|
243
|
+
end
|
244
|
+
EOF
|
245
|
+
runner.prepare('app/models/user.rb', content)
|
246
|
+
content =<<-EOF
|
247
|
+
ActiveRecord::Schema.define(:version => 20100603080629) do
|
248
|
+
create_table "comments", :force => true do |t|
|
249
|
+
t.integer "commentor_id"
|
250
|
+
end
|
251
|
+
create_table "users", :force => true do |t|
|
252
|
+
end
|
253
|
+
end
|
254
|
+
EOF
|
255
|
+
runner.review('db/schema.rb', content)
|
256
|
+
runner.after_review
|
257
|
+
runner.should have(1).errors
|
258
|
+
runner.errors[0].to_s.should == "db/schema.rb:2 - always add db index (comments => [commentor_id])"
|
259
|
+
end
|
188
260
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RailsBestPractices::Reviews::NotUseTimeAgoInWordsReview do
|
4
|
+
let(:runner) { RailsBestPractices::Core::Runner.new(:reviews => RailsBestPractices::Reviews::NotUseTimeAgoInWordsReview.new) }
|
5
|
+
|
6
|
+
describe "time_ago_in_words" do
|
7
|
+
it "should not use in views" do
|
8
|
+
content =<<-EOF
|
9
|
+
<%= time_ago_in_words(post.created_at) %>
|
10
|
+
EOF
|
11
|
+
runner.review('app/views/posts/show.html.erb', content)
|
12
|
+
runner.should have(1).errors
|
13
|
+
runner.errors[0].to_s.should == "app/views/posts/show.html.erb:1 - not use time_ago_in_words"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should not use in helpers" do
|
17
|
+
content =<<-EOF
|
18
|
+
def timeago
|
19
|
+
content_tag(:p, time_ago_in_words(post.created_at))
|
20
|
+
end
|
21
|
+
EOF
|
22
|
+
runner.review('app/helpers/posts_helper.rb', content)
|
23
|
+
runner.should have(1).errors
|
24
|
+
runner.errors[0].to_s.should == "app/helpers/posts_helper.rb:2 - not use time_ago_in_words"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "distance_of_time_in_words_to_now" do
|
29
|
+
it "should not use in views" do
|
30
|
+
content =<<-EOF
|
31
|
+
<%= distance_of_time_in_words_to_now(post.created_at) %>
|
32
|
+
EOF
|
33
|
+
runner.review('app/views/posts/show.html.erb', content)
|
34
|
+
runner.should have(1).errors
|
35
|
+
runner.errors[0].to_s.should == "app/views/posts/show.html.erb:1 - not use time_ago_in_words"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should not use in helpers" do
|
39
|
+
content =<<-EOF
|
40
|
+
def timeago
|
41
|
+
content_tag(:p, distance_of_time_in_words_to_now(post.created_at))
|
42
|
+
end
|
43
|
+
EOF
|
44
|
+
runner.review('app/helpers/posts_helper.rb', content)
|
45
|
+
runner.should have(1).errors
|
46
|
+
runner.errors[0].to_s.should == "app/helpers/posts_helper.rb:2 - not use time_ago_in_words"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -602,5 +602,69 @@ describe RailsBestPractices::Reviews::RemoveUnusedMethodsInModelsReview do
|
|
602
602
|
runner.after_review
|
603
603
|
runner.should have(0).errors
|
604
604
|
end
|
605
|
+
|
606
|
+
it "should not remove unused methods for to_param" do
|
607
|
+
content =<<-EOF
|
608
|
+
class Post < ActiveRecord::Base
|
609
|
+
def to_param
|
610
|
+
id
|
611
|
+
end
|
612
|
+
end
|
613
|
+
EOF
|
614
|
+
runner.prepare("app/models/post.rb", content)
|
615
|
+
runner.review("app/models/post.rb", content)
|
616
|
+
runner.after_review
|
617
|
+
runner.should have(0).errors
|
618
|
+
end
|
619
|
+
end
|
620
|
+
|
621
|
+
context "helper method" do
|
622
|
+
it "should not remove unused method for coommand_call collection_select" do
|
623
|
+
content =<<-EOF
|
624
|
+
class Category < ActiveRecord::Base
|
625
|
+
def indented_name; end
|
626
|
+
end
|
627
|
+
EOF
|
628
|
+
runner.prepare("app/models/category.rb", content)
|
629
|
+
runner.review("app/models/category.rb", content)
|
630
|
+
content =<<-EOF
|
631
|
+
<%= f.collection_select :parent_id, Category.all_hierarchic(except: @category), :id, :indented_name, {include_blank: true} %>
|
632
|
+
EOF
|
633
|
+
runner.review("app/views/categories/_form.html.erb", content)
|
634
|
+
runner.after_review
|
635
|
+
runner.should have(0).errors
|
636
|
+
end
|
637
|
+
|
638
|
+
it "should not remove unused method for command collection_select" do
|
639
|
+
content =<<-EOF
|
640
|
+
class Category < ActiveRecord::Base
|
641
|
+
def indented_name; end
|
642
|
+
end
|
643
|
+
EOF
|
644
|
+
runner.prepare("app/models/category.rb", content)
|
645
|
+
runner.review("app/models/category.rb", content)
|
646
|
+
content =<<-EOF
|
647
|
+
<%= collection_select :category, :parent_id, Category.all_hierarchic(except: @category), :id, :indented_name, {include_blank: true} %>
|
648
|
+
EOF
|
649
|
+
runner.review("app/views/categories/_form.html.erb", content)
|
650
|
+
runner.after_review
|
651
|
+
runner.should have(0).errors
|
652
|
+
end
|
653
|
+
|
654
|
+
it "should not remove unused method for options_from_collection_for_select" do
|
655
|
+
content =<<-EOF
|
656
|
+
class Category < ActiveRecord::Base
|
657
|
+
def indented_name; end
|
658
|
+
end
|
659
|
+
EOF
|
660
|
+
runner.prepare("app/models/category.rb", content)
|
661
|
+
runner.review("app/models/category.rb", content)
|
662
|
+
content =<<-EOF
|
663
|
+
<%= select_tag 'category', options_from_collection_for_select(Category.all_hierachic(except: @category), :id, :indented_name) %>
|
664
|
+
EOF
|
665
|
+
runner.review("app/views/categories/_form.html.erb", content)
|
666
|
+
runner.after_review
|
667
|
+
runner.should have(0).errors
|
668
|
+
end
|
605
669
|
end
|
606
670
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_best_practices
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.8.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2012-02-24 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sexp_processor
|
16
|
-
requirement: &
|
16
|
+
requirement: &70270463469100 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70270463469100
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: progressbar
|
27
|
-
requirement: &
|
27
|
+
requirement: &70270463467440 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70270463467440
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: colored
|
38
|
-
requirement: &
|
38
|
+
requirement: &70270463456860 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70270463456860
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: erubis
|
49
|
-
requirement: &
|
49
|
+
requirement: &70270463455020 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70270463455020
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: i18n
|
60
|
-
requirement: &
|
60
|
+
requirement: &70270463453880 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70270463453880
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: activesupport
|
71
|
-
requirement: &
|
71
|
+
requirement: &70270463452620 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70270463452620
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: rake
|
82
|
-
requirement: &
|
82
|
+
requirement: &70270463451560 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70270463451560
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: rspec
|
93
|
-
requirement: &
|
93
|
+
requirement: &70270463450820 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70270463450820
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: haml
|
104
|
-
requirement: &
|
104
|
+
requirement: &70270463450120 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
@@ -109,10 +109,10 @@ dependencies:
|
|
109
109
|
version: '0'
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *70270463450120
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: slim
|
115
|
-
requirement: &
|
115
|
+
requirement: &70270463444400 !ruby/object:Gem::Requirement
|
116
116
|
none: false
|
117
117
|
requirements:
|
118
118
|
- - ! '>='
|
@@ -120,10 +120,10 @@ dependencies:
|
|
120
120
|
version: '0'
|
121
121
|
type: :development
|
122
122
|
prerelease: false
|
123
|
-
version_requirements: *
|
123
|
+
version_requirements: *70270463444400
|
124
124
|
- !ruby/object:Gem::Dependency
|
125
125
|
name: bundler
|
126
|
-
requirement: &
|
126
|
+
requirement: &70270463443380 !ruby/object:Gem::Requirement
|
127
127
|
none: false
|
128
128
|
requirements:
|
129
129
|
- - ! '>='
|
@@ -131,7 +131,7 @@ dependencies:
|
|
131
131
|
version: '0'
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
|
-
version_requirements: *
|
134
|
+
version_requirements: *70270463443380
|
135
135
|
description: a code metric tool for rails codes, written in Ruby.
|
136
136
|
email:
|
137
137
|
- flyerhzm@gmail.com
|
@@ -179,6 +179,7 @@ files:
|
|
179
179
|
- lib/rails_best_practices/core_ext/enumerable.rb
|
180
180
|
- lib/rails_best_practices/core_ext/erubis.rb
|
181
181
|
- lib/rails_best_practices/core_ext/sexp.rb
|
182
|
+
- lib/rails_best_practices/core_ext/string.rb
|
182
183
|
- lib/rails_best_practices/lexicals.rb
|
183
184
|
- lib/rails_best_practices/lexicals/remove_tab_check.rb
|
184
185
|
- lib/rails_best_practices/lexicals/remove_trailing_whitespace_check.rb
|
@@ -203,6 +204,7 @@ files:
|
|
203
204
|
- lib/rails_best_practices/reviews/move_model_logic_into_model_review.rb
|
204
205
|
- lib/rails_best_practices/reviews/needless_deep_nesting_review.rb
|
205
206
|
- lib/rails_best_practices/reviews/not_use_default_route_review.rb
|
207
|
+
- lib/rails_best_practices/reviews/not_use_time_ago_in_words_review.rb
|
206
208
|
- lib/rails_best_practices/reviews/overuse_route_customizations_review.rb
|
207
209
|
- lib/rails_best_practices/reviews/remove_empty_helpers_review.rb
|
208
210
|
- lib/rails_best_practices/reviews/remove_unused_methods_in_controllers_review.rb
|
@@ -266,6 +268,7 @@ files:
|
|
266
268
|
- spec/rails_best_practices/reviews/move_model_logic_into_model_review_spec.rb
|
267
269
|
- spec/rails_best_practices/reviews/needless_deep_nesting_review_spec.rb
|
268
270
|
- spec/rails_best_practices/reviews/not_use_default_route_review_spec.rb
|
271
|
+
- spec/rails_best_practices/reviews/not_use_times_ago_in_words_review_spec.rb
|
269
272
|
- spec/rails_best_practices/reviews/overuse_route_customizations_review_spec.rb
|
270
273
|
- spec/rails_best_practices/reviews/remove_empty_helpers_review_spec.rb
|
271
274
|
- spec/rails_best_practices/reviews/remove_unused_methods_in_controllers_review_spec.rb
|
@@ -289,7 +292,8 @@ licenses: []
|
|
289
292
|
post_install_message: ! "********************************************************************************\n\n
|
290
293
|
\ rails_best_practices is a code metric tool to check the quality of rails codes.\n\n
|
291
294
|
\ I highly recommend you browse the Rails Best Practices website first.\n\n http://rails-bestpractices.com\n\n
|
292
|
-
\
|
295
|
+
\ Please also try our online service\n\n https://railsbp.com\n\n Enjoy!\n\n
|
296
|
+
\ Richard Huang (flyerhzm@gmail.com)\n\n********************************************************************************\n"
|
293
297
|
rdoc_options: []
|
294
298
|
require_paths:
|
295
299
|
- lib
|
@@ -302,7 +306,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
302
306
|
version: '0'
|
303
307
|
segments:
|
304
308
|
- 0
|
305
|
-
hash:
|
309
|
+
hash: 920336894600409116
|
306
310
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
307
311
|
none: false
|
308
312
|
requirements:
|
@@ -311,7 +315,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
311
315
|
version: 1.3.6
|
312
316
|
requirements: []
|
313
317
|
rubyforge_project:
|
314
|
-
rubygems_version: 1.8.
|
318
|
+
rubygems_version: 1.8.15
|
315
319
|
signing_key:
|
316
320
|
specification_version: 3
|
317
321
|
summary: a code metric tool for rails codes.
|
@@ -357,6 +361,7 @@ test_files:
|
|
357
361
|
- spec/rails_best_practices/reviews/move_model_logic_into_model_review_spec.rb
|
358
362
|
- spec/rails_best_practices/reviews/needless_deep_nesting_review_spec.rb
|
359
363
|
- spec/rails_best_practices/reviews/not_use_default_route_review_spec.rb
|
364
|
+
- spec/rails_best_practices/reviews/not_use_times_ago_in_words_review_spec.rb
|
360
365
|
- spec/rails_best_practices/reviews/overuse_route_customizations_review_spec.rb
|
361
366
|
- spec/rails_best_practices/reviews/remove_empty_helpers_review_spec.rb
|
362
367
|
- spec/rails_best_practices/reviews/remove_unused_methods_in_controllers_review_spec.rb
|