shrine 2.19.3 → 3.6.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +523 -41
- data/LICENSE.txt +1 -1
- data/README.md +83 -979
- 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 +103 -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 +1156 -0
- data/doc/metadata.md +190 -109
- data/doc/multiple_files.md +93 -30
- 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 +186 -101
- data/doc/plugins/derivatives.md +839 -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 +16 -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 +188 -170
- 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 +5 -1
- 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/release_notes/3.5.0.md +63 -0
- data/doc/release_notes/3.6.0.md +23 -0
- data/doc/retrieving_uploads.md +5 -2
- 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 +122 -78
- data/doc/testing.md +141 -133
- data/doc/upgrading_to_3.md +708 -0
- data/doc/validation.md +54 -90
- data/lib/shrine/attacher.rb +292 -169
- 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 +130 -171
- data/lib/shrine/plugins/derivatives.rb +645 -0
- data/lib/shrine/plugins/determine_mime_type.rb +9 -21
- data/lib/shrine/plugins/download_endpoint.rb +118 -133
- data/lib/shrine/plugins/dynamic_storage.rb +5 -11
- data/lib/shrine/plugins/entity.rb +158 -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 +17 -20
- data/lib/shrine/plugins/instrumentation.rb +59 -43
- 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 +160 -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 +27 -28
- 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 +21 -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 +12 -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 +28 -24
- 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 +35 -58
- 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 +173 -160
- data/lib/shrine/uploaded_file.rb +32 -32
- data/lib/shrine/version.rb +3 -3
- data/lib/shrine.rb +87 -150
- data/shrine.gemspec +11 -12
- metadata +92 -82
- 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,13 +233,26 @@ 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)
|
|
265
254
|
io.original_filename
|
|
266
|
-
elsif io.respond_to?(:path)
|
|
255
|
+
elsif io.respond_to?(:path) && io.path
|
|
267
256
|
File.basename(io.path)
|
|
268
257
|
end
|
|
269
258
|
end
|
|
@@ -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,27 +26,25 @@ 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
|
-
gem.add_development_dependency "rack", "
|
|
48
|
-
gem.add_development_dependency "http-form_data", "~> 2.
|
|
49
|
-
gem.add_development_dependency "rack-
|
|
45
|
+
gem.add_development_dependency "rack", ">= 2", "< 4"
|
|
46
|
+
gem.add_development_dependency "http-form_data", "~> 2.2"
|
|
47
|
+
gem.add_development_dependency "rack-test", "~> 2.1"
|
|
50
48
|
|
|
51
49
|
# for determine_mime_type plugin
|
|
52
50
|
gem.add_development_dependency "mimemagic", ">= 0.3.2"
|
|
@@ -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", "~>
|
|
70
|
+
gem.add_development_dependency "activesupport", RUBY_VERSION >= "2.7" ? "~> 7.0" : 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", "~>
|
|
76
|
-
gem.add_development_dependency "sqlite3", "~> 1.
|
|
74
|
+
gem.add_development_dependency "activerecord", RUBY_ENGINE == "jruby" ? "~> 7.0.0" : RUBY_VERSION >= "2.7" ? "~> 7.0" : RUBY_VERSION >= "2.5" ? "~> 6.0" : "~> 5.2"
|
|
75
|
+
gem.add_development_dependency "sqlite3", "~> 1.4" unless RUBY_ENGINE == "jruby"
|
|
77
76
|
end
|