shrine 3.0.0 → 3.2.2

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.

Potentially problematic release.


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

Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +87 -33
  3. data/LICENSE.txt +1 -1
  4. data/README.md +94 -4
  5. data/doc/advantages.md +35 -18
  6. data/doc/attacher.md +16 -17
  7. data/doc/carrierwave.md +75 -34
  8. data/doc/changing_derivatives.md +39 -39
  9. data/doc/design.md +134 -85
  10. data/doc/external/articles.md +56 -41
  11. data/doc/external/extensions.md +38 -34
  12. data/doc/getting_started.md +182 -112
  13. data/doc/metadata.md +79 -43
  14. data/doc/multiple_files.md +5 -3
  15. data/doc/paperclip.md +110 -42
  16. data/doc/plugins/activerecord.md +5 -5
  17. data/doc/plugins/add_metadata.md +92 -35
  18. data/doc/plugins/backgrounding.md +12 -2
  19. data/doc/plugins/column.md +36 -7
  20. data/doc/plugins/data_uri.md +2 -2
  21. data/doc/plugins/default_url.md +6 -3
  22. data/doc/plugins/derivation_endpoint.md +26 -28
  23. data/doc/plugins/derivatives.md +205 -169
  24. data/doc/plugins/determine_mime_type.md +2 -2
  25. data/doc/plugins/entity.md +3 -3
  26. data/doc/plugins/form_assign.md +5 -5
  27. data/doc/plugins/included.md +25 -5
  28. data/doc/plugins/infer_extension.md +2 -2
  29. data/doc/plugins/instrumentation.md +1 -1
  30. data/doc/plugins/metadata_attributes.md +21 -10
  31. data/doc/plugins/model.md +4 -4
  32. data/doc/plugins/persistence.md +1 -0
  33. data/doc/plugins/refresh_metadata.md +5 -4
  34. data/doc/plugins/remote_url.md +8 -3
  35. data/doc/plugins/remove_invalid.md +9 -1
  36. data/doc/plugins/sequel.md +4 -4
  37. data/doc/plugins/signature.md +11 -2
  38. data/doc/plugins/store_dimensions.md +2 -2
  39. data/doc/plugins/type_predicates.md +96 -0
  40. data/doc/plugins/upload_endpoint.md +7 -11
  41. data/doc/plugins/upload_options.md +1 -1
  42. data/doc/plugins/url_options.md +2 -2
  43. data/doc/plugins/validation.md +14 -4
  44. data/doc/plugins/validation_helpers.md +3 -3
  45. data/doc/plugins/versions.md +11 -11
  46. data/doc/processing.md +289 -125
  47. data/doc/refile.md +39 -18
  48. data/doc/release_notes/2.19.0.md +1 -1
  49. data/doc/release_notes/3.0.0.md +275 -258
  50. data/doc/release_notes/3.0.1.md +22 -0
  51. data/doc/release_notes/3.1.0.md +73 -0
  52. data/doc/release_notes/3.2.0.md +96 -0
  53. data/doc/release_notes/3.2.1.md +32 -0
  54. data/doc/release_notes/3.2.2.md +14 -0
  55. data/doc/securing_uploads.md +3 -3
  56. data/doc/storage/file_system.md +1 -1
  57. data/doc/storage/memory.md +19 -0
  58. data/doc/storage/s3.md +105 -86
  59. data/doc/testing.md +2 -2
  60. data/doc/upgrading_to_3.md +115 -33
  61. data/doc/validation.md +3 -2
  62. data/lib/shrine.rb +8 -8
  63. data/lib/shrine/attacher.rb +19 -14
  64. data/lib/shrine/attachment.rb +5 -5
  65. data/lib/shrine/plugins.rb +22 -0
  66. data/lib/shrine/plugins/add_metadata.rb +12 -3
  67. data/lib/shrine/plugins/default_storage.rb +6 -6
  68. data/lib/shrine/plugins/default_url.rb +1 -1
  69. data/lib/shrine/plugins/derivation_endpoint.rb +10 -6
  70. data/lib/shrine/plugins/derivatives.rb +19 -17
  71. data/lib/shrine/plugins/determine_mime_type.rb +3 -3
  72. data/lib/shrine/plugins/entity.rb +6 -6
  73. data/lib/shrine/plugins/metadata_attributes.rb +1 -1
  74. data/lib/shrine/plugins/model.rb +3 -3
  75. data/lib/shrine/plugins/presign_endpoint.rb +2 -2
  76. data/lib/shrine/plugins/pretty_location.rb +1 -1
  77. data/lib/shrine/plugins/processing.rb +1 -1
  78. data/lib/shrine/plugins/refresh_metadata.rb +2 -2
  79. data/lib/shrine/plugins/remote_url.rb +3 -3
  80. data/lib/shrine/plugins/remove_invalid.rb +10 -5
  81. data/lib/shrine/plugins/signature.rb +7 -6
  82. data/lib/shrine/plugins/store_dimensions.rb +18 -9
  83. data/lib/shrine/plugins/type_predicates.rb +113 -0
  84. data/lib/shrine/plugins/upload_endpoint.rb +3 -3
  85. data/lib/shrine/plugins/upload_options.rb +2 -2
  86. data/lib/shrine/plugins/url_options.rb +2 -2
  87. data/lib/shrine/plugins/validation.rb +9 -7
  88. data/lib/shrine/storage/linter.rb +4 -4
  89. data/lib/shrine/storage/s3.rb +62 -38
  90. data/lib/shrine/uploaded_file.rb +5 -1
  91. data/lib/shrine/version.rb +2 -2
  92. data/shrine.gemspec +6 -7
  93. metadata +23 -29
@@ -106,7 +106,7 @@ payload:
106
106
 
107
107
  A default log subscriber is added as well which logs these events:
108
108
 
109
- ```plaintext
109
+ ```
110
110
  MIME Type (33ms) – {:io=>StringIO, :uploader=>Shrine}
111
111
  ```
112
112
 
@@ -117,7 +117,7 @@ plugin :determine_mime_type, log_subscriber: -> (event) {
117
117
  Shrine.logger.info JSON.generate(name: event.name, duration: event.duration, **event.payload)
118
118
  }
119
119
  ```
120
- ```plaintext
120
+ ```
121
121
  {"name":"mime_type","duration":24,"io":"#<StringIO:0x00007fb7c5b08b80>","uploader":"Shrine"}
122
122
  ```
123
123
 
@@ -130,16 +130,16 @@ end
130
130
  photo = Photo.new(image_data: '{"id":"...","storage":"...","metadata":{...}}')
131
131
  attacher = ImageUploader::Attacher.from_entity(photo, :image)
132
132
 
133
- attacher.file #=> #<Shrine::UploadedFile @id="bc2e13.jpg" @storage_key=:store ...>
133
+ attacher.file #=> #<Shrine::UploadedFile id="bc2e13.jpg" storage=:store ...>
134
134
 
135
135
  attacher.attach(file)
136
- attacher.file #=> #<Shrine::UploadedFile @id="397eca.jpg" @storage_key=:store ...>
136
+ attacher.file #=> #<Shrine::UploadedFile id="397eca.jpg" storage=:store ...>
137
137
  attacher.column_values #=> { image_data: '{"id":"397eca.jpg","storage":"store","metadata":{...}}' }
138
138
 
139
139
  photo = Photo.new(attacher.column_values)
140
140
  attacher = ImageUploader::Attacher.from_entity(photo, :image)
141
141
 
142
- attacher.file #=> #<Shrine::UploadedFile @id="397eca.jpg" @storage_key=:store ...>
142
+ attacher.file #=> #<Shrine::UploadedFile id="397eca.jpg" storage=:store ...>
143
143
  ```
144
144
 
145
145
  ### Loading entity
@@ -14,7 +14,7 @@ the attacher:
14
14
 
15
15
  ```rb
16
16
  attacher = photo.image_attacher
17
- attacher.form_assign("image" => file, "title" => "...", "description" => "...")
17
+ attacher.form_assign({ "image" => file, "title" => "...", "description" => "..." })
18
18
  attacher.file #=> #<Shrine::UploadedFile>
19
19
  ```
20
20
 
@@ -22,17 +22,17 @@ It works with `remote_url`, `data_uri`, and `remove_attachment` plugins:
22
22
 
23
23
  ```rb
24
24
  # remote_url plugin
25
- attacher.form_assign("image_remote_url" => "https://example.com/...")
25
+ attacher.form_assign({ "image_remote_url" => "https://example.com/..." })
26
26
  attacher.file #=> #<Shrine::UploadedFile>
27
27
  ```
28
28
  ```rb
29
29
  # data_uri plugin
30
- attacher.form_assign("image_data_uri" => "data:image/jpeg;base64,...")
30
+ attacher.form_assign({ "image_data_uri" => "data:image/jpeg;base64,..." })
31
31
  attacher.file #=> #<Shrine::UploadedFile>
32
32
  ```
33
33
  ```rb
34
34
  # remove_attachment plugin
35
- attacher.form_assign("remove_image" => "1")
35
+ attacher.form_assign({ "remove_image" => "1" })
36
36
  attacher.file #=> nil
37
37
  ```
38
38
 
@@ -40,7 +40,7 @@ The return value is a hash with form params, with file param replaced with
40
40
  cached file data, which can later be assigned again to the record.
41
41
 
42
42
  ```rb
43
- attacher.form_assign("image" => file, "title" => "...", "description" => "...")
43
+ attacher.form_assign({ "image" => file, "title" => "...", "description" => "..." })
44
44
  #=> { :image => '{"id":"...","storage":"...","metadata":"..."}', "title" => "...", "description" => "..." }
45
45
  ```
46
46
 
@@ -7,15 +7,35 @@ of the attachment module, and call additional methods on the model that
7
7
  includes it.
8
8
 
9
9
  ```rb
10
- plugin :included do |name|
11
- # called when attachment module is included into a model
10
+ class ImageUploader < Shrine
11
+ plugin :included do |name|
12
+ # called when attachment module is included into a model
12
13
 
13
- self #=> #<Photo>
14
- name #=> :image
14
+ self #=> Photo (the model class)
15
+ name #=> :image
16
+ end
15
17
  end
16
18
  ```
17
19
  ```rb
18
- Photo.include Shrine::Attachment(:image)
20
+ class Photo
21
+ include ImageUploader::Attachment(:image) # triggers the included block
22
+ end
23
+ ```
24
+
25
+ For example, you can use it to define additional methods on the model:
26
+
27
+ ```rb
28
+ class ImageUploader < Shrine
29
+ plugin :included do |name|
30
+ define_method(:"#{name}_width") { send(name)&.width }
31
+ define_method(:"#{name}_height") { send(name)&.height }
32
+ end
33
+ end
34
+ ```
35
+ ```rb
36
+ photo = Photo.new(image: file)
37
+ photo.image_width #=> 1200
38
+ photo.image_height #=> 800
19
39
  ```
20
40
 
21
41
  [included]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/included.rb
@@ -70,7 +70,7 @@ payload:
70
70
 
71
71
  A default log subscriber is added as well which logs these events:
72
72
 
73
- ```plaintext
73
+ ```
74
74
  Extension (5ms) – {:mime_type=>"image/jpeg", :uploader=>Shrine}
75
75
  ```
76
76
 
@@ -81,7 +81,7 @@ plugin :infer_extension, log_subscriber: -> (event) {
81
81
  Shrine.logger.info JSON.generate(name: event.name, duration: event.duration, **event.payload)
82
82
  }
83
83
  ```
84
- ```plaintext
84
+ ```
85
85
  {"name":"extension","duration":5,"mime_type":"image/jpeg","uploader":"Shrine"}
86
86
  ```
87
87
 
@@ -34,7 +34,7 @@ uploaded_file.exists?
34
34
  uploaded_file.download
35
35
  uploaded_file.delete
36
36
  ```
37
- ```plaintext
37
+ ```
38
38
  Metadata (32ms) – {:storage=>:store, :io=>StringIO, :uploader=>Shrine}
39
39
  Upload (1523ms) – {:storage=>:store, :location=>"ed0e30ddec8b97813f2c1f4cfd1700b4", :io=>StringIO, :upload_options=>{}, :uploader=>Shrine}
40
40
  Exists (755ms) – {:storage=>:store, :location=>"ed0e30ddec8b97813f2c1f4cfd1700b4", :uploader=>Shrine}
@@ -2,21 +2,18 @@
2
2
  title: Metadata Attributes
3
3
  ---
4
4
 
5
- The [`metadata_attributes`][metadata_attributes] plugin allows you to sync
6
- attachment metadata to additional record attributes. You can provide a hash of
7
- mappings to the plugin call itself or the `Attacher.metadata_attributes`
8
- method:
5
+ The [`metadata_attributes`][metadata_attributes] plugin allows you to write
6
+ attachment metadata to additional record attributes. You can configure the
7
+ plugin with a hash of mappings:
9
8
 
10
9
  ```rb
11
10
  plugin :metadata_attributes, :size => :size, :mime_type => :type
12
-
13
11
  # or
14
-
15
12
  plugin :metadata_attributes
16
13
  Attacher.metadata_attributes :size => :size, :mime_type => :type
17
14
  ```
18
15
 
19
- The above configuration will sync `size` metadata field to `<attachment>_size`
16
+ The above configuration will write `size` metadata field to `<attachment>_size`
20
17
  record attribute, and `mime_type` metadata field to `<attachment>_type` record
21
18
  attribute.
22
19
 
@@ -32,6 +29,18 @@ user.avatar_size #=> nil
32
29
  user.avatar_type #=> nil
33
30
  ```
34
31
 
32
+ ## Model and Entity
33
+
34
+ With the [`model`][model] plugin, any method that internally calls
35
+ `Attacher#write` will trigger metadata attributes writing (`Attacher#assign`,
36
+ `Attacher#attach`, `Attacher#change`, `Attacher#set`).
37
+
38
+ ```rb
39
+ attacher.file.metadata["mime_type"] = "other/type"
40
+ attacher.write
41
+ attacher.record.avatar_type #=> "other/type"
42
+ ```
43
+
35
44
  If you're using the [`entity`][entity] plugin, metadata attributes will be
36
45
  added to `Attacher#column_values`:
37
46
 
@@ -45,6 +54,11 @@ attacher.column_values #=>
45
54
  # }
46
55
  ```
47
56
 
57
+ Any metadata attributes that were declared but are missing on the record will
58
+ be skipped.
59
+
60
+ ## Full attribute name
61
+
48
62
  If you want to specify the full record attribute name, pass the record
49
63
  attribute name as a string instead of a symbol.
50
64
 
@@ -56,8 +70,5 @@ photo.image = image
56
70
  photo.original_filename #=> "nature.jpg"
57
71
  ```
58
72
 
59
- Any metadata attributes that were declared but are missing on the record will
60
- be skipped.
61
-
62
73
  [metadata_attributes]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/metadata_attributes.rb
63
74
  [entity]: https://shrinerb.com/docs/plugins/entity
@@ -26,12 +26,12 @@ photo = Photo.new
26
26
 
27
27
  photo.image = file
28
28
 
29
- photo.image #=> #<Shrine::UploadedFile @id="bc2e13.jpg" @storage_key=:cache ...>
29
+ photo.image #=> #<Shrine::UploadedFile id="bc2e13.jpg" storage=:cache ...>
30
30
  photo.image_data #=> '{"id":"bc2e13.jpg","storage":"cache","metadata":{...}}'
31
31
 
32
32
  photo.image_attacher.finalize
33
33
 
34
- photo.image #=> #<Shrine::UploadedFile @id="397eca.jpg" @storage_key=:store ...>
34
+ photo.image #=> #<Shrine::UploadedFile id="397eca.jpg" storage=:store ...>
35
35
  photo.image_data #=> '{"id":"397eca.jpg","storage":"store","metadata":{...}}'
36
36
  ```
37
37
 
@@ -127,12 +127,12 @@ attacher = ImageUploader::Attacher.from_model(photo, :image)
127
127
 
128
128
  attacher.assign(file) # cache
129
129
 
130
- attacher.file #=> #<Shrine::UploadedFile @id="bc2e13.jpg" @storage_key=:cache ...>
130
+ attacher.file #=> #<Shrine::UploadedFile id="bc2e13.jpg" storage=:cache ...>
131
131
  photo.image_data #=> '{"id":"bc2e13.jpg","storage":"cache","metadata":{...}}'
132
132
 
133
133
  attacher.finalize # promote
134
134
 
135
- attacher.file #=> #<Shrine::UploadedFile @id="397eca.jpg" @storage_key=:store ...>
135
+ attacher.file #=> #<Shrine::UploadedFile id="397eca.jpg" storage=:store ...>
136
136
  photo.image_data #=> '{"id":"397eca.jpg","storage":"store","metadata":{...}}'
137
137
  ```
138
138
 
@@ -89,3 +89,4 @@ attacher.persist # saves the underlying record
89
89
 
90
90
  [activerecord]: https://shrinerb.com/docs/plugins/activerecord
91
91
  [sequel]: https://shrinerb.com/docs/plugins/sequel
92
+ [backgrounding]: https://shrinerb.com/docs/plugins/backgrounding
@@ -12,17 +12,18 @@ plugin :refresh_metadata
12
12
  It provides `#refresh_metadata!` method, which triggers metadata extraction
13
13
  (calls `Shrine#extract_metadata`) with the uploaded file opened for reading,
14
14
  and updates the existing metadata hash with the results. This can be done
15
- on the attacher or the uploaded file level.
15
+ on the `Shrine::Attacher` or the `Shrine::UploadedFile` level.
16
16
 
17
17
  ## Attacher
18
18
 
19
19
  Calling `#refresh_metadata!` on a `Shrine::Attacher` object will re-extract
20
- metadata of the attached file. When used with a [model], it will write new file
21
- data back into the attachment attribute.
20
+ metadata of the attached file, and when used with a [model], it will write new
21
+ file data back into the attachment attribute.
22
22
 
23
23
  ```rb
24
24
  attacher.refresh_metadata!
25
- attacher.file.metadata # re-extracted metadata
25
+ attacher.file.metadata # re-extracted metadata
26
+ attacher.record.file_data #=> '{ ... data with updated metadata ... }'
26
27
  ```
27
28
 
28
29
  The `Attacher#context` hash will be forwarded to metadata extraction, as well
@@ -40,7 +40,12 @@ around [open-uri].
40
40
  You can pass options to the downloader via the `:downloader` option:
41
41
 
42
42
  ```rb
43
- attacher.assign_remote_url(url, downloader: { 'Authorization' => 'Basic ...' })
43
+ attacher.assign_remote_url url, downloader: {
44
+ headers: { "Authorization" => "Basic ..." },
45
+ read_timeout: 30, open_timeout: 30,
46
+ max_redirects: 5,
47
+ # ...
48
+ }
44
49
  ```
45
50
 
46
51
  You can also change the downloader:
@@ -166,7 +171,7 @@ following payload:
166
171
 
167
172
  A default log subscriber is added as well which logs these events:
168
173
 
169
- ```plaintext
174
+ ```
170
175
  Remote URL (1550ms) – {:remote_url=>"https://example.com/image.jpg",:download_options=>{},:uploader=>Shrine}
171
176
  ```
172
177
 
@@ -177,7 +182,7 @@ plugin :remote_url, log_subscriber: -> (event) {
177
182
  Shrine.logger.info JSON.generate(name: event.name, duration: event.duration, **event.payload)
178
183
  }
179
184
  ```
180
- ```plaintext
185
+ ```
181
186
  {"name":"remote_url","duration":5,"remote_url":"https://example.com/image.jpg","download_options":{},"uploader":"Shrine"}
182
187
  ```
183
188
 
@@ -11,9 +11,17 @@ plugin :remove_invalid
11
11
  ```
12
12
 
13
13
  ```rb
14
- photo.image = file # invalid file
14
+ # without previous file
15
+ photo.image #=> nil
16
+ photo.image = file # validation fails, assignment is reverted
15
17
  photo.valid? #=> false
16
18
  photo.image #=> nil
19
+
20
+ # with previous file
21
+ photo.image #=> #<Shrine::UploadedFile id="foo" ...>
22
+ photo.image = file # validation fails, assignment is reverted
23
+ photo.valid? #=> false
24
+ photo.image #=> #<Shrine::UploadedFile id="foo" ...>
17
25
  ```
18
26
 
19
27
  [remove_invalid]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/remove_invalid.rb
@@ -27,12 +27,12 @@ photo = Photo.new
27
27
 
28
28
  photo.image = file # cache attachment
29
29
 
30
- photo.image #=> #<Shrine::UploadedFile @id="bc2e13.jpg" @storage_key=:cache ...>
30
+ photo.image #=> #<Shrine::UploadedFile id="bc2e13.jpg" storage=:cache ...>
31
31
  photo.image_data #=> '{"id":"bc2e13.jpg","storage":"cache","metadata":{...}}'
32
32
 
33
33
  photo.save # persist, promote attachment, then persist again
34
34
 
35
- photo.image #=> #<Shrine::UploadedFile @id="397eca.jpg" @storage_key=:store ...>
35
+ photo.image #=> #<Shrine::UploadedFile id="397eca.jpg" storage=:store ...>
36
36
  photo.image_data #=> '{"id":"397eca.jpg","storage":"store","metadata":{...}}'
37
37
 
38
38
  photo.destroy # delete attachment
@@ -161,14 +161,14 @@ attacher = ImageUploader::Attacher.from_model(photo, :image)
161
161
 
162
162
  attacher.assign(file) # cache
163
163
 
164
- attacher.file #=> #<Shrine::UploadedFile @id="bc2e13.jpg" @storage_key=:cache ...>
164
+ attacher.file #=> #<Shrine::UploadedFile id="bc2e13.jpg" storage=:cache ...>
165
165
  photo.image_data #=> '{"id":"bc2e13.jpg","storage":"cache","metadata":{...}}'
166
166
 
167
167
  photo.save # persist
168
168
  attacher.finalize # promote
169
169
  photo.save # persist
170
170
 
171
- attacher.file #=> #<Shrine::UploadedFile @id="397eca.jpg" @storage_key=:store ...>
171
+ attacher.file #=> #<Shrine::UploadedFile id="397eca.jpg" storage=:store ...>
172
172
  photo.image_data #=> '{"id":"397eca.jpg","storage":"store","metadata":{...}}'
173
173
  ```
174
174
 
@@ -55,6 +55,15 @@ add_metadata :md5 do |io, action: nil, **|
55
55
  end
56
56
  ```
57
57
 
58
+ ## Rewinding
59
+
60
+ If you want to calculate signature from a non-rewindable IO object, you can
61
+ tell Shrine to skip rewinding:
62
+
63
+ ```rb
64
+ Shrine.calculate_signature(io, :md5, rewind: false)
65
+ ```
66
+
58
67
  ## Instrumentation
59
68
 
60
69
  If the `instrumentation` plugin has been loaded, the `signature` plugin adds
@@ -76,7 +85,7 @@ following payload:
76
85
 
77
86
  A default log subscriber is added as well which logs these events:
78
87
 
79
- ```plaintext
88
+ ```
80
89
  MIME Type (33ms) – {:io=>StringIO, :uploader=>Shrine}
81
90
  ```
82
91
 
@@ -87,7 +96,7 @@ plugin :signature, log_subscriber: -> (event) {
87
96
  Shrine.logger.info JSON.generate(name: event.name, duration: event.duration, **event.payload)
88
97
  }
89
98
  ```
90
- ```plaintext
99
+ ```
91
100
  {"name":"signature","duration":24,"io":"#<StringIO:0x00007fb7c5b08b80>","uploader":"Shrine"}
92
101
  ```
93
102
 
@@ -110,7 +110,7 @@ following payload:
110
110
 
111
111
  A default log subscriber is added as well which logs these events:
112
112
 
113
- ```plaintext
113
+ ```
114
114
  Image Dimensions (108ms) – {:io=>File, :uploader=>Shrine}
115
115
  ```
116
116
 
@@ -121,7 +121,7 @@ plugin :store_dimensions, log_subscriber: -> (event) {
121
121
  Shrine.logger.info JSON.generate(name: event.name, duration: event.duration, **event.payload)
122
122
  }
123
123
  ```
124
- ```plaintext
124
+ ```
125
125
  {"name":"image_dimensions","duration":114,"io":"#<File:0x00007fc445371d90>","uploader":"Shrine"}
126
126
  ```
127
127
 
@@ -0,0 +1,96 @@
1
+ ---
2
+ title: Type Predicates
3
+ ---
4
+
5
+ The [`type_predicates`][type_predicates] plugin adds predicate methods to
6
+ `Shrine::UploadedFile` based on the MIME type. By default, it uses the
7
+ [MiniMime] gem for looking up MIME types.
8
+
9
+ ```rb
10
+ # Gemfile
11
+ gem "mini_mime"
12
+ ```
13
+ ```rb
14
+ Shrine.plugin :type_predicates
15
+ ```
16
+
17
+ ## General predicates
18
+
19
+ The plugin adds four predicate methods based on the general type of the file:
20
+
21
+ ```rb
22
+ file.image? # returns true for any "image/*" MIME type
23
+ file.video? # returns true for any "video/*" MIME type
24
+ file.audio? # returns true for any "audio/*" MIME type
25
+ file.text? # returns true for any "text/*" MIME type
26
+ ```
27
+
28
+ If `mime_type` metadata value is nil, `Shrine::Error` will be raised.
29
+
30
+ ## Specific predicates
31
+
32
+ The `UploadedFile#type?` method takes a file extension, and returns whether the
33
+ `mime_type` metadata value of the uploaded file matches the MIME type
34
+ associated to the given file extension.
35
+
36
+ ```rb
37
+ file.type?(:jpg) # returns true if MIME type is "image/jpeg"
38
+ file.type?(:svg) # returns true if MIME type is "image/svg+xml"
39
+ file.type?(:mov) # returns true if MIME type is "video/quicktime"
40
+ file.type?(:ppt) # returns true if MIME type is "application/vnd.ms-powerpoint"
41
+ ...
42
+ ```
43
+
44
+ For convenience, you can create predicate methods for specific file types:
45
+
46
+ ```rb
47
+ Shrine.plugin :type_predicates, methods: %i[jpg svg mov ppt]
48
+ ```
49
+ ```rb
50
+ file.jpg? # returns true if MIME type is "image/jpeg"
51
+ file.svg? # returns true if MIME type is "image/svg+xml"
52
+ file.mov? # returns true if MIME type is "video/quicktime"
53
+ file.ppt? # returns true if MIME type is "application/vnd.ms-powerpoint"
54
+ ```
55
+
56
+ If `mime_type` metadata value is nil, or the underlying MIME type library
57
+ doesn't recognize a given type, `Shrine::Error` will be raised.
58
+
59
+ ### MIME database
60
+
61
+ The MIME type lookup by file extension is done by the underlying MIME type
62
+ library ([MiniMime] by default). You can change the MIME type library via the
63
+ `:mime` plugin option:
64
+
65
+ ```rb
66
+ Shrine.plugin :type_predicates, mime: :marcel # requires adding "marcel" gem to the Gemfile
67
+ ```
68
+
69
+ The following MIME type libraries are supported:
70
+
71
+ | Name | Description |
72
+ | :---- | :--------- |
73
+ | `:mini_mime` | (**Default**.) Uses [MiniMime] gem to look up MIME type by extension. |
74
+ | `:mime_types` | Uses [mime-types] gem to look up MIME type by extension. |
75
+ | `:mimemagic` | Uses [MimeMagic] gem to look up MIME type by extension. |
76
+ | `:marcel` | Uses [Marcel] gem to look up MIME type by extension. |
77
+ | `:rack_mime` | Uses [Rack::Mime] to look up MIME type by extension. |
78
+
79
+ You can also specify a custom block, which receives the extension and is
80
+ expected to return the corresponding MIME type. Inside the block you can call
81
+ into existing MIME type libraries:
82
+
83
+ ```rb
84
+ Shrine.plugin :type_predicates, mime: -> (extension) do
85
+ mime_type = Shrine.type_lookup(extension, :marcel)
86
+ mime_type ||= Shrine.type_lookup(extension, :mini_mime)
87
+ mime_type
88
+ end
89
+ ```
90
+
91
+ [type_predicates]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/type_predicates.rb
92
+ [MiniMime]: https://github.com/discourse/mini_mime
93
+ [mime-types]: https://github.com/mime-types/ruby-mime-types
94
+ [MimeMagic]: https://github.com/minad/mimemagic
95
+ [Marcel]: https://github.com/basecamp/marcel
96
+ [Rack::Mime]: https://github.com/rack/rack/blob/master/lib/rack/mime.rb