rubocop-discourse 3.14.0 → 3.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6c45b71e5356cb68292653738d05f27653a5e922d62442130751e8c341506680
|
|
4
|
+
data.tar.gz: 89e1f0b302c37bf300ceb97cea9a2035e49811c33e8d32dc50c22972f128f563
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fa562f62898674a35e4d7d12c513d648727fa20d982812ed4e7af1a30e08b65e6249fd1f20cd250f1a9e422dd15509b7409bec1ed1a9ac4897dedd5e56e1b0e7
|
|
7
|
+
data.tar.gz: 2cf1e4dd9cdaf5a57dfe7d3814c2624c46b3179b93ce5b9341be33e763270bb2f5ffd3ebb66ff74c86e269a4e23c27081b02232a40822d2689c1089e79378a0a
|
data/config/default.yml
CHANGED
|
@@ -56,6 +56,11 @@ Discourse/NoMixingMultisiteAndStandardSpecs:
|
|
|
56
56
|
Include:
|
|
57
57
|
- "**/spec/**/*"
|
|
58
58
|
|
|
59
|
+
Discourse/NoSystemSpecMetadata:
|
|
60
|
+
Enabled: true
|
|
61
|
+
Include:
|
|
62
|
+
- "**/spec/**/*"
|
|
63
|
+
|
|
59
64
|
Discourse/Plugins/CallRequiresPlugin:
|
|
60
65
|
Enabled: true
|
|
61
66
|
Include:
|
|
@@ -89,3 +94,6 @@ Discourse/Services/GroupKeywords:
|
|
|
89
94
|
|
|
90
95
|
Discourse/Services/EmptyLinesAroundBlocks:
|
|
91
96
|
Enabled: true
|
|
97
|
+
|
|
98
|
+
Discourse/Services/MutableAttributeDefault:
|
|
99
|
+
Enabled: true
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Discourse
|
|
6
|
+
# System spec metadata is inferred from the file path, so explicit
|
|
7
|
+
# `type: :system` and `system: true` metadata on `RSpec.describe` is redundant.
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
# # bad
|
|
11
|
+
# RSpec.describe "login", system: true do
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
14
|
+
# # good
|
|
15
|
+
# RSpec.describe "login" do
|
|
16
|
+
# end
|
|
17
|
+
class NoSystemSpecMetadata < Base
|
|
18
|
+
extend AutoCorrector
|
|
19
|
+
|
|
20
|
+
MSG = "Remove redundant `type: :system` and `system: true` metadata from `RSpec.describe`."
|
|
21
|
+
RESTRICT_ON_SEND = %i[describe].freeze
|
|
22
|
+
|
|
23
|
+
def_node_matcher :describe?, <<~PATTERN
|
|
24
|
+
(send
|
|
25
|
+
{nil? (const nil? :RSpec)}
|
|
26
|
+
:describe
|
|
27
|
+
...
|
|
28
|
+
)
|
|
29
|
+
PATTERN
|
|
30
|
+
|
|
31
|
+
def_node_matcher :system_type_pair?, <<~PATTERN
|
|
32
|
+
(pair (sym :type) (sym :system))
|
|
33
|
+
PATTERN
|
|
34
|
+
|
|
35
|
+
def_node_matcher :system_true_pair?, <<~PATTERN
|
|
36
|
+
(pair (sym :system) true)
|
|
37
|
+
PATTERN
|
|
38
|
+
|
|
39
|
+
def on_send(node)
|
|
40
|
+
return unless describe?(node)
|
|
41
|
+
return unless node.last_argument&.hash_type?
|
|
42
|
+
|
|
43
|
+
hash = node.last_argument
|
|
44
|
+
offending_pairs =
|
|
45
|
+
hash.pairs.select { |pair| system_type_pair?(pair) || system_true_pair?(pair) }
|
|
46
|
+
|
|
47
|
+
return if offending_pairs.empty?
|
|
48
|
+
|
|
49
|
+
add_offense(offending_pairs.first) do |corrector|
|
|
50
|
+
corrector.replace(node, corrected_send_source(node, hash, offending_pairs))
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def corrected_send_source(node, hash, offending_pairs)
|
|
57
|
+
remaining_pairs = hash.pairs - offending_pairs
|
|
58
|
+
before_hash = source_for(node.source_range.begin_pos, hash.source_range.begin_pos)
|
|
59
|
+
after_hash = source_for(hash.source_range.end_pos, node.source_range.end_pos)
|
|
60
|
+
|
|
61
|
+
return "#{before_hash.sub(/,\s*\z/m, "")}#{after_hash}" if remaining_pairs.empty?
|
|
62
|
+
|
|
63
|
+
"#{before_hash}#{corrected_hash_source(hash, remaining_pairs)}#{after_hash}"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def corrected_hash_source(hash, remaining_pairs)
|
|
67
|
+
body =
|
|
68
|
+
remaining_pairs
|
|
69
|
+
.each_with_index
|
|
70
|
+
.map do |pair, index|
|
|
71
|
+
separator = index.zero? ? "" : pair_separator(hash, pair)
|
|
72
|
+
"#{separator}#{pair.source}"
|
|
73
|
+
end
|
|
74
|
+
.join
|
|
75
|
+
|
|
76
|
+
return body unless hash.braces?
|
|
77
|
+
|
|
78
|
+
return "{ #{body} }" unless hash.multiline?
|
|
79
|
+
|
|
80
|
+
indentation = " " * remaining_pairs.first.loc.expression.column
|
|
81
|
+
closing_indentation = " " * hash.loc.end.column
|
|
82
|
+
|
|
83
|
+
"{\n#{indentation}#{body}\n#{closing_indentation}}"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def pair_separator(hash, pair)
|
|
87
|
+
return ", " unless hash.multiline?
|
|
88
|
+
|
|
89
|
+
",\n#{" " * pair.loc.expression.column}"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def source_for(begin_pos, end_pos)
|
|
93
|
+
processed_source.buffer.source[begin_pos...end_pos]
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Discourse
|
|
6
|
+
module Services
|
|
7
|
+
# Wrap mutable `attribute` defaults in a proc — `ActiveModel::Attributes`
|
|
8
|
+
# shares the literal across instances, so mutations leak between calls.
|
|
9
|
+
# `:array`-typed attributes are exempt; the type dups on read.
|
|
10
|
+
#
|
|
11
|
+
# @example
|
|
12
|
+
# # bad
|
|
13
|
+
# options do
|
|
14
|
+
# attribute :overrides, default: {}
|
|
15
|
+
# attribute :ids, default: [1, 2]
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# # good
|
|
19
|
+
# options do
|
|
20
|
+
# attribute :overrides, default: -> { {} }
|
|
21
|
+
# attribute :ids, default: -> { [1, 2] }
|
|
22
|
+
# attribute :tags, :array, default: [] # :array dups per read
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
25
|
+
class MutableAttributeDefault < Base
|
|
26
|
+
extend AutoCorrector
|
|
27
|
+
|
|
28
|
+
MSG =
|
|
29
|
+
"Mutable `default: %<source>s` is shared across all instances; wrap it in a proc: `-> { %<source>s }`."
|
|
30
|
+
RESTRICT_ON_SEND = %i[attribute].freeze
|
|
31
|
+
|
|
32
|
+
def_node_matcher :service_include?, <<~MATCHER
|
|
33
|
+
(class _ _
|
|
34
|
+
{
|
|
35
|
+
(begin <(send nil? :include (const (const nil? :Service) :Base)) ...>)
|
|
36
|
+
<(send nil? :include (const (const nil? :Service) :Base)) ...>
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
MATCHER
|
|
40
|
+
|
|
41
|
+
def_node_matcher :mutable_default, <<~PATTERN
|
|
42
|
+
(send nil? :attribute _ ... (hash <(pair (sym :default) ${hash array}) ...>))
|
|
43
|
+
PATTERN
|
|
44
|
+
|
|
45
|
+
def_node_matcher :array_typed?, <<~PATTERN
|
|
46
|
+
(send nil? :attribute _ (sym :array) ...)
|
|
47
|
+
PATTERN
|
|
48
|
+
|
|
49
|
+
def on_class(node)
|
|
50
|
+
@service = true if service_include?(node)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def on_send(node)
|
|
54
|
+
return unless @service
|
|
55
|
+
return if array_typed?(node)
|
|
56
|
+
default = mutable_default(node)
|
|
57
|
+
return unless default
|
|
58
|
+
|
|
59
|
+
source = default.source
|
|
60
|
+
add_offense(default, message: format(MSG, source: source)) do |corrector|
|
|
61
|
+
corrector.replace(default, "-> { #{source} }")
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubocop-discourse
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.17.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Discourse Team
|
|
@@ -167,6 +167,7 @@ files:
|
|
|
167
167
|
- lib/rubocop/cop/discourse/no_mocking_jobs.rb
|
|
168
168
|
- lib/rubocop/cop/discourse/no_nokogiri_html_fragment.rb
|
|
169
169
|
- lib/rubocop/cop/discourse/no_reset_column_information_in_migrations.rb
|
|
170
|
+
- lib/rubocop/cop/discourse/no_system_spec_metadata.rb
|
|
170
171
|
- lib/rubocop/cop/discourse/no_time_new_without_args.rb
|
|
171
172
|
- lib/rubocop/cop/discourse/no_uri_escape_encode.rb
|
|
172
173
|
- lib/rubocop/cop/discourse/only_top_level_multisite_specs.rb
|
|
@@ -178,6 +179,7 @@ files:
|
|
|
178
179
|
- lib/rubocop/cop/discourse/plugins/use_require_relative.rb
|
|
179
180
|
- lib/rubocop/cop/discourse/services/empty_lines_around_blocks.rb
|
|
180
181
|
- lib/rubocop/cop/discourse/services/group_keywords.rb
|
|
182
|
+
- lib/rubocop/cop/discourse/services/mutable_attribute_default.rb
|
|
181
183
|
- lib/rubocop/cop/discourse/time_eq_matcher.rb
|
|
182
184
|
- lib/rubocop/cop/discourse_cops.rb
|
|
183
185
|
- lib/rubocop/discourse/plugin.rb
|