rubocop-thread_safety 0.6.0 → 0.7.1
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 +12 -0
- data/README.md +5 -2
- data/config/default.yml +3 -2
- data/lib/rubocop/cop/thread_safety/class_and_module_attributes.rb +1 -1
- data/lib/rubocop/cop/thread_safety/class_instance_variable.rb +1 -1
- data/lib/rubocop/cop/thread_safety/dir_chdir.rb +36 -8
- data/lib/rubocop/cop/thread_safety/mutable_class_instance_variable.rb +2 -2
- data/lib/rubocop/cop/thread_safety/new_thread.rb +2 -1
- data/lib/rubocop/cop/thread_safety/rack_middleware_instance_variable.rb +2 -1
- data/lib/rubocop/thread_safety/plugin.rb +38 -0
- data/lib/rubocop/thread_safety/version.rb +1 -1
- data/lib/rubocop/thread_safety.rb +0 -7
- data/lib/rubocop-thread_safety.rb +1 -3
- metadata +27 -26
- data/.github/dependabot.yml +0 -6
- data/.github/workflows/ci.yml +0 -55
- data/.github/workflows/lint.yml +0 -23
- data/.gitignore +0 -10
- data/.rspec +0 -3
- data/.rubocop.yml +0 -81
- data/Appraisals +0 -21
- data/Gemfile +0 -17
- data/Rakefile +0 -22
- data/bin/console +0 -15
- data/bin/setup +0 -6
- data/docs/modules/ROOT/pages/cops.adoc +0 -8
- data/docs/modules/ROOT/pages/cops_threadsafety.adoc +0 -361
- data/gemfiles/rubocop_1.48.gemfile +0 -20
- data/gemfiles/rubocop_1.66.gemfile +0 -19
- data/lib/rubocop/thread_safety/inject.rb +0 -20
- data/rubocop-thread_safety.gemspec +0 -39
- data/tasks/cops_documentation.rake +0 -46
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7841ecd07e1f036568eea48b431d4743df6bc7254f83d91218c9f3bb67fd50bb
|
4
|
+
data.tar.gz: 98c2011b6ba532d5140cd693166a9db75c8074c240f4df1ef45c978b601b655c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4a6d03e7a2b51443095239016626b89a739017c2ed5cbf90b44269b1e90bc4bcac9db8342aecca88c32436daa332b8833e0b0d51b768e991407691e3518f196
|
7
|
+
data.tar.gz: 4c2192cff08c1537730848b2f6318293e29a1baef1becfb4a41ac434469caec036466510cf3301e707f4e988b200faf2ef5985cf53122c9d637fa062f5ebd09b
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## master
|
4
|
+
|
5
|
+
## 0.7.1
|
6
|
+
|
7
|
+
- [#84](https://github.com/rubocop/rubocop-thread_safety/pull/84): Rename `InstanceVariableInClassMethod` in default config ([@sambostock](https://github.com/sambostock))
|
8
|
+
|
9
|
+
## 0.7.0
|
10
|
+
|
11
|
+
- [#80](https://github.com/rubocop/rubocop-thread_safety/pull/80) Make RuboCop ThreadSafety work as a RuboCop plugin. ([@bquorning](https://github.com/bquorning))
|
12
|
+
- [#76](https://github.com/rubocop/rubocop-thread_safety/pull/76): Detect offenses when using safe navigation for `ThreadSafety/DirChdir`, `ThreadSafety/NewThread` and `ThreadSafety/RackMiddlewareInstanceVariable` cops. ([@viralpraxis](https://github.com/viralpraxis))
|
13
|
+
- [#73](https://github.com/rubocop/rubocop-thread_safety/pull/73): Add `AllowCallWithBlock` option to `ThreadSafety/DirChdir` cop. ([@viralpraxis](https://github.com/viralpraxis))
|
14
|
+
|
3
15
|
## 0.6.0
|
4
16
|
|
5
17
|
* [#59](https://github.com/rubocop/rubocop-thread_safety/pull/59): Rename `ThreadSafety::InstanceVariableInClassMethod` cop to `ThreadSafety::ClassInstanceVariable` to better reflect its purpose. ([@viralpraxis](https://github.com/viralpraxis))
|
data/README.md
CHANGED
@@ -19,11 +19,14 @@ Install it with Bundler by invoking:
|
|
19
19
|
|
20
20
|
Add this line to your application's `.rubocop.yml`:
|
21
21
|
|
22
|
-
|
22
|
+
plugins: rubocop-thread_safety
|
23
23
|
|
24
24
|
Now you can run `rubocop` and it will automatically load the RuboCop
|
25
25
|
Thread-Safety cops together with the standard cops.
|
26
26
|
|
27
|
+
> [!NOTE]
|
28
|
+
> The plugin system is supported in RuboCop 1.72+. In earlier versions, use `require` instead of `plugins`.
|
29
|
+
|
27
30
|
### Scanning an application without adding it to the Gemfile
|
28
31
|
|
29
32
|
Install the gem:
|
@@ -32,7 +35,7 @@ Install the gem:
|
|
32
35
|
|
33
36
|
Scan the application for just thread-safety issues:
|
34
37
|
|
35
|
-
$ rubocop
|
38
|
+
$ rubocop --plugin rubocop-thread_safety --only ThreadSafety,Style/GlobalVars,Style/ClassVars,Style/MutableConstant
|
36
39
|
|
37
40
|
### Configuration
|
38
41
|
|
data/config/default.yml
CHANGED
@@ -7,8 +7,8 @@ ThreadSafety/ClassAndModuleAttributes:
|
|
7
7
|
Enabled: true
|
8
8
|
ActiveSupportClassAttributeAllowed: false
|
9
9
|
|
10
|
-
ThreadSafety/
|
11
|
-
Description: 'Avoid
|
10
|
+
ThreadSafety/ClassInstanceVariable:
|
11
|
+
Description: 'Avoid class instance variables.'
|
12
12
|
Enabled: true
|
13
13
|
|
14
14
|
ThreadSafety/MutableClassInstanceVariable:
|
@@ -35,6 +35,7 @@ ThreadSafety/NewThread:
|
|
35
35
|
ThreadSafety/DirChdir:
|
36
36
|
Description: Avoid using `Dir.chdir` due to its process-wide effect.
|
37
37
|
Enabled: true
|
38
|
+
AllowCallWithBlock: false
|
38
39
|
|
39
40
|
ThreadSafety/RackMiddlewareInstanceVariable:
|
40
41
|
Description: Avoid instance variables in Rack middleware.
|
@@ -49,7 +49,7 @@ module RuboCop
|
|
49
49
|
...)
|
50
50
|
MATCHER
|
51
51
|
|
52
|
-
def on_send(node)
|
52
|
+
def on_send(node) # rubocop:disable InternalAffairs/OnSendWithoutOnCSend
|
53
53
|
return unless mattr?(node) || (!class_attribute_allowed? && class_attr?(node)) || singleton_attr?(node)
|
54
54
|
|
55
55
|
add_offense(node)
|
@@ -87,7 +87,7 @@ module RuboCop
|
|
87
87
|
end
|
88
88
|
alias on_ivasgn on_ivar
|
89
89
|
|
90
|
-
def on_send(node)
|
90
|
+
def on_send(node) # rubocop:disable InternalAffairs/OnSendWithoutOnCSend
|
91
91
|
return unless instance_variable_call?(node)
|
92
92
|
return unless class_method_definition?(node)
|
93
93
|
return if method_definition?(node)
|
@@ -4,6 +4,8 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module ThreadSafety
|
6
6
|
# Avoid using `Dir.chdir` due to its process-wide effect.
|
7
|
+
# If `AllowCallWithBlock` (disabled by default) option is enabled,
|
8
|
+
# calling `Dir.chdir` with block will be allowed.
|
7
9
|
#
|
8
10
|
# @example
|
9
11
|
# # bad
|
@@ -11,25 +13,51 @@ module RuboCop
|
|
11
13
|
#
|
12
14
|
# # bad
|
13
15
|
# FileUtils.chdir("/var/run")
|
16
|
+
#
|
17
|
+
# @example AllowCallWithBlock: false (default)
|
18
|
+
# # good
|
19
|
+
# Dir.chdir("/var/run") do
|
20
|
+
# puts Dir.pwd
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# @example AllowCallWithBlock: true
|
24
|
+
# # bad
|
25
|
+
# Dir.chdir("/var/run") do
|
26
|
+
# puts Dir.pwd
|
27
|
+
# end
|
28
|
+
#
|
14
29
|
class DirChdir < Base
|
15
|
-
MESSAGE = 'Avoid using `%<module>s
|
30
|
+
MESSAGE = 'Avoid using `%<module>s%<dot>s%<method>s` due to its process-wide effect.'
|
16
31
|
RESTRICT_ON_SEND = %i[chdir cd].freeze
|
17
32
|
|
18
33
|
# @!method chdir?(node)
|
19
34
|
def_node_matcher :chdir?, <<~MATCHER
|
20
35
|
{
|
21
|
-
(
|
22
|
-
(
|
36
|
+
(call (const {nil? cbase} {:Dir :FileUtils}) :chdir ...)
|
37
|
+
(call (const {nil? cbase} :FileUtils) :cd ...)
|
23
38
|
}
|
24
39
|
MATCHER
|
25
40
|
|
26
41
|
def on_send(node)
|
27
|
-
chdir?(node)
|
28
|
-
|
29
|
-
|
30
|
-
|
42
|
+
return unless chdir?(node)
|
43
|
+
return if allow_call_with_block? && (node.block_argument? || node.parent&.block_type?)
|
44
|
+
|
45
|
+
add_offense(
|
46
|
+
node,
|
47
|
+
message: format(
|
48
|
+
MESSAGE,
|
49
|
+
module: node.receiver.short_name,
|
50
|
+
method: node.method_name,
|
51
|
+
dot: node.loc.dot.source
|
31
52
|
)
|
32
|
-
|
53
|
+
)
|
54
|
+
end
|
55
|
+
alias on_csend on_send
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def allow_call_with_block?
|
60
|
+
!!cop_config['AllowCallWithBlock']
|
33
61
|
end
|
34
62
|
end
|
35
63
|
end
|
@@ -198,7 +198,7 @@ module RuboCop
|
|
198
198
|
end
|
199
199
|
|
200
200
|
def range_type?(node)
|
201
|
-
node.
|
201
|
+
node.type?(:range)
|
202
202
|
end
|
203
203
|
|
204
204
|
def correct_splat_expansion(corrector, expr, splat_value)
|
@@ -245,7 +245,7 @@ module RuboCop
|
|
245
245
|
|
246
246
|
# @!method range_enclosed_in_parentheses?(node)
|
247
247
|
def_node_matcher :range_enclosed_in_parentheses?, <<~PATTERN
|
248
|
-
(begin (
|
248
|
+
(begin (range _ _))
|
249
249
|
PATTERN
|
250
250
|
end
|
251
251
|
end
|
@@ -16,12 +16,13 @@ module RuboCop
|
|
16
16
|
|
17
17
|
# @!method new_thread?(node)
|
18
18
|
def_node_matcher :new_thread?, <<~MATCHER
|
19
|
-
(
|
19
|
+
(call (const {nil? cbase} :Thread) {:new :fork :start} ...)
|
20
20
|
MATCHER
|
21
21
|
|
22
22
|
def on_send(node)
|
23
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
|
@@ -88,11 +88,12 @@ module RuboCop
|
|
88
88
|
def on_send(node)
|
89
89
|
argument = node.first_argument
|
90
90
|
|
91
|
-
return unless argument&.
|
91
|
+
return unless argument&.type?(:sym, :str)
|
92
92
|
return if allowed_identifier?(argument.value)
|
93
93
|
|
94
94
|
add_offense node
|
95
95
|
end
|
96
|
+
alias on_csend on_send
|
96
97
|
|
97
98
|
private
|
98
99
|
|
@@ -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,12 +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
|
-
|
12
|
-
::RuboCop::ConfigObsoletion.files << PROJECT_ROOT.join('config', 'obsoletion.yml')
|
13
6
|
end
|
14
7
|
end
|
@@ -4,9 +4,7 @@ require 'rubocop'
|
|
4
4
|
|
5
5
|
require 'rubocop/thread_safety'
|
6
6
|
require 'rubocop/thread_safety/version'
|
7
|
-
require 'rubocop/thread_safety/
|
8
|
-
|
9
|
-
RuboCop::ThreadSafety::Inject.defaults!
|
7
|
+
require 'rubocop/thread_safety/plugin'
|
10
8
|
|
11
9
|
require 'rubocop/cop/mixin/operation_with_threadsafe_result'
|
12
10
|
|
metadata
CHANGED
@@ -1,29 +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.1
|
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-12 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: lint_roller
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '1.1'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - "~>"
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '1.1'
|
13
26
|
- !ruby/object:Gem::Dependency
|
14
27
|
name: rubocop
|
15
28
|
requirement: !ruby/object:Gem::Requirement
|
16
29
|
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '1.72'
|
17
33
|
- - ">="
|
18
34
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.
|
35
|
+
version: 1.72.1
|
20
36
|
type: :runtime
|
21
37
|
prerelease: false
|
22
38
|
version_requirements: !ruby/object:Gem::Requirement
|
23
39
|
requirements:
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '1.72'
|
24
43
|
- - ">="
|
25
44
|
- !ruby/object:Gem::Version
|
26
|
-
version: 1.
|
45
|
+
version: 1.72.1
|
27
46
|
description: |2
|
28
47
|
Thread-safety checks via static analysis.
|
29
48
|
A plugin for the RuboCop code style enforcing & linting tool.
|
@@ -33,26 +52,11 @@ executables: []
|
|
33
52
|
extensions: []
|
34
53
|
extra_rdoc_files: []
|
35
54
|
files:
|
36
|
-
- ".github/dependabot.yml"
|
37
|
-
- ".github/workflows/ci.yml"
|
38
|
-
- ".github/workflows/lint.yml"
|
39
|
-
- ".gitignore"
|
40
|
-
- ".rspec"
|
41
|
-
- ".rubocop.yml"
|
42
|
-
- Appraisals
|
43
55
|
- CHANGELOG.md
|
44
|
-
- Gemfile
|
45
56
|
- LICENSE.txt
|
46
57
|
- README.md
|
47
|
-
- Rakefile
|
48
|
-
- bin/console
|
49
|
-
- bin/setup
|
50
58
|
- config/default.yml
|
51
59
|
- config/obsoletion.yml
|
52
|
-
- docs/modules/ROOT/pages/cops.adoc
|
53
|
-
- docs/modules/ROOT/pages/cops_threadsafety.adoc
|
54
|
-
- gemfiles/rubocop_1.48.gemfile
|
55
|
-
- gemfiles/rubocop_1.66.gemfile
|
56
60
|
- lib/rubocop-thread_safety.rb
|
57
61
|
- lib/rubocop/cop/mixin/operation_with_threadsafe_result.rb
|
58
62
|
- lib/rubocop/cop/thread_safety/class_and_module_attributes.rb
|
@@ -62,10 +66,8 @@ files:
|
|
62
66
|
- lib/rubocop/cop/thread_safety/new_thread.rb
|
63
67
|
- lib/rubocop/cop/thread_safety/rack_middleware_instance_variable.rb
|
64
68
|
- lib/rubocop/thread_safety.rb
|
65
|
-
- lib/rubocop/thread_safety/
|
69
|
+
- lib/rubocop/thread_safety/plugin.rb
|
66
70
|
- lib/rubocop/thread_safety/version.rb
|
67
|
-
- rubocop-thread_safety.gemspec
|
68
|
-
- tasks/cops_documentation.rake
|
69
71
|
homepage: https://github.com/rubocop/rubocop-thread_safety
|
70
72
|
licenses:
|
71
73
|
- MIT
|
@@ -74,7 +76,7 @@ metadata:
|
|
74
76
|
source_code_uri: https://github.com/rubocop/rubocop-thread_safety
|
75
77
|
bug_tracker_uri: https://github.com/rubocop/rubocop-thread_safety/issues
|
76
78
|
rubygems_mfa_required: 'true'
|
77
|
-
|
79
|
+
default_lint_roller_plugin: RuboCop::ThreadSafety::Plugin
|
78
80
|
rdoc_options: []
|
79
81
|
require_paths:
|
80
82
|
- lib
|
@@ -89,8 +91,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
89
91
|
- !ruby/object:Gem::Version
|
90
92
|
version: '0'
|
91
93
|
requirements: []
|
92
|
-
rubygems_version: 3.
|
93
|
-
signing_key:
|
94
|
+
rubygems_version: 3.6.3
|
94
95
|
specification_version: 4
|
95
96
|
summary: Thread-safety checks via static analysis
|
96
97
|
test_files: []
|
data/.github/dependabot.yml
DELETED
data/.github/workflows/ci.yml
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
name: CI
|
2
|
-
|
3
|
-
on:
|
4
|
-
push:
|
5
|
-
branches:
|
6
|
-
- master
|
7
|
-
pull_request:
|
8
|
-
|
9
|
-
jobs:
|
10
|
-
confirm_documentation:
|
11
|
-
runs-on: ubuntu-latest
|
12
|
-
name: Confirm documentation
|
13
|
-
steps:
|
14
|
-
- uses: actions/checkout@v4
|
15
|
-
- uses: ruby/setup-ruby@v1
|
16
|
-
with:
|
17
|
-
ruby-version: "3.2"
|
18
|
-
bundler-cache: true
|
19
|
-
- run: bundle exec rake documentation_syntax_check confirm_documentation
|
20
|
-
|
21
|
-
test:
|
22
|
-
runs-on: ubuntu-latest
|
23
|
-
strategy:
|
24
|
-
fail-fast: false
|
25
|
-
matrix:
|
26
|
-
ruby: ["2.7", "3.0", "3.1", "3.2", "3.3", ruby-head, jruby-9.4]
|
27
|
-
rubocop_version: ["1.48", "1.66"]
|
28
|
-
env:
|
29
|
-
BUNDLE_GEMFILE: "gemfiles/rubocop_${{ matrix.rubocop_version }}.gemfile"
|
30
|
-
steps:
|
31
|
-
- uses: actions/checkout@v4
|
32
|
-
- name: Set up Ruby
|
33
|
-
uses: ruby/setup-ruby@v1
|
34
|
-
with:
|
35
|
-
bundler-cache: true # 'bundle install' and cache gems
|
36
|
-
ruby-version: ${{ matrix.ruby }}
|
37
|
-
bundler: 2.3.26
|
38
|
-
- name: Run tests
|
39
|
-
run: bundle exec rspec
|
40
|
-
|
41
|
-
test-prism:
|
42
|
-
runs-on: ubuntu-latest
|
43
|
-
env:
|
44
|
-
BUNDLE_GEMFILE: "gemfiles/rubocop_1.66.gemfile"
|
45
|
-
PARSER_ENGINE: parser_prism
|
46
|
-
steps:
|
47
|
-
- uses: actions/checkout@v4
|
48
|
-
- name: Set up Ruby
|
49
|
-
uses: ruby/setup-ruby@v1
|
50
|
-
with:
|
51
|
-
bundler-cache: true # 'bundle install' and cache gems
|
52
|
-
ruby-version: 3.3
|
53
|
-
bundler: 2.3.26
|
54
|
-
- name: Run tests
|
55
|
-
run: bundle exec rspec
|
data/.github/workflows/lint.yml
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
name: Lint
|
2
|
-
|
3
|
-
on:
|
4
|
-
push:
|
5
|
-
branches:
|
6
|
-
- master
|
7
|
-
pull_request:
|
8
|
-
|
9
|
-
jobs:
|
10
|
-
lint:
|
11
|
-
|
12
|
-
runs-on: ubuntu-latest
|
13
|
-
name: Rubocop
|
14
|
-
|
15
|
-
steps:
|
16
|
-
- uses: actions/checkout@v4
|
17
|
-
- name: Set up Ruby
|
18
|
-
uses: ruby/setup-ruby@v1
|
19
|
-
with:
|
20
|
-
bundler-cache: true # 'bundle install' and cache gems
|
21
|
-
ruby-version: "2.7"
|
22
|
-
- name: Run Rubocop
|
23
|
-
run: bundle exec rubocop
|
data/.gitignore
DELETED
data/.rspec
DELETED
data/.rubocop.yml
DELETED
@@ -1,81 +0,0 @@
|
|
1
|
-
require:
|
2
|
-
- rubocop/cop/internal_affairs
|
3
|
-
- rubocop-rake
|
4
|
-
- rubocop-rspec
|
5
|
-
|
6
|
-
AllCops:
|
7
|
-
DisplayCopNames: true
|
8
|
-
TargetRubyVersion: 2.7
|
9
|
-
NewCops: enable
|
10
|
-
|
11
|
-
Lint/RaiseException:
|
12
|
-
Enabled: true
|
13
|
-
|
14
|
-
Lint/StructNewOverride:
|
15
|
-
Enabled: true
|
16
|
-
|
17
|
-
Metrics/BlockLength:
|
18
|
-
Exclude:
|
19
|
-
- "spec/**/*"
|
20
|
-
|
21
|
-
Metrics/ClassLength:
|
22
|
-
Enabled: false
|
23
|
-
|
24
|
-
Metrics/MethodLength:
|
25
|
-
Max: 14
|
26
|
-
|
27
|
-
Naming/FileName:
|
28
|
-
Exclude:
|
29
|
-
- lib/rubocop-thread_safety.rb
|
30
|
-
- rubocop-thread_safety.gemspec
|
31
|
-
|
32
|
-
# Enable more cops that are disabled by default:
|
33
|
-
|
34
|
-
Style/AutoResourceCleanup:
|
35
|
-
Enabled: true
|
36
|
-
|
37
|
-
Style/CollectionMethods:
|
38
|
-
Enabled: true
|
39
|
-
|
40
|
-
Style/FormatStringToken:
|
41
|
-
Exclude:
|
42
|
-
- spec/**/*
|
43
|
-
|
44
|
-
Style/HashEachMethods:
|
45
|
-
Enabled: true
|
46
|
-
|
47
|
-
Style/HashTransformKeys:
|
48
|
-
Enabled: false
|
49
|
-
|
50
|
-
Style/HashTransformValues:
|
51
|
-
Enabled: false
|
52
|
-
|
53
|
-
Style/MethodCalledOnDoEndBlock:
|
54
|
-
Enabled: true
|
55
|
-
Exclude:
|
56
|
-
- spec/**/*
|
57
|
-
|
58
|
-
Style/MissingElse:
|
59
|
-
Enabled: true
|
60
|
-
EnforcedStyle: case
|
61
|
-
|
62
|
-
Style/OptionHash:
|
63
|
-
Enabled: true
|
64
|
-
|
65
|
-
Style/Send:
|
66
|
-
Enabled: true
|
67
|
-
|
68
|
-
Style/StringMethods:
|
69
|
-
Enabled: true
|
70
|
-
|
71
|
-
Style/SymbolArray:
|
72
|
-
Enabled: true
|
73
|
-
|
74
|
-
RSpec/ExampleLength:
|
75
|
-
Max: 11
|
76
|
-
Exclude:
|
77
|
-
- spec/rubocop/cop/thread_safety/rack_middleware_instance_variable_spec.rb
|
78
|
-
|
79
|
-
RSpec/ContextWording:
|
80
|
-
Exclude:
|
81
|
-
- spec/shared_contexts.rb
|
data/Appraisals
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
customize_gemfiles do
|
4
|
-
{
|
5
|
-
single_quotes: true,
|
6
|
-
heading: <<~HEADING.strip
|
7
|
-
frozen_string_literal: true
|
8
|
-
|
9
|
-
This file was generated by Appraisal
|
10
|
-
HEADING
|
11
|
-
}
|
12
|
-
end
|
13
|
-
|
14
|
-
appraise 'rubocop-1.48' do
|
15
|
-
gem 'base64', '~> 0.1.1'
|
16
|
-
gem 'rubocop', '~> 1.48.0'
|
17
|
-
end
|
18
|
-
|
19
|
-
appraise 'rubocop-1.66' do
|
20
|
-
gem 'rubocop', '~> 1.66.0'
|
21
|
-
end
|
data/Gemfile
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
source 'https://rubygems.org'
|
4
|
-
|
5
|
-
gemspec
|
6
|
-
|
7
|
-
gem 'appraisal'
|
8
|
-
gem 'bundler', '>= 1.10', '< 3'
|
9
|
-
gem 'prism', '~> 1.2.0'
|
10
|
-
gem 'pry' unless ENV['CI']
|
11
|
-
gem 'rake', '>= 10.0'
|
12
|
-
gem 'rspec', '~> 3.0'
|
13
|
-
gem 'rubocop', github: 'rubocop/rubocop'
|
14
|
-
gem 'rubocop-rake', '~> 0.6.0'
|
15
|
-
gem 'rubocop-rspec'
|
16
|
-
gem 'simplecov'
|
17
|
-
gem 'yard'
|
data/Rakefile
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'bundler/gem_tasks'
|
4
|
-
require 'open3'
|
5
|
-
require 'rspec/core/rake_task'
|
6
|
-
|
7
|
-
Dir['tasks/**/*.rake'].each { |t| load t }
|
8
|
-
|
9
|
-
RSpec::Core::RakeTask.new(:spec)
|
10
|
-
|
11
|
-
desc 'Confirm documentation is up to date'
|
12
|
-
task confirm_documentation: :generate_cops_documentation do
|
13
|
-
_, _, _, process =
|
14
|
-
Open3.popen3('git diff --exit-code docs/')
|
15
|
-
|
16
|
-
unless process.value.success?
|
17
|
-
abort 'Please run `rake generate_cops_documentation` ' \
|
18
|
-
'and add docs/ to the commit.'
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
task default: :spec
|
data/bin/console
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
# frozen_string_literal: true
|
4
|
-
|
5
|
-
require 'bundler/setup'
|
6
|
-
require 'rubocop-thread_safety'
|
7
|
-
|
8
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
9
|
-
# with your gem easier. You can also use a different console, if you like.
|
10
|
-
|
11
|
-
require 'pry'
|
12
|
-
Pry.start
|
13
|
-
|
14
|
-
# require "irb"
|
15
|
-
# IRB.start
|
data/bin/setup
DELETED
@@ -1,8 +0,0 @@
|
|
1
|
-
=== Department xref:cops_threadsafety.adoc[ThreadSafety]
|
2
|
-
|
3
|
-
* xref:cops_threadsafety.adoc#threadsafetyclassandmoduleattributes[ThreadSafety/ClassAndModuleAttributes]
|
4
|
-
* xref:cops_threadsafety.adoc#threadsafetyclassinstancevariable[ThreadSafety/ClassInstanceVariable]
|
5
|
-
* xref:cops_threadsafety.adoc#threadsafetymutableclassinstancevariable[ThreadSafety/MutableClassInstanceVariable]
|
6
|
-
* xref:cops_threadsafety.adoc#threadsafetynewthread[ThreadSafety/NewThread]
|
7
|
-
* xref:cops_threadsafety.adoc#threadsafetydirchdir[ThreadSafety/DirChdir]
|
8
|
-
* xref:cops_threadsafety.adoc#threadsafetyrackmiddlewareinstancevariable[ThreadSafety/RackMiddlewareInstanceVariable]
|
@@ -1,361 +0,0 @@
|
|
1
|
-
////
|
2
|
-
Do NOT edit this file by hand directly, as it is automatically generated.
|
3
|
-
|
4
|
-
Please make any necessary changes to the cop documentation within the source files themselves.
|
5
|
-
////
|
6
|
-
|
7
|
-
= ThreadSafety
|
8
|
-
|
9
|
-
[#threadsafetyclassandmoduleattributes]
|
10
|
-
== ThreadSafety/ClassAndModuleAttributes
|
11
|
-
|
12
|
-
|===
|
13
|
-
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed
|
14
|
-
|
15
|
-
| Enabled
|
16
|
-
| Yes
|
17
|
-
| No
|
18
|
-
| -
|
19
|
-
| -
|
20
|
-
|===
|
21
|
-
|
22
|
-
Avoid mutating class and module attributes.
|
23
|
-
|
24
|
-
They are implemented by class variables, which are not thread-safe.
|
25
|
-
|
26
|
-
[#examples-threadsafetyclassandmoduleattributes]
|
27
|
-
=== Examples
|
28
|
-
|
29
|
-
[source,ruby]
|
30
|
-
----
|
31
|
-
# bad
|
32
|
-
class User
|
33
|
-
cattr_accessor :current_user
|
34
|
-
end
|
35
|
-
----
|
36
|
-
|
37
|
-
[#configurable-attributes-threadsafetyclassandmoduleattributes]
|
38
|
-
=== Configurable attributes
|
39
|
-
|
40
|
-
|===
|
41
|
-
| Name | Default value | Configurable values
|
42
|
-
|
43
|
-
| ActiveSupportClassAttributeAllowed
|
44
|
-
| `false`
|
45
|
-
| Boolean
|
46
|
-
|===
|
47
|
-
|
48
|
-
[#threadsafetyclassinstancevariable]
|
49
|
-
== ThreadSafety/ClassInstanceVariable
|
50
|
-
|
51
|
-
|===
|
52
|
-
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed
|
53
|
-
|
54
|
-
| Enabled
|
55
|
-
| Yes
|
56
|
-
| No
|
57
|
-
| -
|
58
|
-
| -
|
59
|
-
|===
|
60
|
-
|
61
|
-
Avoid class instance variables.
|
62
|
-
|
63
|
-
[#examples-threadsafetyclassinstancevariable]
|
64
|
-
=== Examples
|
65
|
-
|
66
|
-
[source,ruby]
|
67
|
-
----
|
68
|
-
# bad
|
69
|
-
class User
|
70
|
-
def self.notify(info)
|
71
|
-
@info = validate(info)
|
72
|
-
Notifier.new(@info).deliver
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
class Model
|
77
|
-
class << self
|
78
|
-
def table_name(name)
|
79
|
-
@table_name = name
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
class Host
|
85
|
-
%i[uri port].each do |key|
|
86
|
-
define_singleton_method("#{key}=") do |value|
|
87
|
-
instance_variable_set("@#{key}", value)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
module Example
|
93
|
-
module ClassMethods
|
94
|
-
def test(params)
|
95
|
-
@params = params
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
module Example
|
101
|
-
class_methods do
|
102
|
-
def test(params)
|
103
|
-
@params = params
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
module Example
|
109
|
-
module_function
|
110
|
-
|
111
|
-
def test(params)
|
112
|
-
@params = params
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
module Example
|
117
|
-
def test(params)
|
118
|
-
@params = params
|
119
|
-
end
|
120
|
-
|
121
|
-
module_function :test
|
122
|
-
end
|
123
|
-
----
|
124
|
-
|
125
|
-
[#threadsafetydirchdir]
|
126
|
-
== ThreadSafety/DirChdir
|
127
|
-
|
128
|
-
|===
|
129
|
-
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed
|
130
|
-
|
131
|
-
| Enabled
|
132
|
-
| Yes
|
133
|
-
| No
|
134
|
-
| -
|
135
|
-
| -
|
136
|
-
|===
|
137
|
-
|
138
|
-
Avoid using `Dir.chdir` due to its process-wide effect.
|
139
|
-
|
140
|
-
[#examples-threadsafetydirchdir]
|
141
|
-
=== Examples
|
142
|
-
|
143
|
-
[source,ruby]
|
144
|
-
----
|
145
|
-
# bad
|
146
|
-
Dir.chdir("/var/run")
|
147
|
-
|
148
|
-
# bad
|
149
|
-
FileUtils.chdir("/var/run")
|
150
|
-
----
|
151
|
-
|
152
|
-
[#threadsafetymutableclassinstancevariable]
|
153
|
-
== ThreadSafety/MutableClassInstanceVariable
|
154
|
-
|
155
|
-
|===
|
156
|
-
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed
|
157
|
-
|
158
|
-
| Enabled
|
159
|
-
| Yes
|
160
|
-
| Always (Unsafe)
|
161
|
-
| -
|
162
|
-
| -
|
163
|
-
|===
|
164
|
-
|
165
|
-
Checks whether some class instance variable isn't a
|
166
|
-
mutable literal (e.g. array or hash).
|
167
|
-
|
168
|
-
It is based on Style/MutableConstant from RuboCop.
|
169
|
-
See https://github.com/rubocop/rubocop/blob/master/lib/rubocop/cop/style/mutable_constant.rb
|
170
|
-
|
171
|
-
Class instance variables are a risk to threaded code as they are shared
|
172
|
-
between threads. A mutable object such as an array or hash may be
|
173
|
-
updated via an attr_reader so would not be detected by the
|
174
|
-
ThreadSafety/ClassAndModuleAttributes cop.
|
175
|
-
|
176
|
-
Strict mode can be used to freeze all class instance variables, rather
|
177
|
-
than just literals.
|
178
|
-
Strict mode is considered an experimental feature. It has not been
|
179
|
-
updated with an exhaustive list of all methods that will produce frozen
|
180
|
-
objects so there is a decent chance of getting some false positives.
|
181
|
-
Luckily, there is no harm in freezing an already frozen object.
|
182
|
-
|
183
|
-
[#examples-threadsafetymutableclassinstancevariable]
|
184
|
-
=== Examples
|
185
|
-
|
186
|
-
[#enforcedstyle_-literals-_default_-threadsafetymutableclassinstancevariable]
|
187
|
-
==== EnforcedStyle: literals (default)
|
188
|
-
|
189
|
-
[source,ruby]
|
190
|
-
----
|
191
|
-
# bad
|
192
|
-
class Model
|
193
|
-
@list = [1, 2, 3]
|
194
|
-
end
|
195
|
-
|
196
|
-
# good
|
197
|
-
class Model
|
198
|
-
@list = [1, 2, 3].freeze
|
199
|
-
end
|
200
|
-
|
201
|
-
# good
|
202
|
-
class Model
|
203
|
-
@var = <<~TESTING.freeze
|
204
|
-
This is a heredoc
|
205
|
-
TESTING
|
206
|
-
end
|
207
|
-
|
208
|
-
# good
|
209
|
-
class Model
|
210
|
-
@var = Something.new
|
211
|
-
end
|
212
|
-
----
|
213
|
-
|
214
|
-
[#enforcedstyle_-strict-threadsafetymutableclassinstancevariable]
|
215
|
-
==== EnforcedStyle: strict
|
216
|
-
|
217
|
-
[source,ruby]
|
218
|
-
----
|
219
|
-
# bad
|
220
|
-
class Model
|
221
|
-
@var = Something.new
|
222
|
-
end
|
223
|
-
|
224
|
-
# bad
|
225
|
-
class Model
|
226
|
-
@var = Struct.new do
|
227
|
-
def foo
|
228
|
-
puts 1
|
229
|
-
end
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
|
-
# good
|
234
|
-
class Model
|
235
|
-
@var = Something.new.freeze
|
236
|
-
end
|
237
|
-
|
238
|
-
# good
|
239
|
-
class Model
|
240
|
-
@var = Struct.new do
|
241
|
-
def foo
|
242
|
-
puts 1
|
243
|
-
end
|
244
|
-
end.freeze
|
245
|
-
end
|
246
|
-
----
|
247
|
-
|
248
|
-
[#configurable-attributes-threadsafetymutableclassinstancevariable]
|
249
|
-
=== Configurable attributes
|
250
|
-
|
251
|
-
|===
|
252
|
-
| Name | Default value | Configurable values
|
253
|
-
|
254
|
-
| EnforcedStyle
|
255
|
-
| `literals`
|
256
|
-
| `literals`, `strict`
|
257
|
-
|===
|
258
|
-
|
259
|
-
[#threadsafetynewthread]
|
260
|
-
== ThreadSafety/NewThread
|
261
|
-
|
262
|
-
|===
|
263
|
-
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed
|
264
|
-
|
265
|
-
| Enabled
|
266
|
-
| Yes
|
267
|
-
| No
|
268
|
-
| -
|
269
|
-
| -
|
270
|
-
|===
|
271
|
-
|
272
|
-
Avoid starting new threads.
|
273
|
-
|
274
|
-
Let a framework like Sidekiq handle the threads.
|
275
|
-
|
276
|
-
[#examples-threadsafetynewthread]
|
277
|
-
=== Examples
|
278
|
-
|
279
|
-
[source,ruby]
|
280
|
-
----
|
281
|
-
# bad
|
282
|
-
Thread.new { do_work }
|
283
|
-
----
|
284
|
-
|
285
|
-
[#threadsafetyrackmiddlewareinstancevariable]
|
286
|
-
== ThreadSafety/RackMiddlewareInstanceVariable
|
287
|
-
|
288
|
-
|===
|
289
|
-
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed
|
290
|
-
|
291
|
-
| Enabled
|
292
|
-
| Yes
|
293
|
-
| No
|
294
|
-
| -
|
295
|
-
| -
|
296
|
-
|===
|
297
|
-
|
298
|
-
Avoid instance variables in rack middleware.
|
299
|
-
|
300
|
-
Middlewares are initialized once, meaning any instance variables are shared between executor threads.
|
301
|
-
To avoid potential race conditions, it's recommended to design middlewares to be stateless
|
302
|
-
or to implement proper synchronization mechanisms.
|
303
|
-
|
304
|
-
[#examples-threadsafetyrackmiddlewareinstancevariable]
|
305
|
-
=== Examples
|
306
|
-
|
307
|
-
[source,ruby]
|
308
|
-
----
|
309
|
-
# bad
|
310
|
-
class CounterMiddleware
|
311
|
-
def initialize(app)
|
312
|
-
@app = app
|
313
|
-
@counter = 0
|
314
|
-
end
|
315
|
-
|
316
|
-
def call(env)
|
317
|
-
app.call(env)
|
318
|
-
ensure
|
319
|
-
@counter += 1
|
320
|
-
end
|
321
|
-
end
|
322
|
-
|
323
|
-
# good
|
324
|
-
class CounterMiddleware
|
325
|
-
def initialize(app)
|
326
|
-
@app = app
|
327
|
-
@counter = Concurrent::AtomicReference.new(0)
|
328
|
-
end
|
329
|
-
|
330
|
-
def call(env)
|
331
|
-
app.call(env)
|
332
|
-
ensure
|
333
|
-
@counter.update { |ref| ref + 1 }
|
334
|
-
end
|
335
|
-
end
|
336
|
-
|
337
|
-
class IdentityMiddleware
|
338
|
-
def initialize(app)
|
339
|
-
@app = app
|
340
|
-
end
|
341
|
-
|
342
|
-
def call(env)
|
343
|
-
app.call(env)
|
344
|
-
end
|
345
|
-
end
|
346
|
-
----
|
347
|
-
|
348
|
-
[#configurable-attributes-threadsafetyrackmiddlewareinstancevariable]
|
349
|
-
=== Configurable attributes
|
350
|
-
|
351
|
-
|===
|
352
|
-
| Name | Default value | Configurable values
|
353
|
-
|
354
|
-
| Include
|
355
|
-
| `+app/middleware/**/*.rb+`, `+lib/middleware/**/*.rb+`, `+app/middlewares/**/*.rb+`, `+lib/middlewares/**/*.rb+`
|
356
|
-
| Array
|
357
|
-
|
358
|
-
| AllowedIdentifiers
|
359
|
-
| `[]`
|
360
|
-
| Array
|
361
|
-
|===
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# This file was generated by Appraisal
|
4
|
-
|
5
|
-
source 'https://rubygems.org'
|
6
|
-
|
7
|
-
gem 'appraisal'
|
8
|
-
gem 'base64', '~> 0.1.1'
|
9
|
-
gem 'bundler', '>= 1.10', '< 3'
|
10
|
-
gem 'prism', '~> 1.2.0'
|
11
|
-
gem 'pry'
|
12
|
-
gem 'rake', '>= 10.0'
|
13
|
-
gem 'rspec', '~> 3.0'
|
14
|
-
gem 'rubocop', '~> 1.48.0'
|
15
|
-
gem 'rubocop-rake', '~> 0.6.0'
|
16
|
-
gem 'rubocop-rspec'
|
17
|
-
gem 'simplecov'
|
18
|
-
gem 'yard'
|
19
|
-
|
20
|
-
gemspec path: '../'
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# This file was generated by Appraisal
|
4
|
-
|
5
|
-
source 'https://rubygems.org'
|
6
|
-
|
7
|
-
gem 'appraisal'
|
8
|
-
gem 'bundler', '>= 1.10', '< 3'
|
9
|
-
gem 'prism', '~> 1.2.0'
|
10
|
-
gem 'pry'
|
11
|
-
gem 'rake', '>= 10.0'
|
12
|
-
gem 'rspec', '~> 3.0'
|
13
|
-
gem 'rubocop', '~> 1.66.0'
|
14
|
-
gem 'rubocop-rake', '~> 0.6.0'
|
15
|
-
gem 'rubocop-rspec'
|
16
|
-
gem 'simplecov'
|
17
|
-
gem 'yard'
|
18
|
-
|
19
|
-
gemspec path: '../'
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# The original code is from https://github.com/rubocop/rubocop-rspec/blob/master/lib/rubocop/rspec/inject.rb
|
4
|
-
# See https://github.com/rubocop/rubocop-rspec/blob/master/MIT-LICENSE.md
|
5
|
-
module RuboCop
|
6
|
-
module ThreadSafety
|
7
|
-
# Because RuboCop doesn't yet support plugins, we have to monkey patch in a
|
8
|
-
# bit of our configuration.
|
9
|
-
module Inject
|
10
|
-
def self.defaults!
|
11
|
-
path = CONFIG_DEFAULT.to_s
|
12
|
-
hash = ConfigLoader.__send__(:load_yaml_configuration, path)
|
13
|
-
config = Config.new(hash, path).tap(&:make_excludes_absolute)
|
14
|
-
puts "configuration from \#{path}" if ConfigLoader.debug?
|
15
|
-
config = ConfigLoader.merge_with_default(config, path)
|
16
|
-
ConfigLoader.instance_variable_set(:@default_configuration, config)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,39 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
lib = File.expand_path('lib', __dir__)
|
4
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
-
require 'rubocop/thread_safety/version'
|
6
|
-
|
7
|
-
Gem::Specification.new do |spec|
|
8
|
-
spec.name = 'rubocop-thread_safety'
|
9
|
-
spec.version = RuboCop::ThreadSafety::VERSION
|
10
|
-
spec.authors = ['Michael Gee']
|
11
|
-
spec.email = ['michaelpgee@gmail.com']
|
12
|
-
|
13
|
-
spec.summary = 'Thread-safety checks via static analysis'
|
14
|
-
spec.description = <<-DESCRIPTION
|
15
|
-
Thread-safety checks via static analysis.
|
16
|
-
A plugin for the RuboCop code style enforcing & linting tool.
|
17
|
-
DESCRIPTION
|
18
|
-
spec.homepage = 'https://github.com/rubocop/rubocop-thread_safety'
|
19
|
-
spec.licenses = ['MIT']
|
20
|
-
|
21
|
-
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
22
|
-
f.match(%r{^(test|spec|features)/})
|
23
|
-
end
|
24
|
-
|
25
|
-
spec.metadata = {
|
26
|
-
'changelog_uri' => 'https://github.com/rubocop/rubocop-thread_safety/blob/master/CHANGELOG.md',
|
27
|
-
'source_code_uri' => 'https://github.com/rubocop/rubocop-thread_safety',
|
28
|
-
'bug_tracker_uri' => 'https://github.com/rubocop/rubocop-thread_safety/issues',
|
29
|
-
'rubygems_mfa_required' => 'true'
|
30
|
-
}
|
31
|
-
|
32
|
-
spec.bindir = 'exe'
|
33
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
34
|
-
spec.require_paths = ['lib']
|
35
|
-
|
36
|
-
spec.required_ruby_version = '>= 2.7.0'
|
37
|
-
|
38
|
-
spec.add_dependency 'rubocop', '>= 1.48.1'
|
39
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'rubocop'
|
4
|
-
require 'rubocop-thread_safety'
|
5
|
-
require 'rubocop/cops_documentation_generator'
|
6
|
-
require 'yard'
|
7
|
-
|
8
|
-
YARD::Rake::YardocTask.new(:yard_for_generate_documentation) do |task|
|
9
|
-
task.files = ['lib/rubocop/cop/**/*.rb']
|
10
|
-
task.options = ['--no-output']
|
11
|
-
end
|
12
|
-
|
13
|
-
desc 'Generate docs of all cops departments'
|
14
|
-
task generate_cops_documentation: :yard_for_generate_documentation do
|
15
|
-
deps = ['ThreadSafety']
|
16
|
-
CopsDocumentationGenerator.new(departments: deps).call
|
17
|
-
end
|
18
|
-
|
19
|
-
desc 'Syntax check for the documentation comments'
|
20
|
-
task documentation_syntax_check: :yard_for_generate_documentation do
|
21
|
-
require 'parser/ruby31'
|
22
|
-
|
23
|
-
ok = true
|
24
|
-
YARD::Registry.load!
|
25
|
-
cops = RuboCop::Cop::Registry.global
|
26
|
-
cops.each do |cop|
|
27
|
-
examples = YARD::Registry.all(:class).find do |code_object|
|
28
|
-
next unless RuboCop::Cop::Badge.for(code_object.to_s) == cop.badge
|
29
|
-
|
30
|
-
break code_object.tags('example')
|
31
|
-
end
|
32
|
-
|
33
|
-
examples.to_a.each do |example|
|
34
|
-
buffer = Parser::Source::Buffer.new('<code>', 1)
|
35
|
-
buffer.source = example.text
|
36
|
-
parser = Parser::Ruby31.new(RuboCop::AST::Builder.new)
|
37
|
-
parser.diagnostics.all_errors_are_fatal = true
|
38
|
-
parser.parse(buffer)
|
39
|
-
rescue Parser::SyntaxError => e
|
40
|
-
path = example.object.file
|
41
|
-
puts "#{path}: Syntax Error in an example. #{e}"
|
42
|
-
ok = false
|
43
|
-
end
|
44
|
-
end
|
45
|
-
abort unless ok
|
46
|
-
end
|