rubocop-thread_safety 0.4.4 → 0.7.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/CHANGELOG.md +30 -0
- data/LICENSE.txt +2 -1
- data/README.md +15 -8
- data/config/default.yml +19 -2
- data/config/obsoletion.yml +2 -0
- data/lib/rubocop/cop/mixin/operation_with_threadsafe_result.rb +44 -0
- data/lib/rubocop/cop/thread_safety/class_and_module_attributes.rb +18 -5
- data/lib/rubocop/cop/thread_safety/class_instance_variable.rb +259 -0
- data/lib/rubocop/cop/thread_safety/dir_chdir.rb +65 -0
- data/lib/rubocop/cop/thread_safety/mutable_class_instance_variable.rb +41 -60
- data/lib/rubocop/cop/thread_safety/new_thread.rb +6 -5
- data/lib/rubocop/cop/thread_safety/rack_middleware_instance_variable.rb +121 -0
- data/lib/rubocop/thread_safety/plugin.rb +38 -0
- data/lib/rubocop/thread_safety/version.rb +3 -1
- data/lib/rubocop/thread_safety.rb +0 -5
- data/lib/rubocop-thread_safety.rb +5 -3
- metadata +31 -94
- data/.gitignore +0 -10
- data/.rspec +0 -2
- data/.rubocop.yml +0 -70
- data/.travis.yml +0 -64
- data/Appraisals +0 -23
- data/Gemfile +0 -6
- data/Rakefile +0 -8
- data/bin/console +0 -15
- data/bin/setup +0 -6
- data/gemfiles/rubocop_0.53.gemfile +0 -7
- data/gemfiles/rubocop_0.81.gemfile +0 -7
- data/gemfiles/rubocop_0.86.gemfile +0 -7
- data/gemfiles/rubocop_1.20.gemfile +0 -7
- data/lib/rubocop/cop/thread_safety/instance_variable_in_class_method.rb +0 -131
- data/lib/rubocop/thread_safety/inject.rb +0 -20
- data/rubocop-thread_safety.gemspec +0 -38
@@ -3,11 +3,11 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module ThreadSafety
|
6
|
-
#
|
6
|
+
# Checks whether some class instance variable isn't a
|
7
7
|
# mutable literal (e.g. array or hash).
|
8
8
|
#
|
9
9
|
# It is based on Style/MutableConstant from RuboCop.
|
10
|
-
# See https://github.com/rubocop
|
10
|
+
# See https://github.com/rubocop/rubocop/blob/master/lib/rubocop/cop/style/mutable_constant.rb
|
11
11
|
#
|
12
12
|
# Class instance variables are a risk to threaded code as they are shared
|
13
13
|
# between threads. A mutable object such as an array or hash may be
|
@@ -72,9 +72,12 @@ module RuboCop
|
|
72
72
|
# end
|
73
73
|
# end.freeze
|
74
74
|
# end
|
75
|
-
class MutableClassInstanceVariable <
|
75
|
+
class MutableClassInstanceVariable < Base
|
76
|
+
extend AutoCorrector
|
77
|
+
|
76
78
|
include FrozenStringLiteral
|
77
79
|
include ConfigurableEnforcedStyle
|
80
|
+
include OperationWithThreadsafeResult
|
78
81
|
|
79
82
|
MSG = 'Freeze mutable objects assigned to class instance variables.'
|
80
83
|
FROZEN_STRING_LITERAL_TYPES_RUBY27 = %i[str dstr].freeze
|
@@ -83,22 +86,20 @@ module RuboCop
|
|
83
86
|
def on_ivasgn(node)
|
84
87
|
return unless in_class?(node)
|
85
88
|
|
86
|
-
|
87
|
-
on_assignment(value)
|
89
|
+
on_assignment(node.expression)
|
88
90
|
end
|
89
91
|
|
90
92
|
def on_or_asgn(node)
|
91
|
-
|
92
|
-
return unless lhs&.ivasgn_type?
|
93
|
+
return unless node.assignment_node.ivasgn_type?
|
93
94
|
return unless in_class?(node)
|
94
95
|
|
95
|
-
on_assignment(
|
96
|
+
on_assignment(node.expression)
|
96
97
|
end
|
97
98
|
|
98
99
|
def on_masgn(node)
|
99
100
|
return unless in_class?(node)
|
100
101
|
|
101
|
-
mlhs, values = *node
|
102
|
+
mlhs, values = *node # rubocop:disable InternalAffairs/NodeDestructuring
|
102
103
|
return unless values.array_type?
|
103
104
|
|
104
105
|
mlhs.to_a.zip(values.to_a).each do |lhs, value|
|
@@ -108,23 +109,21 @@ module RuboCop
|
|
108
109
|
end
|
109
110
|
end
|
110
111
|
|
111
|
-
def autocorrect(node)
|
112
|
+
def autocorrect(corrector, node)
|
112
113
|
expr = node.source_range
|
113
114
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
corrector.insert_after(expr, ')')
|
124
|
-
end
|
125
|
-
|
126
|
-
corrector.insert_after(expr, '.freeze')
|
115
|
+
splat_value = splat_value(node)
|
116
|
+
if splat_value
|
117
|
+
correct_splat_expansion(corrector, expr, splat_value)
|
118
|
+
elsif node.array_type? && !node.bracketed?
|
119
|
+
corrector.insert_before(expr, '[')
|
120
|
+
corrector.insert_after(expr, ']')
|
121
|
+
elsif requires_parentheses?(node)
|
122
|
+
corrector.insert_before(expr, '(')
|
123
|
+
corrector.insert_after(expr, ')')
|
127
124
|
end
|
125
|
+
|
126
|
+
corrector.insert_after(expr, '.freeze')
|
128
127
|
end
|
129
128
|
|
130
129
|
private
|
@@ -152,7 +151,9 @@ module RuboCop
|
|
152
151
|
return if operation_produces_threadsafe_object?(value)
|
153
152
|
return if frozen_string_literal?(value)
|
154
153
|
|
155
|
-
add_offense(value)
|
154
|
+
add_offense(value) do |corrector|
|
155
|
+
autocorrect(corrector, value)
|
156
|
+
end
|
156
157
|
end
|
157
158
|
|
158
159
|
def check(value)
|
@@ -160,7 +161,9 @@ module RuboCop
|
|
160
161
|
range_enclosed_in_parentheses?(value)
|
161
162
|
return if frozen_string_literal?(value)
|
162
163
|
|
163
|
-
add_offense(value)
|
164
|
+
add_offense(value) do |corrector|
|
165
|
+
autocorrect(corrector, value)
|
166
|
+
end
|
164
167
|
end
|
165
168
|
|
166
169
|
def in_class?(node)
|
@@ -174,12 +177,13 @@ module RuboCop
|
|
174
177
|
|
175
178
|
def container?(node)
|
176
179
|
return true if define_singleton_method?(node)
|
180
|
+
return true if define_method?(node)
|
177
181
|
|
178
182
|
%i[def defs class module].include?(node.type)
|
179
183
|
end
|
180
184
|
|
181
185
|
def mutable_literal?(node)
|
182
|
-
return if node.nil?
|
186
|
+
return false if node.nil?
|
183
187
|
|
184
188
|
node.mutable_literal? || range_type?(node)
|
185
189
|
end
|
@@ -194,7 +198,7 @@ module RuboCop
|
|
194
198
|
end
|
195
199
|
|
196
200
|
def range_type?(node)
|
197
|
-
node.
|
201
|
+
node.type?(:range)
|
198
202
|
end
|
199
203
|
|
200
204
|
def correct_splat_expansion(corrector, expr, splat_value)
|
@@ -205,16 +209,24 @@ module RuboCop
|
|
205
209
|
end
|
206
210
|
end
|
207
211
|
|
212
|
+
# @!method define_singleton_method?(node)
|
208
213
|
def_node_matcher :define_singleton_method?, <<~PATTERN
|
209
214
|
(block (send nil? :define_singleton_method ...) ...)
|
210
215
|
PATTERN
|
211
216
|
|
217
|
+
# @!method define_method?(node)
|
218
|
+
def_node_matcher :define_method?, <<~PATTERN
|
219
|
+
(block (send nil? :define_method ...) ...)
|
220
|
+
PATTERN
|
221
|
+
|
222
|
+
# @!method splat_value(node)
|
212
223
|
def_node_matcher :splat_value, <<~PATTERN
|
213
224
|
(array (splat $_))
|
214
225
|
PATTERN
|
215
226
|
|
216
227
|
# NOTE: Some of these patterns may not actually return an immutable
|
217
228
|
# object but we will consider them immutable for this cop.
|
229
|
+
# @!method operation_produces_immutable_object?(node)
|
218
230
|
def_node_matcher :operation_produces_immutable_object?, <<~PATTERN
|
219
231
|
{
|
220
232
|
(const _ _)
|
@@ -231,40 +243,9 @@ module RuboCop
|
|
231
243
|
}
|
232
244
|
PATTERN
|
233
245
|
|
234
|
-
|
235
|
-
{
|
236
|
-
(send (const {nil? cbase} :Queue) :new ...)
|
237
|
-
(send
|
238
|
-
(const (const {nil? cbase} :ThreadSafe) {:Hash :Array})
|
239
|
-
:new ...)
|
240
|
-
(block
|
241
|
-
(send
|
242
|
-
(const (const {nil? cbase} :ThreadSafe) {:Hash :Array})
|
243
|
-
:new ...)
|
244
|
-
...)
|
245
|
-
(send (const (const {nil? cbase} :Concurrent) _) :new ...)
|
246
|
-
(block
|
247
|
-
(send (const (const {nil? cbase} :Concurrent) _) :new ...)
|
248
|
-
...)
|
249
|
-
(send (const (const (const {nil? cbase} :Concurrent) _) _) :new ...)
|
250
|
-
(block
|
251
|
-
(send
|
252
|
-
(const (const (const {nil? cbase} :Concurrent) _) _)
|
253
|
-
:new ...)
|
254
|
-
...)
|
255
|
-
(send
|
256
|
-
(const (const (const (const {nil? cbase} :Concurrent) _) _) _)
|
257
|
-
:new ...)
|
258
|
-
(block
|
259
|
-
(send
|
260
|
-
(const (const (const (const {nil? cbase} :Concurrent) _) _) _)
|
261
|
-
:new ...)
|
262
|
-
...)
|
263
|
-
}
|
264
|
-
PATTERN
|
265
|
-
|
246
|
+
# @!method range_enclosed_in_parentheses?(node)
|
266
247
|
def_node_matcher :range_enclosed_in_parentheses?, <<~PATTERN
|
267
|
-
(begin (
|
248
|
+
(begin (range _ _))
|
268
249
|
PATTERN
|
269
250
|
end
|
270
251
|
end
|
@@ -10,18 +10,19 @@ module RuboCop
|
|
10
10
|
# @example
|
11
11
|
# # bad
|
12
12
|
# Thread.new { do_work }
|
13
|
-
class NewThread <
|
13
|
+
class NewThread < Base
|
14
14
|
MSG = 'Avoid starting new threads.'
|
15
|
+
RESTRICT_ON_SEND = %i[new fork start].freeze
|
15
16
|
|
17
|
+
# @!method new_thread?(node)
|
16
18
|
def_node_matcher :new_thread?, <<~MATCHER
|
17
|
-
(
|
19
|
+
(call (const {nil? cbase} :Thread) {:new :fork :start} ...)
|
18
20
|
MATCHER
|
19
21
|
|
20
22
|
def on_send(node)
|
21
|
-
|
22
|
-
|
23
|
-
add_offense(node, message: MSG)
|
23
|
+
new_thread?(node) { add_offense(node) }
|
24
24
|
end
|
25
|
+
alias on_csend on_send
|
25
26
|
end
|
26
27
|
end
|
27
28
|
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module ThreadSafety
|
6
|
+
# Avoid instance variables in rack middleware.
|
7
|
+
#
|
8
|
+
# Middlewares are initialized once, meaning any instance variables are shared between executor threads.
|
9
|
+
# To avoid potential race conditions, it's recommended to design middlewares to be stateless
|
10
|
+
# or to implement proper synchronization mechanisms.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# # bad
|
14
|
+
# class CounterMiddleware
|
15
|
+
# def initialize(app)
|
16
|
+
# @app = app
|
17
|
+
# @counter = 0
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# def call(env)
|
21
|
+
# app.call(env)
|
22
|
+
# ensure
|
23
|
+
# @counter += 1
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# # good
|
28
|
+
# class CounterMiddleware
|
29
|
+
# def initialize(app)
|
30
|
+
# @app = app
|
31
|
+
# @counter = Concurrent::AtomicReference.new(0)
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# def call(env)
|
35
|
+
# app.call(env)
|
36
|
+
# ensure
|
37
|
+
# @counter.update { |ref| ref + 1 }
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# class IdentityMiddleware
|
42
|
+
# def initialize(app)
|
43
|
+
# @app = app
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# def call(env)
|
47
|
+
# app.call(env)
|
48
|
+
# end
|
49
|
+
# end
|
50
|
+
class RackMiddlewareInstanceVariable < Base
|
51
|
+
include AllowedIdentifiers
|
52
|
+
include OperationWithThreadsafeResult
|
53
|
+
|
54
|
+
MSG = 'Avoid instance variables in Rack middleware.'
|
55
|
+
|
56
|
+
RESTRICT_ON_SEND = %i[instance_variable_get instance_variable_set].freeze
|
57
|
+
|
58
|
+
# @!method rack_middleware_like_class?(node)
|
59
|
+
def_node_matcher :rack_middleware_like_class?, <<~MATCHER
|
60
|
+
(class (const nil? _) nil? (begin <(def :initialize (args (arg _)+) ...) (def :call (args (arg _)) ...) ...>))
|
61
|
+
MATCHER
|
62
|
+
|
63
|
+
# @!method app_variable(node)
|
64
|
+
def_node_search :app_variable, <<~MATCHER
|
65
|
+
(def :initialize (args (arg $_) ...) `(ivasgn $_ (lvar $_)))
|
66
|
+
MATCHER
|
67
|
+
|
68
|
+
def on_class(node)
|
69
|
+
return unless rack_middleware_like_class?(node)
|
70
|
+
|
71
|
+
constructor_method = find_constructor_method(node)
|
72
|
+
return unless (application_variable = extract_application_variable_from_contructor_method(constructor_method))
|
73
|
+
|
74
|
+
safe_variables = extract_safe_variables_from_constructor_method(constructor_method)
|
75
|
+
|
76
|
+
node.each_node(:def) do |def_node|
|
77
|
+
def_node.each_node(:ivasgn, :ivar) do |ivar_node|
|
78
|
+
variable, = ivar_node.to_a
|
79
|
+
if variable == application_variable || safe_variables.include?(variable) || allowed_identifier?(variable)
|
80
|
+
next
|
81
|
+
end
|
82
|
+
|
83
|
+
add_offense ivar_node
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def on_send(node)
|
89
|
+
argument = node.first_argument
|
90
|
+
|
91
|
+
return unless argument&.type?(:sym, :str)
|
92
|
+
return if allowed_identifier?(argument.value)
|
93
|
+
|
94
|
+
add_offense node
|
95
|
+
end
|
96
|
+
alias on_csend on_send
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def find_constructor_method(class_node)
|
101
|
+
class_node
|
102
|
+
.each_node(:def)
|
103
|
+
.find { |node| node.method?(:initialize) && node.arguments.size >= 1 }
|
104
|
+
end
|
105
|
+
|
106
|
+
def extract_application_variable_from_contructor_method(constructor_method)
|
107
|
+
constructor_method
|
108
|
+
.then { |node| app_variable(node) }
|
109
|
+
.then { |variables| variables.first[1] if variables.first }
|
110
|
+
end
|
111
|
+
|
112
|
+
def extract_safe_variables_from_constructor_method(constructor_method)
|
113
|
+
constructor_method
|
114
|
+
.each_node(:ivasgn)
|
115
|
+
.select { |ivasgn_node| operation_produces_threadsafe_object?(ivasgn_node.to_a[1]) }
|
116
|
+
.map { _1.to_a[0] }
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'lint_roller'
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module ThreadSafety
|
7
|
+
# A plugin that integrates RuboCop ThreadSafety with RuboCop's plugin system.
|
8
|
+
class Plugin < LintRoller::Plugin
|
9
|
+
# :nocov:
|
10
|
+
def about
|
11
|
+
LintRoller::About.new(
|
12
|
+
name: 'rubocop-thread_safety',
|
13
|
+
version: Version::STRING,
|
14
|
+
homepage: 'https://github.com/rubocop/rubocop-thread_safety',
|
15
|
+
description: 'Thread-safety checks via static analysis.'
|
16
|
+
)
|
17
|
+
end
|
18
|
+
# :nocov:
|
19
|
+
|
20
|
+
def supported?(context)
|
21
|
+
context.engine == :rubocop
|
22
|
+
end
|
23
|
+
|
24
|
+
def rules(_context)
|
25
|
+
project_root = Pathname.new(__dir__).join('../../..')
|
26
|
+
|
27
|
+
obsoletion = project_root.join('config', 'obsoletion.yml')
|
28
|
+
ConfigObsoletion.files << obsoletion
|
29
|
+
|
30
|
+
LintRoller::Rules.new(
|
31
|
+
type: :path,
|
32
|
+
config_format: :rubocop,
|
33
|
+
value: project_root.join('config/default.yml')
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -3,10 +3,5 @@
|
|
3
3
|
module RuboCop
|
4
4
|
# RuboCop::ThreadSafety detects some potential thread safety issues.
|
5
5
|
module ThreadSafety
|
6
|
-
PROJECT_ROOT = Pathname.new(File.expand_path('../../', __dir__))
|
7
|
-
CONFIG_DEFAULT = PROJECT_ROOT.join('config', 'default.yml').freeze
|
8
|
-
CONFIG = YAML.safe_load(CONFIG_DEFAULT.read).freeze
|
9
|
-
|
10
|
-
private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT)
|
11
6
|
end
|
12
7
|
end
|
@@ -4,11 +4,13 @@ require 'rubocop'
|
|
4
4
|
|
5
5
|
require 'rubocop/thread_safety'
|
6
6
|
require 'rubocop/thread_safety/version'
|
7
|
-
require 'rubocop/thread_safety/
|
7
|
+
require 'rubocop/thread_safety/plugin'
|
8
8
|
|
9
|
-
|
9
|
+
require 'rubocop/cop/mixin/operation_with_threadsafe_result'
|
10
10
|
|
11
|
-
require 'rubocop/cop/thread_safety/
|
11
|
+
require 'rubocop/cop/thread_safety/class_instance_variable'
|
12
12
|
require 'rubocop/cop/thread_safety/class_and_module_attributes'
|
13
13
|
require 'rubocop/cop/thread_safety/mutable_class_instance_variable'
|
14
14
|
require 'rubocop/cop/thread_safety/new_thread'
|
15
|
+
require 'rubocop/cop/thread_safety/dir_chdir'
|
16
|
+
require 'rubocop/cop/thread_safety/rack_middleware_instance_variable'
|
metadata
CHANGED
@@ -1,105 +1,48 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop-thread_safety
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Gee
|
8
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-03-13 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
13
|
+
name: lint_roller
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
16
15
|
requirements:
|
17
|
-
- - "
|
16
|
+
- - "~>"
|
18
17
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
18
|
+
version: '1.1'
|
20
19
|
type: :runtime
|
21
20
|
prerelease: false
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
23
22
|
requirements:
|
24
|
-
- - "
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: 0.53.0
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: appraisal
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: bundler
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '1.10'
|
48
|
-
- - "<"
|
49
|
-
- !ruby/object:Gem::Version
|
50
|
-
version: '3'
|
51
|
-
type: :development
|
52
|
-
prerelease: false
|
53
|
-
version_requirements: !ruby/object:Gem::Requirement
|
54
|
-
requirements:
|
55
|
-
- - ">="
|
56
|
-
- !ruby/object:Gem::Version
|
57
|
-
version: '1.10'
|
58
|
-
- - "<"
|
23
|
+
- - "~>"
|
59
24
|
- !ruby/object:Gem::Version
|
60
|
-
version: '
|
25
|
+
version: '1.1'
|
61
26
|
- !ruby/object:Gem::Dependency
|
62
|
-
name:
|
27
|
+
name: rubocop
|
63
28
|
requirement: !ruby/object:Gem::Requirement
|
64
29
|
requirements:
|
65
|
-
- - "
|
66
|
-
- !ruby/object:Gem::Version
|
67
|
-
version: '0'
|
68
|
-
type: :development
|
69
|
-
prerelease: false
|
70
|
-
version_requirements: !ruby/object:Gem::Requirement
|
71
|
-
requirements:
|
72
|
-
- - ">="
|
30
|
+
- - "~>"
|
73
31
|
- !ruby/object:Gem::Version
|
74
|
-
version: '
|
75
|
-
- !ruby/object:Gem::Dependency
|
76
|
-
name: rake
|
77
|
-
requirement: !ruby/object:Gem::Requirement
|
78
|
-
requirements:
|
32
|
+
version: '1.72'
|
79
33
|
- - ">="
|
80
34
|
- !ruby/object:Gem::Version
|
81
|
-
version:
|
82
|
-
type: :
|
35
|
+
version: 1.72.1
|
36
|
+
type: :runtime
|
83
37
|
prerelease: false
|
84
38
|
version_requirements: !ruby/object:Gem::Requirement
|
85
|
-
requirements:
|
86
|
-
- - ">="
|
87
|
-
- !ruby/object:Gem::Version
|
88
|
-
version: '10.0'
|
89
|
-
- !ruby/object:Gem::Dependency
|
90
|
-
name: rspec
|
91
|
-
requirement: !ruby/object:Gem::Requirement
|
92
39
|
requirements:
|
93
40
|
- - "~>"
|
94
41
|
- !ruby/object:Gem::Version
|
95
|
-
version: '
|
96
|
-
|
97
|
-
prerelease: false
|
98
|
-
version_requirements: !ruby/object:Gem::Requirement
|
99
|
-
requirements:
|
100
|
-
- - "~>"
|
42
|
+
version: '1.72'
|
43
|
+
- - ">="
|
101
44
|
- !ruby/object:Gem::Version
|
102
|
-
version:
|
45
|
+
version: 1.72.1
|
103
46
|
description: |2
|
104
47
|
Thread-safety checks via static analysis.
|
105
48
|
A plugin for the RuboCop code style enforcing & linting tool.
|
@@ -109,36 +52,31 @@ executables: []
|
|
109
52
|
extensions: []
|
110
53
|
extra_rdoc_files: []
|
111
54
|
files:
|
112
|
-
-
|
113
|
-
- ".rspec"
|
114
|
-
- ".rubocop.yml"
|
115
|
-
- ".travis.yml"
|
116
|
-
- Appraisals
|
117
|
-
- Gemfile
|
55
|
+
- CHANGELOG.md
|
118
56
|
- LICENSE.txt
|
119
57
|
- README.md
|
120
|
-
- Rakefile
|
121
|
-
- bin/console
|
122
|
-
- bin/setup
|
123
58
|
- config/default.yml
|
124
|
-
-
|
125
|
-
- gemfiles/rubocop_0.81.gemfile
|
126
|
-
- gemfiles/rubocop_0.86.gemfile
|
127
|
-
- gemfiles/rubocop_1.20.gemfile
|
59
|
+
- config/obsoletion.yml
|
128
60
|
- lib/rubocop-thread_safety.rb
|
61
|
+
- lib/rubocop/cop/mixin/operation_with_threadsafe_result.rb
|
129
62
|
- lib/rubocop/cop/thread_safety/class_and_module_attributes.rb
|
130
|
-
- lib/rubocop/cop/thread_safety/
|
63
|
+
- lib/rubocop/cop/thread_safety/class_instance_variable.rb
|
64
|
+
- lib/rubocop/cop/thread_safety/dir_chdir.rb
|
131
65
|
- lib/rubocop/cop/thread_safety/mutable_class_instance_variable.rb
|
132
66
|
- lib/rubocop/cop/thread_safety/new_thread.rb
|
67
|
+
- lib/rubocop/cop/thread_safety/rack_middleware_instance_variable.rb
|
133
68
|
- lib/rubocop/thread_safety.rb
|
134
|
-
- lib/rubocop/thread_safety/
|
69
|
+
- lib/rubocop/thread_safety/plugin.rb
|
135
70
|
- lib/rubocop/thread_safety/version.rb
|
136
|
-
|
137
|
-
homepage: https://github.com/covermymeds/rubocop-thread_safety
|
71
|
+
homepage: https://github.com/rubocop/rubocop-thread_safety
|
138
72
|
licenses:
|
139
73
|
- MIT
|
140
|
-
metadata:
|
141
|
-
|
74
|
+
metadata:
|
75
|
+
changelog_uri: https://github.com/rubocop/rubocop-thread_safety/blob/master/CHANGELOG.md
|
76
|
+
source_code_uri: https://github.com/rubocop/rubocop-thread_safety
|
77
|
+
bug_tracker_uri: https://github.com/rubocop/rubocop-thread_safety/issues
|
78
|
+
rubygems_mfa_required: 'true'
|
79
|
+
default_lint_roller_plugin: RuboCop::ThreadSafety::Plugin
|
142
80
|
rdoc_options: []
|
143
81
|
require_paths:
|
144
82
|
- lib
|
@@ -146,15 +84,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
146
84
|
requirements:
|
147
85
|
- - ">="
|
148
86
|
- !ruby/object:Gem::Version
|
149
|
-
version: 2.
|
87
|
+
version: 2.7.0
|
150
88
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
89
|
requirements:
|
152
90
|
- - ">="
|
153
91
|
- !ruby/object:Gem::Version
|
154
92
|
version: '0'
|
155
93
|
requirements: []
|
156
|
-
rubygems_version: 3.
|
157
|
-
signing_key:
|
94
|
+
rubygems_version: 3.6.3
|
158
95
|
specification_version: 4
|
159
96
|
summary: Thread-safety checks via static analysis
|
160
97
|
test_files: []
|
data/.gitignore
DELETED
data/.rspec
DELETED