shrine 3.0.1 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +82 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +15 -5
  5. data/doc/advantages.md +33 -16
  6. data/doc/attacher.md +2 -2
  7. data/doc/carrierwave.md +78 -34
  8. data/doc/changing_derivatives.md +39 -39
  9. data/doc/design.md +134 -85
  10. data/doc/direct_s3.md +1 -0
  11. data/doc/external/articles.md +57 -45
  12. data/doc/external/extensions.md +41 -35
  13. data/doc/external/misc.md +23 -8
  14. data/doc/getting_started.md +177 -112
  15. data/doc/metadata.md +79 -43
  16. data/doc/multiple_files.md +6 -4
  17. data/doc/paperclip.md +119 -42
  18. data/doc/plugins/activerecord.md +1 -1
  19. data/doc/plugins/add_metadata.md +112 -35
  20. data/doc/plugins/atomic_helpers.md +41 -3
  21. data/doc/plugins/backgrounding.md +12 -2
  22. data/doc/plugins/column.md +36 -7
  23. data/doc/plugins/data_uri.md +2 -2
  24. data/doc/plugins/default_url.md +6 -3
  25. data/doc/plugins/derivation_endpoint.md +26 -28
  26. data/doc/plugins/derivatives.md +238 -171
  27. data/doc/plugins/determine_mime_type.md +2 -2
  28. data/doc/plugins/download_endpoint.md +5 -5
  29. data/doc/plugins/dynamic_storage.md +1 -1
  30. data/doc/plugins/form_assign.md +5 -5
  31. data/doc/plugins/included.md +25 -5
  32. data/doc/plugins/infer_extension.md +11 -2
  33. data/doc/plugins/instrumentation.md +1 -1
  34. data/doc/plugins/metadata_attributes.md +22 -10
  35. data/doc/plugins/mirroring.md +1 -1
  36. data/doc/plugins/persistence.md +11 -1
  37. data/doc/plugins/refresh_metadata.md +5 -4
  38. data/doc/plugins/remote_url.md +8 -3
  39. data/doc/plugins/remove_invalid.md +9 -1
  40. data/doc/plugins/signature.md +11 -2
  41. data/doc/plugins/store_dimensions.md +12 -2
  42. data/doc/plugins/type_predicates.md +96 -0
  43. data/doc/plugins/upload_endpoint.md +7 -11
  44. data/doc/plugins/upload_options.md +1 -1
  45. data/doc/plugins/url_options.md +4 -4
  46. data/doc/plugins/validation.md +14 -4
  47. data/doc/plugins/validation_helpers.md +3 -3
  48. data/doc/plugins/versions.md +7 -7
  49. data/doc/processing.md +290 -127
  50. data/doc/refile.md +39 -18
  51. data/doc/release_notes/2.19.0.md +1 -1
  52. data/doc/release_notes/2.8.0.md +1 -1
  53. data/doc/release_notes/3.0.0.md +1 -1
  54. data/doc/release_notes/3.0.1.md +4 -0
  55. data/doc/release_notes/3.1.0.md +73 -0
  56. data/doc/release_notes/3.2.0.md +96 -0
  57. data/doc/release_notes/3.2.1.md +31 -0
  58. data/doc/release_notes/3.2.2.md +14 -0
  59. data/doc/release_notes/3.3.0.md +105 -0
  60. data/doc/securing_uploads.md +3 -3
  61. data/doc/storage/file_system.md +1 -1
  62. data/doc/storage/memory.md +19 -0
  63. data/doc/storage/s3.md +105 -82
  64. data/doc/testing.md +2 -2
  65. data/doc/upgrading_to_3.md +97 -49
  66. data/doc/validation.md +3 -2
  67. data/lib/shrine.rb +8 -8
  68. data/lib/shrine/attacher.rb +24 -14
  69. data/lib/shrine/attachment.rb +5 -5
  70. data/lib/shrine/plugins.rb +22 -0
  71. data/lib/shrine/plugins/activerecord.rb +1 -1
  72. data/lib/shrine/plugins/add_metadata.rb +18 -7
  73. data/lib/shrine/plugins/backgrounding.rb +2 -2
  74. data/lib/shrine/plugins/default_storage.rb +6 -6
  75. data/lib/shrine/plugins/default_url.rb +1 -1
  76. data/lib/shrine/plugins/derivation_endpoint.rb +12 -7
  77. data/lib/shrine/plugins/derivatives.rb +61 -29
  78. data/lib/shrine/plugins/determine_mime_type.rb +3 -3
  79. data/lib/shrine/plugins/entity.rb +6 -6
  80. data/lib/shrine/plugins/mirroring.rb +8 -8
  81. data/lib/shrine/plugins/model.rb +3 -3
  82. data/lib/shrine/plugins/presign_endpoint.rb +16 -4
  83. data/lib/shrine/plugins/pretty_location.rb +1 -1
  84. data/lib/shrine/plugins/processing.rb +1 -1
  85. data/lib/shrine/plugins/refresh_metadata.rb +2 -2
  86. data/lib/shrine/plugins/remote_url.rb +3 -3
  87. data/lib/shrine/plugins/remove_attachment.rb +5 -0
  88. data/lib/shrine/plugins/remove_invalid.rb +10 -5
  89. data/lib/shrine/plugins/sequel.rb +1 -1
  90. data/lib/shrine/plugins/signature.rb +7 -6
  91. data/lib/shrine/plugins/store_dimensions.rb +22 -11
  92. data/lib/shrine/plugins/type_predicates.rb +113 -0
  93. data/lib/shrine/plugins/upload_endpoint.rb +10 -5
  94. data/lib/shrine/plugins/upload_options.rb +2 -2
  95. data/lib/shrine/plugins/url_options.rb +2 -2
  96. data/lib/shrine/plugins/validation.rb +9 -7
  97. data/lib/shrine/storage/linter.rb +4 -4
  98. data/lib/shrine/storage/memory.rb +5 -3
  99. data/lib/shrine/storage/s3.rb +117 -38
  100. data/lib/shrine/uploaded_file.rb +0 -1
  101. data/lib/shrine/version.rb +2 -2
  102. data/shrine.gemspec +7 -8
  103. metadata +25 -31
@@ -1,12 +1,12 @@
1
1
  ---
2
- title: Shrine for Refile Users
2
+ title: Upgrading from Refile
3
3
  ---
4
4
 
5
5
  This guide is aimed at helping Refile users transition to Shrine, and it consists
6
6
  of three parts:
7
7
 
8
8
  1. Explanation of the key differences in design between Refile and Shrine
9
- 2. Instructions how to migrate and existing app that uses Refile to Shrine
9
+ 2. Instructions how to migrate an existing app that uses Refile to Shrine
10
10
  3. Extensive reference of Refile's interface with Shrine equivalents
11
11
 
12
12
  ## Overview
@@ -110,13 +110,6 @@ into separate columns.
110
110
  Shrine provides on-the-fly processing via the
111
111
  [`derivation_endpoint`][derivation_endpoint] plugin:
112
112
 
113
- ```rb
114
- # config/routes.rb (Rails)
115
- Rails.application.routes.draw do
116
- # ...
117
- mount ImageUploader.derivation_endpoint => "/derivations/image"
118
- end
119
- ```
120
113
  ```rb
121
114
  require "image_processing/mini_magick"
122
115
 
@@ -132,8 +125,15 @@ class ImageUploader < Shrine
132
125
  end
133
126
  end
134
127
  ```
128
+ ```rb
129
+ # config/routes.rb (Rails)
130
+ Rails.application.routes.draw do
131
+ # ...
132
+ mount ImageUploader.derivation_endpoint => "/derivations/image"
133
+ end
134
+ ```
135
135
 
136
- Shrine also support processing up front using the [`derivatives`][derivatives]
136
+ Shrine also support eager processing using the [`derivatives`][derivatives]
137
137
  plugin.
138
138
 
139
139
  ### Validation
@@ -199,13 +199,18 @@ explains this setup in more detail.
199
199
  ## Migrating from Refile
200
200
 
201
201
  You have an existing app using Refile and you want to transfer it to
202
- Shrine. Let's assume we have a `Photo` model with the "image" attachment. First
203
- we need to create the `image_data` column for Shrine:
202
+ Shrine. Let's assume we have a `Photo` model with the "image" attachment.
203
+
204
+ ### 1. Add Shrine column
205
+
206
+ First we need to create the `image_data` column for Shrine:
204
207
 
205
208
  ```rb
206
209
  add_column :photos, :image_data, :text
207
210
  ```
208
211
 
212
+ ### 2. Dual write
213
+
209
214
  Afterwards we need to make new uploads write to the `image_data` column. This
210
215
  can be done by including the below module to all models that have Refile
211
216
  attachments:
@@ -219,8 +224,7 @@ Shrine.storages = {
219
224
  }
220
225
 
221
226
  Shrine.plugin :model
222
- ```
223
- ```rb
227
+
224
228
  module RefileShrineSynchronization
225
229
  def write_shrine_data(name)
226
230
  attacher = Shrine::Attacher.from_model(self, name)
@@ -257,8 +261,12 @@ end
257
261
  ```
258
262
 
259
263
  After you deploy this code, the `image_data` column should now be successfully
260
- synchronized with new attachments. Next step is to run a script which writes
261
- all existing Refile attachments to `image_data`:
264
+ synchronized with new attachments.
265
+
266
+ ### 3. Data migration
267
+
268
+ Next step is to run a script which writes all existing Refile attachments to
269
+ `image_data`:
262
270
 
263
271
  ```rb
264
272
  Photo.find_each do |photo|
@@ -267,9 +275,22 @@ Photo.find_each do |photo|
267
275
  end
268
276
  ```
269
277
 
278
+ ### 4. Rewrite code
279
+
270
280
  Now you should be able to rewrite your application so that it uses Shrine
271
- instead of Refile, using equivalent Shrine storages. For help with translating
272
- the code from Refile to Shrine, you can consult the reference below.
281
+ instead of Refile (you can consult the reference in the next section). You can
282
+ remove the `RefileShrineSynchronization` module as well.
283
+
284
+ ### 5. Remove Refile columns
285
+
286
+ If everything is looking good, we can remove Refile columns:
287
+
288
+ ```rb
289
+ remove_column :photos, :image_id
290
+ remove_column :photos, :image_size
291
+ remove_column :photos, :image_filename
292
+ remove_column :photos, :image_content_type
293
+ ```
273
294
 
274
295
  ## Refile to Shrine direct mapping
275
296
 
@@ -16,7 +16,7 @@ title: Shrine 2.19.0
16
16
  uploaded_file.download
17
17
  uploaded_file.delete
18
18
  ```
19
- ```plaintext
19
+ ```
20
20
  Metadata (32ms) – {:storage=>:store, :io=>StringIO, :uploader=>Shrine}
21
21
  Upload (1523ms) – {:storage=>:store, :location=>"ed0e30ddec8b97813f2c1f4cfd1700b4", :io=>StringIO, :upload_options=>{}, :uploader=>Shrine}
22
22
  Exists (755ms) – {:storage=>:store, :location=>"ed0e30ddec8b97813f2c1f4cfd1700b4", :uploader=>Shrine}
@@ -1,5 +1,5 @@
1
1
  ---
2
- title: Shrine 2.9.0
2
+ title: Shrine 2.8.0
3
3
  ---
4
4
 
5
5
  ## New Features
@@ -366,7 +366,7 @@ end
366
366
  ```
367
367
  ```rb
368
368
  attacher = photo.image_attacher
369
- attacher.form_assign("image" => file, "title" => "...", "description" => "...")
369
+ attacher.form_assign({ "image" => file, "title" => "...", "description" => "..." })
370
370
  attacher.file #=> #<Shrine::UploadedFile id="..." storage=:cache ...>
371
371
  ```
372
372
 
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Shrine 3.0.1
3
+ ---
4
+
1
5
  ## Regressions
2
6
 
3
7
  * Fixed `metadata_attributes` plugin raising an exception when the attachment
@@ -0,0 +1,73 @@
1
+ ---
2
+ title: Shrine 3.1.0
3
+ ---
4
+
5
+ ## New features
6
+
7
+ * The `Attacher#create_derivatives` method now accepts a `:storage` option for
8
+ specifying the storage to which derivatives should be uploaded.
9
+
10
+ ```rb
11
+ # with attachment module
12
+ photo.image_derivatives!(storage: :other_store)
13
+
14
+ # with attacher
15
+ attacher.create_derivatives(storage: :other_store)
16
+ ```
17
+
18
+ * The `Shrine.calculate_signature` now accepts a `:rewind` boolean option for
19
+ choosing whether the IO object should be rewinded after reading. This is
20
+ useful if you want to calculate signature from non-rewindable IO objects,
21
+ such as `IO.pipe`, `Socket`, non-rewindable `Down::ChunkedIO` etc.
22
+
23
+ ```rb
24
+ Shrine.signature(io, rewind: false)
25
+ ```
26
+
27
+ ## Improvements
28
+
29
+ * The derivatives processor can now be registered with `Attacher.derivatives`,
30
+ which is just an alias for `Attacher.derivatives_processor`.
31
+
32
+ ```rb
33
+ class ImageUploader < Shrine
34
+ Attacher.derivatives_processor do |original|
35
+ # ...
36
+ end
37
+ end
38
+
39
+ # can now be written as
40
+
41
+ class ImageUploader < Shrine
42
+ Attacher.derivatives do |original|
43
+ # ...
44
+ end
45
+ end
46
+ ```
47
+
48
+ * The `Attacher#cached?` and `Attacher#stored?` methods now work correctly if
49
+ temporary/permanent storage identifiers were specified as strings.
50
+
51
+ * The `store_dimensions` plugin now properly propagates exceptions when loading
52
+ the `ruby-vips` gem in `:vips` analyzer.
53
+
54
+ * The `add_metadata` plugin now respects inheritance again when defining
55
+ metadata methods on the `Shrine::UploadedFile` class. In 2.19.0, the
56
+ `add_metadata` plugin was changed to define metadata methods on the internal
57
+ `FileMethods` plugin module, which is shared across all uploaders. This
58
+ change has now been reverted.
59
+
60
+ ## Backwards compatibility
61
+
62
+ * The `Attacher#cache_key` and `Attacher#store_key` methods now always return
63
+ symbol keys, even if the storage key that was specified was a string key.
64
+
65
+ ```rb
66
+ attacher = Shrine::Attacher.new(cache: "cache", store: "store")
67
+ attacher.cache_key #=> :cache (previously "cache")
68
+ attacher.store_key #=> :store (previously "store")
69
+ ```
70
+
71
+ * The `add_metadata` plugin now defines metadata methods directly on the
72
+ `UploadedFile` class, which means that if you happen to have been overriding
73
+ these metadata methods and calling `super`, this won't work anymore.
@@ -0,0 +1,96 @@
1
+ ---
2
+ title: Shrine 3.2.0
3
+ ---
4
+
5
+ ## New features
6
+
7
+ * The `type_predicates` plugin has been added, which adds convenient predicate
8
+ methods to `Shrine::UploadedFile` based on the MIME type.
9
+
10
+ ```rb
11
+ # Gemfile
12
+ gem "mini_mime" # default dependency of type_predicates
13
+ ```
14
+ ```rb
15
+ Shrine.plugin :type_predicates
16
+ ```
17
+
18
+ The plugin adds four predicate methods based on the general type of the file:
19
+
20
+ ```rb
21
+ file.image? # returns true for any "image/*" MIME type
22
+ file.video? # returns true for any "video/*" MIME type
23
+ file.audio? # returns true for any "audio/*" MIME type
24
+ file.text? # returns true for any "text/*" MIME type
25
+ ```
26
+
27
+ You can also check for specific MIME type using the extension name:
28
+
29
+ ```rb
30
+ file.type?(:jpg) # returns true if MIME type is "image/jpeg"
31
+ file.type?(:svg) # returns true if MIME type is "image/svg+xml"
32
+ file.type?(:mov) # returns true if MIME type is "video/quicktime"
33
+ file.type?(:ppt) # returns true if MIME type is "application/vnd.ms-powerpoint"
34
+ ...
35
+ ```
36
+
37
+ For convenience, you can create predicate methods for specific file types:
38
+
39
+ ```rb
40
+ Shrine.plugin :type_predicates, methods: %i[jpg svg mov ppt]
41
+ ```
42
+ ```rb
43
+ file.jpg? # returns true if MIME type is "image/jpeg"
44
+ file.svg? # returns true if MIME type is "image/svg+xml"
45
+ file.mov? # returns true if MIME type is "video/quicktime"
46
+ file.ppt? # returns true if MIME type is "application/vnd.ms-powerpoint"
47
+ ```
48
+
49
+ * The `#add_metadata` method has been added to the `add_metadata` plugin for
50
+ adding new metadata to an existing file/attachment.
51
+
52
+ ```rb
53
+ attacher.file.metadata #=> { ... }
54
+ attacher.add_metadata("foo" => "bar")
55
+ attacher.file.metadata #=> { ..., "foo" => "bar" }
56
+ ```
57
+
58
+ ## Other improvements
59
+
60
+ * The `remove_invalid` plugin now works correctly with `derivatives` plugin.
61
+
62
+ * The `remove_invalid` plugin is now also activated when `Attacher#validate`
63
+ is called manually.
64
+
65
+ * The current attached file data can now be assigned back to the attachment
66
+ attribute, and this operation will be a no-op.
67
+
68
+ ```rb
69
+ photo.image #=> #<Shrine::UploadedFile id="foo" storage=:store metadata={...}>
70
+ photo.image = { "id" => "foo", "storage" => "store", "metadata" => { ... } } # no-op
71
+ ```
72
+
73
+ This allows treating the attachment attribute as a persistent attribute,
74
+ where the current value can be assigned back on record updates.
75
+
76
+ * When promoting derivatives, the `:derivative` parameter value was being
77
+ passed to the uploader as an array. This has been fixed, and the value is now
78
+ the same as when uploading derivatives directly to permanent storage.
79
+
80
+ * The `derivatives` plugin now includes additional `:io` and `:attacher` values
81
+ in the instrumentation event payload.
82
+
83
+ ## Backwards compatibility
84
+
85
+ * The `validation` plugin now runs validations on `Attacher#attach` and
86
+ `Attacher#attach_cached`. If you were using `Attacher#change` directly and
87
+ expecting the validations to be run automatically, you will need to update
88
+ your code.
89
+
90
+ * If you were updating the cached file metadata via file data assignment, this
91
+ will no longer work.
92
+
93
+ ```rb
94
+ photo.image #=> #<Shrine::UploadedFile id="foo" storage=:cache metadata={...}>
95
+ photo.image = { "id" => "foo", "storage" => "cache", "metadata" => { ... } } # no-op
96
+ ```
@@ -0,0 +1,31 @@
1
+ ---
2
+ title: Shrine 3.2.1
3
+ ---
4
+
5
+ ## Ruby 2.7 compatibility
6
+
7
+ * Shrine doesn't trigger [Ruby 2.7 warnings for separation of positional and
8
+ keyword arguments][kwargs] anymore.
9
+
10
+ * Down 5.1.0 has been released, which resolves warnings and a `FrozenError`
11
+ exception on Ruby 2.7. Shrine now requires at least this version of Down.
12
+
13
+ If you're using `Down::Http`, make sure you're using http.rb 4.3.0 or newer.
14
+
15
+ * ImageProcessing 1.10.3 gem has been released which resolves Ruby 2.7 warnings
16
+ as well. If you're using it for image processing, make sure to upgrade to
17
+ this version:
18
+
19
+ ```rb
20
+ gem "image_processing", ">= 1.10.3", "< 2"
21
+ ```
22
+
23
+ ## Rack 2.1 compatibility
24
+
25
+ * The `derivation_endpoint` plugin now uses `Rack::Files` on Rack 2.1 or newer.
26
+
27
+ ## Other improvements
28
+
29
+ * The `S3#open` method now handles empty S3 objects.
30
+
31
+ [kwargs]: https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/
@@ -0,0 +1,14 @@
1
+ ---
2
+ title: Shrine 3.2.2
3
+ ---
4
+
5
+ ## Bug fixes
6
+
7
+ * aws-sdk-core 3.104.0 introduced a backwards incompatible changes that caused
8
+ `Shrine::Storage::S3#open` to start raising an exception.
9
+
10
+ ```
11
+ NoMethodError: undefined method `bytesize' for #<Array:0x000000000a721be0>
12
+ ```
13
+
14
+ This has now been fixed.
@@ -0,0 +1,105 @@
1
+ ---
2
+ title: Shrine 3.3.0
3
+ ---
4
+
5
+ ## New features
6
+
7
+ * The `:create_on_promote` option has been added to the `derivatives` plugin
8
+ for automatically creating derivatives after the attached cached file is
9
+ promoted to permanent storage.
10
+
11
+ ```rb
12
+ Shrine.plugin :derivatives, create_on_promote: true
13
+ ```
14
+
15
+ * The `:auto_extraction` option has been added to the `store_dimensions` plugin
16
+ for skipping automatically extracting dimensions on upload.
17
+
18
+ ```rb
19
+ Shrine.plugin :store_dimensions, auto_extraction: false
20
+ ```
21
+
22
+ * The `:skip_nil` option has been added to the `add_metadata` plugin for
23
+ excluding metadata keys whose values are nil.
24
+
25
+ ```rb
26
+ class PdfUploader < Shrine
27
+ add_metadata :pages, skip_nil: true do |io|
28
+ if is_pdf?(io)
29
+ reader = PDF::Reader.new(io)
30
+ reader.page_count
31
+ else
32
+ # If this is not a PDF, then the pages metadata will not be stored
33
+ nil
34
+ end
35
+ end
36
+ end
37
+ ```
38
+
39
+ * The `:download` option has been added to derivatives processors in
40
+ `derivatives` plugin for skipping converting the source IO object into a
41
+ file. This can be used to avoid a potentially expensive download/copy when
42
+ the derivatives processor doesn't need the file.
43
+
44
+ ```rb
45
+ Attacher.derivatives :my_processor, download: false do |source|
46
+ source #=> Could be File, Shrine::UploadedFile, or other IO-like object
47
+ shrine_class.with_file(source) do |file|
48
+ # can force download/copy if necessary with `with_file`,
49
+ end
50
+ end
51
+ ```
52
+
53
+ ## Bug fixes
54
+
55
+ * The `upload_endpoint` now handles calling `Shrine.upload_response` method
56
+ from a Rails controller.
57
+
58
+ * The `derivation_endpoint` plugin now applies the `version` query parameter
59
+ to the derivation when creating the response.
60
+
61
+ ## Other improvements
62
+
63
+ * The new `Aws:S3::EncryptionV2::Client` is now supported by the S3 storage for
64
+ client-side encryption.
65
+
66
+ * The `derivation_endpoint` now reduces the possibility of timing attacks by
67
+ comparing URL signatures in constant time using `Rack::Utils.secure_compare`.
68
+
69
+ * The `derivatives` plugin now copies non-file source IO objects to disk before
70
+ passing them to the processor. This is consistent with how a
71
+ `Shrine::UploadedFile` object is downloaded to disk.
72
+
73
+ * The `sequel` and `activerecord` plugins now call `Attacher#reload` when
74
+ reloading the model, which reloads the attached files but keeps other
75
+ attacher state.
76
+
77
+ * The `derivatives` plugin doesn't download the attached file anymore if
78
+ attempting to process derivatives when no derivatives processor was defined.
79
+
80
+ * The `mirroring` plugin now forwards attacher options when uploading to mirror
81
+ storages.
82
+
83
+ * The `presign_endpoint` plugin now handles the `OPTIONS` HTTP verb, which
84
+ newer versions of Uppy are requesting.
85
+
86
+ * `Shrine::Storage::Memory#open` now always returns a `StringIO` in the file
87
+ content's original encoding, instead of the encoding set by
88
+ `Encoding.default_internal`. This works around a [bug][ruby-lang #16497]
89
+ in `StringIO` introduced in Ruby 2.7.0.
90
+
91
+ * The `remove_attachment` plugin now deletes the removed file if a new file was
92
+ attached right after removal.
93
+
94
+ ## Backwards compatibility
95
+
96
+ * If you were passing a non-file IO object to the derivatives processor, Shrine
97
+ will now convert it into a file beforehand. If you're currently doing this
98
+ and are converting the IO object into a file inside the processor, you can
99
+ now remove the conversion code to avoid doubling the amount of disk writes.
100
+
101
+ * When reloading a Sequel/ActiveRecord model, any attacher state other than
102
+ uploaded files will now be retained after the reload. If you were relying on
103
+ all the attacher state being re-initialized, you'll need to update your code.
104
+
105
+ [ruby-lang #16497]: https://bugs.ruby-lang.org/issues/16497