rubocop-thread_safety 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c4f37c2216cfdace60b7ef3f2e2f0b5bb743b9b8a3ee2543bb3a2ed10c90de1a
4
- data.tar.gz: 2cfa26d1da425d7d39ee0897d8137d24a5af25cd8911637dfd8093c7097b5a30
3
+ metadata.gz: fa732d8bbefbcfc25dfd2b8adbfcc84788d77d8a21992b152975d9ee92e2f105
4
+ data.tar.gz: f2d29b69ad8e94c9c4b5de205b7301d45ffb3fb3a1c69429af27a5000e7350c6
5
5
  SHA512:
6
- metadata.gz: 405f5f9007c0d1aef55173a0ee4aefb44d16ec4ae5113acdb05750a8792fcbc7759ceab4267132f47906ac999194f2a550b2ce63eef2d117a35c5c9cd1c7d438
7
- data.tar.gz: 78e4b72c55d6745a979bff3acf5bf4b393534ca448dfec5aaa765f77dd32a66db5b0291a5fb55d8fa02044407ec95c72185b7e28add1801b456b1eb1f0be904a
6
+ metadata.gz: ec8b96d08f872297a64bbf558f93a27e09bbe61d2a06b7248fdb2a3896a7367c520eceb0ca7f1e88fdb26fc8a03e2eab1772794353b5e12a3724a3371360d689
7
+ data.tar.gz: 7479c57f327e71e7fbc7b263ea13af5e4e908d7a29849946329bae072ba454636dca72465b1c7dc64d9150064d5e61ca68a81eb45a4ea247a5af69027afd6fb7
@@ -1,26 +1,55 @@
1
1
  name: CI
2
2
 
3
- on: [push, pull_request]
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+ pull_request:
4
8
 
5
9
  jobs:
6
- test:
7
-
10
+ confirm_documentation:
8
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
9
20
 
21
+ test:
22
+ runs-on: ubuntu-latest
10
23
  strategy:
11
24
  fail-fast: false
12
25
  matrix:
13
- ruby: ["2.5", "2.6", "2.7", "3.0", "3.1", "3.2", ruby-head, jruby-9.2, jruby-9.3]
14
- rubocop_version: ["0.90", "1.20"]
26
+ ruby: ["2.7", "3.0", "3.1", "3.2", "3.3", ruby-head, jruby-9.4]
27
+ rubocop_version: ["1.48", "1.66"]
15
28
  env:
16
29
  BUNDLE_GEMFILE: "gemfiles/rubocop_${{ matrix.rubocop_version }}.gemfile"
17
30
  steps:
18
- - uses: actions/checkout@v3
19
- - name: Set up Ruby
20
- uses: ruby/setup-ruby@v1
21
- with:
22
- bundler-cache: true # 'bundle install' and cache gems
23
- ruby-version: ${{ matrix.ruby }}
24
- bundler: 2.3.26
25
- - name: Run tests
26
- run: bundle exec rspec
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
@@ -1,6 +1,10 @@
1
- name: Lint
1
+ name: Lint
2
2
 
3
- on: [push, pull_request]
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+ pull_request:
4
8
 
5
9
  jobs:
6
10
  lint:
@@ -9,11 +13,11 @@ jobs:
9
13
  name: Rubocop
10
14
 
11
15
  steps:
12
- - uses: actions/checkout@v3
13
- - name: Set up Ruby
14
- uses: ruby/setup-ruby@v1
15
- with:
16
- bundler-cache: true # 'bundle install' and cache gems
17
- ruby-version: "2.7"
18
- - name: Run Rubocop
19
- run: bundle exec rubocop
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/.rspec CHANGED
@@ -1,2 +1,3 @@
1
1
  --color
2
2
  --require spec_helper
3
+ --warnings
data/.rubocop.yml CHANGED
@@ -1,11 +1,12 @@
1
- inherit_from: .rubocop_todo.yml
2
-
3
1
  require:
4
2
  - rubocop/cop/internal_affairs
3
+ - rubocop-rake
4
+ - rubocop-rspec
5
5
 
6
6
  AllCops:
7
7
  DisplayCopNames: true
8
- TargetRubyVersion: 2.5
8
+ TargetRubyVersion: 2.7
9
+ NewCops: enable
9
10
 
10
11
  Lint/RaiseException:
11
12
  Enabled: true
@@ -40,10 +41,6 @@ Style/FormatStringToken:
40
41
  Exclude:
41
42
  - spec/**/*
42
43
 
43
- Style/FrozenStringLiteralComment:
44
- Exclude:
45
- - "gemfiles/*.gemfile"
46
-
47
44
  Style/HashEachMethods:
48
45
  Enabled: true
49
46
 
@@ -68,12 +65,17 @@ Style/OptionHash:
68
65
  Style/Send:
69
66
  Enabled: true
70
67
 
71
- Style/StringLiterals:
72
- Exclude:
73
- - "gemfiles/*.gemfile"
74
-
75
68
  Style/StringMethods:
76
69
  Enabled: true
77
70
 
78
71
  Style/SymbolArray:
79
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 CHANGED
@@ -1,9 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- appraise 'rubocop-0.90' do
4
- gem 'rubocop', '~> 0.90.0'
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'
5
17
  end
6
18
 
7
- appraise 'rubocop-1.20' do
8
- gem 'rubocop', '~> 1.20.0'
19
+ appraise 'rubocop-1.66' do
20
+ gem 'rubocop', '~> 1.66.0'
9
21
  end
data/CHANGELOG.md ADDED
@@ -0,0 +1,14 @@
1
+ # Change log
2
+
3
+ ## 0.6.0
4
+
5
+ * [#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))
6
+ * [#55](https://github.com/rubocop/rubocop-thread_safety/pull/55): Enhance `ThreadSafety::InstanceVariableInClassMethod` cop to detect offenses within `class_eval/exec` blocks. ([@viralpraxis](https://github.com/viralpraxis))
7
+ * [#54](https://github.com/rubocop/rubocop-thread_safety/pull/54): Drop support for RuboCop older than 1.48. ([@viralpraxis](https://github.com/viralpraxis))
8
+ * [#52](https://github.com/rubocop/rubocop-thread_safety/pull/52): Add new `RackMiddlewareInstanceVariable` cop to detect instance variables in Rack middleware. ([@viralpraxis](https://github.com/viralpraxis))
9
+ * [#48](https://github.com/rubocop/rubocop-thread_safety/pull/48): Do not report instance variables in `ActionDispatch` callbacks in singleton methods. ([@viralpraxis](https://github.com/viralpraxis))
10
+ * [#43](https://github.com/rubocop/rubocop-thread_safety/pull/43): Make detection of ActiveSupport's `class_attribute` configurable. ([@viralpraxis](https://github.com/viralpraxis))
11
+ * [#42](https://github.com/rubocop/rubocop-thread_safety/pull/42): Fix some `InstanceVariableInClassMethod` cop false positive offenses. ([@viralpraxis](https://github.com/viralpraxis))
12
+ * [#41](https://github.com/rubocop/rubocop-thread_safety/pull/41): Drop support for MRI older than 2.7. ([@viralpraxis](https://github.com/viralpraxis))
13
+ * [#38](https://github.com/rubocop/rubocop-thread_safety/pull/38): Fix `NewThread` cop detection is case of `Thread.start`, `Thread.fork`, or `Thread.new` with arguments. ([@viralpraxis](https://github.com/viralpraxis))
14
+ * [#36](https://github.com/rubocop/rubocop-thread_safety/pull/36): Add new `DirChdir` cop to detect `Dir.chdir` calls. ([@viralpraxis](https://github.com/viralpraxis))
data/Gemfile CHANGED
@@ -2,5 +2,16 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- # Specify your gem's dependencies in rubocop-thread_safety.gemspec
6
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/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # RuboCop::ThreadSafety
2
2
 
3
3
  Thread-safety analysis for your projects, as an extension to
4
- [RuboCop](https://github.com/bbatsov/rubocop).
4
+ [RuboCop](https://github.com/rubocop/rubocop).
5
5
 
6
6
  ## Installation and Usage
7
7
 
@@ -60,6 +60,8 @@ Improvements that would make shared state thread-safe include:
60
60
  * Use [`RequestStore`](https://github.com/steveklabnik/request_store)
61
61
  * Use `Thread.current[:name]`
62
62
 
63
+ Certain system calls, such as `chdir`, affect the entire process. To avoid potential thread-safety issues, it's preferable to use (if possible) the `chdir` option in methods like `Kernel.system` and `IO.popen` rather than relying on `Dir.chdir`.
64
+
63
65
  ## Development
64
66
 
65
67
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/Rakefile CHANGED
@@ -1,8 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/gem_tasks'
4
+ require 'open3'
4
5
  require 'rspec/core/rake_task'
5
6
 
7
+ Dir['tasks/**/*.rake'].each { |t| load t }
8
+
6
9
  RSpec::Core::RakeTask.new(:spec)
7
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
+
8
22
  task default: :spec
data/config/default.yml CHANGED
@@ -5,6 +5,7 @@
5
5
  ThreadSafety/ClassAndModuleAttributes:
6
6
  Description: 'Avoid mutating class and module attributes.'
7
7
  Enabled: true
8
+ ActiveSupportClassAttributeAllowed: false
8
9
 
9
10
  ThreadSafety/InstanceVariableInClassMethod:
10
11
  Description: 'Avoid using instance variables in class methods.'
@@ -30,3 +31,17 @@ ThreadSafety/NewThread:
30
31
  Avoid starting new threads.
31
32
  Let a framework like Sidekiq handle the threads.
32
33
  Enabled: true
34
+
35
+ ThreadSafety/DirChdir:
36
+ Description: Avoid using `Dir.chdir` due to its process-wide effect.
37
+ Enabled: true
38
+
39
+ ThreadSafety/RackMiddlewareInstanceVariable:
40
+ Description: Avoid instance variables in Rack middleware.
41
+ Enabled: true
42
+ Include:
43
+ - 'app/middleware/**/*.rb'
44
+ - 'lib/middleware/**/*.rb'
45
+ - 'app/middlewares/**/*.rb'
46
+ - 'lib/middlewares/**/*.rb'
47
+ AllowedIdentifiers: []
@@ -0,0 +1,2 @@
1
+ renamed:
2
+ ThreadSafety/InstanceVariableInClassMethod: ThreadSafety/ClassInstanceVariable
@@ -0,0 +1,8 @@
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]
@@ -0,0 +1,361 @@
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
+ |===
@@ -0,0 +1,20 @@
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: '../'