rails_best_practices 1.15.1 → 1.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/rails_best_practices/core/check.rb +24 -7
- data/lib/rails_best_practices/core/checks_loader.rb +48 -0
- data/lib/rails_best_practices/core/runner.rb +6 -47
- data/lib/rails_best_practices/reviews/remove_unused_methods_in_controllers_review.rb +1 -1
- data/lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb +19 -0
- data/lib/rails_best_practices/reviews/use_observer_review.rb +1 -1
- data/lib/rails_best_practices/version.rb +1 -1
- data/spec/rails_best_practices/core/checks_loader_spec.rb +21 -0
- data/spec/rails_best_practices/core/except_methods_spec.rb +63 -0
- data/spec/rails_best_practices/reviews/restrict_auto_generated_routes_review_spec.rb +27 -1
- metadata +7 -3
- data/.gemtest +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 16424767a639f93e65221ccb0a759de20b7ce9fa
|
4
|
+
data.tar.gz: ce5f1080da4406d14d893246af12360ada46308f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 998a80e8e4399e80a8cb555ac596a2758c8beea6bd2f7e8fe13017b4a8931baa40efd2f892a899733dd94803418bdadde63069e21cd351e5dee9db49a2ce8adc
|
7
|
+
data.tar.gz: fb113c8116c5b0e575d2b6fed6e500b83bad9d96fbace45bdbfbb1eca6f5ebf77648ba1af5e16a09327e7a6eb1dc90e9a29e4b1268e9b4cfd2c8b57fe03caaaf
|
@@ -347,13 +347,7 @@ module RailsBestPractices
|
|
347
347
|
# check if the method is in the except methods list.
|
348
348
|
def excepted?(method)
|
349
349
|
is_ignored?(method.file) ||
|
350
|
-
except_methods.any?
|
351
|
-
class_name, method_name = except_method.split('#')
|
352
|
-
(class_name == '*' && method_name == method.method_name) ||
|
353
|
-
(method_name == '*' && class_name == method.class_name) ||
|
354
|
-
(method_name == '*' && class_name == Prepares.klasses.find { |klass| klass.class_name == method.class_name }.try(:extend_class_name)) ||
|
355
|
-
(class_name == method.class_name && method_name == method.method_name)
|
356
|
-
end
|
350
|
+
except_methods.any? { |except_method| Exceptable.matches method, except_method }
|
357
351
|
end
|
358
352
|
|
359
353
|
def internal_except_methods
|
@@ -361,6 +355,29 @@ module RailsBestPractices
|
|
361
355
|
end
|
362
356
|
end
|
363
357
|
end
|
358
|
+
|
359
|
+
def self.matches method, except_method
|
360
|
+
class_name, method_name = except_method.split('#')
|
361
|
+
|
362
|
+
method_name = ".*" if method_name == "*"
|
363
|
+
method_expression = Regexp.new method_name
|
364
|
+
matched = method.method_name =~ method_expression
|
365
|
+
|
366
|
+
if matched
|
367
|
+
class_name = ".*" if class_name == "*"
|
368
|
+
class_expression = Regexp.new class_name
|
369
|
+
|
370
|
+
class_names = Prepares.klasses
|
371
|
+
.select { |klass| klass.class_name == method.class_name }
|
372
|
+
.map(&:extend_class_name)
|
373
|
+
.compact
|
374
|
+
|
375
|
+
class_names.unshift method.class_name
|
376
|
+
matched = class_names.any? { |name| name =~ class_expression }
|
377
|
+
end
|
378
|
+
|
379
|
+
!!matched
|
380
|
+
end
|
364
381
|
end
|
365
382
|
|
366
383
|
# Helper to parse the access control.
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module RailsBestPractices
|
3
|
+
module Core
|
4
|
+
class ChecksLoader
|
5
|
+
def initialize(config)
|
6
|
+
@config = config
|
7
|
+
end
|
8
|
+
|
9
|
+
# load all lexical checks.
|
10
|
+
def load_lexicals
|
11
|
+
load_checks_from_config { |check_name| RailsBestPractices::Lexicals.const_get(check_name) }
|
12
|
+
end
|
13
|
+
|
14
|
+
# load all reviews according to configuration.
|
15
|
+
def load_reviews
|
16
|
+
load_checks_from_config { |check_name| RailsBestPractices::Reviews.const_get(check_name.gsub(/Check$/, 'Review')) }
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
# read the checks from yaml config.
|
21
|
+
def checks_from_config
|
22
|
+
@checks ||= YAML.load_file @config
|
23
|
+
end
|
24
|
+
|
25
|
+
# load all checks from the configuration
|
26
|
+
def load_checks_from_config(&block)
|
27
|
+
checks_from_config.inject([]) do |active_checks, check|
|
28
|
+
check_instance = instantiate_check(block, *check)
|
29
|
+
active_checks << check_instance unless check_instance.nil?
|
30
|
+
active_checks
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# instantiates a check
|
35
|
+
def instantiate_check(block, check_name, options)
|
36
|
+
check_class = load_check_class(check_name, &block)
|
37
|
+
check_class.new(options || {}) unless check_class.nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
# loads the class for a check by calling the given block
|
41
|
+
def load_check_class(check_name, &block)
|
42
|
+
block.call(check_name)
|
43
|
+
rescue NameError
|
44
|
+
# nothing to do, the check does not exist
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -43,9 +43,11 @@ module RailsBestPractices
|
|
43
43
|
lexicals = Array(options[:lexicals])
|
44
44
|
prepares = Array(options[:prepares])
|
45
45
|
reviews = Array(options[:reviews])
|
46
|
-
|
46
|
+
|
47
|
+
checks_loader = ChecksLoader.new(@config)
|
48
|
+
@lexicals = lexicals.empty? ? checks_loader.load_lexicals : lexicals
|
47
49
|
@prepares = prepares.empty? ? load_prepares : prepares
|
48
|
-
@reviews = reviews.empty? ? load_reviews : reviews
|
50
|
+
@reviews = reviews.empty? ? checks_loader.load_reviews : reviews
|
49
51
|
load_plugin_reviews if reviews.empty?
|
50
52
|
|
51
53
|
@lexical_checker ||= CodeAnalyzer::CheckingVisitor::Plain.new(checkers: @lexicals)
|
@@ -66,7 +68,7 @@ module RailsBestPractices
|
|
66
68
|
@lexical_checker.after_check
|
67
69
|
end
|
68
70
|
|
69
|
-
#
|
71
|
+
# prepare the file.
|
70
72
|
#
|
71
73
|
# @param [String] filename of the file
|
72
74
|
# @param [String] content of the file
|
@@ -101,7 +103,7 @@ module RailsBestPractices
|
|
101
103
|
end
|
102
104
|
|
103
105
|
private
|
104
|
-
# parse html
|
106
|
+
# parse html template code, erb, haml and slim.
|
105
107
|
#
|
106
108
|
# @param [String] filename is the filename of the erb, haml or slim code.
|
107
109
|
# @param [String] content is the source code of erb, haml or slim file.
|
@@ -132,41 +134,11 @@ module RailsBestPractices
|
|
132
134
|
content
|
133
135
|
end
|
134
136
|
|
135
|
-
# load all lexical checks.
|
136
|
-
def load_lexicals
|
137
|
-
checks_from_config.inject([]) { |active_checks, check|
|
138
|
-
begin
|
139
|
-
check_name, options = *check
|
140
|
-
klass = RailsBestPractices::Lexicals.const_get(check_name)
|
141
|
-
options = Hash(options)
|
142
|
-
active_checks << (options.empty? ? klass.new : klass.new(options))
|
143
|
-
rescue
|
144
|
-
# the check does not exist in the Lexicals namepace.
|
145
|
-
end
|
146
|
-
active_checks
|
147
|
-
}
|
148
|
-
end
|
149
|
-
|
150
137
|
# load all prepares.
|
151
138
|
def load_prepares
|
152
139
|
Prepares.constants.map { |prepare| Prepares.const_get(prepare).new }
|
153
140
|
end
|
154
141
|
|
155
|
-
# load all reviews according to configuration.
|
156
|
-
def load_reviews
|
157
|
-
checks_from_config.inject([]) { |active_checks, check|
|
158
|
-
begin
|
159
|
-
check_name, options = *check
|
160
|
-
klass = RailsBestPractices::Reviews.const_get(check_name.gsub(/Check$/, 'Review'))
|
161
|
-
options = Hash(options)
|
162
|
-
active_checks << (options.empty? ? klass.new : klass.new(options))
|
163
|
-
rescue
|
164
|
-
# the check does not exist in the Reviews namepace.
|
165
|
-
end
|
166
|
-
active_checks
|
167
|
-
}
|
168
|
-
end
|
169
|
-
|
170
142
|
# load all plugin reviews.
|
171
143
|
def load_plugin_reviews
|
172
144
|
begin
|
@@ -183,19 +155,6 @@ module RailsBestPractices
|
|
183
155
|
end
|
184
156
|
end
|
185
157
|
end
|
186
|
-
|
187
|
-
# read the checks from yaml config.
|
188
|
-
def checks_from_config
|
189
|
-
@checks ||= YAML.load_file @config
|
190
|
-
end
|
191
|
-
|
192
|
-
# read the file content.
|
193
|
-
#
|
194
|
-
# @param [String] filename
|
195
|
-
# @return [String] file conent
|
196
|
-
def read_file(filename)
|
197
|
-
File.open(filename, "r:UTF-8") { |f| f.read }
|
198
|
-
end
|
199
158
|
end
|
200
159
|
end
|
201
160
|
end
|
@@ -105,7 +105,7 @@ module RailsBestPractices
|
|
105
105
|
end
|
106
106
|
|
107
107
|
def internal_except_methods
|
108
|
-
%w(rescue_action).map { |method_name| "*\##{method_name}" } +
|
108
|
+
%w(rescue_action default_url_options).map { |method_name| "*\##{method_name}" } +
|
109
109
|
%w(Devise::OmniauthCallbacksController).map { |controller_name| "#{controller_name}#*" }
|
110
110
|
end
|
111
111
|
|
@@ -29,6 +29,9 @@ module RailsBestPractices
|
|
29
29
|
# check if the generated routes have the corresponding actions in controller for rails routes.
|
30
30
|
add_callback :start_command, :start_command_call do |node|
|
31
31
|
if "resources" == node.message.to_s
|
32
|
+
if (mod = module_option(node))
|
33
|
+
@namespaces << mod
|
34
|
+
end
|
32
35
|
check_resources(node)
|
33
36
|
@resource_controllers << node.arguments.all.first.to_s
|
34
37
|
elsif "resource" == node.message.to_s
|
@@ -40,6 +43,7 @@ module RailsBestPractices
|
|
40
43
|
add_callback :end_command do |node|
|
41
44
|
if "resources" == node.message.to_s
|
42
45
|
@resource_controllers.pop
|
46
|
+
@namespaces.pop if module_option(node)
|
43
47
|
elsif "resource" == node.message.to_s
|
44
48
|
@resource_controllers.pop
|
45
49
|
end
|
@@ -52,6 +56,10 @@ module RailsBestPractices
|
|
52
56
|
@namespaces << node.arguments.all.first.to_s if check_method_add_block?(node)
|
53
57
|
when "resources", "resource"
|
54
58
|
@resource_controllers << node.arguments.all.first.to_s if check_method_add_block?(node)
|
59
|
+
when 'scope'
|
60
|
+
if check_method_add_block?(node) && (mod = module_option(node))
|
61
|
+
@namespaces << mod
|
62
|
+
end
|
55
63
|
else
|
56
64
|
end
|
57
65
|
end
|
@@ -64,6 +72,10 @@ module RailsBestPractices
|
|
64
72
|
@namespaces.pop
|
65
73
|
when "resources", "resource"
|
66
74
|
@resource_controllers.pop
|
75
|
+
when 'scope'
|
76
|
+
if check_method_add_block?(node) && module_option(node)
|
77
|
+
@namespaces.pop
|
78
|
+
end
|
67
79
|
end
|
68
80
|
end
|
69
81
|
end
|
@@ -143,6 +155,13 @@ module RailsBestPractices
|
|
143
155
|
end
|
144
156
|
end
|
145
157
|
|
158
|
+
def module_option(node)
|
159
|
+
option_node = node.arguments[1].last
|
160
|
+
if option_node && option_node.sexp_type == :bare_assoc_hash && hash_key_exist?(option_node, 'module')
|
161
|
+
option_node.hash_value('module').to_s
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
146
165
|
def option_with_hash(node)
|
147
166
|
node.arguments.all.size > 1 && :bare_assoc_hash == node.arguments.all[1].sexp_type
|
148
167
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module RailsBestPractices::Core
|
4
|
+
describe ChecksLoader do
|
5
|
+
let(:checks_loader) { ChecksLoader.new(RailsBestPractices::Analyzer::DEFAULT_CONFIG) }
|
6
|
+
|
7
|
+
describe "load_lexicals" do
|
8
|
+
it "should load lexical checks from the default configuration" do
|
9
|
+
lexicals = checks_loader.load_lexicals
|
10
|
+
expect(lexicals.map(&:class)).to include(RailsBestPractices::Lexicals::RemoveTrailingWhitespaceCheck)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "load_reviews" do
|
15
|
+
it "should load the reviews from the default the configuration" do
|
16
|
+
reviews = checks_loader.load_reviews
|
17
|
+
expect(reviews.map(&:class)).to include(RailsBestPractices::Reviews::AlwaysAddDbIndexReview)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module RailsBestPractices::Core
|
4
|
+
describe Check::Exceptable do
|
5
|
+
let(:method) { Method.new "BlogPost", "approve", "public", {} }
|
6
|
+
|
7
|
+
context "wildcard class and method" do
|
8
|
+
let(:except_method) { '*#*' }
|
9
|
+
|
10
|
+
it "matches" do
|
11
|
+
expect(Check::Exceptable.matches(method, except_method)).to eql true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context "wildcard class and matching explicit method" do
|
16
|
+
let(:except_method) { '*#approve' }
|
17
|
+
|
18
|
+
it "matches" do
|
19
|
+
expect(Check::Exceptable.matches(method, except_method)).to eql true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "wildcard class and non-matching explicit method" do
|
24
|
+
let(:except_method) { '*#disapprove' }
|
25
|
+
|
26
|
+
it "matches" do
|
27
|
+
expect(Check::Exceptable.matches(method, except_method)).to eql false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "matching class and wildcard method" do
|
32
|
+
let(:except_method) { 'BlogPost#*' }
|
33
|
+
|
34
|
+
it "matches" do
|
35
|
+
expect(Check::Exceptable.matches(method, except_method)).to eql true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "non-matching class and wildcard method" do
|
40
|
+
let(:except_method) { 'User#*' }
|
41
|
+
|
42
|
+
it "matches" do
|
43
|
+
expect(Check::Exceptable.matches(method, except_method)).to eql false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "matching class and matching method" do
|
48
|
+
let(:except_method) { 'BlogPost#approve' }
|
49
|
+
|
50
|
+
it "matches" do
|
51
|
+
expect(Check::Exceptable.matches(method, except_method)).to eql true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "non-matching class and non-matching method" do
|
56
|
+
let(:except_method) { 'User#disapprove' }
|
57
|
+
|
58
|
+
it "matches" do
|
59
|
+
expect(Check::Exceptable.matches(method, except_method)).to eql false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -186,7 +186,7 @@ module RailsBestPractices
|
|
186
186
|
end
|
187
187
|
|
188
188
|
describe "namespace" do
|
189
|
-
|
189
|
+
before do
|
190
190
|
content =<<-EOF
|
191
191
|
class Admin::CommentsController < ApplicationController
|
192
192
|
def show; end
|
@@ -198,7 +198,9 @@ module RailsBestPractices
|
|
198
198
|
end
|
199
199
|
EOF
|
200
200
|
runner.prepare('app/controllers/admin/comments_controller.rb', content)
|
201
|
+
end
|
201
202
|
|
203
|
+
it "should restrict auto-generated routes" do
|
202
204
|
content =<<-EOF
|
203
205
|
RailsBestPracticesCom::Application.routes.draw do
|
204
206
|
namespace :admin do
|
@@ -210,6 +212,30 @@ module RailsBestPractices
|
|
210
212
|
expect(runner.errors.size).to eq(1)
|
211
213
|
expect(runner.errors[0].to_s).to eq("config/routes.rb:3 - restrict auto-generated routes admin/comments (except: [:index])")
|
212
214
|
end
|
215
|
+
|
216
|
+
it "should restrict auto-generated routes with scope :module" do
|
217
|
+
content =<<-EOF
|
218
|
+
RailsBestPracticesCom::Application.routes.draw do
|
219
|
+
scope module: :admin do
|
220
|
+
resources :comments
|
221
|
+
end
|
222
|
+
end
|
223
|
+
EOF
|
224
|
+
runner.review('config/routes.rb', content)
|
225
|
+
expect(runner.errors.size).to eq(1)
|
226
|
+
expect(runner.errors[0].to_s).to eq("config/routes.rb:3 - restrict auto-generated routes admin/comments (except: [:index])")
|
227
|
+
end
|
228
|
+
|
229
|
+
it "should restrict auto-generated routes with resources :module" do
|
230
|
+
content =<<-EOF
|
231
|
+
RailsBestPracticesCom::Application.routes.draw do
|
232
|
+
resources :comments, module: :admin
|
233
|
+
end
|
234
|
+
EOF
|
235
|
+
runner.review('config/routes.rb', content)
|
236
|
+
expect(runner.errors.size).to eq(1)
|
237
|
+
expect(runner.errors[0].to_s).to eq("config/routes.rb:2 - restrict auto-generated routes admin/comments (except: [:index])")
|
238
|
+
end
|
213
239
|
end
|
214
240
|
|
215
241
|
describe "nested routes" do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_best_practices
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.15.
|
4
|
+
version: 1.15.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Huang
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -200,7 +200,6 @@ executables:
|
|
200
200
|
extensions: []
|
201
201
|
extra_rdoc_files: []
|
202
202
|
files:
|
203
|
-
- ".gemtest"
|
204
203
|
- ".gitignore"
|
205
204
|
- ".rspec"
|
206
205
|
- ".ruby-version"
|
@@ -218,6 +217,7 @@ files:
|
|
218
217
|
- lib/rails_best_practices/command.rb
|
219
218
|
- lib/rails_best_practices/core.rb
|
220
219
|
- lib/rails_best_practices/core/check.rb
|
220
|
+
- lib/rails_best_practices/core/checks_loader.rb
|
221
221
|
- lib/rails_best_practices/core/configs.rb
|
222
222
|
- lib/rails_best_practices/core/controllers.rb
|
223
223
|
- lib/rails_best_practices/core/error.rb
|
@@ -294,9 +294,11 @@ files:
|
|
294
294
|
- spec/fixtures/lib/rails_best_practices/plugins/reviews/not_use_rails_root_review.rb
|
295
295
|
- spec/rails_best_practices/analyzer_spec.rb
|
296
296
|
- spec/rails_best_practices/core/check_spec.rb
|
297
|
+
- spec/rails_best_practices/core/checks_loader_spec.rb
|
297
298
|
- spec/rails_best_practices/core/configs_spec.rb
|
298
299
|
- spec/rails_best_practices/core/controllers_spec.rb
|
299
300
|
- spec/rails_best_practices/core/error_spec.rb
|
301
|
+
- spec/rails_best_practices/core/except_methods_spec.rb
|
300
302
|
- spec/rails_best_practices/core/gems_spec.rb
|
301
303
|
- spec/rails_best_practices/core/helpers_spec.rb
|
302
304
|
- spec/rails_best_practices/core/klasses_spec.rb
|
@@ -406,9 +408,11 @@ test_files:
|
|
406
408
|
- spec/fixtures/lib/rails_best_practices/plugins/reviews/not_use_rails_root_review.rb
|
407
409
|
- spec/rails_best_practices/analyzer_spec.rb
|
408
410
|
- spec/rails_best_practices/core/check_spec.rb
|
411
|
+
- spec/rails_best_practices/core/checks_loader_spec.rb
|
409
412
|
- spec/rails_best_practices/core/configs_spec.rb
|
410
413
|
- spec/rails_best_practices/core/controllers_spec.rb
|
411
414
|
- spec/rails_best_practices/core/error_spec.rb
|
415
|
+
- spec/rails_best_practices/core/except_methods_spec.rb
|
412
416
|
- spec/rails_best_practices/core/gems_spec.rb
|
413
417
|
- spec/rails_best_practices/core/helpers_spec.rb
|
414
418
|
- spec/rails_best_practices/core/klasses_spec.rb
|
data/.gemtest
DELETED
File without changes
|