barsoom_utils 0.2.0.78 → 0.3.0.82
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/Gemfile +0 -1
- data/README.md +2 -0
- data/VERSION +1 -1
- data/lib/barsoom_utils/exception_notifier.rb +5 -19
- data/lib/barsoom_utils/rubocop.rb +5 -0
- data/lib/rubocop/cop/barsoom/attr_extras_initialize.rb +63 -0
- data/lib/rubocop/cop/barsoom/inline_private_class_method.rb +62 -0
- data/shared_rubocop.yml +13 -0
- data/shared_rubocop_rails.yml +4 -0
- data/spec/exception_notifier_spec.rb +17 -96
- data/spec/rubocop/cop/barsoom/attr_extras_initialize_spec.rb +154 -0
- data/spec/rubocop/cop/barsoom/inline_private_class_method_spec.rb +73 -0
- data/spec/rubocop_helper.rb +8 -0
- metadata +7 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1757860af2eca9a71fffa1fa0c47a42e572314816f4dcf02d752d60c713ace67
|
|
4
|
+
data.tar.gz: 54eb7e03409786d5eb87c34affad0a363b2ac3d17ee19ec22c75c800fd171c6d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 66619d39cab01f97f5da75ab364f6f5f215f1c7755683518e71fa5d91bd7c3c3689828e0088b2ee562b07cf891a852378e6ee5f1533e4ee6c40103cd28db2f25
|
|
7
|
+
data.tar.gz: ae669cd31bb669333412b0ea3f1bb6ebca0c584ed602685acf750f32106716fddd412ac657335ba7fc5b0ca32aa20bc4a0d11770746bf0ea8eddef37ddc1908c
|
data/Gemfile
CHANGED
data/README.md
CHANGED
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.3.0.82
|
|
@@ -13,9 +13,7 @@ module BarsoomUtils
|
|
|
13
13
|
|
|
14
14
|
ensure_notifier!
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
Sentry.capture_exception(exception, extra: context) if defined?(Sentry)
|
|
18
|
-
result
|
|
16
|
+
Sentry.capture_exception(exception, extra: context)
|
|
19
17
|
end
|
|
20
18
|
|
|
21
19
|
def self.message(message, details_or_context = nil, context_or_nothing = nil)
|
|
@@ -32,29 +30,17 @@ module BarsoomUtils
|
|
|
32
30
|
context = {}
|
|
33
31
|
end
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
error_class: message,
|
|
38
|
-
error_message: (details || "(no message)").to_s,
|
|
39
|
-
context: context.to_h,
|
|
40
|
-
)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
if defined?(Sentry)
|
|
44
|
-
title = details ? "#{message}: #{details}" : message.to_s
|
|
45
|
-
Sentry.capture_message(title, extra: context.to_h)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
result
|
|
33
|
+
title = details ? "#{message}: #{details}" : message.to_s
|
|
34
|
+
Sentry.capture_message(title, extra: context.to_h)
|
|
49
35
|
end
|
|
50
36
|
|
|
51
37
|
private
|
|
52
38
|
|
|
53
39
|
private_class_method \
|
|
54
40
|
def self.ensure_notifier!
|
|
55
|
-
return if defined?(
|
|
41
|
+
return if defined?(Sentry)
|
|
56
42
|
|
|
57
|
-
raise "Cannot notify:
|
|
43
|
+
raise "Cannot notify: Sentry is not available."
|
|
58
44
|
end
|
|
59
45
|
end
|
|
60
46
|
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module RuboCop
|
|
3
|
+
module Cop
|
|
4
|
+
module Barsoom
|
|
5
|
+
# Checks for an `initialize` that only assigns each of its arguments to an instance variable of the same name.
|
|
6
|
+
# attr_extras can define that for you.
|
|
7
|
+
#
|
|
8
|
+
# Positional defaults, splats and block arguments are accepted, since attr_extras has no equivalent. So are
|
|
9
|
+
# keyword defaults other than immutable literals: attr_extras evaluates them once, when the class is loaded.
|
|
10
|
+
#
|
|
11
|
+
# @example
|
|
12
|
+
# # bad
|
|
13
|
+
# def initialize(user, notify:)
|
|
14
|
+
# @user = user
|
|
15
|
+
# @notify = notify
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# # good
|
|
19
|
+
# pattr_initialize :user, [ :notify! ]
|
|
20
|
+
class AttrExtrasInitialize < Base
|
|
21
|
+
MSG = "Use attr_extras, e.g. `pattr_initialize`, instead of an `initialize` that only assigns its arguments."
|
|
22
|
+
SUPPORTED_ARGUMENT_TYPES = %i[arg kwarg kwoptarg].freeze
|
|
23
|
+
IMMUTABLE_DEFAULT_TYPES = %i[nil true false sym int float].freeze
|
|
24
|
+
|
|
25
|
+
requires_gem "attr_extras"
|
|
26
|
+
|
|
27
|
+
def on_def(node)
|
|
28
|
+
return unless node.method?(:initialize)
|
|
29
|
+
return unless node.each_ancestor(:class, :module, :sclass).first&.class_type?
|
|
30
|
+
return unless supported_arguments?(node.arguments)
|
|
31
|
+
return unless only_assigns?(node.body, node.arguments.map(&:name))
|
|
32
|
+
|
|
33
|
+
add_offense(node.loc.keyword.join(node.loc.name))
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def supported_arguments?(arguments)
|
|
39
|
+
arguments.any? && arguments.all? { |argument|
|
|
40
|
+
SUPPORTED_ARGUMENT_TYPES.include?(argument.type) &&
|
|
41
|
+
(!argument.kwoptarg_type? || IMMUTABLE_DEFAULT_TYPES.include?(argument.default_value.type))
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def only_assigns?(body, names)
|
|
46
|
+
return false unless body
|
|
47
|
+
|
|
48
|
+
statements = body.begin_type? ? body.children : [ body ]
|
|
49
|
+
assigned = statements.map { |statement| assigned_argument(statement) }
|
|
50
|
+
|
|
51
|
+
assigned.all? && assigned.sort == names.sort
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def assigned_argument(statement)
|
|
55
|
+
return unless statement.ivasgn_type? && statement.expression&.lvar_type?
|
|
56
|
+
|
|
57
|
+
name = statement.expression.children.first
|
|
58
|
+
name if statement.name == :"@#{name}"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module RuboCop
|
|
3
|
+
module Cop
|
|
4
|
+
module Barsoom
|
|
5
|
+
# Checks for `private_class_method` listing class methods by name, when they're defined with `def self.` in the
|
|
6
|
+
# same class body. Putting the modifier before each definition shows at a glance which class methods are private.
|
|
7
|
+
#
|
|
8
|
+
# Names not defined that way, e.g. `private_class_method :new`, are accepted. The offense is only corrected when
|
|
9
|
+
# every listed name is defined in the class body.
|
|
10
|
+
#
|
|
11
|
+
# @example
|
|
12
|
+
# # bad
|
|
13
|
+
# def self.parse(value) = Time.iso8601(value)
|
|
14
|
+
#
|
|
15
|
+
# private_class_method :parse
|
|
16
|
+
#
|
|
17
|
+
# # good
|
|
18
|
+
# private_class_method \
|
|
19
|
+
# def self.parse(value) = Time.iso8601(value)
|
|
20
|
+
class InlinePrivateClassMethod < Base
|
|
21
|
+
include RangeHelp
|
|
22
|
+
extend AutoCorrector
|
|
23
|
+
|
|
24
|
+
MSG = "Use `private_class_method \\` before each `def self.` instead of listing the methods by name."
|
|
25
|
+
RESTRICT_ON_SEND = %i[private_class_method].freeze
|
|
26
|
+
|
|
27
|
+
def on_send(node)
|
|
28
|
+
return if node.receiver || node.arguments.empty? || !node.arguments.all?(&:sym_type?)
|
|
29
|
+
|
|
30
|
+
definitions = class_method_definitions(node.parent)
|
|
31
|
+
names = node.arguments.map(&:value)
|
|
32
|
+
return if names.none? { |name| definitions.key?(name) }
|
|
33
|
+
|
|
34
|
+
add_offense(node) do |corrector|
|
|
35
|
+
next unless names.all? { |name| definitions.key?(name) }
|
|
36
|
+
|
|
37
|
+
names.each do |name|
|
|
38
|
+
definition = definitions.fetch(name)
|
|
39
|
+
corrector.insert_before(definition, "private_class_method \\\n#{" " * definition.loc.column}")
|
|
40
|
+
end
|
|
41
|
+
corrector.remove(removal_range(node))
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def class_method_definitions(body)
|
|
48
|
+
return {} unless body&.begin_type?
|
|
49
|
+
|
|
50
|
+
body.each_child_node(:defs).select { |definition| definition.receiver.self_type? }.to_h { |definition| [ definition.method_name, definition ] }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# The whole line, and the blank line above it, so no blank line is left before the class's `end`.
|
|
54
|
+
def removal_range(node)
|
|
55
|
+
range = range_by_whole_lines(node.source_range, include_final_newline: true)
|
|
56
|
+
previous_line = processed_source.lines[node.first_line - 2]
|
|
57
|
+
previous_line&.strip&.empty? ? range.with(begin_pos: range.begin_pos - previous_line.length - 1) : range
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
data/shared_rubocop.yml
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Configuration for the Rubocop code linting tool. See README.
|
|
2
2
|
|
|
3
|
+
# Our custom cops, in lib/rubocop/cop/barsoom.
|
|
4
|
+
require:
|
|
5
|
+
- barsoom_utils/rubocop
|
|
6
|
+
|
|
3
7
|
AllCops:
|
|
4
8
|
ActiveSupportExtensionsEnabled: true
|
|
5
9
|
DisabledByDefault: true
|
|
@@ -381,3 +385,12 @@ Gemspec/RequireMFA:
|
|
|
381
385
|
# https://docs.rubocop.org/rubocop/cops_naming.html#namingblockforwarding
|
|
382
386
|
Naming/BlockForwarding:
|
|
383
387
|
Enabled: true
|
|
388
|
+
|
|
389
|
+
# Allow e.g. `pattr_initialize :user` and disallow an `initialize` that only assigns `@user = user`.
|
|
390
|
+
# Only runs in projects that have attr_extras in their Gemfile.lock.
|
|
391
|
+
Barsoom/AttrExtrasInitialize:
|
|
392
|
+
Enabled: true
|
|
393
|
+
|
|
394
|
+
# Allow e.g. `private_class_method \` before `def self.parse` and disallow `private_class_method :parse` further down.
|
|
395
|
+
Barsoom/InlinePrivateClassMethod:
|
|
396
|
+
Enabled: true
|
data/shared_rubocop_rails.yml
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
require "barsoom_utils/exception_notifier"
|
|
3
|
-
require "honeybadger"
|
|
4
3
|
require "sentry-ruby"
|
|
5
4
|
require "fixme"
|
|
6
5
|
|
|
7
6
|
RSpec.describe BarsoomUtils::ExceptionNotifier do
|
|
8
7
|
before do
|
|
9
|
-
allow(Honeybadger).to receive(:notify)
|
|
10
8
|
allow(Sentry).to receive(:capture_exception)
|
|
11
9
|
allow(Sentry).to receive(:capture_message)
|
|
12
10
|
end
|
|
@@ -14,17 +12,15 @@ RSpec.describe BarsoomUtils::ExceptionNotifier do
|
|
|
14
12
|
describe ".notify" do
|
|
15
13
|
let(:ex) { StandardError.new("boom") }
|
|
16
14
|
|
|
17
|
-
it "passes an exception to
|
|
15
|
+
it "passes an exception to Sentry" do
|
|
18
16
|
BarsoomUtils::ExceptionNotifier.notify(ex)
|
|
19
17
|
|
|
20
|
-
expect(Honeybadger).to have_received(:notify).with(ex, context: {})
|
|
21
18
|
expect(Sentry).to have_received(:capture_exception).with(ex, extra: {})
|
|
22
19
|
end
|
|
23
20
|
|
|
24
21
|
it "can pass through context info" do
|
|
25
22
|
BarsoomUtils::ExceptionNotifier.notify(ex, context: { foo: "bar" })
|
|
26
23
|
|
|
27
|
-
expect(Honeybadger).to have_received(:notify).with(ex, context: { foo: "bar" })
|
|
28
24
|
expect(Sentry).to have_received(:capture_exception).with(ex, extra: { foo: "bar" })
|
|
29
25
|
end
|
|
30
26
|
|
|
@@ -33,74 +29,38 @@ RSpec.describe BarsoomUtils::ExceptionNotifier do
|
|
|
33
29
|
BarsoomUtils::ExceptionNotifier.notify({ foo: "bar" })
|
|
34
30
|
}.to raise_error(/Expected an exception but got:.*foo.*bar/)
|
|
35
31
|
|
|
36
|
-
expect(Honeybadger).not_to have_received(:notify)
|
|
37
32
|
expect(Sentry).not_to have_received(:capture_exception)
|
|
38
33
|
end
|
|
39
34
|
|
|
40
|
-
it "returns
|
|
41
|
-
allow(
|
|
35
|
+
it "returns Sentry's result" do
|
|
36
|
+
allow(Sentry).to receive(:capture_exception).and_return(:sentinel)
|
|
42
37
|
|
|
43
38
|
expect(BarsoomUtils::ExceptionNotifier.notify(ex)).to eq(:sentinel)
|
|
44
39
|
end
|
|
45
40
|
|
|
46
|
-
|
|
47
|
-
|
|
41
|
+
it "raises without Sentry" do
|
|
42
|
+
hide_const("Sentry")
|
|
48
43
|
|
|
49
|
-
|
|
50
|
-
BarsoomUtils::ExceptionNotifier.notify(ex
|
|
51
|
-
|
|
52
|
-
expect(Honeybadger).to have_received(:notify).with(ex, context: { foo: "bar" })
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
context "without Honeybadger" do
|
|
57
|
-
before { hide_const("Honeybadger") }
|
|
58
|
-
|
|
59
|
-
it "still notifies Sentry and raises nothing" do
|
|
60
|
-
BarsoomUtils::ExceptionNotifier.notify(ex, context: { foo: "bar" })
|
|
61
|
-
|
|
62
|
-
expect(Sentry).to have_received(:capture_exception).with(ex, extra: { foo: "bar" })
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
context "without either notifier" do
|
|
67
|
-
before do
|
|
68
|
-
hide_const("Honeybadger")
|
|
69
|
-
hide_const("Sentry")
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
it "raises" do
|
|
73
|
-
expect {
|
|
74
|
-
BarsoomUtils::ExceptionNotifier.notify(ex)
|
|
75
|
-
}.to raise_error(/neither Honeybadger nor Sentry/)
|
|
76
|
-
end
|
|
44
|
+
expect {
|
|
45
|
+
BarsoomUtils::ExceptionNotifier.notify(ex)
|
|
46
|
+
}.to raise_error(/Sentry is not available/)
|
|
77
47
|
end
|
|
78
48
|
end
|
|
79
49
|
|
|
80
50
|
describe ".message" do
|
|
81
|
-
it "passes a message to
|
|
51
|
+
it "passes a message to Sentry" do
|
|
82
52
|
BarsoomUtils::ExceptionNotifier.message("Boom!")
|
|
83
53
|
|
|
84
|
-
expect(Honeybadger).to have_received(:notify).with(
|
|
85
|
-
error_class: "Boom!",
|
|
86
|
-
error_message: "(no message)",
|
|
87
|
-
context: {},
|
|
88
|
-
)
|
|
89
54
|
expect(Sentry).to have_received(:capture_message).with("Boom!", extra: {})
|
|
90
55
|
end
|
|
91
56
|
|
|
92
57
|
it "can take a custom details string" do
|
|
93
58
|
BarsoomUtils::ExceptionNotifier.message("Boom!", "Details!")
|
|
94
59
|
|
|
95
|
-
expect(Honeybadger).to have_received(:notify).with(
|
|
96
|
-
error_class: "Boom!",
|
|
97
|
-
error_message: "Details!",
|
|
98
|
-
context: {},
|
|
99
|
-
)
|
|
100
60
|
expect(Sentry).to have_received(:capture_message).with("Boom!: Details!", extra: {})
|
|
101
61
|
end
|
|
102
62
|
|
|
103
|
-
it "coerces the message to a string
|
|
63
|
+
it "coerces the message to a string" do
|
|
104
64
|
BarsoomUtils::ExceptionNotifier.message(:boom)
|
|
105
65
|
|
|
106
66
|
expect(Sentry).to have_received(:capture_message).with("boom", extra: {})
|
|
@@ -109,66 +69,27 @@ RSpec.describe BarsoomUtils::ExceptionNotifier do
|
|
|
109
69
|
it "can take a context hash" do
|
|
110
70
|
BarsoomUtils::ExceptionNotifier.message("Boom!", foo: "bar")
|
|
111
71
|
|
|
112
|
-
expect(Honeybadger).to have_received(:notify).with(
|
|
113
|
-
error_class: "Boom!",
|
|
114
|
-
error_message: "(no message)",
|
|
115
|
-
context: { foo: "bar" },
|
|
116
|
-
)
|
|
117
72
|
expect(Sentry).to have_received(:capture_message).with("Boom!", extra: { foo: "bar" })
|
|
118
73
|
end
|
|
119
74
|
|
|
120
75
|
it "can take a custom details string and a context hash" do
|
|
121
76
|
BarsoomUtils::ExceptionNotifier.message("Boom!", "Details!", foo: "bar")
|
|
122
77
|
|
|
123
|
-
expect(Honeybadger).to have_received(:notify).with(
|
|
124
|
-
error_class: "Boom!",
|
|
125
|
-
error_message: "Details!",
|
|
126
|
-
context: { foo: "bar" },
|
|
127
|
-
)
|
|
128
78
|
expect(Sentry).to have_received(:capture_message).with("Boom!: Details!", extra: { foo: "bar" })
|
|
129
79
|
end
|
|
130
80
|
|
|
131
|
-
it "returns
|
|
132
|
-
allow(
|
|
81
|
+
it "returns Sentry's result" do
|
|
82
|
+
allow(Sentry).to receive(:capture_message).and_return(:sentinel)
|
|
133
83
|
|
|
134
84
|
expect(BarsoomUtils::ExceptionNotifier.message("Boom!")).to eq(:sentinel)
|
|
135
85
|
end
|
|
136
86
|
|
|
137
|
-
|
|
138
|
-
|
|
87
|
+
it "raises without Sentry" do
|
|
88
|
+
hide_const("Sentry")
|
|
139
89
|
|
|
140
|
-
|
|
141
|
-
BarsoomUtils::ExceptionNotifier.message("Boom!"
|
|
142
|
-
|
|
143
|
-
expect(Honeybadger).to have_received(:notify).with(
|
|
144
|
-
error_class: "Boom!",
|
|
145
|
-
error_message: "Details!",
|
|
146
|
-
context: { foo: "bar" },
|
|
147
|
-
)
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
context "without Honeybadger" do
|
|
152
|
-
before { hide_const("Honeybadger") }
|
|
153
|
-
|
|
154
|
-
it "still notifies Sentry and raises nothing" do
|
|
155
|
-
BarsoomUtils::ExceptionNotifier.message("Boom!", "Details!", foo: "bar")
|
|
156
|
-
|
|
157
|
-
expect(Sentry).to have_received(:capture_message).with("Boom!: Details!", extra: { foo: "bar" })
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
context "without either notifier" do
|
|
162
|
-
before do
|
|
163
|
-
hide_const("Honeybadger")
|
|
164
|
-
hide_const("Sentry")
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
it "raises" do
|
|
168
|
-
expect {
|
|
169
|
-
BarsoomUtils::ExceptionNotifier.message("Boom!")
|
|
170
|
-
}.to raise_error(/neither Honeybadger nor Sentry/)
|
|
171
|
-
end
|
|
90
|
+
expect {
|
|
91
|
+
BarsoomUtils::ExceptionNotifier.message("Boom!")
|
|
92
|
+
}.to raise_error(/Sentry is not available/)
|
|
172
93
|
end
|
|
173
94
|
end
|
|
174
95
|
end
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require "rubocop_helper"
|
|
3
|
+
|
|
4
|
+
RSpec.describe RuboCop::Cop::Barsoom::AttrExtrasInitialize, :config do
|
|
5
|
+
let(:gem_versions) { { "attr_extras" => "7.1.0" } }
|
|
6
|
+
|
|
7
|
+
it "registers an offense for an initialize that only assigns its positional arguments" do
|
|
8
|
+
expect_offense(<<~RUBY)
|
|
9
|
+
class Foo
|
|
10
|
+
def initialize(bar, baz)
|
|
11
|
+
^^^^^^^^^^^^^^ Use attr_extras, e.g. `pattr_initialize`, instead of an `initialize` that only assigns its arguments.
|
|
12
|
+
@bar = bar
|
|
13
|
+
@baz = baz
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
RUBY
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "registers an offense for required keyword arguments" do
|
|
20
|
+
expect_offense(<<~RUBY)
|
|
21
|
+
class Foo
|
|
22
|
+
def initialize(bar, baz:)
|
|
23
|
+
^^^^^^^^^^^^^^ Use attr_extras, e.g. `pattr_initialize`, instead of an `initialize` that only assigns its arguments.
|
|
24
|
+
@bar = bar
|
|
25
|
+
@baz = baz
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
RUBY
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "registers an offense for keyword arguments with immutable literal defaults" do
|
|
32
|
+
expect_offense(<<~RUBY)
|
|
33
|
+
class Foo
|
|
34
|
+
def initialize(bar: nil, baz: :qux, limit: 10)
|
|
35
|
+
^^^^^^^^^^^^^^ Use attr_extras, e.g. `pattr_initialize`, instead of an `initialize` that only assigns its arguments.
|
|
36
|
+
@bar = bar
|
|
37
|
+
@baz = baz
|
|
38
|
+
@limit = limit
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
RUBY
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "accepts keyword defaults that attr_extras would evaluate once, at load time" do
|
|
45
|
+
expect_no_offenses(<<~RUBY)
|
|
46
|
+
class Foo
|
|
47
|
+
def initialize(now: Time.now, list: [], name: "x")
|
|
48
|
+
@now = now
|
|
49
|
+
@list = list
|
|
50
|
+
@name = name
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
RUBY
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "accepts positional defaults, which attr_extras doesn't support" do
|
|
57
|
+
expect_no_offenses(<<~RUBY)
|
|
58
|
+
class Foo
|
|
59
|
+
def initialize(bar, baz = nil)
|
|
60
|
+
@bar = bar
|
|
61
|
+
@baz = baz
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
RUBY
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "accepts splat and block arguments" do
|
|
68
|
+
expect_no_offenses(<<~RUBY)
|
|
69
|
+
class Foo
|
|
70
|
+
def initialize(*bars, **opts, &block)
|
|
71
|
+
@bars = bars
|
|
72
|
+
@opts = opts
|
|
73
|
+
@block = block
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
RUBY
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "accepts an initialize that does anything besides assigning its arguments" do
|
|
80
|
+
expect_no_offenses(<<~RUBY)
|
|
81
|
+
class Foo
|
|
82
|
+
def initialize(bar, baz)
|
|
83
|
+
@bar = bar
|
|
84
|
+
@baz = baz.to_s
|
|
85
|
+
@qux = []
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
RUBY
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "accepts an initialize that calls super" do
|
|
92
|
+
expect_no_offenses(<<~RUBY)
|
|
93
|
+
class Foo < Base
|
|
94
|
+
def initialize(bar)
|
|
95
|
+
super()
|
|
96
|
+
@bar = bar
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
RUBY
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "accepts instance variables named differently from the arguments" do
|
|
103
|
+
expect_no_offenses(<<~RUBY)
|
|
104
|
+
class Foo
|
|
105
|
+
def initialize(bar)
|
|
106
|
+
@baz = bar
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
RUBY
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it "accepts an initialize that leaves an argument unassigned" do
|
|
113
|
+
expect_no_offenses(<<~RUBY)
|
|
114
|
+
class Foo
|
|
115
|
+
def initialize(bar, _baz)
|
|
116
|
+
@bar = bar
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
RUBY
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it "accepts an initialize without arguments" do
|
|
123
|
+
expect_no_offenses(<<~RUBY)
|
|
124
|
+
class Foo
|
|
125
|
+
def initialize
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
RUBY
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it "accepts an initialize in a module" do
|
|
132
|
+
expect_no_offenses(<<~RUBY)
|
|
133
|
+
module Foo
|
|
134
|
+
def initialize(bar)
|
|
135
|
+
@bar = bar
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
RUBY
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
context "when the project doesn't use attr_extras" do
|
|
142
|
+
let(:gem_versions) { {} }
|
|
143
|
+
|
|
144
|
+
it "accepts the initialize" do
|
|
145
|
+
expect_no_offenses(<<~RUBY)
|
|
146
|
+
class Foo
|
|
147
|
+
def initialize(bar)
|
|
148
|
+
@bar = bar
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
RUBY
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require "rubocop_helper"
|
|
3
|
+
|
|
4
|
+
RSpec.describe RuboCop::Cop::Barsoom::InlinePrivateClassMethod, :config do
|
|
5
|
+
let(:ruby_version) { 3.4 }
|
|
6
|
+
|
|
7
|
+
it "registers an offense for listing class methods by name, and moves the modifier onto each definition" do
|
|
8
|
+
expect_offense(<<~RUBY)
|
|
9
|
+
class Foo
|
|
10
|
+
def self.call = parse
|
|
11
|
+
|
|
12
|
+
def self.parse
|
|
13
|
+
:parsed
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.verifier = :verifier
|
|
17
|
+
|
|
18
|
+
private_class_method :parse, :verifier
|
|
19
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `private_class_method \\` before each `def self.` instead of listing the methods by name.
|
|
20
|
+
end
|
|
21
|
+
RUBY
|
|
22
|
+
|
|
23
|
+
expect_correction(<<~RUBY)
|
|
24
|
+
class Foo
|
|
25
|
+
def self.call = parse
|
|
26
|
+
|
|
27
|
+
private_class_method \\
|
|
28
|
+
def self.parse
|
|
29
|
+
:parsed
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private_class_method \\
|
|
33
|
+
def self.verifier = :verifier
|
|
34
|
+
end
|
|
35
|
+
RUBY
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "registers an offense without correcting it when some of the names aren't defined in the class body" do
|
|
39
|
+
expect_offense(<<~RUBY)
|
|
40
|
+
class Foo
|
|
41
|
+
def self.build = new
|
|
42
|
+
|
|
43
|
+
def self.parse = :parsed
|
|
44
|
+
|
|
45
|
+
private_class_method :new, :parse
|
|
46
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `private_class_method \\` before each `def self.` instead of listing the methods by name.
|
|
47
|
+
end
|
|
48
|
+
RUBY
|
|
49
|
+
|
|
50
|
+
expect_no_corrections
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "accepts the modifier before the definition" do
|
|
54
|
+
expect_no_offenses(<<~RUBY)
|
|
55
|
+
class Foo
|
|
56
|
+
private_class_method \\
|
|
57
|
+
def self.parse = :parsed
|
|
58
|
+
|
|
59
|
+
private_class_method def self.verifier = :verifier
|
|
60
|
+
end
|
|
61
|
+
RUBY
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "accepts names that aren't defined with `def self.` in the class body" do
|
|
65
|
+
expect_no_offenses(<<~RUBY)
|
|
66
|
+
class Foo
|
|
67
|
+
def self.build = new
|
|
68
|
+
|
|
69
|
+
private_class_method :new
|
|
70
|
+
end
|
|
71
|
+
RUBY
|
|
72
|
+
end
|
|
73
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: barsoom_utils
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0.82
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tomas Skogberg
|
|
@@ -29,13 +29,19 @@ files:
|
|
|
29
29
|
- lib/barsoom_utils.rb
|
|
30
30
|
- lib/barsoom_utils/exception_notifier.rb
|
|
31
31
|
- lib/barsoom_utils/feature_toggle.rb
|
|
32
|
+
- lib/barsoom_utils/rubocop.rb
|
|
32
33
|
- lib/barsoom_utils/spec/debug_helpers.rb
|
|
33
34
|
- lib/barsoom_utils/version.rb
|
|
35
|
+
- lib/rubocop/cop/barsoom/attr_extras_initialize.rb
|
|
36
|
+
- lib/rubocop/cop/barsoom/inline_private_class_method.rb
|
|
34
37
|
- script/test
|
|
35
38
|
- shared_rubocop.yml
|
|
36
39
|
- shared_rubocop_rails.yml
|
|
37
40
|
- spec/exception_notifier_spec.rb
|
|
38
41
|
- spec/feature_toggle_spec.rb
|
|
42
|
+
- spec/rubocop/cop/barsoom/attr_extras_initialize_spec.rb
|
|
43
|
+
- spec/rubocop/cop/barsoom/inline_private_class_method_spec.rb
|
|
44
|
+
- spec/rubocop_helper.rb
|
|
39
45
|
- spec/spec/debug_helpers_spec.rb
|
|
40
46
|
- spec/spec_helper.rb
|
|
41
47
|
homepage: https://dev.auctionet.com/
|