shrine 3.1.0 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +82 -0
  3. data/README.md +11 -4
  4. data/doc/advantages.md +4 -4
  5. data/doc/attacher.md +2 -2
  6. data/doc/carrierwave.md +24 -12
  7. data/doc/changing_derivatives.md +1 -1
  8. data/doc/changing_location.md +6 -5
  9. data/doc/design.md +134 -85
  10. data/doc/direct_s3.md +26 -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 +156 -85
  15. data/doc/metadata.md +80 -44
  16. data/doc/multiple_files.md +1 -1
  17. data/doc/paperclip.md +28 -9
  18. data/doc/plugins/add_metadata.md +112 -35
  19. data/doc/plugins/atomic_helpers.md +41 -3
  20. data/doc/plugins/backgrounding.md +12 -2
  21. data/doc/plugins/column.md +36 -7
  22. data/doc/plugins/default_url.md +6 -3
  23. data/doc/plugins/derivatives.md +83 -44
  24. data/doc/plugins/download_endpoint.md +5 -5
  25. data/doc/plugins/dynamic_storage.md +1 -1
  26. data/doc/plugins/entity.md +12 -4
  27. data/doc/plugins/form_assign.md +5 -5
  28. data/doc/plugins/included.md +25 -5
  29. data/doc/plugins/infer_extension.md +9 -0
  30. data/doc/plugins/instrumentation.md +1 -1
  31. data/doc/plugins/metadata_attributes.md +1 -0
  32. data/doc/plugins/mirroring.md +1 -1
  33. data/doc/plugins/model.md +8 -3
  34. data/doc/plugins/persistence.md +10 -1
  35. data/doc/plugins/remote_url.md +6 -1
  36. data/doc/plugins/remove_invalid.md +9 -1
  37. data/doc/plugins/sequel.md +1 -1
  38. data/doc/plugins/store_dimensions.md +10 -0
  39. data/doc/plugins/type_predicates.md +96 -0
  40. data/doc/plugins/upload_endpoint.md +1 -1
  41. data/doc/plugins/upload_options.md +1 -1
  42. data/doc/plugins/url_options.md +4 -4
  43. data/doc/plugins/validation.md +14 -4
  44. data/doc/plugins/versions.md +7 -7
  45. data/doc/processing.md +287 -123
  46. data/doc/refile.md +9 -9
  47. data/doc/release_notes/2.8.0.md +1 -1
  48. data/doc/release_notes/3.0.0.md +1 -1
  49. data/doc/release_notes/3.2.0.md +96 -0
  50. data/doc/release_notes/3.2.1.md +31 -0
  51. data/doc/release_notes/3.2.2.md +14 -0
  52. data/doc/release_notes/3.3.0.md +105 -0
  53. data/doc/release_notes/3.4.0.md +35 -0
  54. data/doc/securing_uploads.md +2 -2
  55. data/doc/storage/memory.md +19 -0
  56. data/doc/storage/s3.md +104 -77
  57. data/doc/testing.md +12 -2
  58. data/doc/upgrading_to_3.md +99 -53
  59. data/lib/shrine.rb +9 -8
  60. data/lib/shrine/attacher.rb +20 -10
  61. data/lib/shrine/attachment.rb +2 -2
  62. data/lib/shrine/plugins.rb +22 -0
  63. data/lib/shrine/plugins/activerecord.rb +3 -3
  64. data/lib/shrine/plugins/add_metadata.rb +20 -5
  65. data/lib/shrine/plugins/backgrounding.rb +2 -2
  66. data/lib/shrine/plugins/default_url.rb +1 -1
  67. data/lib/shrine/plugins/derivation_endpoint.rb +13 -8
  68. data/lib/shrine/plugins/derivatives.rb +59 -30
  69. data/lib/shrine/plugins/determine_mime_type.rb +5 -3
  70. data/lib/shrine/plugins/entity.rb +12 -11
  71. data/lib/shrine/plugins/instrumentation.rb +12 -18
  72. data/lib/shrine/plugins/mirroring.rb +8 -8
  73. data/lib/shrine/plugins/model.rb +3 -3
  74. data/lib/shrine/plugins/presign_endpoint.rb +16 -4
  75. data/lib/shrine/plugins/pretty_location.rb +1 -1
  76. data/lib/shrine/plugins/processing.rb +1 -1
  77. data/lib/shrine/plugins/refresh_metadata.rb +2 -2
  78. data/lib/shrine/plugins/remote_url.rb +3 -3
  79. data/lib/shrine/plugins/remove_attachment.rb +5 -0
  80. data/lib/shrine/plugins/remove_invalid.rb +10 -5
  81. data/lib/shrine/plugins/sequel.rb +1 -1
  82. data/lib/shrine/plugins/store_dimensions.rb +4 -2
  83. data/lib/shrine/plugins/type_predicates.rb +113 -0
  84. data/lib/shrine/plugins/upload_endpoint.rb +10 -5
  85. data/lib/shrine/plugins/upload_options.rb +2 -2
  86. data/lib/shrine/plugins/url_options.rb +2 -2
  87. data/lib/shrine/plugins/validation.rb +9 -7
  88. data/lib/shrine/storage/linter.rb +4 -4
  89. data/lib/shrine/storage/memory.rb +5 -3
  90. data/lib/shrine/storage/s3.rb +117 -38
  91. data/lib/shrine/version.rb +1 -1
  92. data/shrine.gemspec +8 -8
  93. metadata +42 -34
@@ -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
@@ -7,7 +7,7 @@ class Shrine
7
7
 
8
8
  module VERSION
9
9
  MAJOR = 3
10
- MINOR = 1
10
+ MINOR = 4
11
11
  TINY = 0
12
12
  PRE = nil
13
13
 
data/shrine.gemspec CHANGED
@@ -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,16 @@ 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"
66
+ gem.add_development_dependency "rexml"
67
67
 
68
68
  # for instrumentation plugin
69
69
  gem.add_development_dependency "dry-monitor"
70
- gem.add_development_dependency "activesupport", "~> 5.2.0"
70
+ gem.add_development_dependency "activesupport", RUBY_VERSION >= "2.5" ? "~> 6.0" : "~> 5.2"
71
71
 
72
72
  # for ORM plugins
73
73
  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"
74
+ gem.add_development_dependency "activerecord", RUBY_VERSION >= "2.5" ? "~> 6.0" : "~> 5.2"
75
+ gem.add_development_dependency "sqlite3", "~> 1.4" unless RUBY_ENGINE == "jruby"
76
76
  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.1.0
4
+ version: 3.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janko Marohnić
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-15 00:00:00.000000000 Z
11
+ date: 2021-06-14 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
@@ -276,6 +262,20 @@ dependencies:
276
262
  - - "~>"
277
263
  - !ruby/object:Gem::Version
278
264
  version: '3.23'
265
+ - !ruby/object:Gem::Dependency
266
+ name: rexml
267
+ requirement: !ruby/object:Gem::Requirement
268
+ requirements:
269
+ - - ">="
270
+ - !ruby/object:Gem::Version
271
+ version: '0'
272
+ type: :development
273
+ prerelease: false
274
+ version_requirements: !ruby/object:Gem::Requirement
275
+ requirements:
276
+ - - ">="
277
+ - !ruby/object:Gem::Version
278
+ version: '0'
279
279
  - !ruby/object:Gem::Dependency
280
280
  name: dry-monitor
281
281
  requirement: !ruby/object:Gem::Requirement
@@ -296,14 +296,14 @@ dependencies:
296
296
  requirements:
297
297
  - - "~>"
298
298
  - !ruby/object:Gem::Version
299
- version: 5.2.0
299
+ version: '6.0'
300
300
  type: :development
301
301
  prerelease: false
302
302
  version_requirements: !ruby/object:Gem::Requirement
303
303
  requirements:
304
304
  - - "~>"
305
305
  - !ruby/object:Gem::Version
306
- version: 5.2.0
306
+ version: '6.0'
307
307
  - !ruby/object:Gem::Dependency
308
308
  name: sequel
309
309
  requirement: !ruby/object:Gem::Requirement
@@ -324,28 +324,28 @@ dependencies:
324
324
  requirements:
325
325
  - - "~>"
326
326
  - !ruby/object:Gem::Version
327
- version: 5.2.0
327
+ version: '6.0'
328
328
  type: :development
329
329
  prerelease: false
330
330
  version_requirements: !ruby/object:Gem::Requirement
331
331
  requirements:
332
332
  - - "~>"
333
333
  - !ruby/object:Gem::Version
334
- version: 5.2.0
334
+ version: '6.0'
335
335
  - !ruby/object:Gem::Dependency
336
336
  name: sqlite3
337
337
  requirement: !ruby/object:Gem::Requirement
338
338
  requirements:
339
339
  - - "~>"
340
340
  - !ruby/object:Gem::Version
341
- version: 1.3.6
341
+ version: '1.4'
342
342
  type: :development
343
343
  prerelease: false
344
344
  version_requirements: !ruby/object:Gem::Requirement
345
345
  requirements:
346
346
  - - "~>"
347
347
  - !ruby/object:Gem::Version
348
- version: 1.3.6
348
+ version: '1.4'
349
349
  description: |
350
350
  Shrine is a toolkit for file attachments in Ruby applications. It supports
351
351
  uploading, downloading, processing and deleting IO objects, backed by various
@@ -424,6 +424,7 @@ files:
424
424
  - doc/plugins/signature.md
425
425
  - doc/plugins/store_dimensions.md
426
426
  - doc/plugins/tempfile.md
427
+ - doc/plugins/type_predicates.md
427
428
  - doc/plugins/upload_endpoint.md
428
429
  - doc/plugins/upload_options.md
429
430
  - doc/plugins/url_options.md
@@ -468,9 +469,15 @@ files:
468
469
  - doc/release_notes/3.0.0.md
469
470
  - doc/release_notes/3.0.1.md
470
471
  - doc/release_notes/3.1.0.md
472
+ - doc/release_notes/3.2.0.md
473
+ - doc/release_notes/3.2.1.md
474
+ - doc/release_notes/3.2.2.md
475
+ - doc/release_notes/3.3.0.md
476
+ - doc/release_notes/3.4.0.md
471
477
  - doc/retrieving_uploads.md
472
478
  - doc/securing_uploads.md
473
479
  - doc/storage/file_system.md
480
+ - doc/storage/memory.md
474
481
  - doc/storage/s3.md
475
482
  - doc/testing.md
476
483
  - doc/upgrading_to_3.md
@@ -523,6 +530,7 @@ files:
523
530
  - lib/shrine/plugins/signature.rb
524
531
  - lib/shrine/plugins/store_dimensions.rb
525
532
  - lib/shrine/plugins/tempfile.rb
533
+ - lib/shrine/plugins/type_predicates.rb
526
534
  - lib/shrine/plugins/upload_endpoint.rb
527
535
  - lib/shrine/plugins/upload_options.rb
528
536
  - lib/shrine/plugins/url_options.rb
@@ -545,7 +553,7 @@ metadata:
545
553
  documentation_uri: https://shrinerb.com
546
554
  mailing_list_uri: https://discourse.shrinerb.com
547
555
  source_code_uri: https://github.com/shrinerb/shrine
548
- post_install_message:
556
+ post_install_message:
549
557
  rdoc_options: []
550
558
  require_paths:
551
559
  - lib
@@ -560,8 +568,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
560
568
  - !ruby/object:Gem::Version
561
569
  version: '0'
562
570
  requirements: []
563
- rubygems_version: 3.0.3
564
- signing_key:
571
+ rubygems_version: 3.2.15
572
+ signing_key:
565
573
  specification_version: 4
566
574
  summary: Toolkit for file attachments in Ruby applications
567
575
  test_files: []