shrine 3.0.1 → 3.3.0

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.
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
@@ -9,11 +9,11 @@ class Shrine
9
9
  module Plugins
10
10
  # Documentation can be found on https://shrinerb.com/docs/plugins/upload_endpoint
11
11
  module UploadEndpoint
12
- def self.load_dependencies(uploader, opts = {})
12
+ def self.load_dependencies(uploader, **)
13
13
  uploader.plugin :rack_file
14
14
  end
15
15
 
16
- def self.configure(uploader, opts = {})
16
+ def self.configure(uploader, **opts)
17
17
  uploader.opts[:upload_endpoint] ||= {}
18
18
  uploader.opts[:upload_endpoint].merge!(opts)
19
19
  end
@@ -135,9 +135,14 @@ class Shrine
135
135
  end
136
136
 
137
137
  error!(400, "Upload Not Found") if value.nil?
138
- error!(400, "Upload Not Valid") unless value.is_a?(Hash) && value[:tempfile]
139
138
 
140
- @shrine_class.rack_file(value)
139
+ if value.is_a?(Hash) && value[:tempfile]
140
+ @shrine_class.rack_file(value)
141
+ elsif %i[read rewind eof? close].all? { |m| value.respond_to?(m) }
142
+ value
143
+ else
144
+ error!(400, "Upload Not Valid")
145
+ end
141
146
  end
142
147
 
143
148
  # Returns a hash of information containing `:action` and `:request`
@@ -156,7 +161,7 @@ class Shrine
156
161
  if @upload
157
162
  @upload.call(io, context, request)
158
163
  else
159
- uploader.upload(io, context)
164
+ uploader.upload(io, **context)
160
165
  end
161
166
  end
162
167
 
@@ -4,9 +4,9 @@ class Shrine
4
4
  module Plugins
5
5
  # Documentation can be found on https://shrinerb.com/docs/plugins/upload_options
6
6
  module UploadOptions
7
- def self.configure(uploader, options = {})
7
+ def self.configure(uploader, **opts)
8
8
  uploader.opts[:upload_options] ||= {}
9
- uploader.opts[:upload_options].merge!(options)
9
+ uploader.opts[:upload_options].merge!(opts)
10
10
  end
11
11
 
12
12
  module InstanceMethods
@@ -4,9 +4,9 @@ class Shrine
4
4
  module Plugins
5
5
  # Documentation can be found on https://shrinerb.com/docs/plugins/url_options
6
6
  module UrlOptions
7
- def self.configure(uploader, **options)
7
+ def self.configure(uploader, **opts)
8
8
  uploader.opts[:url_options] ||= {}
9
- uploader.opts[:url_options].merge!(options)
9
+ uploader.opts[:url_options].merge!(opts)
10
10
  end
11
11
 
12
12
  module FileMethods
@@ -29,14 +29,16 @@ class Shrine
29
29
  @errors = []
30
30
  end
31
31
 
32
- # Leaves out :validate option when calling `Shrine.upload`.
33
- def upload(*args, validate: nil, **options)
34
- super(*args, **options)
32
+ # Performs validations after attaching cached file.
33
+ def attach_cached(value, validate: nil, **options)
34
+ result = super(value, validate: false, **options)
35
+ validation(validate)
36
+ result
35
37
  end
36
38
 
37
- # Performs validations after changing the file.
38
- def change(file, validate: nil, **)
39
- result = super
39
+ # Performs validations after attaching file.
40
+ def attach(io, validate: nil, **options)
41
+ result = super(io, **options)
40
42
  validation(validate)
41
43
  result
42
44
  end
@@ -52,7 +54,7 @@ class Shrine
52
54
  # Calls validation appropriately based on the :validate value.
53
55
  def validation(argument)
54
56
  case argument
55
- when Hash then validate(argument)
57
+ when Hash then validate(**argument)
56
58
  when false then errors.clear # skip validation
57
59
  else validate
58
60
  end
@@ -35,7 +35,7 @@ class Shrine
35
35
  end
36
36
 
37
37
  def call(io_factory = default_io_factory)
38
- storage.upload(io_factory.call, id = "foo", {})
38
+ storage.upload(io_factory.call, id = "foo", shrine_metadata: { "foo" => "bar" })
39
39
 
40
40
  lint_open(id)
41
41
  lint_exists(id)
@@ -67,13 +67,13 @@ class Shrine
67
67
  end
68
68
 
69
69
  def lint_open(id)
70
- opened = storage.open(id, {})
70
+ opened = storage.open(id)
71
71
  error :open, "doesn't return a valid IO object" if !io?(opened)
72
72
  error :open, "returns an empty IO object" if opened.read.empty?
73
73
  opened.close
74
74
 
75
75
  begin
76
- storage.open(@nonexisting, {})
76
+ storage.open(@nonexisting)
77
77
  error :open, "should raise an exception on nonexisting file"
78
78
  rescue Shrine::FileNotFound
79
79
  rescue => exception
@@ -107,7 +107,7 @@ class Shrine
107
107
  end
108
108
 
109
109
  def lint_presign(id)
110
- data = storage.presign(id, {})
110
+ data = storage.presign(id)
111
111
  error :presign, "result should be a Hash" unless data.respond_to?(:to_h)
112
112
  error :presign, "result should include :method key" unless data.to_h.key?(:method)
113
113
  error :presign, "result should include :url key" unless data.to_h.key?(:url)
@@ -12,12 +12,14 @@ class Shrine
12
12
  @store = store
13
13
  end
14
14
 
15
- def upload(io, id, *)
15
+ def upload(io, id, **)
16
16
  store[id] = io.read
17
17
  end
18
18
 
19
- def open(id, *)
20
- StringIO.new(store.fetch(id))
19
+ def open(id, **)
20
+ io = StringIO.new(store.fetch(id))
21
+ io.set_encoding(io.string.encoding) # Ruby 2.7.0 – https://bugs.ruby-lang.org/issues/16497
22
+ io
21
23
  rescue KeyError
22
24
  raise Shrine::FileNotFound, "file #{id.inspect} not found on storage"
23
25
  end
@@ -9,6 +9,7 @@ require "down/chunked_io"
9
9
  require "content_disposition"
10
10
 
11
11
  require "uri"
12
+ require "tempfile"
12
13
 
13
14
  class Shrine
14
15
  module Storage
@@ -103,7 +104,7 @@ class Shrine
103
104
  #
104
105
  # [`Aws::S3::Object#get`]: http://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Object.html#get-instance_method
105
106
  def open(id, rewindable: true, **options)
106
- chunks, length = get_object(object(id), options)
107
+ chunks, length = get(id, **options)
107
108
 
108
109
  Down::ChunkedIO.new(chunks: chunks, rewindable: rewindable, size: length)
109
110
  rescue Aws::S3::Errors::NoSuchKey
@@ -179,25 +180,7 @@ class Shrine
179
180
  options.merge!(@upload_options)
180
181
  options.merge!(presign_options)
181
182
 
182
- if method == :post
183
- presigned_post = object(id).presigned_post(options)
184
-
185
- { method: method, url: presigned_post.url, fields: presigned_post.fields }
186
- else
187
- url = object(id).presigned_url(method, options)
188
-
189
- # When any of these options are specified, the corresponding request
190
- # headers must be included in the upload request.
191
- headers = {}
192
- headers["Content-Length"] = options[:content_length] if options[:content_length]
193
- headers["Content-Type"] = options[:content_type] if options[:content_type]
194
- headers["Content-Disposition"] = options[:content_disposition] if options[:content_disposition]
195
- headers["Content-Encoding"] = options[:content_encoding] if options[:content_encoding]
196
- headers["Content-Language"] = options[:content_language] if options[:content_language]
197
- headers["Content-MD5"] = options[:content_md5] if options[:content_md5]
198
-
199
- { method: method, url: url, headers: headers }
200
- end
183
+ send(:"presign_#{method}", id, options)
201
184
  end
202
185
 
203
186
  # Deletes the file from the storage.
@@ -230,11 +213,22 @@ class Shrine
230
213
 
231
214
  # Returns an `Aws::S3::Object` for the given id.
232
215
  def object(id)
233
- bucket.object([*prefix, id].join("/"))
216
+ bucket.object(object_key(id))
234
217
  end
235
218
 
236
219
  private
237
220
 
221
+ # Uploads the file to S3. Uses multipart upload for large files.
222
+ def put(io, id, **options)
223
+ if io.respond_to?(:size) && io.size && io.size <= @multipart_threshold[:upload]
224
+ object(id).put(body: io, **options)
225
+ else # multipart upload
226
+ object(id).upload_stream(part_size: part_size(io), **options) do |write_stream|
227
+ IO.copy_stream(io, write_stream)
228
+ end
229
+ end
230
+ end
231
+
238
232
  # Copies an existing S3 object to a new location. Uses multipart copy for
239
233
  # large files.
240
234
  def copy(io, id, **copy_options)
@@ -250,15 +244,28 @@ class Shrine
250
244
  object(id).copy_from(io.storage.object(io.id), **options)
251
245
  end
252
246
 
253
- # Uploads the file to S3. Uses multipart upload for large files.
254
- def put(io, id, **options)
255
- if io.respond_to?(:size) && io.size && io.size <= @multipart_threshold[:upload]
256
- object(id).put(body: io, **options)
257
- else # multipart upload
258
- object(id).upload_stream(part_size: part_size(io), **options) do |write_stream|
259
- IO.copy_stream(io, write_stream)
260
- end
261
- end
247
+ # Generates parameters for a POST upload request.
248
+ def presign_post(id, options)
249
+ presigned_post = object(id).presigned_post(options)
250
+
251
+ { method: :post, url: presigned_post.url, fields: presigned_post.fields }
252
+ end
253
+
254
+ # Generates parameters for a PUT upload request.
255
+ def presign_put(id, options)
256
+ url = object(id).presigned_url(:put, options)
257
+
258
+ # When any of these options are specified, the corresponding request
259
+ # headers must be included in the upload request.
260
+ headers = {}
261
+ headers["Content-Length"] = options[:content_length] if options[:content_length]
262
+ headers["Content-Type"] = options[:content_type] if options[:content_type]
263
+ headers["Content-Disposition"] = options[:content_disposition] if options[:content_disposition]
264
+ headers["Content-Encoding"] = options[:content_encoding] if options[:content_encoding]
265
+ headers["Content-Language"] = options[:content_language] if options[:content_language]
266
+ headers["Content-MD5"] = options[:content_md5] if options[:content_md5]
267
+
268
+ { method: :put, url: url, headers: headers }
262
269
  end
263
270
 
264
271
  # Determins the part size that should be used when uploading the given IO
@@ -274,17 +281,38 @@ class Shrine
274
281
  end
275
282
 
276
283
  # Aws::S3::Object#get doesn't allow us to get the content length of the
277
- # object before the content is downloaded, so we hack our way around it.
278
- def get_object(object, params)
279
- req = client.build_request(:get_object, **params, bucket: bucket.name, key: object.key)
284
+ # object before all content is downloaded, so we hack our way around it.
285
+ # This way get the content length without an additional HEAD request.
286
+ if Gem::Version.new(Aws::CORE_GEM_VERSION) >= Gem::Version.new("3.104.0")
287
+ def get(id, **params)
288
+ enum = object(id).enum_for(:get, **params)
289
+
290
+ begin
291
+ content_length = Integer(enum.peek.last["content-length"])
292
+ rescue StopIteration
293
+ content_length = 0
294
+ end
280
295
 
281
- body = req.enum_for(:send_request)
282
- body.peek # start the request
296
+ chunks = Enumerator.new { |y| loop { y << enum.next.first } }
297
+
298
+ [chunks, content_length]
299
+ end
300
+ else
301
+ def get(id, **params)
302
+ req = client.build_request(:get_object, bucket: bucket.name, key: object_key(id), **params)
303
+
304
+ body = req.enum_for(:send_request)
305
+ begin
306
+ body.peek # start the request
307
+ rescue StopIteration
308
+ # the S3 object is empty
309
+ end
283
310
 
284
- content_length = Integer(req.context.http_response.headers["Content-Length"])
285
- chunks = Enumerator.new { |y| loop { y << body.next } }
311
+ content_length = Integer(req.context.http_response.headers["Content-Length"])
312
+ chunks = Enumerator.new { |y| loop { y << body.next } }
286
313
 
287
- [chunks, content_length]
314
+ [chunks, content_length]
315
+ end
288
316
  end
289
317
 
290
318
  # The file is copyable if it's on S3 and on the same Amazon account.
@@ -302,6 +330,57 @@ class Shrine
302
330
  bucket.delete_objects(delete: delete_params)
303
331
  end
304
332
  end
333
+
334
+ # Returns object key with potential prefix.
335
+ def object_key(id)
336
+ [*prefix, id].join("/")
337
+ end
338
+
339
+ # Adds support for Aws::S3::Encryption::Client.
340
+ module ClientSideEncryption
341
+ attr_reader :encryption_client
342
+
343
+ # Save the encryption client and continue initialization with normal
344
+ # client.
345
+ def initialize(client: nil, **options)
346
+ return super unless client.class.name.start_with?("Aws::S3::Encryption")
347
+
348
+ super(client: client.client, **options)
349
+ @encryption_client = client
350
+ end
351
+
352
+ private
353
+
354
+ # Encryption client doesn't support multipart uploads, so we always use
355
+ # #put_object.
356
+ def put(io, id, **options)
357
+ return super unless encryption_client
358
+
359
+ encryption_client.put_object(body: io, bucket: bucket.name, key: object_key(id), **options)
360
+ end
361
+
362
+ def get(id, **options)
363
+ return super unless encryption_client
364
+
365
+ # Encryption client v2 warns against streaming download, so we first
366
+ # download all content into a file.
367
+ tempfile = Tempfile.new("shrine-s3", binmode: true)
368
+ response = encryption_client.get_object(response_target: tempfile, bucket: bucket.name, key: object_key(id), **options)
369
+ tempfile.rewind
370
+
371
+ chunks = Enumerator.new do |yielder|
372
+ begin
373
+ yielder << tempfile.read(16*1024) until tempfile.eof?
374
+ ensure
375
+ tempfile.close!
376
+ end
377
+ end
378
+
379
+ [chunks, tempfile.size]
380
+ end
381
+ end
382
+
383
+ prepend ClientSideEncryption
305
384
  end
306
385
  end
307
386
  end
@@ -6,7 +6,6 @@ require "uri"
6
6
 
7
7
  class Shrine
8
8
  # Core class that represents a file uploaded to a storage.
9
- # Base implementation is defined in InstanceMethods and ClassMethods.
10
9
  class UploadedFile
11
10
  @shrine_class = ::Shrine
12
11
 
@@ -7,8 +7,8 @@ class Shrine
7
7
 
8
8
  module VERSION
9
9
  MAJOR = 3
10
- MINOR = 0
11
- TINY = 1
10
+ MINOR = 3
11
+ TINY = 0
12
12
  PRE = nil
13
13
 
14
14
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -33,18 +33,17 @@ direct uploads for fully asynchronous user experience.
33
33
  gem.files = Dir["README.md", "LICENSE.txt", "CHANGELOG.md", "lib/**/*.rb", "shrine.gemspec", "doc/**/*.md"]
34
34
  gem.require_path = "lib"
35
35
 
36
- gem.add_dependency "down", "~> 5.0"
36
+ gem.add_dependency "down", "~> 5.1"
37
37
  gem.add_dependency "content_disposition", "~> 1.0"
38
38
 
39
39
  # general testing helpers
40
40
  gem.add_development_dependency "rake", ">= 11.1"
41
41
  gem.add_development_dependency "minitest", "~> 5.8"
42
- gem.add_development_dependency "mocha", "~> 1.4"
43
- gem.add_development_dependency "dry-initializer"
42
+ gem.add_development_dependency "mocha", "~> 1.11"
44
43
 
45
44
  # for endpoint plugins
46
45
  gem.add_development_dependency "rack", "~> 2.0"
47
- gem.add_development_dependency "http-form_data", "~> 2.0"
46
+ gem.add_development_dependency "http-form_data", "~> 2.2"
48
47
  gem.add_development_dependency "rack-test_app"
49
48
 
50
49
  # for determine_mime_type plugin
@@ -62,15 +61,15 @@ direct uploads for fully asynchronous user experience.
62
61
  gem.add_development_dependency "ruby-vips", "~> 2.0" unless ENV["CI"]
63
62
 
64
63
  # for S3 storage
65
- gem.add_development_dependency "aws-sdk-s3", "~> 1.16"
64
+ gem.add_development_dependency "aws-sdk-s3", "~> 1.69"
66
65
  gem.add_development_dependency "aws-sdk-core", "~> 3.23"
67
66
 
68
67
  # for instrumentation plugin
69
68
  gem.add_development_dependency "dry-monitor"
70
- gem.add_development_dependency "activesupport", "~> 5.2.0"
69
+ gem.add_development_dependency "activesupport", RUBY_VERSION >= "2.5" ? "~> 6.0" : "~> 5.2"
71
70
 
72
71
  # for ORM plugins
73
72
  gem.add_development_dependency "sequel"
74
- gem.add_development_dependency "activerecord", "~> 5.2.0"
75
- gem.add_development_dependency "sqlite3", "~> 1.3.6" unless RUBY_ENGINE == "jruby"
73
+ gem.add_development_dependency "activerecord", RUBY_VERSION >= "2.5" ? "~> 6.0" : "~> 5.2"
74
+ gem.add_development_dependency "sqlite3", "~> 1.4" unless RUBY_ENGINE == "jruby"
76
75
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shrine
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 3.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janko Marohnić
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-10-17 00:00:00.000000000 Z
11
+ date: 2020-10-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: down
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '5.0'
19
+ version: '5.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '5.0'
26
+ version: '5.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: content_disposition
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -72,28 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '1.4'
75
+ version: '1.11'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '1.4'
83
- - !ruby/object:Gem::Dependency
84
- name: dry-initializer
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
82
+ version: '1.11'
97
83
  - !ruby/object:Gem::Dependency
98
84
  name: rack
99
85
  requirement: !ruby/object:Gem::Requirement
@@ -114,14 +100,14 @@ dependencies:
114
100
  requirements:
115
101
  - - "~>"
116
102
  - !ruby/object:Gem::Version
117
- version: '2.0'
103
+ version: '2.2'
118
104
  type: :development
119
105
  prerelease: false
120
106
  version_requirements: !ruby/object:Gem::Requirement
121
107
  requirements:
122
108
  - - "~>"
123
109
  - !ruby/object:Gem::Version
124
- version: '2.0'
110
+ version: '2.2'
125
111
  - !ruby/object:Gem::Dependency
126
112
  name: rack-test_app
127
113
  requirement: !ruby/object:Gem::Requirement
@@ -254,14 +240,14 @@ dependencies:
254
240
  requirements:
255
241
  - - "~>"
256
242
  - !ruby/object:Gem::Version
257
- version: '1.16'
243
+ version: '1.69'
258
244
  type: :development
259
245
  prerelease: false
260
246
  version_requirements: !ruby/object:Gem::Requirement
261
247
  requirements:
262
248
  - - "~>"
263
249
  - !ruby/object:Gem::Version
264
- version: '1.16'
250
+ version: '1.69'
265
251
  - !ruby/object:Gem::Dependency
266
252
  name: aws-sdk-core
267
253
  requirement: !ruby/object:Gem::Requirement
@@ -296,14 +282,14 @@ dependencies:
296
282
  requirements:
297
283
  - - "~>"
298
284
  - !ruby/object:Gem::Version
299
- version: 5.2.0
285
+ version: '6.0'
300
286
  type: :development
301
287
  prerelease: false
302
288
  version_requirements: !ruby/object:Gem::Requirement
303
289
  requirements:
304
290
  - - "~>"
305
291
  - !ruby/object:Gem::Version
306
- version: 5.2.0
292
+ version: '6.0'
307
293
  - !ruby/object:Gem::Dependency
308
294
  name: sequel
309
295
  requirement: !ruby/object:Gem::Requirement
@@ -324,28 +310,28 @@ dependencies:
324
310
  requirements:
325
311
  - - "~>"
326
312
  - !ruby/object:Gem::Version
327
- version: 5.2.0
313
+ version: '6.0'
328
314
  type: :development
329
315
  prerelease: false
330
316
  version_requirements: !ruby/object:Gem::Requirement
331
317
  requirements:
332
318
  - - "~>"
333
319
  - !ruby/object:Gem::Version
334
- version: 5.2.0
320
+ version: '6.0'
335
321
  - !ruby/object:Gem::Dependency
336
322
  name: sqlite3
337
323
  requirement: !ruby/object:Gem::Requirement
338
324
  requirements:
339
325
  - - "~>"
340
326
  - !ruby/object:Gem::Version
341
- version: 1.3.6
327
+ version: '1.4'
342
328
  type: :development
343
329
  prerelease: false
344
330
  version_requirements: !ruby/object:Gem::Requirement
345
331
  requirements:
346
332
  - - "~>"
347
333
  - !ruby/object:Gem::Version
348
- version: 1.3.6
334
+ version: '1.4'
349
335
  description: |
350
336
  Shrine is a toolkit for file attachments in Ruby applications. It supports
351
337
  uploading, downloading, processing and deleting IO objects, backed by various
@@ -424,6 +410,7 @@ files:
424
410
  - doc/plugins/signature.md
425
411
  - doc/plugins/store_dimensions.md
426
412
  - doc/plugins/tempfile.md
413
+ - doc/plugins/type_predicates.md
427
414
  - doc/plugins/upload_endpoint.md
428
415
  - doc/plugins/upload_options.md
429
416
  - doc/plugins/url_options.md
@@ -467,9 +454,15 @@ files:
467
454
  - doc/release_notes/2.9.0.md
468
455
  - doc/release_notes/3.0.0.md
469
456
  - doc/release_notes/3.0.1.md
457
+ - doc/release_notes/3.1.0.md
458
+ - doc/release_notes/3.2.0.md
459
+ - doc/release_notes/3.2.1.md
460
+ - doc/release_notes/3.2.2.md
461
+ - doc/release_notes/3.3.0.md
470
462
  - doc/retrieving_uploads.md
471
463
  - doc/securing_uploads.md
472
464
  - doc/storage/file_system.md
465
+ - doc/storage/memory.md
473
466
  - doc/storage/s3.md
474
467
  - doc/testing.md
475
468
  - doc/upgrading_to_3.md
@@ -522,6 +515,7 @@ files:
522
515
  - lib/shrine/plugins/signature.rb
523
516
  - lib/shrine/plugins/store_dimensions.rb
524
517
  - lib/shrine/plugins/tempfile.rb
518
+ - lib/shrine/plugins/type_predicates.rb
525
519
  - lib/shrine/plugins/upload_endpoint.rb
526
520
  - lib/shrine/plugins/upload_options.rb
527
521
  - lib/shrine/plugins/url_options.rb
@@ -559,7 +553,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
559
553
  - !ruby/object:Gem::Version
560
554
  version: '0'
561
555
  requirements: []
562
- rubygems_version: 3.0.3
556
+ rubygems_version: 3.1.4
563
557
  signing_key:
564
558
  specification_version: 4
565
559
  summary: Toolkit for file attachments in Ruby applications