shrine 2.19.4 → 3.0.0.alpha

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of shrine might be problematic. Click here for more details.

Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +299 -11
  3. data/README.md +9 -3
  4. data/doc/advantages.md +1 -1
  5. data/doc/carrierwave.md +4 -4
  6. data/doc/creating_persistence_plugins.md +172 -0
  7. data/doc/creating_plugins.md +1 -1
  8. data/doc/creating_storages.md +3 -1
  9. data/doc/design.md +2 -2
  10. data/doc/direct_s3.md +0 -22
  11. data/doc/paperclip.md +3 -3
  12. data/doc/plugins/activerecord.md +211 -42
  13. data/doc/plugins/atomic_helpers.md +153 -0
  14. data/doc/plugins/column.md +90 -0
  15. data/doc/plugins/derivation_endpoint.md +54 -62
  16. data/doc/plugins/derivatives.md +752 -0
  17. data/doc/plugins/entity.md +204 -0
  18. data/doc/plugins/infer_extension.md +8 -8
  19. data/doc/plugins/instrumentation.md +33 -13
  20. data/doc/plugins/keep_files.md +5 -15
  21. data/doc/plugins/model.md +157 -0
  22. data/doc/plugins/presign_endpoint.md +2 -1
  23. data/doc/plugins/refresh_metadata.md +44 -7
  24. data/doc/plugins/sequel.md +190 -33
  25. data/doc/plugins/{default_url_options.md → url_options.md} +5 -5
  26. data/doc/processing.md +1 -1
  27. data/doc/release_notes/1.1.0.md +2 -2
  28. data/doc/release_notes/2.15.0.md +1 -1
  29. data/doc/storage/s3.md +2 -2
  30. data/doc/testing.md +1 -1
  31. data/lib/shrine.rb +72 -138
  32. data/lib/shrine/attacher.rb +272 -176
  33. data/lib/shrine/attachment.rb +2 -42
  34. data/lib/shrine/plugins/activerecord.rb +103 -26
  35. data/lib/shrine/plugins/add_metadata.rb +9 -10
  36. data/lib/shrine/plugins/atomic_helpers.rb +111 -0
  37. data/lib/shrine/plugins/attacher_options.rb +55 -0
  38. data/lib/shrine/plugins/backgrounding.rb +147 -115
  39. data/lib/shrine/plugins/cached_attachment_data.rb +6 -9
  40. data/lib/shrine/plugins/column.rb +104 -0
  41. data/lib/shrine/plugins/data_uri.rb +35 -38
  42. data/lib/shrine/plugins/default_storage.rb +18 -12
  43. data/lib/shrine/plugins/default_url.rb +11 -21
  44. data/lib/shrine/plugins/default_url_options.rb +3 -30
  45. data/lib/shrine/plugins/delete_raw.rb +9 -13
  46. data/lib/shrine/plugins/derivation_endpoint.rb +75 -114
  47. data/lib/shrine/plugins/derivatives.rb +576 -0
  48. data/lib/shrine/plugins/determine_mime_type.rb +3 -15
  49. data/lib/shrine/plugins/download_endpoint.rb +83 -131
  50. data/lib/shrine/plugins/dynamic_storage.rb +4 -8
  51. data/lib/shrine/plugins/entity.rb +128 -0
  52. data/lib/shrine/plugins/form_assign.rb +107 -0
  53. data/lib/shrine/plugins/included.rb +4 -3
  54. data/lib/shrine/plugins/infer_extension.rb +10 -17
  55. data/lib/shrine/plugins/instrumentation.rb +45 -25
  56. data/lib/shrine/plugins/keep_files.rb +2 -12
  57. data/lib/shrine/plugins/metadata_attributes.rb +15 -14
  58. data/lib/shrine/plugins/model.rb +137 -0
  59. data/lib/shrine/plugins/module_include.rb +2 -0
  60. data/lib/shrine/plugins/presign_endpoint.rb +1 -15
  61. data/lib/shrine/plugins/pretty_location.rb +5 -5
  62. data/lib/shrine/plugins/processing.rb +21 -6
  63. data/lib/shrine/plugins/rack_file.rb +1 -39
  64. data/lib/shrine/plugins/rack_response.rb +14 -7
  65. data/lib/shrine/plugins/recache.rb +5 -2
  66. data/lib/shrine/plugins/refresh_metadata.rb +12 -8
  67. data/lib/shrine/plugins/remote_url.rb +44 -53
  68. data/lib/shrine/plugins/remove_attachment.rb +7 -2
  69. data/lib/shrine/plugins/remove_invalid.rb +8 -4
  70. data/lib/shrine/plugins/restore_cached_data.rb +12 -4
  71. data/lib/shrine/plugins/sequel.rb +115 -27
  72. data/lib/shrine/plugins/signature.rb +2 -7
  73. data/lib/shrine/plugins/store_dimensions.rb +13 -27
  74. data/lib/shrine/plugins/upload_endpoint.rb +14 -15
  75. data/lib/shrine/plugins/upload_options.rb +9 -8
  76. data/lib/shrine/plugins/url_options.rb +33 -0
  77. data/lib/shrine/plugins/validation.rb +87 -0
  78. data/lib/shrine/plugins/validation_helpers.rb +33 -54
  79. data/lib/shrine/plugins/versions.rb +106 -84
  80. data/lib/shrine/storage/file_system.rb +32 -57
  81. data/lib/shrine/storage/linter.rb +9 -1
  82. data/lib/shrine/storage/memory.rb +42 -0
  83. data/lib/shrine/storage/s3.rb +38 -146
  84. data/lib/shrine/uploaded_file.rb +22 -29
  85. data/lib/shrine/version.rb +4 -4
  86. data/shrine.gemspec +2 -3
  87. metadata +27 -54
  88. data/doc/plugins/backup.md +0 -31
  89. data/doc/plugins/copy.md +0 -24
  90. data/doc/plugins/delete_promoted.md +0 -12
  91. data/doc/plugins/direct_upload.md +0 -172
  92. data/doc/plugins/hooks.md +0 -58
  93. data/doc/plugins/logging.md +0 -42
  94. data/doc/plugins/migration_helpers.md +0 -60
  95. data/doc/plugins/moving.md +0 -19
  96. data/doc/plugins/multi_delete.md +0 -20
  97. data/doc/plugins/parallelize.md +0 -16
  98. data/doc/plugins/parsed_json.md +0 -23
  99. data/lib/shrine/plugins/background_helpers.rb +0 -5
  100. data/lib/shrine/plugins/backup.rb +0 -90
  101. data/lib/shrine/plugins/copy.rb +0 -50
  102. data/lib/shrine/plugins/delete_promoted.rb +0 -20
  103. data/lib/shrine/plugins/direct_upload.rb +0 -217
  104. data/lib/shrine/plugins/hooks.rb +0 -90
  105. data/lib/shrine/plugins/logging.rb +0 -142
  106. data/lib/shrine/plugins/migration_helpers.rb +0 -70
  107. data/lib/shrine/plugins/moving.rb +0 -57
  108. data/lib/shrine/plugins/multi_delete.rb +0 -32
  109. data/lib/shrine/plugins/parallelize.rb +0 -78
  110. data/lib/shrine/plugins/parsed_json.rb +0 -29
@@ -6,24 +6,30 @@ class Shrine
6
6
  #
7
7
  # [doc/plugins/default_storage.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/default_storage.md
8
8
  module DefaultStorage
9
- def self.configure(uploader, opts = {})
10
- uploader.opts[:default_storage_cache] = opts.fetch(:cache, uploader.opts[:default_storage_cache])
11
- uploader.opts[:default_storage_store] = opts.fetch(:store, uploader.opts[:default_storage_store])
9
+ def self.configure(uploader, **opts)
10
+ uploader.opts[:default_storage] ||= {}
11
+ uploader.opts[:default_storage].merge!(opts)
12
12
  end
13
13
 
14
14
  module AttacherMethods
15
- def initialize(record, name, **options)
16
- if cache = shrine_class.opts[:default_storage_cache]
17
- cache = cache.call(record, name) if cache.respond_to?(:call)
18
- options[:cache] = cache
19
- end
15
+ def initialize(**options)
16
+ super(**shrine_class.opts[:default_storage], **options)
17
+ end
20
18
 
21
- if store = shrine_class.opts[:default_storage_store]
22
- store = store.call(record, name) if store.respond_to?(:call)
23
- options[:store] = store
19
+ def cache_key
20
+ if @cache.respond_to?(:call)
21
+ @cache.call(record, name)
22
+ else
23
+ @cache
24
24
  end
25
+ end
25
26
 
26
- super
27
+ def store_key
28
+ if @store.respond_to?(:call)
29
+ @store.call(record, name)
30
+ else
31
+ @store
32
+ end
27
33
  end
28
34
  end
29
35
  end
@@ -6,18 +6,14 @@ class Shrine
6
6
  #
7
7
  # [doc/plugins/default_url.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/default_url.md
8
8
  module DefaultUrl
9
- def self.configure(uploader, opts = {}, &block)
10
- uploader.opts[:default_url_host] = opts.fetch(:host, uploader.opts[:default_url_host])
11
-
12
- if block
13
- uploader.opts[:default_url] = block
14
- Shrine.deprecation("Passing a block to default_url plugin is deprecated and will probably be removed in future versions of Shrine. Use `Attacher.default_url { ... }` instead.")
15
- end
9
+ def self.configure(uploader, **opts)
10
+ uploader.opts[:default_url] ||= {}
11
+ uploader.opts[:default_url].merge!(opts)
16
12
  end
17
13
 
18
14
  module AttacherClassMethods
19
15
  def default_url(&block)
20
- shrine_class.opts[:default_url_block] = block
16
+ shrine_class.opts[:default_url][:block] = block
21
17
  end
22
18
  end
23
19
 
@@ -29,25 +25,19 @@ class Shrine
29
25
  private
30
26
 
31
27
  def default_url(**options)
32
- url = if default_url_block
33
- instance_exec(options, &default_url_block)
34
- elsif shrine_class.opts[:default_url]
35
- shrine_class.opts[:default_url].call(context.merge(options){|k, old, new| old})
36
- end
37
-
38
- if default_url_host
39
- [default_url_host, url].join
40
- else
41
- url
42
- end
28
+ return unless default_url_block
29
+
30
+ url = instance_exec(options, &default_url_block)
31
+
32
+ [*default_url_host, url].join
43
33
  end
44
34
 
45
35
  def default_url_block
46
- shrine_class.opts[:default_url_block]
36
+ shrine_class.opts[:default_url][:block]
47
37
  end
48
38
 
49
39
  def default_url_host
50
- shrine_class.opts[:default_url_host]
40
+ shrine_class.opts[:default_url][:host]
51
41
  end
52
42
  end
53
43
  end
@@ -1,34 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Shrine
4
- module Plugins
5
- # Documentation lives in [doc/plugins/default_url_options.md] on GitHub.
6
- #
7
- # [doc/plugins/default_url_options.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/default_url_options.md
8
- module DefaultUrlOptions
9
- def self.configure(uploader, options = {})
10
- uploader.opts[:default_url_options] ||= {}
11
- uploader.opts[:default_url_options].merge!(options)
12
- end
3
+ Shrine.deprecation("The default_url_options plugin has been renamed to url_options, so `plugin :default_url_options` should be replaced with `plugin :url_options`. The default_url_options alias will be removed in Shrine 4.")
13
4
 
14
- module FileMethods
15
- def url(**options)
16
- default_options = default_url_options
17
- default_options = default_options.call(self, options) if default_options.respond_to?(:call)
18
- default_options ||= {}
5
+ require "shrine/plugins/url_options"
19
6
 
20
- super(default_options.merge(options))
21
- end
22
-
23
- private
24
-
25
- def default_url_options
26
- options = shrine_class.opts[:default_url_options]
27
- options[storage_key.to_sym]
28
- end
29
- end
30
- end
31
-
32
- register_plugin(:default_url_options, DefaultUrlOptions)
33
- end
34
- end
7
+ Shrine::Plugins.register_plugin(:default_url_options, Shrine::Plugins::UrlOptions)
@@ -1,33 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ Shrine.deprecation("The delete_raw plugin is deprecated and will be removed in Shrine 4. If you were using it with versions plugin, use the new derivatives plugin instead.")
4
+
3
5
  class Shrine
4
6
  module Plugins
5
7
  # Documentation lives in [doc/plugins/delete_raw.md] on GitHub.
6
8
  #
7
9
  # [doc/plugins/delete_raw.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/delete_raw.md
8
10
  module DeleteRaw
9
- def self.configure(uploader, opts = {})
10
- uploader.opts[:delete_raw_storages] = opts.fetch(:storages, uploader.opts[:delete_raw_storages])
11
+ def self.configure(uploader, **opts)
12
+ uploader.opts[:delete_raw] ||= {}
13
+ uploader.opts[:delete_raw].merge!(opts)
11
14
  end
12
15
 
13
16
  module InstanceMethods
14
17
  private
15
18
 
16
19
  # Deletes the file that was uploaded, unless it's an UploadedFile.
17
- def copy(io, context)
18
- super
19
- if io.respond_to?(:path) && io.path && delete_raw? && context[:delete] != false
20
- begin
21
- File.delete(io.path)
22
- rescue Errno::ENOENT
23
- # file might already be deleted by the moving plugin
24
- end
25
- end
20
+ def _upload(io, delete: delete_raw?, **options)
21
+ super(io, delete: delete, **options)
26
22
  end
27
23
 
28
24
  def delete_raw?
29
- opts[:delete_raw_storages].nil? ||
30
- opts[:delete_raw_storages].include?(storage_key)
25
+ opts[:delete_raw][:storages].nil? ||
26
+ opts[:delete_raw][:storages].include?(storage_key)
31
27
  end
32
28
  end
33
29
  end
@@ -5,6 +5,7 @@ require "content_disposition"
5
5
 
6
6
  require "openssl"
7
7
  require "tempfile"
8
+ require "pathname"
8
9
 
9
10
  class Shrine
10
11
  module Plugins
@@ -20,25 +21,21 @@ class Shrine
20
21
  }.inspect}"
21
22
  end
22
23
 
23
- def self.load_dependencies(uploader, opts = {})
24
+ def self.load_dependencies(uploader, **)
24
25
  uploader.plugin :rack_response
25
26
  uploader.plugin :_urlsafe_serialization
26
27
  end
27
28
 
28
- def self.configure(uploader, opts = {})
29
- uploader.opts[:derivation_endpoint_options] ||= { log_subscriber: LOG_SUBSCRIBER }
30
- uploader.opts[:derivation_endpoint_options].merge!(opts)
29
+ def self.configure(uploader, log_subscriber: LOG_SUBSCRIBER, **opts)
30
+ uploader.opts[:derivation_endpoint] ||= { options: {}, derivations: {} }
31
+ uploader.opts[:derivation_endpoint][:options].merge!(opts)
31
32
 
32
- uploader.opts[:derivation_endpoint_derivations] ||= {}
33
-
34
- unless uploader.opts[:derivation_endpoint_options][:secret_key]
33
+ unless uploader.opts[:derivation_endpoint][:options][:secret_key]
35
34
  fail Error, "must provide :secret_key option to derivation_endpoint plugin"
36
35
  end
37
36
 
38
37
  # instrumentation plugin integration
39
- if uploader.respond_to?(:subscribe)
40
- uploader.subscribe(:derivation, &uploader.opts[:derivation_endpoint_options][:log_subscriber])
41
- end
38
+ uploader.subscribe(:derivation, &log_subscriber) if uploader.respond_to?(:subscribe)
42
39
  end
43
40
 
44
41
  module ClassMethods
@@ -76,15 +73,15 @@ class Shrine
76
73
  # Registers a derivation block, which is called when the corresponding
77
74
  # derivation URL is requested.
78
75
  def derivation(name, &block)
79
- derivations[name] = block
76
+ derivations[name.to_sym] = block
80
77
  end
81
78
 
82
79
  def derivations
83
- opts[:derivation_endpoint_derivations]
80
+ opts[:derivation_endpoint][:derivations]
84
81
  end
85
82
 
86
83
  def derivation_options
87
- opts[:derivation_endpoint_options]
84
+ opts[:derivation_endpoint][:options]
88
85
  end
89
86
  end
90
87
 
@@ -127,7 +124,7 @@ class Shrine
127
124
  attr_reader :name, :args, :source, :options
128
125
 
129
126
  def initialize(name:, args:, source:, options:)
130
- @name = name
127
+ @name = name.to_sym
131
128
  @args = args
132
129
  @source = source
133
130
  @options = options
@@ -163,16 +160,22 @@ class Shrine
163
160
 
164
161
  # Uploads the derivation result to a dedicated destination on the specified
165
162
  # Shrine storage.
166
- def upload(file = nil)
167
- Derivation::Upload.new(self).call(file)
163
+ def upload(file = nil, **options)
164
+ Derivation::Upload.new(self).call(file, **options)
168
165
  end
169
166
 
170
- # Returns a Shrine::UploadedFile object pointing to the uploaded derivation
171
- # result.
167
+ # Returns a Shrine::UploadedFile object pointing to the uploaded derivative
168
+ # if it exists.
172
169
  def retrieve
173
170
  Derivation::Retrieve.new(self).call
174
171
  end
175
172
 
173
+ # Returns opened Shrine::UploadedFile object pointing to the uploaded
174
+ # derivative if it exists.
175
+ def opened
176
+ Derivation::Opened.new(self).call
177
+ end
178
+
176
179
  # Deletes the derivation result from the storage.
177
180
  def delete
178
181
  Derivation::Delete.new(self).call
@@ -189,12 +192,10 @@ class Shrine
189
192
  option :cache_control, default: -> { default_cache_control }
190
193
  option :disposition, default: -> { "inline" }
191
194
  option :download, default: -> { true }
192
- option :download_errors, default: -> { [] }
193
195
  option :download_options, default: -> { {} }
194
196
  option :expires_in
195
197
  option :filename, default: -> { default_filename }
196
198
  option :host
197
- option :include_uploaded_file, default: -> { false }
198
199
  option :metadata, default: -> { [] }
199
200
  option :prefix
200
201
  option :secret_key
@@ -260,7 +261,7 @@ class Shrine
260
261
 
261
262
  # The source uploaded file storage is the default derivative storage.
262
263
  def default_upload_storage
263
- source.storage_key.to_sym
264
+ source.storage_key
264
265
  end
265
266
 
266
267
  # Allows caching for 1 year or until the URL expires.
@@ -399,10 +400,10 @@ class Shrine
399
400
 
400
401
  begin
401
402
  status, headers, body = derivation.response(request.env)
402
- rescue Derivation::NotFound
403
- error!(404, "Unknown derivation \"#{name}\"")
404
403
  rescue Derivation::SourceNotFound
405
404
  error!(404, "Source file not found")
405
+ rescue Derivation::NotFound
406
+ error!(404, "Unknown derivation \"#{name}\"")
406
407
  end
407
408
 
408
409
  # tell clients to cache the derivation result if it was successful
@@ -504,28 +505,21 @@ class Shrine
504
505
  # uploads the result. If the derivation result is already uploaded, uses
505
506
  # the `rack_response` plugin to generate a Rack response triple.
506
507
  def upload_response(env)
507
- uploaded_file = derivation.retrieve
508
+ uploaded_file = upload_redirect ? derivation.retrieve : derivation.opened
508
509
 
509
510
  unless uploaded_file
510
511
  derivative = derivation.generate
511
- uploaded_file = derivation.upload(derivative)
512
+ uploaded_file = derivation.upload(derivative, delete: upload_redirect)
512
513
  end
513
514
 
514
515
  if upload_redirect
515
- # we don't need the local derivation result here
516
- if derivative
517
- derivative.close
518
- File.delete(derivative.path)
519
- end
520
-
521
516
  redirect_url = uploaded_file.url(upload_redirect_url_options)
522
517
 
523
518
  [302, { "Location" => redirect_url }, []]
524
519
  else
525
- if derivative && File.exist?(derivative.path)
520
+ if derivative
526
521
  file_response(derivative, env)
527
522
  else
528
- uploaded_file.open(**upload_open_options)
529
523
  uploaded_file.to_rack_response(
530
524
  type: type,
531
525
  disposition: disposition,
@@ -544,8 +538,10 @@ class Shrine
544
538
  if Rack.release > "2"
545
539
  server.serving(Rack::Request.new(env), path)
546
540
  else
541
+ # :nocov:
547
542
  server.path = path
548
543
  server.serving(env)
544
+ # :nocov:
549
545
  end
550
546
  end
551
547
 
@@ -572,9 +568,7 @@ class Shrine
572
568
  end
573
569
 
574
570
  class Derivation::Generate < Derivation::Command
575
- delegate :name, :args, :source,
576
- :download, :download_errors, :download_options,
577
- :include_uploaded_file
571
+ delegate :name, :args, :source, :download, :download_options
578
572
 
579
573
  def call(file = nil)
580
574
  derivative = generate(file)
@@ -589,22 +583,16 @@ class Shrine
589
583
  # file.
590
584
  def generate(file)
591
585
  if download
592
- with_downloaded(file) do |file|
593
- if include_uploaded_file
594
- derive(file, source, *args)
595
- else
596
- derive(file, *args)
597
- end
598
- end
586
+ with_downloaded(file) { |file| derive(file, *args) }
599
587
  else
600
- derive(source, *args)
588
+ derive(*args)
601
589
  end
602
590
  end
603
591
 
604
592
  # Calls the derivation block.
605
593
  def derive(*args)
606
594
  instrument_derivation do
607
- uploader.instance_exec(*args, &derivation_block)
595
+ derivation.instance_exec(*args, &derivation_block)
608
596
  end
609
597
  end
610
598
 
@@ -624,51 +612,35 @@ class Shrine
624
612
  # Massages the derivation result, ensuring it's opened in binary mode,
625
613
  # rewinded and flushed to disk.
626
614
  def normalize(derivative)
627
- if derivative.is_a?(Tempfile)
628
- derivative.open
629
- elsif derivative.is_a?(File)
630
- derivative.close
631
- derivative = File.open(derivative.path)
632
- elsif derivative.is_a?(String)
633
- derivative = File.open(derivative)
634
- elsif defined?(Pathname) && derivative.is_a?(Pathname)
635
- derivative = derivative.open
636
- else
637
- fail Error, "unexpected derivation result: #{derivation.inspect} (expected File, Tempfile, String, or Pathname object)"
638
- end
615
+ derivative =
616
+ case derivative
617
+ when Tempfile then derivative.tap(&:open)
618
+ when File then File.open(derivative.tap(&:close))
619
+ when String, Pathname then File.open(derivative)
620
+ else
621
+ fail Error, "unexpected derivation result: #{derivation.inspect} (expected File, Tempfile, String, or Pathname object)"
622
+ end
639
623
 
640
624
  derivative.binmode
641
625
  derivative
642
626
  end
643
627
 
644
628
  def with_downloaded(file, &block)
645
- if file
646
- yield file
647
- else
648
- download_source(&block)
649
- end
629
+ return yield(file) if file
630
+
631
+ download_source(&block)
650
632
  end
651
633
 
652
634
  # Downloads the source uploaded file from the storage.
653
- def download_source
654
- begin
655
- file = source.download(**download_options)
656
- rescue *download_errors
657
- raise Derivation::SourceNotFound, "source file \"#{source.id}\" was not found on storage :#{source.storage_key}"
658
- end
659
-
660
- yield file
661
- ensure
662
- file.close! if file
635
+ def download_source(&block)
636
+ source.download(**download_options, &block)
637
+ rescue Shrine::FileNotFound
638
+ raise Derivation::SourceNotFound, "source file \"#{source.id}\" was not found on storage :#{source.storage_key}"
663
639
  end
664
640
 
665
641
  def derivation_block
666
642
  shrine_class.derivations[name] or fail Derivation::NotFound, "derivation #{name.inspect} is not defined"
667
643
  end
668
-
669
- def uploader
670
- source.uploader
671
- end
672
644
  end
673
645
 
674
646
  class Derivation::Upload < Derivation::Command
@@ -677,59 +649,48 @@ class Shrine
677
649
  # Uploads the derivation result to the dedicated location on the storage.
678
650
  # If a file object is given, uploads that to the storage, otherwise calls
679
651
  # the derivation block and uploads the result.
680
- def call(derivative = nil)
681
- with_derivative(derivative) do |uploadable|
682
- uploader.upload uploadable,
683
- location: upload_location,
684
- upload_options: upload_options
685
- end
686
- end
687
-
688
- private
689
-
690
- def with_derivative(derivative)
652
+ def call(derivative = nil, **options)
691
653
  if derivative
692
- begin
693
- # we want to keep the provided file open and rewinded
694
- File.open(derivative.path, binmode: true) do |file|
695
- yield file
696
- end
697
- ensure
698
- # close the file handler if the file was deleted during upload
699
- derivative.close if !File.exist?(derivative.path)
700
- end
654
+ upload(derivative, **options)
701
655
  else
702
- # generate the derivative and delete it afterwards
703
- begin
704
- file = derivation.generate
705
- yield file
706
- ensure
707
- file.close
708
- File.delete(file.path)
709
- end
656
+ upload(derivation.generate, delete: true, **options)
710
657
  end
711
658
  end
712
659
 
713
- def uploader
714
- shrine_class.new(upload_storage)
660
+ private
661
+
662
+ def upload(io, **options)
663
+ shrine_class.upload io, upload_storage,
664
+ location: upload_location,
665
+ upload_options: upload_options,
666
+ **options
715
667
  end
716
668
  end
717
669
 
718
670
  class Derivation::Retrieve < Derivation::Command
719
- delegate :upload_location, :upload_storage
671
+ delegate :upload_storage, :upload_location
720
672
 
721
- # Returns a Shrine::UploadedFile object pointing to the uploaded derivation
722
- # result it exists on the storage.
673
+ # Returns a Shrine::UploadedFile object pointing to the uploaded derivative
674
+ # if it exists on the storage.
723
675
  def call
724
- uploaded_file = shrine_class::UploadedFile.new(
725
- "storage" => upload_storage.to_s,
726
- "id" => upload_location,
727
- )
728
-
676
+ uploaded_file = shrine_class.uploaded_file(storage: upload_storage, id: upload_location)
729
677
  uploaded_file if uploaded_file.exists?
730
678
  end
731
679
  end
732
680
 
681
+ class Derivation::Opened < Derivation::Command
682
+ delegate :upload_storage, :upload_location, :upload_open_options
683
+
684
+ # Returns opened Shrine::UploadedFile object pointing to the uploaded if
685
+ # it exists on the storage.
686
+ def call
687
+ uploaded_file = shrine_class.uploaded_file(storage: upload_storage, id: upload_location)
688
+ uploaded_file.open(**upload_open_options)
689
+ uploaded_file
690
+ rescue Shrine::FileNotFound
691
+ end
692
+ end
693
+
733
694
  class Derivation::Delete < Derivation::Command
734
695
  delegate :upload_location, :upload_storage
735
696