shrine 0.9.0

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 (41) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +663 -0
  4. data/doc/creating_plugins.md +100 -0
  5. data/doc/creating_storages.md +108 -0
  6. data/doc/direct_s3.md +97 -0
  7. data/doc/migrating_storage.md +79 -0
  8. data/doc/regenerating_versions.md +38 -0
  9. data/lib/shrine.rb +806 -0
  10. data/lib/shrine/plugins/activerecord.rb +89 -0
  11. data/lib/shrine/plugins/background_helpers.rb +148 -0
  12. data/lib/shrine/plugins/cached_attachment_data.rb +47 -0
  13. data/lib/shrine/plugins/data_uri.rb +93 -0
  14. data/lib/shrine/plugins/default_storage.rb +39 -0
  15. data/lib/shrine/plugins/delete_invalid.rb +25 -0
  16. data/lib/shrine/plugins/determine_mime_type.rb +119 -0
  17. data/lib/shrine/plugins/direct_upload.rb +274 -0
  18. data/lib/shrine/plugins/dynamic_storage.rb +57 -0
  19. data/lib/shrine/plugins/hooks.rb +123 -0
  20. data/lib/shrine/plugins/included.rb +48 -0
  21. data/lib/shrine/plugins/keep_files.rb +54 -0
  22. data/lib/shrine/plugins/logging.rb +158 -0
  23. data/lib/shrine/plugins/migration_helpers.rb +61 -0
  24. data/lib/shrine/plugins/moving.rb +75 -0
  25. data/lib/shrine/plugins/multi_delete.rb +47 -0
  26. data/lib/shrine/plugins/parallelize.rb +62 -0
  27. data/lib/shrine/plugins/pretty_location.rb +32 -0
  28. data/lib/shrine/plugins/recache.rb +36 -0
  29. data/lib/shrine/plugins/remote_url.rb +127 -0
  30. data/lib/shrine/plugins/remove_attachment.rb +59 -0
  31. data/lib/shrine/plugins/restore_cached.rb +36 -0
  32. data/lib/shrine/plugins/sequel.rb +94 -0
  33. data/lib/shrine/plugins/store_dimensions.rb +82 -0
  34. data/lib/shrine/plugins/validation_helpers.rb +168 -0
  35. data/lib/shrine/plugins/versions.rb +177 -0
  36. data/lib/shrine/storage/file_system.rb +165 -0
  37. data/lib/shrine/storage/linter.rb +94 -0
  38. data/lib/shrine/storage/s3.rb +118 -0
  39. data/lib/shrine/version.rb +14 -0
  40. data/shrine.gemspec +46 -0
  41. metadata +364 -0
@@ -0,0 +1,94 @@
1
+ require "shrine"
2
+
3
+ require "forwardable"
4
+ require "stringio"
5
+ require "tempfile"
6
+
7
+ class Shrine
8
+ # Error which is thrown when Storage::Linter fails.
9
+ class LintError < Error
10
+ attr_reader :errors
11
+
12
+ def initialize(errors)
13
+ @errors = errors
14
+ super(errors.to_s)
15
+ end
16
+ end
17
+
18
+ module Storage
19
+ # Checks if the storage conforms to Shrine's specification. If the check
20
+ # fails a LintError is raised.
21
+ class Linter
22
+ def self.call(storage)
23
+ new(storage).call
24
+ end
25
+
26
+ def initialize(storage)
27
+ @storage = storage
28
+ @errors = []
29
+ end
30
+
31
+ def call
32
+ fakeio = FakeIO.new("image")
33
+
34
+ storage.upload(fakeio, "foo.jpg", {"mime_type" => "image/jpeg"})
35
+ error! "#upload doesn't rewind the file" if !(fakeio.read == "image")
36
+
37
+ file = storage.download("foo.jpg")
38
+ error! "#download doesn't return a Tempfile" if !file.is_a?(Tempfile)
39
+ error! "#download doesn't return the uploaded file" if !(file.read == "image")
40
+
41
+ if storage.respond_to?(:move)
42
+ if storage.respond_to?(:movable?)
43
+ error! "#movable? doesn't accept 2 arguments" if !(storage.method(:movable?).arity == 2)
44
+ error! "#move doesn't accept 3 arguments" if !(storage.method(:move).arity == -3)
45
+ else
46
+ error! "doesn't respond to #movable?" if !storage.respond_to?(:movable?)
47
+ end
48
+ end
49
+
50
+ begin
51
+ Shrine.io!(storage.open("foo.jpg"))
52
+ rescue Shrine::InvalidFile => error
53
+ error! "#open doesn't return a valid IO object"
54
+ end
55
+
56
+ error! "#read doesn't return content of the uploaded file" if !(storage.read("foo.jpg") == "image")
57
+ error! "#exists? returns false for a file that was uploaded" if !storage.exists?("foo.jpg")
58
+ error! "#url doesn't return a string" if !storage.url("foo.jpg", {}).is_a?(String)
59
+
60
+ storage.delete("foo.jpg")
61
+ error! "#exists? returns true for a file that was deleted" if storage.exists?("foo.jpg")
62
+
63
+ begin
64
+ storage.clear!
65
+ error! "#clear! should raise Shrine::Confirm unless :confirm is passed in"
66
+ rescue Shrine::Confirm
67
+ end
68
+
69
+ storage.upload(FakeIO.new("image"), "foo.jpg", {"mime_type" => "image/jpeg"})
70
+ storage.clear!(:confirm)
71
+ error! "a file still #exists? after #clear! was called" if storage.exists?("foo.jpg")
72
+
73
+ raise LintError.new(@errors) if @errors.any?
74
+ end
75
+
76
+ private
77
+
78
+ def error!(message)
79
+ @errors << message
80
+ end
81
+
82
+ attr_reader :storage
83
+
84
+ class FakeIO
85
+ def initialize(content)
86
+ @io = StringIO.new(content)
87
+ end
88
+
89
+ extend Forwardable
90
+ delegate Shrine::IO_METHODS.keys => :@io
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,118 @@
1
+ require "aws-sdk"
2
+ require "down"
3
+
4
+ class Shrine
5
+ module Storage
6
+ class S3
7
+ attr_reader :prefix, :bucket, :s3
8
+
9
+ # Example:
10
+ #
11
+ # Shrine::Storage::S3.new(
12
+ # access_key_id: "xyz",
13
+ # secret_access_key: "abc",
14
+ # region: "eu-west-1"
15
+ # bucket: "my-app",
16
+ # prefix: "cache",
17
+ # )
18
+ #
19
+ # The above storage will store file into the "my-app" bucket in the
20
+ # "cache" directory.
21
+ def initialize(bucket:, prefix: nil, **s3_options)
22
+ @prefix = prefix
23
+ @s3 = Aws::S3::Resource.new(s3_options)
24
+ @bucket = @s3.bucket(bucket)
25
+ end
26
+
27
+ # If the file is an UploadedFile from S3, issues a COPY command, otherwise
28
+ # uploads the file.
29
+ #
30
+ # It assigns the correct "Content-Type" taken from the MIME type, because
31
+ # by default S3 sets everything to "application/octet-stream".
32
+ def upload(io, id, metadata = {})
33
+ options = {content_type: metadata["mime_type"]}
34
+
35
+ if copyable?(io)
36
+ object(id).copy_from(io.storage.object(io.id), **options)
37
+ else
38
+ object(id).put(body: io, **options)
39
+ io.rewind
40
+ end
41
+ end
42
+
43
+ # Downloads the file from S3, and returns a `Tempfile`.
44
+ def download(id)
45
+ Down.download(url(id))
46
+ end
47
+
48
+ # Alias for #download.
49
+ def open(id)
50
+ download(id)
51
+ end
52
+
53
+ # Returns the contents of the file as a String.
54
+ def read(id)
55
+ object(id).get.body.read
56
+ end
57
+
58
+ # Returns true file exists on S3.
59
+ def exists?(id)
60
+ object(id).exists?
61
+ end
62
+
63
+ # Deletes the file from S3.
64
+ def delete(id)
65
+ object(id).delete
66
+ end
67
+
68
+ # This is called when multiple files are being deleted at once. Issues
69
+ # a single MULTI DELETE command.
70
+ def multi_delete(ids)
71
+ bucket.delete_objects(delete: {objects: ids.map { |id| {key: id} }})
72
+ end
73
+
74
+ # Returns the presigned URL to the file. If `download: true` is passed,
75
+ # returns a forced download link.
76
+ def url(id, download: nil, **options)
77
+ options[:response_content_disposition] = "attachment" if download
78
+ object(id).presigned_url(:get, **options)
79
+ end
80
+
81
+ # Deletes all files from the storage (requires confirmation).
82
+ def clear!(confirm = nil)
83
+ raise Shrine::Confirm unless confirm == :confirm
84
+ @bucket.clear!
85
+ end
86
+
87
+ # Returns a signature for direct uploads. Internally it calls
88
+ # [`Aws::S3::Bucket#presigned_post`], and forwards any additional options
89
+ # to it.
90
+ #
91
+ # [`Aws::S3::Bucket#presigned_post`]: http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Bucket.html#presigned_post-instance_method
92
+ def presign(id, **options)
93
+ @bucket.presigned_post(key: object(id).key, **options)
94
+ end
95
+
96
+ protected
97
+
98
+ # Returns the S3 object.
99
+ def object(id)
100
+ @bucket.object([*prefix, id].join("/"))
101
+ end
102
+
103
+ # This is used to check whether an S3 file is copyable.
104
+ def access_key_id
105
+ @s3.client.config.credentials.access_key_id
106
+ end
107
+
108
+ private
109
+
110
+ # The file is copyable if it's on S3 and on the same Amazon account.
111
+ def copyable?(io)
112
+ io.respond_to?(:storage) &&
113
+ io.storage.is_a?(Storage::S3) &&
114
+ io.storage.access_key_id == access_key_id
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,14 @@
1
+ class Shrine
2
+ def self.version
3
+ Gem::Version.new VERSION::STRING
4
+ end
5
+
6
+ module VERSION
7
+ MAJOR = 0
8
+ MINOR = 9
9
+ TINY = 0
10
+ PRE = nil
11
+
12
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
13
+ end
14
+ end
@@ -0,0 +1,46 @@
1
+ require "./lib/shrine/version"
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "shrine"
5
+ gem.version = Shrine.version
6
+
7
+ gem.required_ruby_version = ">= 2.1"
8
+
9
+ gem.summary = "Toolkit for file uploads in Ruby"
10
+ gem.description = "Toolkit for file uploads in Ruby"
11
+ gem.homepage = "https://github.com/janko-m/shrine"
12
+ gem.authors = ["Janko Marohnić"]
13
+ gem.email = ["janko.marohnic@gmail.com"]
14
+ gem.license = "MIT"
15
+
16
+ gem.files = Dir["README.md", "LICENSE.txt", "lib/**/*.rb", "shrine.gemspec", "doc/*.md"]
17
+ gem.require_path = "lib"
18
+
19
+ gem.add_dependency "down", ">= 1.0.2"
20
+
21
+ gem.add_development_dependency "minitest", "~> 5.8"
22
+ gem.add_development_dependency "minitest-hooks", "~> 1.3.0"
23
+ gem.add_development_dependency "mocha"
24
+ gem.add_development_dependency "vcr", "~> 2.9"
25
+ gem.add_development_dependency "webmock"
26
+ gem.add_development_dependency "rack-test"
27
+ gem.add_development_dependency "dotenv"
28
+
29
+ gem.add_development_dependency "roda"
30
+ gem.add_development_dependency "ruby-filemagic", "~> 0.7" unless RUBY_ENGINE == "jruby"
31
+ gem.add_development_dependency "mimemagic"
32
+ gem.add_development_dependency "mime-types"
33
+ gem.add_development_dependency "fastimage"
34
+ gem.add_development_dependency "thread", "~> 0.2"
35
+ gem.add_development_dependency "aws-sdk", "~> 2.1"
36
+ gem.add_development_dependency "image_processing", ">= 0.2.4"
37
+ gem.add_development_dependency "mini_magick", ">= 4.3.5"
38
+
39
+ gem.add_development_dependency "sequel"
40
+ gem.add_development_dependency "activerecord"
41
+ unless RUBY_ENGINE == "jruby"
42
+ gem.add_development_dependency "sqlite3"
43
+ else
44
+ gem.add_development_dependency "activerecord-jdbcsqlite3-adapter"
45
+ end
46
+ end
metadata ADDED
@@ -0,0 +1,364 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: shrine
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ platform: ruby
6
+ authors:
7
+ - Janko Marohnić
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-10-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: down
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 1.0.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.8'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5.8'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest-hooks
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.3.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.3.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: mocha
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: vcr
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.9'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.9'
83
+ - !ruby/object:Gem::Dependency
84
+ name: webmock
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rack-test
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: dotenv
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: roda
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: ruby-filemagic
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '0.7'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '0.7'
153
+ - !ruby/object:Gem::Dependency
154
+ name: mimemagic
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: mime-types
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: fastimage
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: thread
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - "~>"
200
+ - !ruby/object:Gem::Version
201
+ version: '0.2'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - "~>"
207
+ - !ruby/object:Gem::Version
208
+ version: '0.2'
209
+ - !ruby/object:Gem::Dependency
210
+ name: aws-sdk
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - "~>"
214
+ - !ruby/object:Gem::Version
215
+ version: '2.1'
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - "~>"
221
+ - !ruby/object:Gem::Version
222
+ version: '2.1'
223
+ - !ruby/object:Gem::Dependency
224
+ name: image_processing
225
+ requirement: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - ">="
228
+ - !ruby/object:Gem::Version
229
+ version: 0.2.4
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - ">="
235
+ - !ruby/object:Gem::Version
236
+ version: 0.2.4
237
+ - !ruby/object:Gem::Dependency
238
+ name: mini_magick
239
+ requirement: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - ">="
242
+ - !ruby/object:Gem::Version
243
+ version: 4.3.5
244
+ type: :development
245
+ prerelease: false
246
+ version_requirements: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - ">="
249
+ - !ruby/object:Gem::Version
250
+ version: 4.3.5
251
+ - !ruby/object:Gem::Dependency
252
+ name: sequel
253
+ requirement: !ruby/object:Gem::Requirement
254
+ requirements:
255
+ - - ">="
256
+ - !ruby/object:Gem::Version
257
+ version: '0'
258
+ type: :development
259
+ prerelease: false
260
+ version_requirements: !ruby/object:Gem::Requirement
261
+ requirements:
262
+ - - ">="
263
+ - !ruby/object:Gem::Version
264
+ version: '0'
265
+ - !ruby/object:Gem::Dependency
266
+ name: activerecord
267
+ requirement: !ruby/object:Gem::Requirement
268
+ requirements:
269
+ - - ">="
270
+ - !ruby/object:Gem::Version
271
+ version: '0'
272
+ type: :development
273
+ prerelease: false
274
+ version_requirements: !ruby/object:Gem::Requirement
275
+ requirements:
276
+ - - ">="
277
+ - !ruby/object:Gem::Version
278
+ version: '0'
279
+ - !ruby/object:Gem::Dependency
280
+ name: sqlite3
281
+ requirement: !ruby/object:Gem::Requirement
282
+ requirements:
283
+ - - ">="
284
+ - !ruby/object:Gem::Version
285
+ version: '0'
286
+ type: :development
287
+ prerelease: false
288
+ version_requirements: !ruby/object:Gem::Requirement
289
+ requirements:
290
+ - - ">="
291
+ - !ruby/object:Gem::Version
292
+ version: '0'
293
+ description: Toolkit for file uploads in Ruby
294
+ email:
295
+ - janko.marohnic@gmail.com
296
+ executables: []
297
+ extensions: []
298
+ extra_rdoc_files: []
299
+ files:
300
+ - LICENSE.txt
301
+ - README.md
302
+ - doc/creating_plugins.md
303
+ - doc/creating_storages.md
304
+ - doc/direct_s3.md
305
+ - doc/migrating_storage.md
306
+ - doc/regenerating_versions.md
307
+ - lib/shrine.rb
308
+ - lib/shrine/plugins/activerecord.rb
309
+ - lib/shrine/plugins/background_helpers.rb
310
+ - lib/shrine/plugins/cached_attachment_data.rb
311
+ - lib/shrine/plugins/data_uri.rb
312
+ - lib/shrine/plugins/default_storage.rb
313
+ - lib/shrine/plugins/delete_invalid.rb
314
+ - lib/shrine/plugins/determine_mime_type.rb
315
+ - lib/shrine/plugins/direct_upload.rb
316
+ - lib/shrine/plugins/dynamic_storage.rb
317
+ - lib/shrine/plugins/hooks.rb
318
+ - lib/shrine/plugins/included.rb
319
+ - lib/shrine/plugins/keep_files.rb
320
+ - lib/shrine/plugins/logging.rb
321
+ - lib/shrine/plugins/migration_helpers.rb
322
+ - lib/shrine/plugins/moving.rb
323
+ - lib/shrine/plugins/multi_delete.rb
324
+ - lib/shrine/plugins/parallelize.rb
325
+ - lib/shrine/plugins/pretty_location.rb
326
+ - lib/shrine/plugins/recache.rb
327
+ - lib/shrine/plugins/remote_url.rb
328
+ - lib/shrine/plugins/remove_attachment.rb
329
+ - lib/shrine/plugins/restore_cached.rb
330
+ - lib/shrine/plugins/sequel.rb
331
+ - lib/shrine/plugins/store_dimensions.rb
332
+ - lib/shrine/plugins/validation_helpers.rb
333
+ - lib/shrine/plugins/versions.rb
334
+ - lib/shrine/storage/file_system.rb
335
+ - lib/shrine/storage/linter.rb
336
+ - lib/shrine/storage/s3.rb
337
+ - lib/shrine/version.rb
338
+ - shrine.gemspec
339
+ homepage: https://github.com/janko-m/shrine
340
+ licenses:
341
+ - MIT
342
+ metadata: {}
343
+ post_install_message:
344
+ rdoc_options: []
345
+ require_paths:
346
+ - lib
347
+ required_ruby_version: !ruby/object:Gem::Requirement
348
+ requirements:
349
+ - - ">="
350
+ - !ruby/object:Gem::Version
351
+ version: '2.1'
352
+ required_rubygems_version: !ruby/object:Gem::Requirement
353
+ requirements:
354
+ - - ">="
355
+ - !ruby/object:Gem::Version
356
+ version: '0'
357
+ requirements: []
358
+ rubyforge_project:
359
+ rubygems_version: 2.4.5
360
+ signing_key:
361
+ specification_version: 4
362
+ summary: Toolkit for file uploads in Ruby
363
+ test_files: []
364
+ has_rdoc: