rails_best_practices 1.7.2 → 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Build Status](https://secure.travis-ci.org/railsbp/rails_best_practices.png)](http://travis-ci.org/railsbp/rails_best_practices)
|
5
5
|
|
6
|
-
[![Click here to lend your support to: rails
|
6
|
+
[![Click here to lend your support to: rails best practices and make a donation at www.pledgie.com !](http://www.pledgie.com/campaigns/12057.png?skin_name=chrome)](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
|