rubocop-discourse 3.6.0 → 3.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +7 -0
- data/config/default.yml +28 -0
- data/lib/rubocop/cop/discourse/fabricator_shorthand.rb +52 -0
- data/lib/rubocop/cop/discourse/plugins/call_requires_plugin.rb +71 -0
- data/lib/rubocop/cop/discourse/plugins/namespace_constants.rb +35 -0
- data/lib/rubocop/cop/discourse/plugins/namespace_methods.rb +37 -0
- data/lib/rubocop/cop/discourse/plugins/no_monkey_patching.rb +92 -0
- data/lib/rubocop/cop/discourse/plugins/use_plugin_instance_on.rb +42 -0
- data/lib/rubocop/cop/discourse/plugins/use_require_relative.rb +32 -0
- data/lib/rubocop/cop/discourse_cops.rb +1 -1
- data/lib/rubocop-discourse.rb +2 -0
- data/rubocop-capybara.yml +5 -0
- data/rubocop-core.yml +1 -0
- data/rubocop-discourse.gemspec +4 -1
- data/rubocop-factory_bot.yml +11 -0
- data/rubocop-rspec.yml +0 -15
- data/spec/fixtures/controllers/bad_controller.rb +5 -0
- data/spec/fixtures/controllers/base_controller.rb +11 -0
- data/spec/fixtures/controllers/good_controller.rb +4 -0
- data/spec/fixtures/controllers/inherit_from_outside_controller.rb +5 -0
- data/spec/fixtures/controllers/namespaced_parent_controller.rb +5 -0
- data/spec/fixtures/controllers/no_requires_plugin_controller.rb +5 -0
- data/spec/fixtures/controllers/requires_plugin_controller.rb +6 -0
- data/spec/lib/rubocop/cop/fabricator_shorthand_spec.rb +34 -0
- data/spec/lib/rubocop/cop/plugins/call_requires_plugin_spec.rb +81 -0
- data/spec/lib/rubocop/cop/plugins/namespace_constants_spec.rb +42 -0
- data/spec/lib/rubocop/cop/plugins/namespace_methods_spec.rb +86 -0
- data/spec/lib/rubocop/cop/plugins/no_monkey_patching_spec.rb +93 -0
- data/spec/lib/rubocop/cop/plugins/use_plugin_instance_on_spec.rb +39 -0
- data/spec/lib/rubocop/cop/plugins/use_require_relative_spec.rb +26 -0
- data/stree-compat.yml +8 -0
- metadata +67 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d347009b4a77b64450a20ef3afc5ca102dd361c60e3fbde2e5fd0ea976469cd
|
4
|
+
data.tar.gz: c98b24bd73f783f154320e337e44f6859e050c43ff9219cfa0be6f63a891fc13
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 98c56b4b42703f8fc1fe0b3f68344507e2001d7a71d5530c89b8f21a29b5276fc518542b445e9dd9a902cb30be38ce0d4df18218b2cf08bfb50465411d7c7d77
|
7
|
+
data.tar.gz: f7f5f50325374fe530a26c20ed113b4cb827ed7541a8a9f6dbae1a81c0dca29be2cc7073c8f543b5200dab2e2238617984a7f4dbd87d838ff8a1d4cfa8da0db6
|
data/.rubocop.yml
CHANGED
data/config/default.yml
CHANGED
@@ -62,3 +62,31 @@ Discourse/NoMixingMultisiteAndStandardSpecs:
|
|
62
62
|
Patterns:
|
63
63
|
- _spec.rb
|
64
64
|
- '(?:^|/)spec/'
|
65
|
+
|
66
|
+
Discourse/Plugins/CallRequiresPlugin:
|
67
|
+
Enabled: true
|
68
|
+
Include:
|
69
|
+
- 'app/controllers/**/*'
|
70
|
+
|
71
|
+
Discourse/Plugins/UsePluginInstanceOn:
|
72
|
+
Enabled: true
|
73
|
+
|
74
|
+
Discourse/Plugins/NamespaceMethods:
|
75
|
+
Enabled: true
|
76
|
+
Exclude:
|
77
|
+
- '**/spec/**/*'
|
78
|
+
- '**/tasks/**/*.rake'
|
79
|
+
- '**/db/fixtures/**/*'
|
80
|
+
|
81
|
+
Discourse/Plugins/NamespaceConstants:
|
82
|
+
Enabled: true
|
83
|
+
Exclude:
|
84
|
+
- '**/spec/**/*'
|
85
|
+
- '**/tasks/**/*.rake'
|
86
|
+
- '**/db/fixtures/**/*'
|
87
|
+
|
88
|
+
Discourse/Plugins/UseRequireRelative:
|
89
|
+
Enabled: true
|
90
|
+
|
91
|
+
Discourse/Plugins/NoMonkeyPatching:
|
92
|
+
Enabled: true
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Discourse
|
6
|
+
# When fabricating a record without custom attributes, we can use the
|
7
|
+
# fabricator shorthand as long as the identifier matches the fabricator
|
8
|
+
# name.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
# fab!(:user) { Fabricate(:user) }
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# fab!(:user)
|
17
|
+
#
|
18
|
+
# When using custom attributes or the identifier doesn't match, the
|
19
|
+
# shorthand can't be used.
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# fab!(:user) { Fabricate(:user, trust_level: TrustLevel[0]) }
|
25
|
+
#
|
26
|
+
# # good
|
27
|
+
# fab!(:another_user) { Fabricate(:user) }
|
28
|
+
class FabricatorShorthand < Base
|
29
|
+
def_node_matcher :offending_fabricator?, <<-MATCHER
|
30
|
+
(block
|
31
|
+
(send nil? :fab!
|
32
|
+
(sym $_identifier))
|
33
|
+
(args)
|
34
|
+
(send nil? :Fabricate
|
35
|
+
(sym $_identifier)))
|
36
|
+
MATCHER
|
37
|
+
|
38
|
+
def on_block(node)
|
39
|
+
offending_fabricator?(node) do |identifier|
|
40
|
+
add_offense(node, message: message(identifier))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def message(identifier)
|
47
|
+
"Use the fabricator shorthand: `fab!(:#{identifier})`"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Discourse
|
6
|
+
module Plugins
|
7
|
+
# Plugin controllers must call `requires_plugin` to prevent routes from
|
8
|
+
# being accessible when the plugin is disabled.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# # bad
|
12
|
+
# class MyController
|
13
|
+
# def my_action
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# class MyController
|
19
|
+
# requires_plugin PLUGIN_NAME
|
20
|
+
# def my_action
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
class CallRequiresPlugin < Base
|
25
|
+
MSG =
|
26
|
+
"Use `requires_plugin` in controllers to prevent routes from being accessible when plugin is disabled."
|
27
|
+
|
28
|
+
def_node_matcher :requires_plugin_present?, <<~MATCHER
|
29
|
+
(class _ _
|
30
|
+
{
|
31
|
+
(begin <(send nil? :requires_plugin _) ...>)
|
32
|
+
<(send nil? :requires_plugin _) ...>
|
33
|
+
}
|
34
|
+
)
|
35
|
+
MATCHER
|
36
|
+
|
37
|
+
def on_class(node)
|
38
|
+
return if requires_plugin_present?(node)
|
39
|
+
return if requires_plugin_present_in_parent_classes(node)
|
40
|
+
add_offense(node, message: MSG)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def requires_plugin_present_in_parent_classes(node)
|
46
|
+
return unless processed_source.path
|
47
|
+
controller_path =
|
48
|
+
base_controller_path(node.parent_class&.const_name.to_s)
|
49
|
+
return unless controller_path
|
50
|
+
Commissioner
|
51
|
+
.new([self.class.new(config, @options)])
|
52
|
+
.investigate(parse(controller_path.read, controller_path.to_s))
|
53
|
+
.offenses
|
54
|
+
.empty?
|
55
|
+
end
|
56
|
+
|
57
|
+
def base_controller_path(base_class)
|
58
|
+
return if base_class.blank?
|
59
|
+
base_path = "#{base_class.underscore}.rb"
|
60
|
+
path = Pathname.new("#{processed_source.path}/../").cleanpath
|
61
|
+
until path.root?
|
62
|
+
controller_path = path.join(base_path)
|
63
|
+
return controller_path if controller_path.exist?
|
64
|
+
path = path.join("..").cleanpath
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Discourse
|
6
|
+
module Plugins
|
7
|
+
# Constants must be defined inside the plugin namespace (module or class).
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# MY_CONSTANT = :value
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# module MyPlugin
|
15
|
+
# MY_CONSTANT = :value
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
class NamespaceConstants < Base
|
19
|
+
MSG = "Don’t define constants outside a class or a module."
|
20
|
+
|
21
|
+
def on_casgn(node)
|
22
|
+
return if inside_namespace?(node)
|
23
|
+
add_offense(node, message: MSG)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def inside_namespace?(node)
|
29
|
+
node.each_ancestor.detect { _1.class_type? || _1.module_type? }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Discourse
|
6
|
+
module Plugins
|
7
|
+
# Methods must be defined inside the plugin namespace (module or class).
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# def my_method
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# module MyPlugin
|
16
|
+
# def my_method
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
class NamespaceMethods < Base
|
21
|
+
MSG = "Don’t define methods outside a class or a module."
|
22
|
+
|
23
|
+
def on_def(node)
|
24
|
+
return if inside_namespace?(node)
|
25
|
+
add_offense(node, message: MSG)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def inside_namespace?(node)
|
31
|
+
node.each_ancestor.detect { _1.class_type? || _1.module_type? }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Discourse
|
6
|
+
module Plugins
|
7
|
+
# Don’t monkey-patch classes directly in `plugin.rb`. Instead, define
|
8
|
+
# additional methods in a dedicated mixin (an ActiveSupport concern for
|
9
|
+
# example) and use `prepend` (this allows calling `super` from the mixin).
|
10
|
+
#
|
11
|
+
# If you’re just adding new methods to an existing serializer, then use
|
12
|
+
# `add_to_serializer` instead.
|
13
|
+
#
|
14
|
+
# @example generic monkey-patching
|
15
|
+
# # bad
|
16
|
+
# ::Topic.class_eval do
|
17
|
+
# has_many :new_items
|
18
|
+
#
|
19
|
+
# def new_method
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# module MyPlugin::TopicExtension
|
25
|
+
# extend ActiveSupport::Concern
|
26
|
+
#
|
27
|
+
# prepended do
|
28
|
+
# has_many :new_items
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# def new_method
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# reloadable_patch { ::Topic.prepend(MyPlugin::TopicExtension) }
|
36
|
+
#
|
37
|
+
# @example for serializers
|
38
|
+
# # bad
|
39
|
+
# UserSerializer.class_eval do
|
40
|
+
# def new_method
|
41
|
+
# do_processing
|
42
|
+
# end
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# # good
|
46
|
+
# add_to_serializer(:user, :new_method) { do_processing }
|
47
|
+
#
|
48
|
+
class NoMonkeyPatching < Base
|
49
|
+
MSG =
|
50
|
+
"Don’t reopen existing classes. Instead, create a mixin and use `prepend`."
|
51
|
+
MSG_CLASS_EVAL =
|
52
|
+
"Don’t call `class_eval`. Instead, create a mixin and use `prepend`."
|
53
|
+
MSG_CLASS_EVAL_SERIALIZERS =
|
54
|
+
"Don’t call `class_eval` on a serializer. If you’re adding new methods, use `add_to_serializer`. Otherwise, create a mixin and use `prepend`."
|
55
|
+
MSG_SERIALIZERS =
|
56
|
+
"Don’t reopen serializers. Instead, use `add_to_serializer`."
|
57
|
+
RESTRICT_ON_SEND = [:class_eval].freeze
|
58
|
+
|
59
|
+
def_node_matcher :existing_class?, <<~MATCHER
|
60
|
+
(class (const (cbase) _) ...)
|
61
|
+
MATCHER
|
62
|
+
|
63
|
+
def_node_matcher :serializer?, <<~MATCHER
|
64
|
+
({class send} (const _ /Serializer$/) ...)
|
65
|
+
MATCHER
|
66
|
+
|
67
|
+
def on_send(node)
|
68
|
+
if serializer?(node)
|
69
|
+
return add_offense(node, message: MSG_CLASS_EVAL_SERIALIZERS)
|
70
|
+
end
|
71
|
+
add_offense(node, message: MSG_CLASS_EVAL)
|
72
|
+
end
|
73
|
+
|
74
|
+
def on_class(node)
|
75
|
+
return unless in_plugin_rb_file?
|
76
|
+
return unless existing_class?(node)
|
77
|
+
if serializer?(node)
|
78
|
+
return add_offense(node, message: MSG_SERIALIZERS)
|
79
|
+
end
|
80
|
+
add_offense(node, message: MSG)
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def in_plugin_rb_file?
|
86
|
+
processed_source.path.split("/").last == "plugin.rb"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Discourse
|
6
|
+
module Plugins
|
7
|
+
# Using `DiscourseEvent.on` leaves the handler enabled when the plugin is disabled.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# DiscourseEvent.on(:event) { do_something }
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# on(:event) { do_something }
|
15
|
+
#
|
16
|
+
class UsePluginInstanceOn < Base
|
17
|
+
MSG =
|
18
|
+
"Use `on` instead of `DiscourseEvent.on` as the latter will listen to events even if the plugin is disabled."
|
19
|
+
NOT_OUTSIDE_PLUGIN_RB =
|
20
|
+
"Don’t call `DiscourseEvent.on` outside `plugin.rb`."
|
21
|
+
RESTRICT_ON_SEND = [:on].freeze
|
22
|
+
|
23
|
+
def_node_matcher :discourse_event_on?, <<~MATCHER
|
24
|
+
(send (const nil? :DiscourseEvent) :on _)
|
25
|
+
MATCHER
|
26
|
+
|
27
|
+
def on_send(node)
|
28
|
+
return unless discourse_event_on?(node)
|
29
|
+
return add_offense(node, message: MSG) if in_plugin_rb_file?
|
30
|
+
add_offense(node, message: NOT_OUTSIDE_PLUGIN_RB)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def in_plugin_rb_file?
|
36
|
+
processed_source.path.split("/").last == "plugin.rb"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Discourse
|
6
|
+
module Plugins
|
7
|
+
# Use `require_relative` to load dependencies.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# load File.expand_path("../lib/my_file.rb", __FILE__)
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# require_relative "lib/my_file"
|
15
|
+
#
|
16
|
+
class UseRequireRelative < Base
|
17
|
+
MSG = "Use `require_relative` instead of `load`."
|
18
|
+
RESTRICT_ON_SEND = [:load].freeze
|
19
|
+
|
20
|
+
def_node_matcher :load_called?, <<~MATCHER
|
21
|
+
(send nil? :load _)
|
22
|
+
MATCHER
|
23
|
+
|
24
|
+
def on_send(node)
|
25
|
+
return unless load_called?(node)
|
26
|
+
add_offense(node, message: MSG)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/rubocop-discourse.rb
CHANGED
data/rubocop-core.yml
CHANGED
data/rubocop-discourse.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "rubocop-discourse"
|
5
|
-
s.version = "3.
|
5
|
+
s.version = "3.7.0"
|
6
6
|
s.summary = "Custom rubocop cops used by Discourse"
|
7
7
|
s.authors = ["Discourse Team"]
|
8
8
|
s.license = "MIT"
|
@@ -11,8 +11,11 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.files = `git ls-files`.split($/)
|
12
12
|
s.require_paths = ["lib"]
|
13
13
|
|
14
|
+
s.add_runtime_dependency "activesupport", ">= 6.1"
|
14
15
|
s.add_runtime_dependency "rubocop", ">= 1.59.0"
|
15
16
|
s.add_runtime_dependency "rubocop-rspec", ">= 2.25.0"
|
17
|
+
s.add_runtime_dependency "rubocop-factory_bot", ">= 2.0.0"
|
18
|
+
s.add_runtime_dependency "rubocop-capybara", ">= 2.0.0"
|
16
19
|
|
17
20
|
s.add_development_dependency "rake", "~> 13.1.0"
|
18
21
|
s.add_development_dependency "rspec", "~> 3.12.0"
|
data/rubocop-rspec.yml
CHANGED
@@ -223,23 +223,8 @@ RSpec/VoidExpect:
|
|
223
223
|
RSpec/Yield:
|
224
224
|
Enabled: true
|
225
225
|
|
226
|
-
Capybara/CurrentPathExpectation:
|
227
|
-
Enabled: true
|
228
|
-
|
229
226
|
RSpec/Capybara/FeatureMethods:
|
230
227
|
Enabled: true
|
231
228
|
|
232
|
-
Capybara/VisibilityMatcher:
|
233
|
-
Enabled: true
|
234
|
-
|
235
|
-
FactoryBot/AttributeDefinedStatically:
|
236
|
-
Enabled: true
|
237
|
-
|
238
|
-
FactoryBot/CreateList:
|
239
|
-
Enabled: true
|
240
|
-
|
241
|
-
FactoryBot/FactoryClassName:
|
242
|
-
Enabled: true
|
243
|
-
|
244
229
|
RSpec/Rails/HttpStatus:
|
245
230
|
Enabled: true
|
@@ -0,0 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class BadController < NoRequiresPluginController
|
4
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Discourse/Plugins/CallRequiresPlugin: Use `requires_plugin` in controllers to prevent routes from being accessible when plugin is disabled.
|
5
|
+
end
|
@@ -0,0 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class InheritFromOutsideController < ApplicationController
|
4
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Discourse/Plugins/CallRequiresPlugin: Use `requires_plugin` in controllers to prevent routes from being accessible when plugin is disabled.
|
5
|
+
end
|
@@ -0,0 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class InheritFromOutsideController < MyPlugin::ApplicationController
|
4
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Discourse/Plugins/CallRequiresPlugin: Use `requires_plugin` in controllers to prevent routes from being accessible when plugin is disabled.
|
5
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe RuboCop::Cop::Discourse::FabricatorShorthand, :config do
|
6
|
+
subject(:cop) { described_class.new(config) }
|
7
|
+
|
8
|
+
let(:config) { RuboCop::Config.new }
|
9
|
+
|
10
|
+
it "registers an offense when not using the fabricator shorthand" do
|
11
|
+
expect_offense(<<~RUBY)
|
12
|
+
RSpec.describe "Foo" do
|
13
|
+
fab!(:foo) { Fabricate(:foo) }
|
14
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Discourse/FabricatorShorthand: Use the fabricator shorthand: `fab!(:foo)`
|
15
|
+
end
|
16
|
+
RUBY
|
17
|
+
end
|
18
|
+
|
19
|
+
it "does not register an offense when the fabricator has attributes" do
|
20
|
+
expect_no_offenses(<<~RUBY)
|
21
|
+
RSpec.describe "Foo" do
|
22
|
+
fab!(:foo) { Fabricate(:foo, bar: 1) }
|
23
|
+
end
|
24
|
+
RUBY
|
25
|
+
end
|
26
|
+
|
27
|
+
it "does not register an offense when the identifier doesn't match" do
|
28
|
+
expect_no_offenses(<<~RUBY)
|
29
|
+
RSpec.describe "Foo" do
|
30
|
+
fab!(:bar) { Fabricate(:foo) }
|
31
|
+
end
|
32
|
+
RUBY
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe RuboCop::Cop::Discourse::Plugins::CallRequiresPlugin, :config do
|
6
|
+
subject(:cop) { described_class.new(config) }
|
7
|
+
|
8
|
+
let(:config) { RuboCop::Config.new }
|
9
|
+
|
10
|
+
context "when `requires_plugin` is missing" do
|
11
|
+
it "registers an offense" do
|
12
|
+
expect_offense(<<~RUBY)
|
13
|
+
class MyController < ApplicationController
|
14
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Discourse/Plugins/CallRequiresPlugin: Use `requires_plugin` in controllers to prevent routes from being accessible when plugin is disabled.
|
15
|
+
requires_login
|
16
|
+
end
|
17
|
+
RUBY
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "when `requires_plugin` is not missing" do
|
22
|
+
it "does not register an offense" do
|
23
|
+
expect_no_offenses(<<~RUBY)
|
24
|
+
class MyController
|
25
|
+
requires_plugin MyPlugin::PLUGIN_NAME
|
26
|
+
requires_login
|
27
|
+
end
|
28
|
+
RUBY
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "when inheriting" do
|
33
|
+
let(:controllers_path) do
|
34
|
+
Pathname.new("#{__dir__}/../../../../fixtures/controllers").cleanpath
|
35
|
+
end
|
36
|
+
|
37
|
+
before do
|
38
|
+
# As we’re providing real files, we need to get rid of the default config
|
39
|
+
# restricting the cop to `app/controllers/*`
|
40
|
+
configuration.for_cop(cop).delete("Include")
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when `requires_plugin` is called in a parent controller" do
|
44
|
+
let(:good_controller) { controllers_path.join("good_controller.rb") }
|
45
|
+
|
46
|
+
it "does not register an offense" do
|
47
|
+
expect_no_offenses(good_controller.read, good_controller.to_s)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when `requires_plugin` is not called in a parent controller" do
|
52
|
+
let(:bad_controller) { controllers_path.join("bad_controller.rb") }
|
53
|
+
|
54
|
+
it "registers an offense" do
|
55
|
+
expect_offense(bad_controller.read, bad_controller.to_s)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "when parent controller can’t be located" do
|
60
|
+
context "when parent controller is namespaced" do
|
61
|
+
let(:controller) do
|
62
|
+
controllers_path.join("namespaced_parent_controller.rb")
|
63
|
+
end
|
64
|
+
|
65
|
+
it "registers an offense" do
|
66
|
+
expect_offense(controller.read, controller.to_s)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "when parent controller is not namespaced" do
|
71
|
+
let(:controller) do
|
72
|
+
controllers_path.join("inherit_from_outside_controller.rb")
|
73
|
+
end
|
74
|
+
|
75
|
+
it "registers an offense" do
|
76
|
+
expect_offense(controller.read, controller.to_s)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe RuboCop::Cop::Discourse::Plugins::NamespaceConstants, :config do
|
6
|
+
subject(:cop) { described_class.new(config) }
|
7
|
+
|
8
|
+
let(:config) { RuboCop::Config.new }
|
9
|
+
|
10
|
+
context "when defining a constant outside any namespace" do
|
11
|
+
it "registers an offense" do
|
12
|
+
expect_offense(<<~RUBY)
|
13
|
+
MY_CONSTANT = "my_value"
|
14
|
+
^^^^^^^^^^^^^^^^^^^^^^^^ Discourse/Plugins/NamespaceConstants: Don’t define constants outside a class or a module.
|
15
|
+
|
16
|
+
class MyClass
|
17
|
+
MY_CONSTANT = "my_value"
|
18
|
+
end
|
19
|
+
RUBY
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when defining a constant inside a class" do
|
24
|
+
it "does not register an offense" do
|
25
|
+
expect_no_offenses(<<~RUBY)
|
26
|
+
class MyClass
|
27
|
+
MY_CONSTANT = "my_value"
|
28
|
+
end
|
29
|
+
RUBY
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "when defining a constant inside a module" do
|
34
|
+
it "does not register an offense" do
|
35
|
+
expect_no_offenses(<<~RUBY)
|
36
|
+
module MyModule
|
37
|
+
MY_CONSTANT = "my_value"
|
38
|
+
end
|
39
|
+
RUBY
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe RuboCop::Cop::Discourse::Plugins::NamespaceMethods, :config do
|
6
|
+
subject(:cop) { described_class.new(config) }
|
7
|
+
|
8
|
+
let(:config) { RuboCop::Config.new }
|
9
|
+
|
10
|
+
context "when defining a method outside any namespace" do
|
11
|
+
it "registers an offense" do
|
12
|
+
expect_offense(<<~RUBY)
|
13
|
+
def my_method
|
14
|
+
^^^^^^^^^^^^^ Discourse/Plugins/NamespaceMethods: Don’t define methods outside a class or a module.
|
15
|
+
"my_value"
|
16
|
+
end
|
17
|
+
|
18
|
+
class MyClass
|
19
|
+
def my_method
|
20
|
+
"my_method"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
RUBY
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when defining a method inside a class" do
|
28
|
+
context "when defining an instance method" do
|
29
|
+
it "does not register an offense" do
|
30
|
+
expect_no_offenses(<<~RUBY)
|
31
|
+
class MyClass
|
32
|
+
def my_method
|
33
|
+
"my_value"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
RUBY
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when defining a class method" do
|
41
|
+
it "does not register an offense" do
|
42
|
+
expect_no_offenses(<<~RUBY)
|
43
|
+
class MyClass
|
44
|
+
class << self
|
45
|
+
def my_method
|
46
|
+
"my_value"
|
47
|
+
end
|
48
|
+
|
49
|
+
def another_method
|
50
|
+
"plop"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
RUBY
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "when defining a method inside a module" do
|
60
|
+
context "when defining an instance method" do
|
61
|
+
it "does not register an offense" do
|
62
|
+
expect_no_offenses(<<~RUBY)
|
63
|
+
module MyModule
|
64
|
+
def my_method
|
65
|
+
"my_value"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
RUBY
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "when defining a class method" do
|
73
|
+
it "does not register an offense" do
|
74
|
+
expect_no_offenses(<<~RUBY)
|
75
|
+
module MyModule
|
76
|
+
class << self
|
77
|
+
def my_method
|
78
|
+
"my_value"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
RUBY
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe RuboCop::Cop::Discourse::Plugins::NoMonkeyPatching, :config do
|
6
|
+
subject(:cop) { described_class.new(config) }
|
7
|
+
|
8
|
+
let(:config) { RuboCop::Config.new }
|
9
|
+
|
10
|
+
context "when outside `plugin.rb`" do
|
11
|
+
it "does not register an offense" do
|
12
|
+
expect_no_offenses(<<~RUBY, "my_class.rb")
|
13
|
+
class ::MyClass
|
14
|
+
def my_method
|
15
|
+
"my_value"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class AnotherClass
|
20
|
+
def my_method
|
21
|
+
"my_value"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
RUBY
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "when inside `plugin.rb`" do
|
29
|
+
context "when opening an existing class" do
|
30
|
+
it "registers an offense" do
|
31
|
+
expect_offense(<<~RUBY, "plugin.rb")
|
32
|
+
after_initialize do
|
33
|
+
module MyPlugin
|
34
|
+
class Engine < Rails::Engine
|
35
|
+
isolate_namespace MyPlugin
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class ::Topic
|
40
|
+
^^^^^^^^^^^^^ Discourse/Plugins/NoMonkeyPatching: Don’t reopen existing classes. [...]
|
41
|
+
def self.new_method
|
42
|
+
:new_value
|
43
|
+
end
|
44
|
+
|
45
|
+
def my_new_method
|
46
|
+
"my_new_value"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
RUBY
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "when opening an existing serializer" do
|
55
|
+
it "registers an offense" do
|
56
|
+
expect_offense(<<~RUBY, "plugin.rb")
|
57
|
+
class ::TopicSerializer
|
58
|
+
^^^^^^^^^^^^^^^^^^^^^^^ Discourse/Plugins/NoMonkeyPatching: Don’t reopen serializers. [...]
|
59
|
+
def new_attribute
|
60
|
+
"my_attribute"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
RUBY
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when calling `.class_eval` on a class" do
|
68
|
+
it "registers an offense" do
|
69
|
+
expect_offense(<<~RUBY)
|
70
|
+
User.class_eval do
|
71
|
+
^^^^^^^^^^^^^^^ Discourse/Plugins/NoMonkeyPatching: Don’t call `class_eval`. [...]
|
72
|
+
def a_new_method
|
73
|
+
:new_value
|
74
|
+
end
|
75
|
+
end
|
76
|
+
RUBY
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "when calling `.class_eval` on a serializer" do
|
81
|
+
it "registers an offense" do
|
82
|
+
expect_offense(<<~RUBY)
|
83
|
+
UserSerializer.class_eval do
|
84
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^ Discourse/Plugins/NoMonkeyPatching: Don’t call `class_eval` on a serializer. [...]
|
85
|
+
def a_new_method
|
86
|
+
:new_value
|
87
|
+
end
|
88
|
+
end
|
89
|
+
RUBY
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe RuboCop::Cop::Discourse::Plugins::UsePluginInstanceOn, :config do
|
6
|
+
subject(:cop) { described_class.new(config) }
|
7
|
+
|
8
|
+
let(:config) { RuboCop::Config.new }
|
9
|
+
|
10
|
+
context "when outside `plugin.rb`" do
|
11
|
+
context "when `DiscourseEvent.on` is called" do
|
12
|
+
it "registers an offense" do
|
13
|
+
expect_offense(<<~RUBY, "another_file.rb")
|
14
|
+
DiscourseEvent.on(:topic_status_updated) { do_something }
|
15
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Discourse/Plugins/UsePluginInstanceOn: Don’t call `DiscourseEvent.on` outside `plugin.rb`.
|
16
|
+
RUBY
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "when inside `plugin.rb`" do
|
22
|
+
context "when `DiscourseEvent.on` is called" do
|
23
|
+
it "registers an offense" do
|
24
|
+
expect_offense(<<~RUBY, "plugin.rb")
|
25
|
+
DiscourseEvent.on(:topic_status_updated) { do_something }
|
26
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Discourse/Plugins/UsePluginInstanceOn: Use `on` instead of `DiscourseEvent.on` [...]
|
27
|
+
RUBY
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when `on` is called" do
|
32
|
+
it "does not register an offense" do
|
33
|
+
expect_no_offenses(<<~RUBY, "plugin.rb")
|
34
|
+
on(:topic_status_updated) { do_something }
|
35
|
+
RUBY
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe RuboCop::Cop::Discourse::Plugins::UseRequireRelative, :config do
|
6
|
+
subject(:cop) { described_class.new(config) }
|
7
|
+
|
8
|
+
let(:config) { RuboCop::Config.new }
|
9
|
+
|
10
|
+
context "when using `load`" do
|
11
|
+
it "registers an offense" do
|
12
|
+
expect_offense(<<~RUBY)
|
13
|
+
load File.expand_path("../app/jobs/onceoff/voting_ensure_consistency.rb", __FILE__)
|
14
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Discourse/Plugins/UseRequireRelative: Use `require_relative` instead of `load`.
|
15
|
+
RUBY
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "when using `require_relative`" do
|
20
|
+
it "does not register an offense" do
|
21
|
+
expect_no_offenses(<<~RUBY)
|
22
|
+
require_relative "app/controllers/encrypt_controller.rb"
|
23
|
+
RUBY
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/stree-compat.yml
CHANGED
@@ -3,10 +3,13 @@ require:
|
|
3
3
|
|
4
4
|
inherit_from:
|
5
5
|
- ./rubocop-core.yml
|
6
|
+
- ./rubocop-capybara.yml
|
7
|
+
- ./rubocop-factory_bot.yml
|
6
8
|
- ./rubocop-rspec.yml
|
7
9
|
|
8
10
|
AllCops:
|
9
11
|
TargetRubyVersion: 3.2
|
12
|
+
SuggestExtensions: false
|
10
13
|
DisabledByDefault: true
|
11
14
|
Exclude:
|
12
15
|
- 'db/schema.rb'
|
@@ -19,3 +22,8 @@ AllCops:
|
|
19
22
|
|
20
23
|
Discourse:
|
21
24
|
Enabled: true
|
25
|
+
|
26
|
+
Discourse/FabricatorShorthand:
|
27
|
+
Enabled: true
|
28
|
+
Include:
|
29
|
+
- 'spec/**/*_spec.rb'
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop-discourse
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Discourse Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '6.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '6.1'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rubocop
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,6 +52,34 @@ dependencies:
|
|
38
52
|
- - ">="
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: 2.25.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubocop-factory_bot
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.0.0
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.0.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop-capybara
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 2.0.0
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.0.0
|
41
83
|
- !ruby/object:Gem::Dependency
|
42
84
|
name: rake
|
43
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -82,6 +124,7 @@ files:
|
|
82
124
|
- config/default.yml
|
83
125
|
- default.yml
|
84
126
|
- lib/rubocop-discourse.rb
|
127
|
+
- lib/rubocop/cop/discourse/fabricator_shorthand.rb
|
85
128
|
- lib/rubocop/cop/discourse/no_add_reference_active_record_migrations.rb
|
86
129
|
- lib/rubocop/cop/discourse/no_chdir.rb
|
87
130
|
- lib/rubocop/cop/discourse/no_direct_multisite_manipulation.rb
|
@@ -93,19 +136,41 @@ files:
|
|
93
136
|
- lib/rubocop/cop/discourse/no_time_new_without_args.rb
|
94
137
|
- lib/rubocop/cop/discourse/no_uri_escape_encode.rb
|
95
138
|
- lib/rubocop/cop/discourse/only_top_level_multisite_specs.rb
|
139
|
+
- lib/rubocop/cop/discourse/plugins/call_requires_plugin.rb
|
140
|
+
- lib/rubocop/cop/discourse/plugins/namespace_constants.rb
|
141
|
+
- lib/rubocop/cop/discourse/plugins/namespace_methods.rb
|
142
|
+
- lib/rubocop/cop/discourse/plugins/no_monkey_patching.rb
|
143
|
+
- lib/rubocop/cop/discourse/plugins/use_plugin_instance_on.rb
|
144
|
+
- lib/rubocop/cop/discourse/plugins/use_require_relative.rb
|
96
145
|
- lib/rubocop/cop/discourse/time_eq_matcher.rb
|
97
146
|
- lib/rubocop/cop/discourse_cops.rb
|
98
147
|
- lib/rubocop/discourse.rb
|
99
148
|
- lib/rubocop/discourse/inject.rb
|
149
|
+
- rubocop-capybara.yml
|
100
150
|
- rubocop-core.yml
|
101
151
|
- rubocop-discourse.gemspec
|
152
|
+
- rubocop-factory_bot.yml
|
102
153
|
- rubocop-layout.yml
|
103
154
|
- rubocop-rspec.yml
|
155
|
+
- spec/fixtures/controllers/bad_controller.rb
|
156
|
+
- spec/fixtures/controllers/base_controller.rb
|
157
|
+
- spec/fixtures/controllers/good_controller.rb
|
158
|
+
- spec/fixtures/controllers/inherit_from_outside_controller.rb
|
159
|
+
- spec/fixtures/controllers/namespaced_parent_controller.rb
|
160
|
+
- spec/fixtures/controllers/no_requires_plugin_controller.rb
|
161
|
+
- spec/fixtures/controllers/requires_plugin_controller.rb
|
162
|
+
- spec/lib/rubocop/cop/fabricator_shorthand_spec.rb
|
104
163
|
- spec/lib/rubocop/cop/no_add_reference_active_record_migrations_spec.rb
|
105
164
|
- spec/lib/rubocop/cop/no_mixing_multisite_and_standard_specs_spec.rb
|
106
165
|
- spec/lib/rubocop/cop/no_mocking_jobs_enqueue_spec.rb
|
107
166
|
- spec/lib/rubocop/cop/no_reset_column_information_migrations_spec.rb
|
108
167
|
- spec/lib/rubocop/cop/only_top_level_multisite_specs_spec.rb
|
168
|
+
- spec/lib/rubocop/cop/plugins/call_requires_plugin_spec.rb
|
169
|
+
- spec/lib/rubocop/cop/plugins/namespace_constants_spec.rb
|
170
|
+
- spec/lib/rubocop/cop/plugins/namespace_methods_spec.rb
|
171
|
+
- spec/lib/rubocop/cop/plugins/no_monkey_patching_spec.rb
|
172
|
+
- spec/lib/rubocop/cop/plugins/use_plugin_instance_on_spec.rb
|
173
|
+
- spec/lib/rubocop/cop/plugins/use_require_relative_spec.rb
|
109
174
|
- spec/lib/rubocop/cop/time_eq_matcher_spec.rb
|
110
175
|
- spec/spec_helper.rb
|
111
176
|
- stree-compat.yml
|