shrine 3.5.0 → 3.7.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 +28 -0
- data/doc/changing_derivatives.md +2 -1
- data/doc/changing_location.md +17 -5
- data/doc/getting_started.md +4 -2
- data/doc/plugins/derivation_endpoint.md +2 -1
- data/doc/plugins/derivatives.md +2 -1
- data/doc/plugins/download_endpoint.md +16 -4
- data/doc/plugins/refresh_metadata.md +20 -0
- data/doc/plugins/signature.md +8 -6
- data/doc/processing.md +5 -3
- data/doc/release_notes/3.6.0.md +23 -0
- data/doc/release_notes/3.7.0.md +75 -0
- data/doc/storage/s3.md +10 -0
- data/lib/shrine/attacher.rb +28 -21
- data/lib/shrine/attachment.rb +2 -2
- data/lib/shrine/plugins/_urlsafe_serialization.rb +4 -4
- data/lib/shrine/plugins/add_metadata.rb +2 -4
- data/lib/shrine/plugins/atomic_helpers.rb +7 -7
- data/lib/shrine/plugins/backgrounding.rb +9 -9
- data/lib/shrine/plugins/column.rb +6 -4
- data/lib/shrine/plugins/default_url.rb +4 -4
- data/lib/shrine/plugins/delete_raw.rb +2 -2
- data/lib/shrine/plugins/derivation_endpoint.rb +37 -34
- data/lib/shrine/plugins/derivatives.rb +5 -1
- data/lib/shrine/plugins/download_endpoint.rb +65 -11
- data/lib/shrine/plugins/entity.rb +7 -7
- data/lib/shrine/plugins/infer_extension.rb +1 -1
- data/lib/shrine/plugins/instrumentation.rb +8 -8
- data/lib/shrine/plugins/mirroring.rb +10 -10
- data/lib/shrine/plugins/model.rb +9 -9
- data/lib/shrine/plugins/presign_endpoint.rb +13 -10
- data/lib/shrine/plugins/pretty_location.rb +2 -2
- data/lib/shrine/plugins/processing.rb +3 -3
- data/lib/shrine/plugins/rack_file.rb +2 -2
- data/lib/shrine/plugins/rack_response.rb +10 -4
- data/lib/shrine/plugins/refresh_metadata.rb +6 -6
- data/lib/shrine/plugins/remote_url.rb +3 -3
- data/lib/shrine/plugins/restore_cached_data.rb +3 -3
- data/lib/shrine/plugins/signature.rb +2 -2
- data/lib/shrine/plugins/store_dimensions.rb +2 -2
- data/lib/shrine/plugins/upload_endpoint.rb +7 -5
- data/lib/shrine/plugins/upload_options.rb +1 -1
- data/lib/shrine/plugins/validation.rb +8 -8
- data/lib/shrine/plugins/versions.rb +10 -10
- data/lib/shrine/plugins.rb +6 -14
- data/lib/shrine/storage/file_system.rb +4 -17
- data/lib/shrine/storage/linter.rb +8 -8
- data/lib/shrine/storage/memory.rb +1 -3
- data/lib/shrine/storage/s3.rb +53 -38
- data/lib/shrine/uploaded_file.rb +21 -18
- data/lib/shrine/version.rb +1 -1
- data/lib/shrine.rb +18 -18
- data/shrine.gemspec +8 -8
- metadata +31 -26
|
@@ -21,12 +21,12 @@ class Shrine
|
|
|
21
21
|
# The `storage_key` needs to be one of the registered Shrine storages.
|
|
22
22
|
# Additional options can be given to override the options given on
|
|
23
23
|
# plugin initialization.
|
|
24
|
-
def presign_endpoint(storage_key, **
|
|
24
|
+
def presign_endpoint(storage_key, **)
|
|
25
25
|
Shrine::PresignEndpoint.new(
|
|
26
26
|
shrine_class: self,
|
|
27
27
|
storage_key: storage_key,
|
|
28
28
|
**opts[:presign_endpoint],
|
|
29
|
-
|
|
29
|
+
**,
|
|
30
30
|
)
|
|
31
31
|
end
|
|
32
32
|
|
|
@@ -36,7 +36,7 @@ class Shrine
|
|
|
36
36
|
# It performs the same mounting logic that Rack and other web
|
|
37
37
|
# frameworks use, and is meant for cases where statically mounting the
|
|
38
38
|
# endpoint in the router isn't enough.
|
|
39
|
-
def presign_response(storage_key, env, **
|
|
39
|
+
def presign_response(storage_key, env, **)
|
|
40
40
|
script_name = env["SCRIPT_NAME"]
|
|
41
41
|
path_info = env["PATH_INFO"]
|
|
42
42
|
|
|
@@ -44,7 +44,7 @@ class Shrine
|
|
|
44
44
|
env["SCRIPT_NAME"] += path_info
|
|
45
45
|
env["PATH_INFO"] = ""
|
|
46
46
|
|
|
47
|
-
presign_endpoint(storage_key, **
|
|
47
|
+
presign_endpoint(storage_key, **).call(env)
|
|
48
48
|
ensure
|
|
49
49
|
env["SCRIPT_NAME"] = script_name
|
|
50
50
|
env["PATH_INFO"] = path_info
|
|
@@ -91,7 +91,9 @@ class Shrine
|
|
|
91
91
|
end
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
-
headers[
|
|
94
|
+
headers = Rack::Headers[headers] if Rack.release >= "3"
|
|
95
|
+
headers["Content-Length"] ||= body.respond_to?(:bytesize) ? body.bytesize.to_s :
|
|
96
|
+
body.map(&:bytesize).inject(0, :+).to_s
|
|
95
97
|
|
|
96
98
|
[status, headers, body]
|
|
97
99
|
end
|
|
@@ -158,16 +160,17 @@ class Shrine
|
|
|
158
160
|
# headers, and a body enumerable. If `:rack_response` option is given,
|
|
159
161
|
# calls that instead.
|
|
160
162
|
def make_response(object, request)
|
|
161
|
-
if @rack_response
|
|
162
|
-
|
|
163
|
+
status, headers, body = if @rack_response
|
|
164
|
+
@rack_response.call(object, request)
|
|
163
165
|
else
|
|
164
|
-
|
|
166
|
+
[200, { "Content-Type" => CONTENT_TYPE_JSON }, [object.to_json]]
|
|
165
167
|
end
|
|
166
168
|
|
|
169
|
+
headers = Rack::Headers[headers] if Rack.release >= "3"
|
|
167
170
|
# prevent browsers from caching the response
|
|
168
|
-
|
|
171
|
+
headers["Cache-Control"] = "no-store" unless headers.key?("Cache-Control")
|
|
169
172
|
|
|
170
|
-
|
|
173
|
+
[status, headers, body]
|
|
171
174
|
end
|
|
172
175
|
|
|
173
176
|
# Used for early returning an error response.
|
|
@@ -10,8 +10,8 @@ class Shrine
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
module InstanceMethods
|
|
13
|
-
def generate_location(io, **
|
|
14
|
-
pretty_location(io, **
|
|
13
|
+
def generate_location(io, **)
|
|
14
|
+
pretty_location(io, **)
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def pretty_location(io, name: nil, record: nil, version: nil, derivative: nil, identifier: nil, metadata: {}, **)
|
|
@@ -18,14 +18,14 @@ class Shrine
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
module InstanceMethods
|
|
21
|
-
def upload(io, process: true, **
|
|
21
|
+
def upload(io, process: true, **)
|
|
22
22
|
if process
|
|
23
|
-
input = process(io, **
|
|
23
|
+
input = process(io, **)
|
|
24
24
|
else
|
|
25
25
|
input = io
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
super(input, **
|
|
28
|
+
super(input, **)
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
private
|
|
@@ -24,9 +24,9 @@ class Shrine
|
|
|
24
24
|
module AttacherMethods
|
|
25
25
|
# Checks whether a file is a Rack file hash, and in that case wraps the
|
|
26
26
|
# hash in an IO-like object.
|
|
27
|
-
def assign(value, **
|
|
27
|
+
def assign(value, **)
|
|
28
28
|
if rack_file?(value)
|
|
29
|
-
assign shrine_class.rack_file(value), **
|
|
29
|
+
assign shrine_class.rack_file(value), **
|
|
30
30
|
else
|
|
31
31
|
super
|
|
32
32
|
end
|
|
@@ -10,8 +10,8 @@ class Shrine
|
|
|
10
10
|
module RackResponse
|
|
11
11
|
module FileMethods
|
|
12
12
|
# Returns a Rack response triple for the uploaded file.
|
|
13
|
-
def to_rack_response(**
|
|
14
|
-
FileResponse.new(self).call(**
|
|
13
|
+
def to_rack_response(**)
|
|
14
|
+
FileResponse.new(self).call(**)
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
|
|
@@ -32,6 +32,8 @@ class Shrine
|
|
|
32
32
|
headers = rack_headers(**options)
|
|
33
33
|
body = rack_body(**options)
|
|
34
34
|
|
|
35
|
+
headers = Rack::Headers[headers] if Rack.release >= "3"
|
|
36
|
+
|
|
35
37
|
[status, headers, body]
|
|
36
38
|
end
|
|
37
39
|
|
|
@@ -73,7 +75,7 @@ class Shrine
|
|
|
73
75
|
def content_disposition(disposition, filename)
|
|
74
76
|
filename ||= file.original_filename || file.id.split("/").last
|
|
75
77
|
|
|
76
|
-
ContentDisposition.format(disposition
|
|
78
|
+
ContentDisposition.format(disposition:, filename:)
|
|
77
79
|
end
|
|
78
80
|
|
|
79
81
|
# Value for the "Content-Range" header.
|
|
@@ -96,7 +98,7 @@ class Shrine
|
|
|
96
98
|
# Returns an object that responds to #each and #close, which yields
|
|
97
99
|
# contents of the file.
|
|
98
100
|
def rack_body(range: nil, **)
|
|
99
|
-
FileBody.new(file, range:
|
|
101
|
+
FileBody.new(file, range:)
|
|
100
102
|
end
|
|
101
103
|
|
|
102
104
|
# Retrieves a range value parsed from HTTP "Range" header.
|
|
@@ -141,6 +143,10 @@ class Shrine
|
|
|
141
143
|
file.close
|
|
142
144
|
end
|
|
143
145
|
|
|
146
|
+
def bytesize
|
|
147
|
+
each.inject(0) { |sum, chunk| sum += chunk.length }
|
|
148
|
+
end
|
|
149
|
+
|
|
144
150
|
# Rack::Sendfile is activated when response body responds to #to_path.
|
|
145
151
|
def respond_to_missing?(name, include_private = false)
|
|
146
152
|
name == :to_path && path
|
|
@@ -5,19 +5,19 @@ class Shrine
|
|
|
5
5
|
# Documentation can be found on https://shrinerb.com/docs/plugins/refresh_metadata
|
|
6
6
|
module RefreshMetadata
|
|
7
7
|
module AttacherMethods
|
|
8
|
-
def refresh_metadata!(**
|
|
9
|
-
file!.refresh_metadata!(**context, **
|
|
8
|
+
def refresh_metadata!(**)
|
|
9
|
+
file!.refresh_metadata!(**context, **)
|
|
10
10
|
set(file) # trigger model write
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
module FileMethods
|
|
15
|
-
def refresh_metadata!(**
|
|
16
|
-
return open { refresh_metadata!(**
|
|
15
|
+
def refresh_metadata!(replace: false, **)
|
|
16
|
+
return open { refresh_metadata!(replace:, **) } unless opened?
|
|
17
17
|
|
|
18
|
-
refreshed_metadata = uploader.send(:get_metadata, self, metadata: true, **
|
|
18
|
+
refreshed_metadata = uploader.send(:get_metadata, self, metadata: true, **)
|
|
19
19
|
|
|
20
|
-
@metadata = @metadata.merge(refreshed_metadata)
|
|
20
|
+
@metadata = replace ? refreshed_metadata : @metadata.merge(refreshed_metadata)
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
end
|
|
@@ -84,11 +84,11 @@ class Shrine
|
|
|
84
84
|
# Downloads the remote file and assigns it. If download failed, sets
|
|
85
85
|
# the error message and assigns the url to an instance variable so that
|
|
86
86
|
# it shows up in the form.
|
|
87
|
-
def assign_remote_url(url, downloader: {}, **
|
|
87
|
+
def assign_remote_url(url, downloader: {}, **)
|
|
88
88
|
return if url == "" || url.nil?
|
|
89
89
|
|
|
90
90
|
downloaded_file = shrine_class.remote_url(url, **downloader)
|
|
91
|
-
attach_cached(downloaded_file, **
|
|
91
|
+
attach_cached(downloaded_file, **)
|
|
92
92
|
rescue DownloadError => error
|
|
93
93
|
errors.clear << remote_url_error_message(url, error)
|
|
94
94
|
false
|
|
@@ -110,7 +110,7 @@ class Shrine
|
|
|
110
110
|
# Generates an error message for failed remote URL download.
|
|
111
111
|
def remote_url_error_message(url, error)
|
|
112
112
|
message = shrine_class.opts[:remote_url][:error_message]
|
|
113
|
-
message = message.call
|
|
113
|
+
message = message.call(*[url, error].take(message.arity.abs)) if message.respond_to?(:call)
|
|
114
114
|
message || "download failed: #{error.message}"
|
|
115
115
|
end
|
|
116
116
|
end
|
|
@@ -11,14 +11,14 @@ class Shrine
|
|
|
11
11
|
module AttacherMethods
|
|
12
12
|
private
|
|
13
13
|
|
|
14
|
-
def cached(value, **
|
|
14
|
+
def cached(value, **)
|
|
15
15
|
cached_file = super
|
|
16
16
|
|
|
17
17
|
# TODO: Remove this conditional when we remove the versions plugin
|
|
18
18
|
if cached_file.is_a?(Hash) || cached_file.is_a?(Array)
|
|
19
|
-
uploaded_file(cached_file) { |file| file.refresh_metadata!(**context, **
|
|
19
|
+
uploaded_file(cached_file) { |file| file.refresh_metadata!(**context, **) }
|
|
20
20
|
else
|
|
21
|
-
cached_file.refresh_metadata!(**context, **
|
|
21
|
+
cached_file.refresh_metadata!(**context, **)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
cached_file
|
|
@@ -37,7 +37,7 @@ class Shrine
|
|
|
37
37
|
def instrument_signature(io, algorithm, format, &block)
|
|
38
38
|
return yield unless respond_to?(:instrument)
|
|
39
39
|
|
|
40
|
-
instrument(:signature, io
|
|
40
|
+
instrument(:signature, io:, algorithm:, format:, &block)
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
|
|
@@ -45,7 +45,7 @@ class Shrine
|
|
|
45
45
|
# Calculates `algorithm` hash of the contents of the IO object, and
|
|
46
46
|
# encodes it into `format`.
|
|
47
47
|
def calculate_signature(io, algorithm, format: :hex)
|
|
48
|
-
self.class.calculate_signature(io, algorithm, format:
|
|
48
|
+
self.class.calculate_signature(io, algorithm, format:)
|
|
49
49
|
end
|
|
50
50
|
end
|
|
51
51
|
|
|
@@ -57,7 +57,7 @@ class Shrine
|
|
|
57
57
|
def dimensions_analyzer(name)
|
|
58
58
|
on_error = opts[:store_dimensions][:on_error]
|
|
59
59
|
|
|
60
|
-
DimensionsAnalyzer.new(name, on_error:
|
|
60
|
+
DimensionsAnalyzer.new(name, on_error:).method(:call)
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
private
|
|
@@ -66,7 +66,7 @@ class Shrine
|
|
|
66
66
|
def instrument_dimensions(io, &block)
|
|
67
67
|
return yield unless respond_to?(:instrument)
|
|
68
68
|
|
|
69
|
-
instrument(:image_dimensions, io
|
|
69
|
+
instrument(:image_dimensions, io:, &block)
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
72
|
|
|
@@ -26,12 +26,12 @@ class Shrine
|
|
|
26
26
|
# The `storage_key` needs to be one of the registered Shrine storages.
|
|
27
27
|
# Additional options can be given to override the options given on
|
|
28
28
|
# plugin initialization.
|
|
29
|
-
def upload_endpoint(storage_key, **
|
|
29
|
+
def upload_endpoint(storage_key, **)
|
|
30
30
|
Shrine::UploadEndpoint.new(
|
|
31
31
|
shrine_class: self,
|
|
32
32
|
storage_key: storage_key,
|
|
33
33
|
**opts[:upload_endpoint],
|
|
34
|
-
|
|
34
|
+
**,
|
|
35
35
|
)
|
|
36
36
|
end
|
|
37
37
|
|
|
@@ -41,7 +41,7 @@ class Shrine
|
|
|
41
41
|
# It performs the same mounting logic that Rack and other web
|
|
42
42
|
# frameworks use, and is meant for cases where statically mounting the
|
|
43
43
|
# endpoint in the router isn't enough.
|
|
44
|
-
def upload_response(storage_key, env, **
|
|
44
|
+
def upload_response(storage_key, env, **)
|
|
45
45
|
script_name = env["SCRIPT_NAME"]
|
|
46
46
|
path_info = env["PATH_INFO"]
|
|
47
47
|
|
|
@@ -49,7 +49,7 @@ class Shrine
|
|
|
49
49
|
env["SCRIPT_NAME"] += path_info
|
|
50
50
|
env["PATH_INFO"] = ""
|
|
51
51
|
|
|
52
|
-
upload_endpoint(storage_key, **
|
|
52
|
+
upload_endpoint(storage_key, **).call(env)
|
|
53
53
|
ensure
|
|
54
54
|
env["SCRIPT_NAME"] = script_name
|
|
55
55
|
env["PATH_INFO"] = path_info
|
|
@@ -91,7 +91,9 @@ class Shrine
|
|
|
91
91
|
handle_request(request)
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
-
headers[
|
|
94
|
+
headers = Rack::Headers[headers] if Rack.release >= "3"
|
|
95
|
+
headers["Content-Length"] ||= body.respond_to?(:bytesize) ? body.bytesize.to_s :
|
|
96
|
+
body.map(&:bytesize).inject(0, :+).to_s
|
|
95
97
|
|
|
96
98
|
[status, headers, body]
|
|
97
99
|
end
|
|
@@ -24,21 +24,21 @@ class Shrine
|
|
|
24
24
|
attr_reader :errors
|
|
25
25
|
|
|
26
26
|
# Initializes validation errors to an empty array.
|
|
27
|
-
def initialize(**
|
|
27
|
+
def initialize(**)
|
|
28
28
|
super
|
|
29
29
|
@errors = []
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
# Performs validations after attaching cached file.
|
|
33
|
-
def attach_cached(value, validate: nil, **
|
|
34
|
-
result = super(value, validate: false, **
|
|
33
|
+
def attach_cached(value, validate: nil, **)
|
|
34
|
+
result = super(value, validate: false, **)
|
|
35
35
|
validation(validate)
|
|
36
36
|
result
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
# Performs validations after attaching file.
|
|
40
|
-
def attach(io, validate: nil, **
|
|
41
|
-
result = super(io, **
|
|
40
|
+
def attach(io, validate: nil, **)
|
|
41
|
+
result = super(io, **)
|
|
42
42
|
validation(validate)
|
|
43
43
|
result
|
|
44
44
|
end
|
|
@@ -61,16 +61,16 @@ class Shrine
|
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
# Calls #validate_block, passing it accepted parameters.
|
|
64
|
-
def _validate(**
|
|
64
|
+
def _validate(**)
|
|
65
65
|
if method(:validate_block).arity.zero?
|
|
66
66
|
validate_block
|
|
67
67
|
else
|
|
68
|
-
validate_block(**
|
|
68
|
+
validate_block(**)
|
|
69
69
|
end
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
# Overridden by the `Attacher.validate` block.
|
|
73
|
-
def validate_block(**
|
|
73
|
+
def validate_block(**)
|
|
74
74
|
end
|
|
75
75
|
end
|
|
76
76
|
end
|
|
@@ -59,16 +59,16 @@ class Shrine
|
|
|
59
59
|
|
|
60
60
|
# Smart versioned URLs, which include the version name in the default
|
|
61
61
|
# URL, and properly forwards any options to the underlying storage.
|
|
62
|
-
def url(version = nil, **
|
|
62
|
+
def url(version = nil, **)
|
|
63
63
|
if file.is_a?(Hash)
|
|
64
64
|
if version
|
|
65
65
|
version = version.to_sym
|
|
66
66
|
if file.key?(version)
|
|
67
|
-
file[version].url(**
|
|
67
|
+
file[version].url(**)
|
|
68
68
|
elsif fallback = shrine_class.version_fallbacks[version]
|
|
69
|
-
url(fallback, **
|
|
69
|
+
url(fallback, **)
|
|
70
70
|
else
|
|
71
|
-
default_url(
|
|
71
|
+
default_url(**, version:)
|
|
72
72
|
end
|
|
73
73
|
else
|
|
74
74
|
raise Error, "must call Shrine::Attacher#url with the name of the version"
|
|
@@ -76,12 +76,12 @@ class Shrine
|
|
|
76
76
|
else
|
|
77
77
|
if version
|
|
78
78
|
if file && shrine_class.opts[:versions][:fallback_to_original]
|
|
79
|
-
file.url(**
|
|
79
|
+
file.url(**)
|
|
80
80
|
else
|
|
81
|
-
default_url(
|
|
81
|
+
default_url(**, version:)
|
|
82
82
|
end
|
|
83
83
|
else
|
|
84
|
-
super(**
|
|
84
|
+
super(**)
|
|
85
85
|
end
|
|
86
86
|
end
|
|
87
87
|
end
|
|
@@ -130,7 +130,7 @@ class Shrine
|
|
|
130
130
|
|
|
131
131
|
def map_file(object, transform_keys: :to_sym)
|
|
132
132
|
if object.is_a?(Hash) || object.is_a?(Array)
|
|
133
|
-
deep_map(object, transform_keys:
|
|
133
|
+
deep_map(object, transform_keys:) do |path, value|
|
|
134
134
|
yield path, value unless value.is_a?(Hash) || value.is_a?(Array)
|
|
135
135
|
end
|
|
136
136
|
elsif object
|
|
@@ -150,7 +150,7 @@ class Shrine
|
|
|
150
150
|
key = key.send(transform_keys)
|
|
151
151
|
result = yield [*path, key], value
|
|
152
152
|
|
|
153
|
-
hash.merge! key => (result || deep_map(value, [*path, key], transform_keys
|
|
153
|
+
hash.merge! key => (result || deep_map(value, [*path, key], transform_keys:, &block))
|
|
154
154
|
end
|
|
155
155
|
elsif object.is_a?(Array)
|
|
156
156
|
result = yield path, object
|
|
@@ -160,7 +160,7 @@ class Shrine
|
|
|
160
160
|
object.map.with_index do |value, idx|
|
|
161
161
|
result = yield [*path, idx], value
|
|
162
162
|
|
|
163
|
-
result || deep_map(value, [*path, idx], transform_keys
|
|
163
|
+
result || deep_map(value, [*path, idx], transform_keys:, &block)
|
|
164
164
|
end
|
|
165
165
|
else
|
|
166
166
|
result = yield path, object
|
data/lib/shrine/plugins.rb
CHANGED
|
@@ -18,26 +18,18 @@ class Shrine
|
|
|
18
18
|
plugin
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
# Delegate
|
|
22
|
-
def self.load_dependencies(plugin, uploader,
|
|
21
|
+
# Delegate to the plugin's `load_dependencies` method.
|
|
22
|
+
def self.load_dependencies(plugin, uploader, ...)
|
|
23
23
|
return unless plugin.respond_to?(:load_dependencies)
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
plugin.load_dependencies(uploader, *args, **kwargs, &block)
|
|
27
|
-
else
|
|
28
|
-
plugin.load_dependencies(uploader, *args, &block)
|
|
29
|
-
end
|
|
25
|
+
plugin.load_dependencies(uploader, ...)
|
|
30
26
|
end
|
|
31
27
|
|
|
32
|
-
# Delegate
|
|
33
|
-
def self.configure(plugin, uploader,
|
|
28
|
+
# Delegate to the plugin's `load_dependencies` method.
|
|
29
|
+
def self.configure(plugin, uploader, ...)
|
|
34
30
|
return unless plugin.respond_to?(:configure)
|
|
35
31
|
|
|
36
|
-
|
|
37
|
-
plugin.configure(uploader, *args, **kwargs, &block)
|
|
38
|
-
else
|
|
39
|
-
plugin.configure(uploader, *args, &block)
|
|
40
|
-
end
|
|
32
|
+
plugin.configure(uploader, ...)
|
|
41
33
|
end
|
|
42
34
|
|
|
43
35
|
# Register the given plugin with Shrine, so that it can be loaded using
|
|
@@ -59,8 +59,8 @@ class Shrine
|
|
|
59
59
|
|
|
60
60
|
# Opens the file on the given location in read mode. Accepts additional
|
|
61
61
|
# `File.open` arguments.
|
|
62
|
-
def open(id, **
|
|
63
|
-
path(id).open(binmode: true, **
|
|
62
|
+
def open(id, **)
|
|
63
|
+
path(id).open(binmode: true, **)
|
|
64
64
|
rescue Errno::ENOENT
|
|
65
65
|
raise Shrine::FileNotFound, "file #{id.inspect} not found on storage"
|
|
66
66
|
end
|
|
@@ -75,7 +75,7 @@ class Shrine
|
|
|
75
75
|
# from the returned path (e.g. #directory can be set to "public" folder).
|
|
76
76
|
# Both cases accept a `:host` value which will be prefixed to the
|
|
77
77
|
# generated path.
|
|
78
|
-
def url(id, host: nil, **
|
|
78
|
+
def url(id, host: nil, **)
|
|
79
79
|
path = (prefix ? relative_path(id) : path(id)).to_s
|
|
80
80
|
host ? host + path : path
|
|
81
81
|
end
|
|
@@ -123,7 +123,7 @@ class Shrine
|
|
|
123
123
|
# Cleans all empty subdirectories up the hierarchy.
|
|
124
124
|
def clean(path)
|
|
125
125
|
path.dirname.ascend do |pathname|
|
|
126
|
-
if
|
|
126
|
+
if Dir.empty?(pathname) && pathname != directory
|
|
127
127
|
pathname.rmdir
|
|
128
128
|
else
|
|
129
129
|
break
|
|
@@ -175,19 +175,6 @@ class Shrine
|
|
|
175
175
|
.find
|
|
176
176
|
.each { |path| yield path if path.file? }
|
|
177
177
|
end
|
|
178
|
-
|
|
179
|
-
if RUBY_VERSION >= "2.4"
|
|
180
|
-
def dir_empty?(path)
|
|
181
|
-
Dir.empty?(path)
|
|
182
|
-
end
|
|
183
|
-
else
|
|
184
|
-
# :nocov:
|
|
185
|
-
def dir_empty?(path)
|
|
186
|
-
Dir.foreach(path) { |x| return false unless [".", ".."].include?(x) }
|
|
187
|
-
true
|
|
188
|
-
end
|
|
189
|
-
# :nocov:
|
|
190
|
-
end
|
|
191
178
|
end
|
|
192
179
|
end
|
|
193
180
|
end
|
|
@@ -24,18 +24,18 @@ class Shrine
|
|
|
24
24
|
#
|
|
25
25
|
# Shrine::Storage::Linter.new(storage).call(->{File.open("test/fixtures/image.jpg")})
|
|
26
26
|
class Linter
|
|
27
|
-
def self.call(*
|
|
28
|
-
new(*
|
|
27
|
+
def self.call(*)
|
|
28
|
+
new(*).call
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
def initialize(storage, action: :error, nonexisting: "nonexisting")
|
|
31
|
+
def initialize(storage, action: :error, nonexisting: String.new("nonexisting"))
|
|
32
32
|
@storage = storage
|
|
33
33
|
@action = action
|
|
34
34
|
@nonexisting = nonexisting
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
def call(io_factory = default_io_factory)
|
|
38
|
-
storage.upload(io_factory.call, id = "foo", shrine_metadata: { "foo" => "bar" })
|
|
38
|
+
storage.upload(io_factory.call, id = String.new("foo"), shrine_metadata: { "foo" => "bar" })
|
|
39
39
|
|
|
40
40
|
lint_open(id)
|
|
41
41
|
lint_exists(id)
|
|
@@ -43,9 +43,9 @@ class Shrine
|
|
|
43
43
|
lint_delete(id)
|
|
44
44
|
|
|
45
45
|
if storage.respond_to?(:delete_prefixed)
|
|
46
|
-
storage.upload(io_factory.call, id1 = "a/a/a")
|
|
47
|
-
storage.upload(io_factory.call, id2 = "a/a/b")
|
|
48
|
-
storage.upload(io_factory.call, id3 = "a/aaa/a")
|
|
46
|
+
storage.upload(io_factory.call, id1 = String.new("a/a/a"))
|
|
47
|
+
storage.upload(io_factory.call, id2 = String.new("a/a/b"))
|
|
48
|
+
storage.upload(io_factory.call, id3 = String.new("a/aaa/a"))
|
|
49
49
|
|
|
50
50
|
lint_delete_prefixed(prefix: "a/a/",
|
|
51
51
|
expect_deleted: [id1, id2],
|
|
@@ -55,7 +55,7 @@ class Shrine
|
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
if storage.respond_to?(:clear!)
|
|
58
|
-
storage.upload(io_factory.call, id = "quux"
|
|
58
|
+
storage.upload(io_factory.call, id = String.new("quux"))
|
|
59
59
|
lint_clear(id)
|
|
60
60
|
end
|
|
61
61
|
|
|
@@ -17,9 +17,7 @@ class Shrine
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def open(id, **)
|
|
20
|
-
|
|
21
|
-
io.set_encoding(io.string.encoding) # Ruby 2.7.0 – https://bugs.ruby-lang.org/issues/16497
|
|
22
|
-
io
|
|
20
|
+
StringIO.new(store.fetch(id))
|
|
23
21
|
rescue KeyError
|
|
24
22
|
raise Shrine::FileNotFound, "file #{id.inspect} not found on storage"
|
|
25
23
|
end
|