shrine 2.19.4 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +485 -43
- data/LICENSE.txt +1 -1
- data/README.md +81 -977
- data/doc/advantages.md +231 -204
- data/doc/attacher.md +304 -153
- data/doc/carrierwave.md +297 -226
- data/doc/changing_derivatives.md +308 -0
- data/doc/changing_location.md +102 -21
- data/doc/changing_storage.md +110 -0
- data/doc/creating_persistence_plugins.md +132 -0
- data/doc/creating_plugins.md +43 -23
- data/doc/creating_storages.md +19 -5
- data/doc/design.md +147 -97
- data/doc/direct_s3.md +38 -28
- data/doc/external/articles.md +63 -0
- data/doc/external/extensions.md +53 -0
- data/doc/external/misc.md +32 -0
- data/doc/getting_started.md +1115 -0
- data/doc/metadata.md +190 -109
- data/doc/multiple_files.md +62 -34
- data/doc/paperclip.md +384 -262
- data/doc/plugins/activerecord.md +177 -46
- data/doc/plugins/add_metadata.md +139 -38
- data/doc/plugins/atomic_helpers.md +217 -0
- data/doc/plugins/backgrounding.md +156 -98
- data/doc/plugins/cached_attachment_data.md +7 -5
- data/doc/plugins/column.md +121 -0
- data/doc/plugins/data_uri.md +23 -22
- data/doc/plugins/default_storage.md +36 -10
- data/doc/plugins/default_url.md +30 -13
- data/doc/plugins/delete_raw.md +4 -2
- data/doc/plugins/derivation_endpoint.md +162 -101
- data/doc/plugins/derivatives.md +829 -0
- data/doc/plugins/determine_mime_type.md +4 -2
- data/doc/plugins/download_endpoint.md +64 -8
- data/doc/plugins/dynamic_storage.md +5 -3
- data/doc/plugins/entity.md +263 -0
- data/doc/plugins/form_assign.md +55 -0
- data/doc/plugins/included.md +31 -8
- data/doc/plugins/infer_extension.md +21 -10
- data/doc/plugins/instrumentation.md +38 -16
- data/doc/plugins/keep_files.md +14 -17
- data/doc/plugins/metadata_attributes.md +42 -13
- data/doc/plugins/mirroring.md +118 -0
- data/doc/plugins/model.md +210 -0
- data/doc/plugins/module_include.md +4 -2
- data/doc/plugins/multi_cache.md +24 -0
- data/doc/plugins/persistence.md +101 -0
- data/doc/plugins/presign_endpoint.md +9 -4
- data/doc/plugins/pretty_location.md +16 -3
- data/doc/plugins/processing.md +4 -2
- data/doc/plugins/rack_file.md +8 -2
- data/doc/plugins/rack_response.md +6 -2
- data/doc/plugins/recache.md +4 -2
- data/doc/plugins/refresh_metadata.md +49 -9
- data/doc/plugins/remote_url.md +84 -47
- data/doc/plugins/remove_attachment.md +27 -6
- data/doc/plugins/remove_invalid.md +21 -6
- data/doc/plugins/restore_cached_data.md +11 -3
- data/doc/plugins/sequel.md +159 -35
- data/doc/plugins/signature.md +16 -5
- data/doc/plugins/store_dimensions.md +14 -2
- data/doc/plugins/tempfile.md +4 -2
- data/doc/plugins/type_predicates.md +96 -0
- data/doc/plugins/upload_endpoint.md +13 -13
- data/doc/plugins/upload_options.md +6 -4
- data/doc/plugins/{default_url_options.md → url_options.md} +9 -7
- data/doc/plugins/validation.md +97 -0
- data/doc/plugins/validation_helpers.md +16 -13
- data/doc/plugins/versions.md +15 -19
- data/doc/processing.md +438 -221
- data/doc/refile.md +185 -167
- data/doc/release_notes/1.0.0.md +4 -0
- data/doc/release_notes/1.1.0.md +6 -2
- data/doc/release_notes/1.2.0.md +4 -0
- data/doc/release_notes/1.3.0.md +4 -0
- data/doc/release_notes/1.4.0.md +4 -0
- data/doc/release_notes/1.4.1.md +4 -0
- data/doc/release_notes/1.4.2.md +4 -0
- data/doc/release_notes/2.0.0.md +4 -0
- data/doc/release_notes/2.0.1.md +4 -0
- data/doc/release_notes/2.1.0.md +4 -0
- data/doc/release_notes/2.1.1.md +4 -0
- data/doc/release_notes/2.10.0.md +4 -0
- data/doc/release_notes/2.10.1.md +4 -0
- data/doc/release_notes/2.11.0.md +4 -0
- data/doc/release_notes/2.12.0.md +4 -0
- data/doc/release_notes/2.13.0.md +4 -0
- data/doc/release_notes/2.14.0.md +5 -1
- data/doc/release_notes/2.15.0.md +11 -7
- data/doc/release_notes/2.16.0.md +4 -0
- data/doc/release_notes/2.17.0.md +4 -0
- data/doc/release_notes/2.18.0.md +4 -0
- data/doc/release_notes/2.19.0.md +6 -3
- data/doc/release_notes/2.2.0.md +4 -0
- data/doc/release_notes/2.3.0.md +4 -0
- data/doc/release_notes/2.3.1.md +4 -0
- data/doc/release_notes/2.4.0.md +4 -0
- data/doc/release_notes/2.4.1.md +4 -0
- data/doc/release_notes/2.5.0.md +4 -0
- data/doc/release_notes/2.6.0.md +4 -0
- data/doc/release_notes/2.6.1.md +4 -0
- data/doc/release_notes/2.7.0.md +4 -0
- data/doc/release_notes/2.8.0.md +4 -0
- data/doc/release_notes/2.9.0.md +4 -0
- data/doc/release_notes/3.0.0.md +981 -0
- data/doc/release_notes/3.0.1.md +22 -0
- data/doc/release_notes/3.1.0.md +73 -0
- data/doc/release_notes/3.2.0.md +96 -0
- data/doc/release_notes/3.2.1.md +31 -0
- data/doc/release_notes/3.2.2.md +14 -0
- data/doc/release_notes/3.3.0.md +105 -0
- data/doc/release_notes/3.4.0.md +35 -0
- data/doc/retrieving_uploads.md +4 -1
- data/doc/securing_uploads.md +60 -37
- data/doc/storage/file_system.md +20 -3
- data/doc/storage/memory.md +19 -0
- data/doc/storage/s3.md +117 -83
- data/doc/testing.md +124 -144
- data/doc/upgrading_to_3.md +710 -0
- data/doc/validation.md +54 -90
- data/lib/shrine/attacher.rb +287 -171
- data/lib/shrine/attachment.rb +13 -46
- data/lib/shrine/plugins/_persistence.rb +93 -0
- data/lib/shrine/plugins/activerecord.rb +77 -34
- data/lib/shrine/plugins/add_metadata.rb +25 -17
- data/lib/shrine/plugins/atomic_helpers.rb +119 -0
- data/lib/shrine/plugins/backgrounding.rb +77 -113
- data/lib/shrine/plugins/cached_attachment_data.rb +6 -15
- data/lib/shrine/plugins/column.rb +102 -0
- data/lib/shrine/plugins/data_uri.rb +38 -36
- data/lib/shrine/plugins/default_storage.rb +45 -15
- data/lib/shrine/plugins/default_url.rb +12 -24
- data/lib/shrine/plugins/default_url_options.rb +3 -30
- data/lib/shrine/plugins/delete_raw.rb +10 -16
- data/lib/shrine/plugins/derivation_endpoint.rb +89 -134
- data/lib/shrine/plugins/derivatives.rb +637 -0
- data/lib/shrine/plugins/determine_mime_type.rb +9 -21
- data/lib/shrine/plugins/download_endpoint.rb +109 -133
- data/lib/shrine/plugins/dynamic_storage.rb +5 -11
- data/lib/shrine/plugins/entity.rb +152 -0
- data/lib/shrine/plugins/form_assign.rb +108 -0
- data/lib/shrine/plugins/included.rb +6 -6
- data/lib/shrine/plugins/infer_extension.rb +13 -20
- data/lib/shrine/plugins/instrumentation.rb +54 -42
- data/lib/shrine/plugins/keep_files.rb +3 -15
- data/lib/shrine/plugins/metadata_attributes.rb +28 -19
- data/lib/shrine/plugins/mirroring.rb +142 -0
- data/lib/shrine/plugins/model.rb +158 -0
- data/lib/shrine/plugins/module_include.rb +3 -3
- data/lib/shrine/plugins/multi_cache.rb +27 -0
- data/lib/shrine/plugins/presign_endpoint.rb +18 -22
- data/lib/shrine/plugins/pretty_location.rb +15 -9
- data/lib/shrine/plugins/processing.rb +22 -9
- data/lib/shrine/plugins/rack_file.rb +2 -42
- data/lib/shrine/plugins/rack_response.rb +15 -10
- data/lib/shrine/plugins/recache.rb +6 -5
- data/lib/shrine/plugins/refresh_metadata.rb +13 -11
- data/lib/shrine/plugins/remote_url.rb +49 -49
- data/lib/shrine/plugins/remove_attachment.rb +10 -6
- data/lib/shrine/plugins/remove_invalid.rb +19 -8
- data/lib/shrine/plugins/restore_cached_data.rb +13 -7
- data/lib/shrine/plugins/sequel.rb +86 -36
- data/lib/shrine/plugins/signature.rb +10 -16
- data/lib/shrine/plugins/store_dimensions.rb +35 -40
- data/lib/shrine/plugins/tempfile.rb +1 -3
- data/lib/shrine/plugins/type_predicates.rb +113 -0
- data/lib/shrine/plugins/upload_endpoint.rb +25 -23
- data/lib/shrine/plugins/upload_options.rb +14 -15
- data/lib/shrine/plugins/url_options.rb +31 -0
- data/lib/shrine/plugins/validation.rb +80 -0
- data/lib/shrine/plugins/validation_helpers.rb +34 -57
- data/lib/shrine/plugins/versions.rb +107 -87
- data/lib/shrine/plugins.rb +22 -0
- data/lib/shrine/storage/file_system.rb +46 -64
- data/lib/shrine/storage/linter.rb +42 -7
- data/lib/shrine/storage/memory.rb +49 -0
- data/lib/shrine/storage/s3.rb +154 -158
- data/lib/shrine/uploaded_file.rb +28 -30
- data/lib/shrine/version.rb +3 -3
- data/lib/shrine.rb +86 -149
- data/shrine.gemspec +9 -10
- metadata +79 -83
- data/doc/migrating_storage.md +0 -76
- data/doc/plugins/backup.md +0 -31
- data/doc/plugins/copy.md +0 -24
- data/doc/plugins/delete_promoted.md +0 -12
- data/doc/plugins/direct_upload.md +0 -172
- data/doc/plugins/hooks.md +0 -58
- data/doc/plugins/logging.md +0 -42
- data/doc/plugins/migration_helpers.md +0 -60
- data/doc/plugins/moving.md +0 -19
- data/doc/plugins/multi_delete.md +0 -20
- data/doc/plugins/parallelize.md +0 -16
- data/doc/plugins/parsed_json.md +0 -23
- data/doc/regenerating_versions.md +0 -143
- data/lib/shrine/plugins/background_helpers.rb +0 -5
- data/lib/shrine/plugins/backup.rb +0 -90
- data/lib/shrine/plugins/copy.rb +0 -50
- data/lib/shrine/plugins/delete_promoted.rb +0 -20
- data/lib/shrine/plugins/direct_upload.rb +0 -217
- data/lib/shrine/plugins/hooks.rb +0 -90
- data/lib/shrine/plugins/logging.rb +0 -142
- data/lib/shrine/plugins/migration_helpers.rb +0 -70
- data/lib/shrine/plugins/moving.rb +0 -57
- data/lib/shrine/plugins/multi_delete.rb +0 -32
- data/lib/shrine/plugins/parallelize.rb +0 -78
- data/lib/shrine/plugins/parsed_json.rb +0 -29
data/lib/shrine.rb
CHANGED
@@ -1,40 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "shrine/version"
|
4
3
|
require "shrine/uploaded_file"
|
5
4
|
require "shrine/attacher"
|
6
5
|
require "shrine/attachment"
|
7
6
|
require "shrine/plugins"
|
7
|
+
require "shrine/version"
|
8
8
|
|
9
9
|
require "securerandom"
|
10
10
|
require "json"
|
11
11
|
require "tempfile"
|
12
12
|
require "logger"
|
13
13
|
|
14
|
-
# Core class that
|
15
|
-
# Base implementation is defined in InstanceMethods and ClassMethods.
|
14
|
+
# Core class that handles uploading files to specified storage.
|
16
15
|
class Shrine
|
17
16
|
# A generic exception used by Shrine.
|
18
|
-
class Error < StandardError
|
17
|
+
class Error < StandardError
|
18
|
+
end
|
19
19
|
|
20
20
|
# Raised when a file is not a valid IO.
|
21
21
|
class InvalidFile < Error
|
22
22
|
def initialize(io, missing_methods)
|
23
|
-
super "#{io.inspect} is not a valid IO object (it doesn't respond to
|
24
|
-
#{missing_methods.map{|m, _|"##{m}"}.join(", ")})"
|
23
|
+
super "#{io.inspect} is not a valid IO object (it doesn't respond to #{missing_methods.map{|m, _|"##{m}"}.join(", ")})"
|
25
24
|
end
|
26
25
|
end
|
27
26
|
|
28
|
-
#
|
29
|
-
|
30
|
-
|
31
|
-
read: [:length, :outbuf],
|
32
|
-
eof?: [],
|
33
|
-
rewind: [],
|
34
|
-
size: [],
|
35
|
-
close: [],
|
36
|
-
}
|
37
|
-
deprecate_constant(:IO_METHODS)
|
27
|
+
# Raised by the storage in the #open method.
|
28
|
+
class FileNotFound < Error
|
29
|
+
end
|
38
30
|
|
39
31
|
@opts = {}
|
40
32
|
@storages = {}
|
@@ -54,12 +46,7 @@ class Shrine
|
|
54
46
|
# When inheriting Shrine, copy the instance variables into the subclass,
|
55
47
|
# and create subclasses of core classes.
|
56
48
|
def inherited(subclass)
|
57
|
-
subclass.instance_variable_set(:@opts, opts
|
58
|
-
subclass.opts.each do |key, value|
|
59
|
-
if value.is_a?(Enumerable) && !value.frozen?
|
60
|
-
subclass.opts[key] = value.dup
|
61
|
-
end
|
62
|
-
end
|
49
|
+
subclass.instance_variable_set(:@opts, deep_dup(opts))
|
63
50
|
subclass.instance_variable_set(:@storages, storages.dup)
|
64
51
|
|
65
52
|
file_class = Class.new(self::UploadedFile)
|
@@ -81,9 +68,9 @@ class Shrine
|
|
81
68
|
#
|
82
69
|
# Shrine.plugin MyPlugin
|
83
70
|
# Shrine.plugin :my_plugin
|
84
|
-
def plugin(plugin, *args, &block)
|
71
|
+
def plugin(plugin, *args, **kwargs, &block)
|
85
72
|
plugin = Plugins.load_plugin(plugin) if plugin.is_a?(Symbol)
|
86
|
-
|
73
|
+
Plugins.load_dependencies(plugin, self, *args, **kwargs, &block)
|
87
74
|
self.include(plugin::InstanceMethods) if defined?(plugin::InstanceMethods)
|
88
75
|
self.extend(plugin::ClassMethods) if defined?(plugin::ClassMethods)
|
89
76
|
self::UploadedFile.include(plugin::FileMethods) if defined?(plugin::FileMethods)
|
@@ -92,7 +79,7 @@ class Shrine
|
|
92
79
|
self::Attachment.extend(plugin::AttachmentClassMethods) if defined?(plugin::AttachmentClassMethods)
|
93
80
|
self::Attacher.include(plugin::AttacherMethods) if defined?(plugin::AttacherMethods)
|
94
81
|
self::Attacher.extend(plugin::AttacherClassMethods) if defined?(plugin::AttacherClassMethods)
|
95
|
-
|
82
|
+
Plugins.configure(plugin, self, *args, **kwargs, &block)
|
96
83
|
plugin
|
97
84
|
end
|
98
85
|
|
@@ -108,8 +95,8 @@ class Shrine
|
|
108
95
|
# class Photo
|
109
96
|
# include Shrine::Attachment(:image) # creates a Shrine::Attachment object
|
110
97
|
# end
|
111
|
-
def Attachment(name,
|
112
|
-
self::Attachment.new(name,
|
98
|
+
def Attachment(name, **args)
|
99
|
+
self::Attachment.new(name, **args)
|
113
100
|
end
|
114
101
|
alias attachment Attachment
|
115
102
|
alias [] Attachment
|
@@ -117,25 +104,26 @@ class Shrine
|
|
117
104
|
# Uploads the file to the specified storage. It delegates to `Shrine#upload`.
|
118
105
|
#
|
119
106
|
# Shrine.upload(io, :store) #=> #<Shrine::UploadedFile>
|
120
|
-
def upload(io, storage,
|
121
|
-
new(storage).upload(io,
|
107
|
+
def upload(io, storage, **options)
|
108
|
+
new(storage).upload(io, **options)
|
122
109
|
end
|
123
110
|
|
124
111
|
# Instantiates a Shrine::UploadedFile from a hash, and optionally
|
125
112
|
# yields the returned object.
|
126
113
|
#
|
127
|
-
# data = {"storage" => "cache", "id" => "abc123.jpg", "metadata" => {}}
|
114
|
+
# data = { "storage" => "cache", "id" => "abc123.jpg", "metadata" => {} }
|
128
115
|
# Shrine.uploaded_file(data) #=> #<Shrine::UploadedFile>
|
129
|
-
def uploaded_file(object
|
116
|
+
def uploaded_file(object)
|
130
117
|
case object
|
131
118
|
when String
|
132
|
-
uploaded_file(JSON.parse(object)
|
119
|
+
uploaded_file(JSON.parse(object))
|
133
120
|
when Hash
|
134
|
-
|
121
|
+
object = JSON.parse(object.to_json) if object.keys.grep(Symbol).any? # deep stringify keys
|
122
|
+
self::UploadedFile.new(object)
|
135
123
|
when self::UploadedFile
|
136
|
-
object
|
124
|
+
object
|
137
125
|
else
|
138
|
-
|
126
|
+
fail ArgumentError, "cannot convert #{object.inspect} to a #{self}::UploadedFile"
|
139
127
|
end
|
140
128
|
end
|
141
129
|
|
@@ -169,27 +157,39 @@ class Shrine
|
|
169
157
|
def deprecation(message)
|
170
158
|
Shrine.logger.warn "SHRINE DEPRECATION WARNING: #{message}"
|
171
159
|
end
|
160
|
+
|
161
|
+
private
|
162
|
+
|
163
|
+
# Deep duplicates a nested hash of options.
|
164
|
+
def deep_dup(collection)
|
165
|
+
duplicate_collection = collection.dup
|
166
|
+
|
167
|
+
if duplicate_collection.is_a?(Hash)
|
168
|
+
duplicate_collection.each do |key, value|
|
169
|
+
duplicate_collection[key] = deep_dup(value) if value.is_a?(Enumerable)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
duplicate_collection
|
174
|
+
end
|
172
175
|
end
|
173
176
|
|
174
177
|
module InstanceMethods
|
175
178
|
# The symbol identifier for the storage used by the uploader.
|
176
179
|
attr_reader :storage_key
|
177
180
|
|
178
|
-
# The storage object used by the uploader.
|
179
|
-
attr_reader :storage
|
180
|
-
|
181
181
|
# Accepts a storage symbol registered in `Shrine.storages`.
|
182
182
|
#
|
183
183
|
# Shrine.new(:store)
|
184
184
|
def initialize(storage_key)
|
185
|
-
@storage = self.class.find_storage(storage_key)
|
186
185
|
@storage_key = storage_key.to_sym
|
186
|
+
|
187
|
+
storage # ensure storage is registered
|
187
188
|
end
|
188
189
|
|
189
|
-
#
|
190
|
-
|
191
|
-
|
192
|
-
self.class.opts
|
190
|
+
# Returns the storage object referenced by the identifier.
|
191
|
+
def storage
|
192
|
+
self.class.find_storage(storage_key)
|
193
193
|
end
|
194
194
|
|
195
195
|
# The main method for uploading files. Takes an IO-like object and an
|
@@ -201,55 +201,31 @@ class Shrine
|
|
201
201
|
# uploader.upload(io, metadata: { "foo" => "bar" }) # add metadata
|
202
202
|
# uploader.upload(io, location: "path/to/file") # specify location
|
203
203
|
# uploader.upload(io, upload_options: { acl: "public-read" }) # add upload options
|
204
|
-
def upload(io,
|
205
|
-
|
206
|
-
store(io, context)
|
207
|
-
end
|
204
|
+
def upload(io, **options)
|
205
|
+
_enforce_io(io)
|
208
206
|
|
209
|
-
|
210
|
-
|
211
|
-
# has been done and that the original file should be used.
|
212
|
-
#
|
213
|
-
# class ImageUploader < Shrine
|
214
|
-
# def process(io, context)
|
215
|
-
# # do processing and return processed files
|
216
|
-
# end
|
217
|
-
# end
|
218
|
-
def process(io, context = {})
|
219
|
-
end
|
207
|
+
metadata = get_metadata(io, **options)
|
208
|
+
location = get_location(io, **options, metadata: metadata)
|
220
209
|
|
221
|
-
|
222
|
-
# default the location of the file is automatically generated by
|
223
|
-
# \#generate_location, but you can pass in `:location` to upload to
|
224
|
-
# a specific location.
|
225
|
-
#
|
226
|
-
# uploader.store(io)
|
227
|
-
def store(io, context = {})
|
228
|
-
_store(io, context)
|
229
|
-
end
|
210
|
+
_upload(io, **options, location: location, metadata: metadata)
|
230
211
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
# Deletes the given uploaded file and returns it.
|
238
|
-
def delete(uploaded_file, context = {})
|
239
|
-
_delete(uploaded_file, context)
|
240
|
-
uploaded_file
|
212
|
+
self.class::UploadedFile.new(
|
213
|
+
id: location,
|
214
|
+
storage: storage_key,
|
215
|
+
metadata: metadata,
|
216
|
+
)
|
241
217
|
end
|
242
218
|
|
243
219
|
# Generates a unique location for the uploaded file, preserving the
|
244
220
|
# file extension. Can be overriden in uploaders for generating custom
|
245
221
|
# location.
|
246
|
-
def generate_location(io,
|
247
|
-
basic_location(io, metadata:
|
222
|
+
def generate_location(io, metadata: {}, **options)
|
223
|
+
basic_location(io, metadata: metadata)
|
248
224
|
end
|
249
225
|
|
250
226
|
# Extracts filename, size and MIME type from the file, which is later
|
251
227
|
# accessible through UploadedFile#metadata.
|
252
|
-
def extract_metadata(io,
|
228
|
+
def extract_metadata(io, **options)
|
253
229
|
{
|
254
230
|
"filename" => extract_filename(io),
|
255
231
|
"size" => extract_size(io),
|
@@ -257,8 +233,21 @@ class Shrine
|
|
257
233
|
}
|
258
234
|
end
|
259
235
|
|
236
|
+
# The class-level options hash. This should probably not be modified at
|
237
|
+
# the instance level.
|
238
|
+
def opts
|
239
|
+
self.class.opts
|
240
|
+
end
|
241
|
+
|
260
242
|
private
|
261
243
|
|
244
|
+
def _upload(io, location:, metadata:, upload_options: {}, close: true, delete: false, **)
|
245
|
+
storage.upload(io, location, shrine_metadata: metadata, **upload_options)
|
246
|
+
ensure
|
247
|
+
io.close if close
|
248
|
+
File.unlink(io.path) if delete && io.respond_to?(:path) && File.exist?(io.path)
|
249
|
+
end
|
250
|
+
|
262
251
|
# Attempts to extract the appropriate filename from the IO object.
|
263
252
|
def extract_filename(io)
|
264
253
|
if io.respond_to?(:original_filename)
|
@@ -281,87 +270,35 @@ class Shrine
|
|
281
270
|
io.size if io.respond_to?(:size)
|
282
271
|
end
|
283
272
|
|
284
|
-
# It first asserts that `io` is a valid IO object. It then extracts
|
285
|
-
# metadata and generates the location, before calling the storage to
|
286
|
-
# upload the IO object, passing the extracted metadata and location.
|
287
|
-
# Finally it returns a Shrine::UploadedFile object which represents the
|
288
|
-
# file that was uploaded.
|
289
|
-
def _store(io, context)
|
290
|
-
_enforce_io(io)
|
291
|
-
|
292
|
-
metadata = get_metadata(io, context)
|
293
|
-
metadata = metadata.merge(context[:metadata]) if context[:metadata].is_a?(Hash)
|
294
|
-
|
295
|
-
location = get_location(io, context.merge(metadata: metadata))
|
296
|
-
|
297
|
-
put(io, context.merge(location: location, metadata: metadata))
|
298
|
-
|
299
|
-
self.class.uploaded_file(
|
300
|
-
"id" => location,
|
301
|
-
"storage" => storage_key.to_s,
|
302
|
-
"metadata" => metadata,
|
303
|
-
)
|
304
|
-
end
|
305
|
-
|
306
|
-
# Delegates to #remove.
|
307
|
-
def _delete(uploaded_file, context)
|
308
|
-
remove(uploaded_file, context)
|
309
|
-
end
|
310
|
-
|
311
|
-
# Delegates to #copy.
|
312
|
-
def put(io, context)
|
313
|
-
copy(io, context)
|
314
|
-
end
|
315
|
-
|
316
|
-
# Calls `#upload` on the storage, passing to it the location, metadata
|
317
|
-
# and any upload options. The storage might modify the location or
|
318
|
-
# metadata that were passed in. The uploaded IO is then closed.
|
319
|
-
def copy(io, context)
|
320
|
-
location = context[:location]
|
321
|
-
metadata = context[:metadata]
|
322
|
-
upload_options = context[:upload_options] || {}
|
323
|
-
|
324
|
-
storage.upload(io, location, shrine_metadata: metadata, **upload_options)
|
325
|
-
ensure
|
326
|
-
io.close rescue nil
|
327
|
-
end
|
328
|
-
|
329
|
-
# Delegates to `UploadedFile#delete`.
|
330
|
-
def remove(uploaded_file, context)
|
331
|
-
uploaded_file.delete
|
332
|
-
end
|
333
|
-
|
334
|
-
# Delegates to #process.
|
335
|
-
def processed(io, context)
|
336
|
-
process(io, context)
|
337
|
-
end
|
338
|
-
|
339
273
|
# Generates a basic location for an uploaded file
|
340
274
|
def basic_location(io, metadata:)
|
341
275
|
extension = ".#{io.extension}" if io.is_a?(UploadedFile) && io.extension
|
342
|
-
extension ||= File.extname(
|
276
|
+
extension ||= File.extname(metadata["filename"].to_s).downcase
|
343
277
|
basename = generate_uid(io)
|
344
278
|
|
345
279
|
basename + extension
|
346
280
|
end
|
347
281
|
|
348
|
-
# Retrieves the location for the given IO and context. First it looks
|
349
|
-
# for the `:location` option, otherwise it calls #generate_location.
|
350
|
-
def get_location(io, context)
|
351
|
-
location = context[:location] || generate_location(io, context)
|
352
|
-
location or raise Error, "location generated for #{io.inspect} was nil (context = #{context})"
|
353
|
-
end
|
354
|
-
|
355
282
|
# If the IO object is a Shrine::UploadedFile, it simply copies over its
|
356
283
|
# metadata, otherwise it calls #extract_metadata.
|
357
|
-
def get_metadata(io,
|
358
|
-
if io.is_a?(UploadedFile) &&
|
359
|
-
io.metadata.dup
|
360
|
-
elsif
|
361
|
-
extract_metadata(io,
|
284
|
+
def get_metadata(io, metadata: nil, **options)
|
285
|
+
if io.is_a?(UploadedFile) && metadata != true
|
286
|
+
result = io.metadata.dup
|
287
|
+
elsif metadata != false
|
288
|
+
result = extract_metadata(io, **options)
|
362
289
|
else
|
363
|
-
{}
|
290
|
+
result = {}
|
364
291
|
end
|
292
|
+
|
293
|
+
result = result.merge(metadata) if metadata.is_a?(Hash)
|
294
|
+
result
|
295
|
+
end
|
296
|
+
|
297
|
+
# Retrieves the location for the given IO and context. First it looks
|
298
|
+
# for the `:location` option, otherwise it calls #generate_location.
|
299
|
+
def get_location(io, location: nil, **options)
|
300
|
+
location ||= generate_location(io, **options)
|
301
|
+
location or fail Error, "location generated for #{io.inspect} was nil"
|
365
302
|
end
|
366
303
|
|
367
304
|
# Asserts that the object is a valid IO object, specifically that it
|
data/shrine.gemspec
CHANGED
@@ -26,26 +26,24 @@ direct uploads for fully asynchronous user experience.
|
|
26
26
|
"bug_tracker_uri" => "https://github.com/shrinerb/shrine/issues",
|
27
27
|
"changelog_uri" => "https://github.com/shrinerb/shrine/blob/master/CHANGELOG.md",
|
28
28
|
"documentation_uri" => "https://shrinerb.com",
|
29
|
-
"mailing_list_uri" => "https://
|
29
|
+
"mailing_list_uri" => "https://discourse.shrinerb.com",
|
30
30
|
"source_code_uri" => "https://github.com/shrinerb/shrine",
|
31
31
|
}
|
32
32
|
|
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", "
|
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 "
|
43
|
-
gem.add_development_dependency "mocha", "~> 1.4"
|
44
|
-
gem.add_development_dependency "shrine-memory", ">= 0.2.2"
|
42
|
+
gem.add_development_dependency "mocha", "~> 1.11"
|
45
43
|
|
46
44
|
# for endpoint plugins
|
47
45
|
gem.add_development_dependency "rack", "~> 2.0"
|
48
|
-
gem.add_development_dependency "http-form_data", "~> 2.
|
46
|
+
gem.add_development_dependency "http-form_data", "~> 2.2"
|
49
47
|
gem.add_development_dependency "rack-test_app"
|
50
48
|
|
51
49
|
# for determine_mime_type plugin
|
@@ -63,15 +61,16 @@ direct uploads for fully asynchronous user experience.
|
|
63
61
|
gem.add_development_dependency "ruby-vips", "~> 2.0" unless ENV["CI"]
|
64
62
|
|
65
63
|
# for S3 storage
|
66
|
-
gem.add_development_dependency "aws-sdk-s3", "~> 1.
|
64
|
+
gem.add_development_dependency "aws-sdk-s3", "~> 1.69"
|
67
65
|
gem.add_development_dependency "aws-sdk-core", "~> 3.23"
|
66
|
+
gem.add_development_dependency "rexml"
|
68
67
|
|
69
68
|
# for instrumentation plugin
|
70
69
|
gem.add_development_dependency "dry-monitor"
|
71
|
-
gem.add_development_dependency "activesupport", "~> 5.2
|
70
|
+
gem.add_development_dependency "activesupport", RUBY_VERSION >= "2.5" ? "~> 6.0" : "~> 5.2"
|
72
71
|
|
73
72
|
# for ORM plugins
|
74
73
|
gem.add_development_dependency "sequel"
|
75
|
-
gem.add_development_dependency "activerecord", "~> 5.2
|
76
|
-
gem.add_development_dependency "sqlite3", "~> 1.
|
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"
|
77
76
|
end
|