shrine-transloadit 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f9ad060395c4432e137702840eba7f23eef980b5
4
+ data.tar.gz: 983a7aaf98794573d4f946fe14d0014162b02bfd
5
+ SHA512:
6
+ metadata.gz: 48003055afa7b725f0f42213daf2dedb6ecf91d03f8c5805921b0ff57953202aa0a8463300a40246cb1b0984eda816972cd8a0af2b99676188ac62bd18e010c0
7
+ data.tar.gz: a4aec56c9856366f4d8fb87c00ce6d6ff8f91750033ed6c0aba48b241533358c6bc5af7b4930f7bda463ebf06ff35322de5fc948d229597b8e855808439d4bdc
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Janko Marohnić
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,345 @@
1
+ # Shrine::Plugins::Transloadit
2
+
3
+ Provides [Transloadit] integration for [Shrine].
4
+
5
+ Transloadit offers advanced file processing for all sorts of media, including
6
+ images, videos, audio, and documents, along with importing from and exporting
7
+ to various file storage services.
8
+
9
+ ## Setup
10
+
11
+ While Transloadit is able to export processed files to [many storage
12
+ services], this plugin currently supports only Amazon S3 (just because there
13
+ are no Shrine integrations written for other services on that list yet).
14
+
15
+ ```rb
16
+ gem "shrine-transloadit"
17
+ gem "aws-sdk"
18
+ ```
19
+
20
+ ```rb
21
+ require "shrine"
22
+ require "shrine/storage/s3"
23
+
24
+ s3_options = {
25
+ access_key_id: "xyz",
26
+ secret_access_key: "abc",
27
+ region: "my-region",
28
+ bucket: "my-app",
29
+ }
30
+
31
+ Shrine.storages = {
32
+ cache: Shrine::Storage::S3.new(prefix: "cache", **s3_options),
33
+ store: Shrine::Storage::S3.new(prefix: "store", **s3_options),
34
+ }
35
+
36
+ Shrine.plugin :transloadit,
37
+ auth_key: "your transloadit key",
38
+ auth_secret: "your transloadit secret"
39
+ ```
40
+ ```rb
41
+ post "/webhooks/transloadit" do
42
+ Shrine::Attacher.transloadit_save(params)
43
+ end
44
+ ```
45
+
46
+ ## How it works
47
+
48
+ Transloadit works in a way that you create an "assembly", which contains all
49
+ information about how the file(s) should be processed, from import to export.
50
+ Processing itself happens asynchronously, and you can give Transloadit a URL
51
+ which it will POST results to when processing finishes.
52
+
53
+ This plugin allows you to easily implement this webhook flow. You can intercept
54
+ promoting, and submit a Transloadit assembly using the cached file, along with
55
+ a URL to the route in your app where you'd like Transloadit to POST the results
56
+ of processing. Then you can call the plugin again in the route to save the
57
+ results to your attachment column.
58
+
59
+ ## Usage
60
+
61
+ Transloadit assemblies are built inside `#transloadit_process` method in your
62
+ uploader, and you can use some convenient helper methods which the plugin
63
+ provides.
64
+
65
+ ```rb
66
+ class MyUploader < Shrine
67
+ def transloadit_process(io, context)
68
+ resized = transloadit_file(io)
69
+ .add_step("resize", "/image/resize", width: 800)
70
+
71
+ transloadit_assembly(resized, context: context)
72
+ end
73
+ end
74
+ ```
75
+
76
+ These helper methods just provide a higher-level interface over the
77
+ [transloadit gem], which you might want look at to get a better understanding
78
+ of how building assemblies works.
79
+
80
+ In short, in Transloadit every action, be it import, processing, or export, is
81
+ a "step". Each step is defined by its [robot and arguments], and needs to have
82
+ a *unique name*. Transloadit allows you to define the entire processing flow
83
+ (which can result in multiple files) as a collection of steps, which is called
84
+ an "assembly". Once the assembly is built it can be submitted to Transloadit.
85
+
86
+ ### Versions
87
+
88
+ With Transloadit you can create multiple files in a single assembly, and this
89
+ plugin allows you to leverage that in form of a hash of versions.
90
+
91
+ ```rb
92
+ class MyUploader < Shrine
93
+ plugin :versions
94
+
95
+ def transloadit_process(io, context)
96
+ original = transloadit_file(io)
97
+ medium = original.add_step("resize_500", "/image/resize", width: 500)
98
+ small = original.add_step("resize_300", "/image/resize", width: 300)
99
+
100
+ files = {original: original, medium: medium, small: small}
101
+
102
+ transloadit_assembly(files, context: context)
103
+ end
104
+ end
105
+ ```
106
+
107
+ ### Webhooks
108
+
109
+ Transloadit performs its processing asynchronously, and you can provide a URL
110
+ where you want Transloadit to POST results of processing once it's finished.
111
+
112
+ ```rb
113
+ class MyUploader < Shrine
114
+ def transloadit_process(io, context)
115
+ # ...
116
+
117
+ transloadit_assembly(files, notify_url: "http://myapp.com/webhooks/transloadit")
118
+ end
119
+ end
120
+ ```
121
+
122
+ Then in your `POST /webhooks/transloadit` route you can call the plugin to
123
+ automatically save the results to the attachment column in Shrine's format.
124
+
125
+ ```rb
126
+ post "/webhooks/transloadit" do
127
+ Shrine::Attacher.transloadit_save(params)
128
+ end
129
+ ```
130
+
131
+ ### Templates
132
+
133
+ Transloadit recommends using [templates], since they allow you to replay failed
134
+ assemblies, and also allow you not to expose credentials in your HTML.
135
+
136
+ Here is an example where the whole processing is defined inside a template,
137
+ and we just set the location of the imported file.
138
+
139
+ ```rb
140
+ # Your saved template
141
+ {
142
+ steps: {
143
+ import: {
144
+ robot: "/http/import",
145
+ url: "..."
146
+ },
147
+ resize: {
148
+ robot: "/image/resize",
149
+ use: "import",
150
+ width: 800
151
+ }
152
+ }
153
+ }
154
+ ```
155
+ ```rb
156
+ class MyUploader < Shrine
157
+ def transloadit_process(io, context)
158
+ transloadit_assembly("my_template", steps: {import: {url: io.url}})
159
+ end
160
+ end
161
+ ```
162
+
163
+ ### Backgrounding
164
+
165
+ Even though submitting a Transloadit assembly doesn't require any uploading, it
166
+ still does two HTTP requests, so you might want to put it into a backgrond job.
167
+ This plugin naturally hooks onto Shrine's backgrounding plugin:
168
+
169
+ ```rb
170
+ Shrine::Attacher.promote { |data| TransloaditJob.perform_async(data) }
171
+ ```
172
+ ```rb
173
+ class TransloaditJob
174
+ include Sidekiq::Worker
175
+
176
+ def perform(data)
177
+ Shrine::Attacher.transloadit_process(data)
178
+ end
179
+ end
180
+ ```
181
+
182
+ ### Tracking progress
183
+
184
+ When an assembly is submitted, Transloadit returns a lot of useful information
185
+ about the status of that assembly, which the plugin saves to the cached
186
+ attachment's metadata.
187
+
188
+ ```rb
189
+ response = photo.image.transloadit_response
190
+ response.body #=>
191
+ # {
192
+ # "ok" => "ASSEMBLY_EXECUTING",
193
+ # "message" => "The assembly is currently being executed.",
194
+ # "assembly_id" => "83d07d10414011e68cc8c5df79919836",
195
+ # "assembly_url" => "http://api2.janani.transloadit.com/assemblies/83d07d10414011e68cc8c5df79919836",
196
+ # "execution_start" => "2016/07/03 17:06:42 GMT",
197
+ # "execution_duration" => 2.113,
198
+ # "params" => "{\"steps\":{...}}",
199
+ # ...
200
+ # }
201
+ ```
202
+
203
+ At an point during the execution of the assembly you can refresh this
204
+ information:
205
+
206
+ ```rb
207
+ response.finished? #=> false
208
+ response.reload!
209
+ response.finished? #=> true
210
+ ```
211
+
212
+ ### Import & Export
213
+
214
+ Every `TransloaditFile` needs to have an import and an export step. This plugin
215
+ automatically generates those steps for you:
216
+
217
+ ```rb
218
+ transloadit_file(io)
219
+
220
+ # is equivalent to
221
+
222
+ file = transloadit_file
223
+ file.add_step(transloadit_import_step("import", io))
224
+ ```
225
+
226
+ ```rb
227
+ transloadit_assembly({original: original, thumb: thumb})
228
+
229
+ # is equivalent to
230
+
231
+ transloadit_assembly({
232
+ original: original.add_step(transloadit_export_step("export_original")),
233
+ thumb: thumb.add_step(transloadit_export_step("export_thumb")),
234
+ })
235
+ ```
236
+
237
+ If you want/need to generate these steps yourself, you can just use the
238
+ expanded forms.
239
+
240
+ ### Transloadit gem
241
+
242
+ If you want to have complete control over how steps are generated, you can just
243
+ use the [transloadit gem] directly. This plugin doesn't care how you generate
244
+ your steps, it only requires you to return an instance of
245
+ `Transloadit::Assembly`.
246
+
247
+ ```rb
248
+ class MyUploader < Shrine
249
+ def transloadit_process(io, context)
250
+ # build options
251
+ transloadit #=> #<Transloadit>
252
+ transloadit.assembly(options)
253
+ end
254
+ end
255
+ ```
256
+
257
+ The import/export helper methods simply generate a `Transloadit::Step` object,
258
+ and you can pass additional options:
259
+
260
+ ```rb
261
+ class MyUploader < Shrinee
262
+ def transloadit_process(io, context)
263
+ transloadit_import_step("import", io) #=> #<Transloadit::Step>
264
+ transloadit_export_step("export", path: "mypath") #=> #<Transloadit::Step>
265
+ end
266
+ end
267
+ ```
268
+
269
+ The `#add_step` method for `TransloaditFile` is just a convenient way to add
270
+ steps where `:use` is automatically set to previous step.
271
+
272
+ ### Testing
273
+
274
+ In development or test environment you cannot use webhooks, because Transloadit
275
+ as an external service cannot access your localhost. In this case you can just
276
+ do polling:
277
+
278
+ ```rb
279
+ class MyUploader < Shrine
280
+ def transloadit_process(io, context)
281
+ # ...
282
+
283
+ if ENV["RACK_ENV"] == "production"
284
+ notify_url = "https://myapp.com/webhooks/transloadit"
285
+ else
286
+ # In development we cannot receive webhooks, because Transloadit as an
287
+ # external service cannot reach our localhost.
288
+ end
289
+
290
+ transloadit_assembly(files, context: context, notify_url: notify_url)
291
+ end
292
+ end
293
+ ```
294
+
295
+ ```rb
296
+ class TransloaditJob
297
+ include Sidekiq::Worker
298
+
299
+ def perform(data)
300
+ attacher = Shrine::Attacher.transloadit_process(data)
301
+
302
+ # Webhooks won't work in development, so we can just use polling.
303
+ unless ENV["RACK_ENV"] == "production"
304
+ response = attacher.get.transloadit_response
305
+ until response.finished?
306
+ sleep 1
307
+ response.reload!
308
+ end
309
+ attacher.transloadit_save(response.body)
310
+ end
311
+ end
312
+ end
313
+ ```
314
+
315
+ ## Contributing
316
+
317
+ Before you can run tests, you need to first create an `.env` file in the
318
+ project root containing your Transloadit and Amazon S3 credentials:
319
+
320
+ ```sh
321
+ # .env
322
+ TRANSLOADIT_AUTH_KEY="..."
323
+ TRANSLOADIT_AUTH_SECRET="..."
324
+ S3_BUCKET="..."
325
+ S3_REGION="..."
326
+ S3_ACCESS_KEY_ID="..."
327
+ S3_SECRET_ACCESS_KEY="..."
328
+ ```
329
+
330
+ Afterwards you can run the tests:
331
+
332
+ ```sh
333
+ $ bundle exec rake test
334
+ ```
335
+
336
+ ## License
337
+
338
+ [MIT](LICENSE.txt)
339
+
340
+ [Shrine]: https://github.com/janko-m/shrine
341
+ [Transloadit]: https://transloadit.com/
342
+ [many storage services]: https://transloadit.com/docs/conversion-robots/#file-export-robots
343
+ [transloadit gem]: https://github.com/transloadit/ruby-sdk
344
+ [robot and arguments]: https://transloadit.com/docs/conversion-robots/
345
+ [templates]: https://transloadit.com/docs/#templates
@@ -0,0 +1,267 @@
1
+ require "transloadit"
2
+ require "uri"
3
+ require "json"
4
+ require "openssl"
5
+
6
+ class Shrine
7
+ module Plugins
8
+ module Transloadit
9
+ def self.configure(uploader, opts = {})
10
+ uploader.opts[:transloadit_auth_key] = opts.fetch(:auth_key, uploader.opts[:transloadit_auth_key])
11
+ uploader.opts[:transloadit_auth_secret] = opts.fetch(:auth_secret, uploader.opts[:transloadit_auth_secret])
12
+
13
+ raise Error, "The :auth_key is required for transloadit plugin" if uploader.opts[:transloadit_auth_key].nil?
14
+ raise Error, "The :auth_secret is required for transloadit plugin" if uploader.opts[:transloadit_auth_secret].nil?
15
+
16
+ uploader.opts[:backgrounding_promote] ||= proc { transloadit_process }
17
+ end
18
+
19
+ def self.load_dependencies(uploader, opts = {})
20
+ uploader.plugin :backgrounding
21
+ end
22
+
23
+ module AttacherClassMethods
24
+ def transloadit_process(data)
25
+ attacher = self.load(data)
26
+ cached_file = attacher.uploaded_file(data["attachment"])
27
+ attacher.transloadit_process(cached_file)
28
+ attacher
29
+ end
30
+
31
+ def transloadit_save(params)
32
+ params["transloadit"] = params["transloadit"].to_json if params["transloadit"].is_a?(Hash)
33
+ check_transloadit_signature!(params)
34
+ response = JSON.parse(params["transloadit"])
35
+ data = response["fields"]["attacher"]
36
+ attacher = self.load(data)
37
+ cached_file = attacher.uploaded_file(data["attachment"])
38
+ return if cached_file != attacher.get
39
+ attacher.transloadit_save(response)
40
+ attacher
41
+ end
42
+
43
+ def check_transloadit_signature!(params)
44
+ sent_signature = params["signature"]
45
+ payload = params["transloadit"]
46
+ algorithm = OpenSSL::Digest.new('sha1')
47
+ secret = shrine_class.opts[:transloadit_auth_secret]
48
+ calculated_signature = OpenSSL::HMAC.hexdigest(algorithm, secret, payload)
49
+ raise Error, "Transloadit signature that was sent doesn't match the calculated signature" if calculated_signature != sent_signature
50
+ end
51
+ end
52
+
53
+ module AttacherMethods
54
+ def transloadit_process(cached_file = get)
55
+ assembly = store.transloadit_process(cached_file, context)
56
+ assembly.options[:fields] ||= {}
57
+ assembly.options[:fields]["attacher"] = self.dump.merge("attachment" => cached_file.to_json)
58
+ response = assembly.submit!
59
+ raise Error, "#{response["error"]}: #{response["message"]}" if response["error"]
60
+ cached_file.metadata["transloadit_response"] = response.body.to_json
61
+ swap(cached_file)
62
+ end
63
+
64
+ def transloadit_save(response)
65
+ if versions = response["fields"]["versions"]
66
+ stored_file = versions.inject({}) do |hash, (name, key)|
67
+ result = response["results"].fetch(key)[0]
68
+ uploaded_file = store.transloadit_uploaded_file(result)
69
+ hash.update(name => uploaded_file)
70
+ end
71
+ else
72
+ result = response["results"].values.last[0]
73
+ stored_file = store.transloadit_uploaded_file(result)
74
+ end
75
+
76
+ update(stored_file)
77
+ end
78
+ end
79
+
80
+ module ClassMethods
81
+ def transloadit
82
+ ::Transloadit.new(
83
+ key: opts[:transloadit_auth_key],
84
+ secret: opts[:transloadit_auth_secret],
85
+ )
86
+ end
87
+ end
88
+
89
+ module InstanceMethods
90
+ def transloadit_uploaded_file(result)
91
+ case url = result.fetch("url")
92
+ when /amazonaws\.com/
93
+ raise Error, "Cannot save a processed file which wasn't exported: #{url.inspect}" if url.include?("tmp.transloadit.com")
94
+ path = URI(url).path
95
+ id = path.match(/^\/#{storage.prefix}/).post_match
96
+ else
97
+ raise Error, "The transloadit Shrine plugin doesn't support storage identified by #{url.inspect}"
98
+ end
99
+
100
+ self.class::UploadedFile.new(
101
+ "id" => id,
102
+ "storage" => storage_key,
103
+ "metadata" => {
104
+ "filename" => result.fetch("name"),
105
+ "size" => result.fetch("size"),
106
+ "mime_type" => result.fetch("mime"),
107
+ "width" => (result["meta"] && result["meta"]["width"]),
108
+ "height" => (result["meta"] && result["meta"]["height"]),
109
+ "transloadit" => result["meta"],
110
+ }
111
+ )
112
+ end
113
+
114
+ def transloadit_import_step(name, io, **step_options)
115
+ uri = URI.parse(io.url)
116
+
117
+ if defined?(Storage::S3) && io.storage.is_a?(Storage::S3)
118
+ step = transloadit.step(name, "/s3/import",
119
+ key: io.storage.s3.client.config.access_key_id,
120
+ secret: io.storage.s3.client.config.secret_access_key,
121
+ bucket: io.storage.bucket.name,
122
+ bucket_region: io.storage.s3.client.config.region,
123
+ path: [*io.storage.prefix, io.id].join("/"),
124
+ )
125
+ elsif uri.scheme == "http" || uri.scheme == "https"
126
+ step = transloadit.step(name, "/http/import",
127
+ url: uri.to_s,
128
+ )
129
+ elsif uri.scheme == "ftp"
130
+ step = transloadit.step(name, "/ftp/import",
131
+ host: uri.host,
132
+ user: uri.user,
133
+ password: uri.password,
134
+ path: uri.path,
135
+ )
136
+ else
137
+ raise Error, "Cannot construct a transloadit import step from #{io.inspect}"
138
+ end
139
+
140
+ step.options.update(step_options)
141
+
142
+ step
143
+ end
144
+
145
+ def transloadit_export_step(name, **step_options)
146
+ if defined?(Storage::S3) && storage.is_a?(Storage::S3)
147
+ step = transloadit.step(name, "/s3/store",
148
+ key: storage.s3.client.config.access_key_id,
149
+ secret: storage.s3.client.config.secret_access_key,
150
+ bucket: storage.bucket.name,
151
+ bucket_region: storage.s3.client.config.region
152
+ )
153
+ else
154
+ raise Error, "Cannot construct a transloadit export step from #{storage.inspect}"
155
+ end
156
+
157
+ step.options.update(step_options)
158
+
159
+ step
160
+ end
161
+
162
+ def transloadit_file(io = nil)
163
+ file = TransloaditFile.new(transloadit: transloadit)
164
+ file = file.add_step(transloadit_import_step("import", io)) if io
165
+ file
166
+ end
167
+
168
+ def transloadit_assembly(value, context: {}, **options)
169
+ options[:steps] ||= []
170
+ options[:fields] ||= {}
171
+
172
+ if (versions = value).is_a?(Hash)
173
+ options[:fields]["versions"] = {}
174
+ raise Error, "The versions Shrine plugin isn't loaded" if !defined?(Shrine::Plugins::Versions)
175
+ versions.each do |name, transloadit_file|
176
+ raise Error, "The given TransloaditFile is missing an import step" if !transloadit_file.imported?
177
+ unless transloadit_file.exported?
178
+ path = generate_location(transloadit_file, context.merge(version: name)) + ".${file.ext}"
179
+ export_step = transloadit_export_step("export_#{name}", path: path)
180
+ transloadit_file = transloadit_file.add_step(export_step)
181
+ end
182
+ options[:steps] |= transloadit_file.steps
183
+ options[:fields]["versions"][name] = transloadit_file.name
184
+ end
185
+ elsif (transloadit_file = value).is_a?(TransloaditFile)
186
+ raise Error, "The given TransloaditFile is missing an import step" if !transloadit_file.imported?
187
+ unless transloadit_file.exported?
188
+ path = generate_location(transloadit_file, context) + ".${file.ext}"
189
+ export_step = transloadit_export_step("export", path: path)
190
+ transloadit_file = transloadit_file.add_step(export_step)
191
+ end
192
+ options[:steps] += transloadit_file.steps
193
+ elsif (template = value).is_a?(String)
194
+ options[:template_id] = template
195
+ else
196
+ raise Error, "First argument has to be a TransloaditFile, a hash of TransloaditFiles, or a template"
197
+ end
198
+
199
+ if options[:steps].uniq(&:name) != options[:steps]
200
+ raise Error, "There are different transloadit steps using the same name"
201
+ end
202
+
203
+ transloadit.assembly(options)
204
+ end
205
+
206
+ def transloadit
207
+ @transloadit ||= self.class.transloadit
208
+ end
209
+ end
210
+
211
+ module FileMethods
212
+ def transloadit_response
213
+ @transloadit_response ||= (
214
+ body = metadata.fetch("transloadit_response")
215
+ body.instance_eval { def body; self; end }
216
+ response = ::Transloadit::Response.new(body)
217
+ response.extend ::Transloadit::Response::Assembly
218
+ response
219
+ )
220
+ end
221
+ end
222
+
223
+ class TransloaditFile
224
+ attr_reader :transloadit, :steps
225
+
226
+ def initialize(transloadit:, steps: [])
227
+ @transloadit = transloadit
228
+ @steps = steps
229
+ end
230
+
231
+ def add_step(*args)
232
+ if args[0].is_a?(::Transloadit::Step)
233
+ step = args[0]
234
+ else
235
+ step = transloadit.step(*args)
236
+ end
237
+
238
+ unless step.options[:use]
239
+ step.use @steps.last if @steps.any?
240
+ end
241
+
242
+ TransloaditFile.new(transloadit: transloadit, steps: @steps + [step])
243
+ end
244
+
245
+ # Transloadit in its result uses the name of the last step before the
246
+ # export step.
247
+ def name
248
+ if exported?
249
+ @steps[-2].name
250
+ else
251
+ @steps.last.name
252
+ end
253
+ end
254
+
255
+ def imported?
256
+ @steps.any? && @steps.first.robot.end_with?("/import")
257
+ end
258
+
259
+ def exported?
260
+ @steps.any? && @steps.last.robot.end_with?("/store")
261
+ end
262
+ end
263
+ end
264
+
265
+ register_plugin(:transloadit, Transloadit)
266
+ end
267
+ end
@@ -0,0 +1,26 @@
1
+ Gem::Specification.new do |gem|
2
+ gem.name = "shrine-transloadit"
3
+ gem.version = "0.1.0"
4
+
5
+ gem.required_ruby_version = ">= 2.1"
6
+
7
+ gem.summary = "Provides Transloadit integration for Shrine."
8
+ gem.homepage = "https://github.com/janko-m/shrine-transloadit"
9
+ gem.authors = ["Janko Marohnić"]
10
+ gem.email = ["janko.marohnic@gmail.com"]
11
+ gem.license = "MIT"
12
+
13
+ gem.files = Dir["README.md", "LICENSE.txt", "lib/**/*.rb", "*.gemspec"]
14
+ gem.require_path = "lib"
15
+
16
+ gem.add_dependency "shrine", "~> 2.1"
17
+ gem.add_dependency "transloadit", "~> 1.2"
18
+
19
+ gem.add_development_dependency "rake"
20
+ gem.add_development_dependency "minitest"
21
+ gem.add_development_dependency "minitest-hooks"
22
+ gem.add_development_dependency "dotenv"
23
+ gem.add_development_dependency "aws-sdk"
24
+ gem.add_development_dependency "sequel"
25
+ gem.add_development_dependency "sqlite3"
26
+ end
metadata ADDED
@@ -0,0 +1,175 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: shrine-transloadit
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Janko Marohnić
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-07-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: shrine
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: transloadit
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
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: minitest-hooks
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: dotenv
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: aws-sdk
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: sequel
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: sqlite3
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
+ description:
140
+ email:
141
+ - janko.marohnic@gmail.com
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - LICENSE.txt
147
+ - README.md
148
+ - lib/shrine/plugins/transloadit.rb
149
+ - shrine-transloadit.gemspec
150
+ homepage: https://github.com/janko-m/shrine-transloadit
151
+ licenses:
152
+ - MIT
153
+ metadata: {}
154
+ post_install_message:
155
+ rdoc_options: []
156
+ require_paths:
157
+ - lib
158
+ required_ruby_version: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ version: '2.1'
163
+ required_rubygems_version: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ requirements: []
169
+ rubyforge_project:
170
+ rubygems_version: 2.5.1
171
+ signing_key:
172
+ specification_version: 4
173
+ summary: Provides Transloadit integration for Shrine.
174
+ test_files: []
175
+ has_rdoc: