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.
Files changed (32) hide show
  1. data/Gemfile.lock +1 -1
  2. data/README.md +5 -1
  3. data/lib/rails_best_practices/analyzer.rb +15 -1
  4. data/lib/rails_best_practices/command.rb +11 -1
  5. data/lib/rails_best_practices/core/check.rb +12 -5
  6. data/lib/rails_best_practices/core/error.rb +10 -6
  7. data/lib/rails_best_practices/core/model_associations.rb +16 -1
  8. data/lib/rails_best_practices/core/runner.rb +1 -0
  9. data/lib/rails_best_practices/core.rb +1 -0
  10. data/lib/rails_best_practices/core_ext/sexp.rb +6 -2
  11. data/lib/rails_best_practices/core_ext/string.rb +5 -0
  12. data/lib/rails_best_practices/prepares/model_prepare.rb +37 -2
  13. data/lib/rails_best_practices/prepares/route_prepare.rb +19 -3
  14. data/lib/rails_best_practices/reviews/always_add_db_index_review.rb +30 -0
  15. data/lib/rails_best_practices/reviews/not_use_time_ago_in_words_review.rb +30 -0
  16. data/lib/rails_best_practices/reviews/remove_unused_methods_in_controllers_review.rb +2 -1
  17. data/lib/rails_best_practices/reviews/remove_unused_methods_in_helpers_review.rb +1 -1
  18. data/lib/rails_best_practices/reviews/remove_unused_methods_in_models_review.rb +47 -5
  19. data/lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb +2 -2
  20. data/lib/rails_best_practices/reviews.rb +1 -0
  21. data/lib/rails_best_practices/version.rb +1 -1
  22. data/rails_best_practices.gemspec +4 -0
  23. data/rails_best_practices.yml +1 -0
  24. data/spec/rails_best_practices/core/error_spec.rb +15 -3
  25. data/spec/rails_best_practices/core_ext/sexp_spec.rb +6 -1
  26. data/spec/rails_best_practices/prepares/helper_prepare_spec.rb +1 -1
  27. data/spec/rails_best_practices/prepares/model_prepare_spec.rb +40 -0
  28. data/spec/rails_best_practices/prepares/route_prepare_spec.rb +50 -0
  29. data/spec/rails_best_practices/reviews/always_add_db_index_review_spec.rb +72 -0
  30. data/spec/rails_best_practices/reviews/not_use_times_ago_in_words_review_spec.rb +49 -0
  31. data/spec/rails_best_practices/reviews/remove_unused_methods_in_models_review_spec.rb +64 -0
  32. metadata +32 -27
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rails_best_practices (1.7.2)
4
+ rails_best_practices (1.8.0)
5
5
  activesupport
6
6
  colored
7
7
  erubis
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-bestpractices.com and make a donation at www.pledgie.com !](https://www.pledgie.com/campaigns/12057.png?skin_name=chrome)](http://www.pledgie.com/campaigns/12057)
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 #{error.filename[@runner.class.base_path.size..-1]} | sed -n #{error.line_number.split(',').first}p`
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(/,/).map{|x| Regexp.new x}
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] file, is the filename of source code
77
- # @param [Integer] line, is the line number of the source code which is reviewing
78
- def add_error(message, file = @node.file, line = @node.line)
79
- errors << RailsBestPractices::Core::Error.new("#{file}", "#{line}", message, self.class.to_s, url)
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 /(before|after)_/
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(filename, line_number, message, type, url = nil)
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
@@ -3,6 +3,7 @@ require 'yaml'
3
3
  require 'ripper'
4
4
  require 'active_support/inflector'
5
5
  require 'active_support/core_ext/object/blank'
6
+ require 'active_support/core_ext/object/try'
6
7
 
7
8
  module RailsBestPractices
8
9
  module Core
@@ -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
- if :def == sexp_type
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
 
@@ -0,0 +1,5 @@
1
+ class String
2
+ def table_name
3
+ self.gsub("::", "").tableize
4
+ end
5
+ end
@@ -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 ref node to remember all methods.
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
- if current_controller_name.present?
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)
@@ -40,7 +40,7 @@ module RailsBestPractices
40
40
  end
41
41
 
42
42
  def internal_except_methods
43
- []
43
+ ["*#url_for"]
44
44
  end
45
45
  end
46
46
  end
@@ -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
- node.arguments.all.each { |argument| mark_used(argument) }
38
- else
39
- # nothing
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(initialize validate validate_each to_xml to_json assign_attributes after_find after_initialize).map { |method_name| "*\##{method_name}" }
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.tableize
89
+ name = node.arguments.all.first.to_s.table_name
90
90
  end
91
91
  else
92
- name = node.arguments.all.first.to_s.tableize
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'
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module RailsBestPractices
3
- VERSION = "1.7.2"
3
+ VERSION = "1.8.0"
4
4
  end
@@ -40,6 +40,10 @@ Gem::Specification.new do |s|
40
40
 
41
41
  http://rails-bestpractices.com
42
42
 
43
+ Please also try our online service
44
+
45
+ https://railsbp.com
46
+
43
47
  Enjoy!
44
48
 
45
49
  Richard Huang (flyerhzm@gmail.com)
@@ -30,3 +30,4 @@ RestrictAutoGeneratedRoutesCheck: { }
30
30
  RemoveUnusedMethodsInModelsCheck: { except_methods: [] }
31
31
  RemoveUnusedMethodsInControllersCheck: { except_methods: [] }
32
32
  RemoveUnusedMethodsInHelpersCheck: { except_methods: [] }
33
+ NotUseTimeAgoInWordsCheck: { }
@@ -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("app/models/user.rb", "100", "not good", "BogusReview").to_s.should == "app/models/user.rb:100 - not good"
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("../rails-bestpractices.com/app/models/user.rb", "100", "not good", "BogusReview").short_filename.should == "app/models/user.rb"
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("app/models/user.rb", "50,70,100", "not good", "BogusReview").first_line_number.should == "50"
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 defn" do
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(:parepare => RailsBestPractices::Prepares::HelperPrepare.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.7.2
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: 2011-12-28 00:00:00.000000000Z
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: &70233747842020 !ruby/object:Gem::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: *70233747842020
24
+ version_requirements: *70270463469100
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: progressbar
27
- requirement: &70233747840780 !ruby/object:Gem::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: *70233747840780
35
+ version_requirements: *70270463467440
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: colored
38
- requirement: &70233747835040 !ruby/object:Gem::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: *70233747835040
46
+ version_requirements: *70270463456860
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: erubis
49
- requirement: &70233747833880 !ruby/object:Gem::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: *70233747833880
57
+ version_requirements: *70270463455020
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: i18n
60
- requirement: &70233747832640 !ruby/object:Gem::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: *70233747832640
68
+ version_requirements: *70270463453880
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: activesupport
71
- requirement: &70233747831960 !ruby/object:Gem::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: *70233747831960
79
+ version_requirements: *70270463452620
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rake
82
- requirement: &70233747831080 !ruby/object:Gem::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: *70233747831080
90
+ version_requirements: *70270463451560
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: rspec
93
- requirement: &70233747830280 !ruby/object:Gem::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: *70233747830280
101
+ version_requirements: *70270463450820
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: haml
104
- requirement: &70233747829320 !ruby/object:Gem::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: *70233747829320
112
+ version_requirements: *70270463450120
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: slim
115
- requirement: &70233747828460 !ruby/object:Gem::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: *70233747828460
123
+ version_requirements: *70270463444400
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: bundler
126
- requirement: &70233747827520 !ruby/object:Gem::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: *70233747827520
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
- \ Enjoy!\n\n Richard Huang (flyerhzm@gmail.com)\n\n********************************************************************************\n"
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: 539864756318375074
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.10
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