transloadit 3.1.2 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitattributes +44 -5
- data/.github/workflows/ci.yml +18 -15
- data/.gitignore +1 -1
- data/.standard.yml +2 -0
- data/CHANGELOG.md +8 -0
- data/Dockerfile +1 -1
- data/MIGRATING_TO_V4.md +136 -0
- data/README.md +3 -0
- data/lib/transloadit/assembly.rb +13 -4
- data/lib/transloadit/exception.rb +14 -6
- data/lib/transloadit/request.rb +54 -22
- data/lib/transloadit/response.rb +36 -34
- data/lib/transloadit/version.rb +1 -1
- data/lib/transloadit.rb +1 -1
- data/test/test_helper.rb +26 -0
- data/test/unit/test_transloadit.rb +1 -1
- data/test/unit/transloadit/test_assembly.rb +91 -8
- data/test/unit/transloadit/test_request.rb +1 -19
- data/test/unit/transloadit/test_response.rb +33 -31
- data/test/unit/transloadit/test_transport_compatibility.rb +222 -0
- data/transloadit.gemspec +5 -4
- metadata +33 -14
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fc246e913322624e733835f51e2924112ec4131af0930694ae322da3a10ea9e7
|
|
4
|
+
data.tar.gz: 79bd642651fd5d6b3c0f3153bfb9d44c6f78b16a7b91171d094e227b430f8949
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6ab26e103e6653f9b4126aed543446c6080e6bd30f1348cecefa38bb8406c706ec289e61e9c36c27512535f8590908ca15473cb042bf6ea38ebacac3eb7cd0a8
|
|
7
|
+
data.tar.gz: ef78d102680364717e5d4a4193a15cd553a7296478da13134c0cefa65fcc96138acca340990c7173b04e34fa741825788527d5d067e53eab057656acbf20bf1d
|
data/.gitattributes
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
*.
|
|
1
|
+
/.yarn/** linguist-vendored
|
|
2
|
+
/.yarn/releases/* binary
|
|
3
|
+
/.yarn/plugins/**/* binary
|
|
4
|
+
/.pnp.* binary linguist-generated
|
|
5
|
+
*.7z filter=lfs diff=lfs merge=lfs -text
|
|
6
|
+
*.aac filter=lfs diff=lfs merge=lfs -text
|
|
7
|
+
*.ai filter=lfs diff=lfs merge=lfs -text
|
|
8
|
+
*.avi filter=lfs diff=lfs merge=lfs -text
|
|
9
|
+
*.bmp filter=lfs diff=lfs merge=lfs -text
|
|
10
|
+
*.br filter=lfs diff=lfs merge=lfs -text
|
|
11
|
+
*.cr2 filter=lfs diff=lfs merge=lfs -text
|
|
12
|
+
*.dll filter=lfs diff=lfs merge=lfs -text
|
|
13
|
+
*.doc filter=lfs diff=lfs merge=lfs -text
|
|
14
|
+
*.docx filter=lfs diff=lfs merge=lfs -text
|
|
15
|
+
*.exe filter=lfs diff=lfs merge=lfs -text
|
|
16
|
+
*.flac filter=lfs diff=lfs merge=lfs -text
|
|
17
|
+
*.gif filter=lfs diff=lfs merge=lfs -text
|
|
18
|
+
*.gz filter=lfs diff=lfs merge=lfs -text
|
|
19
|
+
*.ico filter=lfs diff=lfs merge=lfs -text
|
|
20
|
+
*.jpeg filter=lfs diff=lfs merge=lfs -text
|
|
21
|
+
*.jpg filter=lfs diff=lfs merge=lfs -text
|
|
22
|
+
*.JPG filter=lfs diff=lfs merge=lfs -text
|
|
23
|
+
*.m4a filter=lfs diff=lfs merge=lfs -text
|
|
24
|
+
*.m4v filter=lfs diff=lfs merge=lfs -text
|
|
25
|
+
*.mkv filter=lfs diff=lfs merge=lfs -text
|
|
26
|
+
*.mov filter=lfs diff=lfs merge=lfs -text
|
|
27
|
+
*.mp3 filter=lfs diff=lfs merge=lfs -text
|
|
28
|
+
*.mp4 filter=lfs diff=lfs merge=lfs -text
|
|
29
|
+
*.ogg filter=lfs diff=lfs merge=lfs -text
|
|
30
|
+
*.pages filter=lfs diff=lfs merge=lfs -text
|
|
31
|
+
*.pdf filter=lfs diff=lfs merge=lfs -text
|
|
32
|
+
*.png filter=lfs diff=lfs merge=lfs -text
|
|
33
|
+
*.PNG filter=lfs diff=lfs merge=lfs -text
|
|
34
|
+
*.psd filter=lfs diff=lfs merge=lfs -text
|
|
35
|
+
*.pxm filter=lfs diff=lfs merge=lfs -text
|
|
36
|
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
|
37
|
+
*.tgz filter=lfs diff=lfs merge=lfs -text
|
|
38
|
+
*.tif filter=lfs diff=lfs merge=lfs -text
|
|
39
|
+
*.tiff filter=lfs diff=lfs merge=lfs -text
|
|
40
|
+
*.webm filter=lfs diff=lfs merge=lfs -text
|
|
41
|
+
*.webp filter=lfs diff=lfs merge=lfs -text
|
|
42
|
+
*.woff2 filter=lfs diff=lfs merge=lfs -text
|
|
43
|
+
*.xlsx filter=lfs diff=lfs merge=lfs -text
|
|
44
|
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -13,32 +13,33 @@ jobs:
|
|
|
13
13
|
strategy:
|
|
14
14
|
matrix:
|
|
15
15
|
ruby:
|
|
16
|
-
- 3.
|
|
17
|
-
- 3.
|
|
18
|
-
- 3.
|
|
19
|
-
- 3.
|
|
20
|
-
-
|
|
21
|
-
- truffleruby
|
|
16
|
+
- "3.1"
|
|
17
|
+
- "3.2"
|
|
18
|
+
- "3.3"
|
|
19
|
+
- "3.4"
|
|
20
|
+
- "4.0"
|
|
22
21
|
fail-fast: false
|
|
23
22
|
steps:
|
|
24
|
-
- uses: actions/checkout@
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
with:
|
|
25
|
+
lfs: true
|
|
25
26
|
- uses: actions/setup-node@v4
|
|
26
27
|
with:
|
|
27
28
|
node-version: 20
|
|
28
29
|
- run: npm install -g tsx
|
|
29
|
-
- uses: ruby/setup-ruby@
|
|
30
|
+
- uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f
|
|
30
31
|
with:
|
|
31
32
|
ruby-version: ${{ matrix.ruby }}
|
|
32
33
|
bundler-cache: true
|
|
33
34
|
- run: bundle exec standardrb
|
|
34
35
|
- name: Run tests
|
|
35
36
|
env:
|
|
36
|
-
COVERAGE: ${{ matrix.ruby == '
|
|
37
|
-
TEST_NODE_PARITY: ${{ matrix.ruby == '
|
|
37
|
+
COVERAGE: ${{ matrix.ruby == '4.0' && '1' || '0' }}
|
|
38
|
+
TEST_NODE_PARITY: ${{ matrix.ruby == '4.0' && '1' || '0' }}
|
|
38
39
|
run: bundle exec rake test
|
|
39
40
|
- name: Upload coverage to Codecov
|
|
40
|
-
if: matrix.ruby == '
|
|
41
|
-
uses: codecov/codecov-action@
|
|
41
|
+
if: matrix.ruby == '4.0'
|
|
42
|
+
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f
|
|
42
43
|
with:
|
|
43
44
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
44
45
|
files: ./coverage/coverage.json
|
|
@@ -53,10 +54,12 @@ jobs:
|
|
|
53
54
|
TRANSLOADIT_KEY: ${{ secrets.TRANSLOADIT_KEY }}
|
|
54
55
|
TRANSLOADIT_SECRET: ${{ secrets.TRANSLOADIT_SECRET }}
|
|
55
56
|
steps:
|
|
56
|
-
- uses: actions/checkout@
|
|
57
|
-
|
|
57
|
+
- uses: actions/checkout@v4
|
|
58
|
+
with:
|
|
59
|
+
lfs: true
|
|
60
|
+
- uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f
|
|
58
61
|
with:
|
|
59
|
-
ruby-version:
|
|
62
|
+
ruby-version: "4.0"
|
|
60
63
|
bundler-cache: true
|
|
61
64
|
- name: Ensure e2e credentials are configured
|
|
62
65
|
if: ${{ env.TRANSLOADIT_KEY == '' || env.TRANSLOADIT_SECRET == '' }}
|
data/.gitignore
CHANGED
data/.standard.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
### 4.0.0 / 2026-09-03
|
|
2
|
+
|
|
3
|
+
- BREAKING: Replace the long-dormant `rest-client` transport with Faraday 2 and `faraday-multipart`.
|
|
4
|
+
- BREAKING: Raise the minimum supported Ruby version from 3.0 to 3.1.
|
|
5
|
+
- Keep HTTP client types out of SDK responses and exceptions while preserving response status, headers, body access, multipart ordering, and rate-limit retries.
|
|
6
|
+
- Add a [v3 to v4 migration guide](MIGRATING_TO_V4.md).
|
|
7
|
+
- Test all Ruby versions from the supported minimum through Ruby 4.0.
|
|
8
|
+
|
|
1
9
|
### 3.1.2 / 2025-10-29
|
|
2
10
|
|
|
3
11
|
- Compress e2e fixture asset to keep gem size close to previous releases (kvz)
|
data/Dockerfile
CHANGED
data/MIGRATING_TO_V4.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Migrating from v3 to v4
|
|
2
|
+
|
|
3
|
+
Version 4 replaces the `rest-client` HTTP transport with Faraday 2. Most applications only use the
|
|
4
|
+
Transloadit API exposed by this gem and do not need code changes. The migration is a major release
|
|
5
|
+
because v3 also delegated undocumented methods to RestClient response objects and exposed
|
|
6
|
+
RestClient exception inheritance.
|
|
7
|
+
|
|
8
|
+
Version 4 requires Ruby 3.1 or newer. The final v3 release allowed Ruby 3.0, so applications still
|
|
9
|
+
running Ruby 3.0 must upgrade Ruby before updating this gem.
|
|
10
|
+
|
|
11
|
+
## Update the dependency
|
|
12
|
+
|
|
13
|
+
Once v4 is released, update the application Gemfile and bundle:
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
gem "transloadit", "~> 4.0"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```shell
|
|
20
|
+
bundle update transloadit
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The SDK installs Faraday and its multipart middleware. Applications do not need to add Faraday
|
|
24
|
+
directly. Remove an explicit `rest-client` dependency only if the application does not use it for
|
|
25
|
+
anything else. Version 4 no longer installs or loads the `RestClient` constant on the application's
|
|
26
|
+
behalf.
|
|
27
|
+
|
|
28
|
+
## Responses
|
|
29
|
+
|
|
30
|
+
Use the SDK-owned response API:
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
response = transloadit.assembly.get(assembly_id)
|
|
34
|
+
|
|
35
|
+
response["ok"]
|
|
36
|
+
response[:assembly_id]
|
|
37
|
+
response.body
|
|
38
|
+
response.headers
|
|
39
|
+
response.code
|
|
40
|
+
response.status
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`code` continues to return the integer HTTP status, and `status` is its new explicit alias. Header
|
|
44
|
+
names remain normalized to lowercase symbols with underscores, for example
|
|
45
|
+
`response.headers[:retry_after]`.
|
|
46
|
+
|
|
47
|
+
HTTP error statuses still return `Transloadit::Response` objects. They are not converted into
|
|
48
|
+
transport exceptions:
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
response = transloadit.assembly.get(assembly_id)
|
|
52
|
+
|
|
53
|
+
if response.code >= 400
|
|
54
|
+
warn response["error"]
|
|
55
|
+
end
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Remove raw RestClient response usage
|
|
59
|
+
|
|
60
|
+
In v3, `Transloadit::Response` delegated unknown methods to a `RestClient::Response`. Version 4 no
|
|
61
|
+
longer exposes the underlying HTTP client. Replace calls to RestClient-specific response methods
|
|
62
|
+
with the SDK-owned response API above.
|
|
63
|
+
|
|
64
|
+
For example:
|
|
65
|
+
|
|
66
|
+
```ruby
|
|
67
|
+
# v3: relied on the delegated RestClient object
|
|
68
|
+
response.raw_headers
|
|
69
|
+
|
|
70
|
+
# v4
|
|
71
|
+
response.headers
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
If an application relies on another delegated method that has no equivalent, open an issue with the
|
|
75
|
+
use case before upgrading.
|
|
76
|
+
|
|
77
|
+
## Request failures
|
|
78
|
+
|
|
79
|
+
Network, TLS, and timeout failures now raise `Transloadit::Exception::RequestFailed` instead of a
|
|
80
|
+
RestClient exception:
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
# v3
|
|
84
|
+
begin
|
|
85
|
+
transloadit.assembly.get(assembly_id)
|
|
86
|
+
rescue RestClient::Exception => error
|
|
87
|
+
warn error.message
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# v4
|
|
91
|
+
begin
|
|
92
|
+
transloadit.assembly.get(assembly_id)
|
|
93
|
+
rescue Transloadit::Exception::RequestFailed => error
|
|
94
|
+
warn error.message
|
|
95
|
+
end
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The original adapter exception is retained as `error.cause` for diagnostics. Avoid branching on its
|
|
99
|
+
class so application behavior does not become coupled to Faraday.
|
|
100
|
+
|
|
101
|
+
## Rate-limit failures
|
|
102
|
+
|
|
103
|
+
Continue rescuing the SDK exception directly:
|
|
104
|
+
|
|
105
|
+
```ruby
|
|
106
|
+
begin
|
|
107
|
+
assembly.create!(file)
|
|
108
|
+
rescue Transloadit::Exception::RateLimitReached => error
|
|
109
|
+
retry_after = error.response.wait_time
|
|
110
|
+
end
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`RateLimitReached` remains a `StandardError` and retains its Transloadit response through
|
|
114
|
+
`error.response`, but it no longer inherits from `RestClient::RequestEntityTooLarge`. Replace code
|
|
115
|
+
that rescues the RestClient superclass with the SDK exception.
|
|
116
|
+
|
|
117
|
+
## Uploaded file handles
|
|
118
|
+
|
|
119
|
+
Version 4 does not close path-backed file objects supplied by the caller. Prefer a block so ownership
|
|
120
|
+
is explicit:
|
|
121
|
+
|
|
122
|
+
```ruby
|
|
123
|
+
File.open("video.mp4", "rb") do |file|
|
|
124
|
+
assembly.create!(file)
|
|
125
|
+
end
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Multipart field order is unchanged: `params` and `signature` are sent before file bodies.
|
|
129
|
+
|
|
130
|
+
## Upgrade checklist
|
|
131
|
+
|
|
132
|
+
- Update the gem and run the application's request and upload tests.
|
|
133
|
+
- Replace rescues of `RestClient::Exception` and `RestClient::RequestEntityTooLarge`.
|
|
134
|
+
- Replace calls to delegated RestClient response methods.
|
|
135
|
+
- Confirm the application closes files that it opens.
|
|
136
|
+
- Remove the direct `rest-client` dependency if nothing else uses it.
|
data/README.md
CHANGED
|
@@ -19,6 +19,9 @@ _If you run Ruby on Rails and are looking to integrate with the browser for file
|
|
|
19
19
|
gem install transloadit
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
+
Upgrading from v3? See the [v4 migration guide](MIGRATING_TO_V4.md) for response, exception, and
|
|
23
|
+
file-handle compatibility notes.
|
|
24
|
+
|
|
22
25
|
## Usage
|
|
23
26
|
|
|
24
27
|
To get started, you need to require the 'transloadit' gem:
|
data/lib/transloadit/assembly.rb
CHANGED
|
@@ -143,11 +143,22 @@ class Transloadit::Assembly < Transloadit::ApiModel
|
|
|
143
143
|
when nil then steps
|
|
144
144
|
when Hash then steps
|
|
145
145
|
when Transloadit::Step then steps.to_hash
|
|
146
|
-
|
|
147
|
-
|
|
146
|
+
when Array
|
|
147
|
+
names = steps.inject([]) do |array, step|
|
|
148
|
+
case step
|
|
149
|
+
when Transloadit::Step then array << step.name
|
|
150
|
+
when Hash then array + step.keys.map(&:to_s)
|
|
151
|
+
else
|
|
152
|
+
raise ArgumentError, "Unsupported array element"
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
if names.uniq != names
|
|
148
157
|
raise ArgumentError, "There are different Assembly steps using the same name"
|
|
149
158
|
end
|
|
150
159
|
steps.inject({}) { |h, s| h.update s }
|
|
160
|
+
else
|
|
161
|
+
raise ArgumentError, "Unsupported steps class"
|
|
151
162
|
end
|
|
152
163
|
end
|
|
153
164
|
|
|
@@ -162,8 +173,6 @@ class Transloadit::Assembly < Transloadit::ApiModel
|
|
|
162
173
|
if is_retrying
|
|
163
174
|
warn "Rate limit reached. Waiting for #{response.wait_time} seconds before retrying."
|
|
164
175
|
sleep response.wait_time
|
|
165
|
-
# RestClient closes file streams at the end of a request.
|
|
166
|
-
ios.collect! { |file| File.open file.path }
|
|
167
176
|
else
|
|
168
177
|
raise Transloadit::Exception::RateLimitReached.new(response)
|
|
169
178
|
end
|
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
require "transloadit"
|
|
2
2
|
|
|
3
|
-
require "rest-client"
|
|
4
|
-
|
|
5
3
|
module Transloadit::Exception
|
|
4
|
+
#
|
|
5
|
+
# Exception raised when an HTTP request cannot be completed.
|
|
6
|
+
# The original transport error is available through +cause+.
|
|
7
|
+
#
|
|
8
|
+
class RequestFailed < StandardError
|
|
9
|
+
end
|
|
10
|
+
|
|
6
11
|
#
|
|
7
12
|
# Exception raised when Rate limit error response is returned from the API.
|
|
8
13
|
# See {Rate Limiting}[https://transloadit.com/docs/api-docs/#rate-limiting]
|
|
9
14
|
#
|
|
10
|
-
class RateLimitReached <
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
class RateLimitReached < StandardError
|
|
16
|
+
# @return [Transloadit::Response] the API response that reported the rate limit
|
|
17
|
+
attr_reader :response
|
|
18
|
+
|
|
19
|
+
def initialize(response)
|
|
20
|
+
@response = response
|
|
21
|
+
super("Transloadit Rate Limit Reached. Retry in #{response.wait_time} seconds")
|
|
14
22
|
end
|
|
15
23
|
end
|
|
16
24
|
|
data/lib/transloadit/request.rb
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
require "transloadit"
|
|
2
2
|
|
|
3
|
-
require "
|
|
3
|
+
require "faraday"
|
|
4
|
+
require "faraday/multipart"
|
|
5
|
+
require "mime/types"
|
|
4
6
|
require "openssl"
|
|
5
7
|
|
|
6
8
|
#
|
|
@@ -47,7 +49,7 @@ class Transloadit::Request
|
|
|
47
49
|
#
|
|
48
50
|
def get(params = {})
|
|
49
51
|
request! do
|
|
50
|
-
api
|
|
52
|
+
api.get(url.path + to_query(params), nil, API_HEADERS)
|
|
51
53
|
end
|
|
52
54
|
end
|
|
53
55
|
|
|
@@ -60,8 +62,10 @@ class Transloadit::Request
|
|
|
60
62
|
#
|
|
61
63
|
def delete(payload = {})
|
|
62
64
|
request! do
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
api.delete(url.path) do |request|
|
|
66
|
+
request.headers.update(API_HEADERS)
|
|
67
|
+
request.body = to_payload(payload)
|
|
68
|
+
end
|
|
65
69
|
end
|
|
66
70
|
end
|
|
67
71
|
|
|
@@ -74,7 +78,7 @@ class Transloadit::Request
|
|
|
74
78
|
#
|
|
75
79
|
def post(payload = {})
|
|
76
80
|
request! do
|
|
77
|
-
api
|
|
81
|
+
api.post(url.path, to_payload(payload), API_HEADERS)
|
|
78
82
|
end
|
|
79
83
|
end
|
|
80
84
|
|
|
@@ -87,7 +91,7 @@ class Transloadit::Request
|
|
|
87
91
|
#
|
|
88
92
|
def put(payload = {})
|
|
89
93
|
request! do
|
|
90
|
-
api
|
|
94
|
+
api.put(url.path, to_payload(payload), API_HEADERS)
|
|
91
95
|
end
|
|
92
96
|
end
|
|
93
97
|
|
|
@@ -118,12 +122,20 @@ class Transloadit::Request
|
|
|
118
122
|
# hostname, then the hostname is used as the base endpoint of the API.
|
|
119
123
|
# Otherwise uses the class-level API base.
|
|
120
124
|
#
|
|
121
|
-
# @return [
|
|
125
|
+
# @return [Faraday::Connection] the API endpoint for this instance
|
|
122
126
|
#
|
|
123
|
-
def api
|
|
127
|
+
def api
|
|
124
128
|
@api ||= case url.host
|
|
125
|
-
when String then
|
|
126
|
-
else
|
|
129
|
+
when String then connection_for("#{url.scheme}://#{url.host}")
|
|
130
|
+
else connection_for("#{API_ENDPOINT.scheme}://#{API_ENDPOINT.host}")
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def connection_for(base_url)
|
|
135
|
+
Faraday.new(url: base_url) do |connection|
|
|
136
|
+
connection.request :multipart
|
|
137
|
+
connection.request :url_encoded
|
|
138
|
+
connection.adapter Faraday.default_adapter
|
|
127
139
|
end
|
|
128
140
|
end
|
|
129
141
|
|
|
@@ -151,12 +163,33 @@ class Transloadit::Request
|
|
|
151
163
|
sig = signature(new_payload[:params])
|
|
152
164
|
new_payload[:signature] = sig unless sig.nil?
|
|
153
165
|
|
|
154
|
-
|
|
155
|
-
|
|
166
|
+
payload.each do |key, value|
|
|
167
|
+
next if key == :params || key == :signature
|
|
168
|
+
|
|
169
|
+
new_payload[key] = upload?(value) ? multipart_file(value) : value
|
|
170
|
+
end
|
|
156
171
|
|
|
157
172
|
new_payload
|
|
158
173
|
end
|
|
159
174
|
|
|
175
|
+
def upload?(value)
|
|
176
|
+
value.respond_to?(:read)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def multipart_file(file)
|
|
180
|
+
path = file.path if file.respond_to?(:path)
|
|
181
|
+
filename = file.original_filename if file.respond_to?(:original_filename)
|
|
182
|
+
filename = File.basename(path) if filename.to_s.empty? && path
|
|
183
|
+
filename = "upload" if filename.to_s.empty?
|
|
184
|
+
|
|
185
|
+
content_type = file.content_type if file.respond_to?(:content_type)
|
|
186
|
+
content_type = MIME::Types.type_for(path).first&.content_type if content_type.to_s.empty? && path
|
|
187
|
+
content_type = "application/octet-stream" if content_type.to_s.empty?
|
|
188
|
+
|
|
189
|
+
source = path || file
|
|
190
|
+
Faraday::Multipart::FilePart.new(source, content_type, filename)
|
|
191
|
+
end
|
|
192
|
+
|
|
160
193
|
#
|
|
161
194
|
# Updates the GET/DELETE params hash to be compliant with the Transloadit
|
|
162
195
|
# API by URI escaping and encoding the params hash, and attaching a
|
|
@@ -181,18 +214,17 @@ class Transloadit::Request
|
|
|
181
214
|
end
|
|
182
215
|
|
|
183
216
|
#
|
|
184
|
-
# Wraps a request's
|
|
185
|
-
# is raised by RestClient.
|
|
217
|
+
# Wraps a request's result in a Transloadit::Response.
|
|
186
218
|
#
|
|
187
219
|
def request!(&request)
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
Transloadit::
|
|
220
|
+
response = yield
|
|
221
|
+
Transloadit::Response.new(
|
|
222
|
+
body: response.body,
|
|
223
|
+
headers: response.headers,
|
|
224
|
+
status: response.status
|
|
225
|
+
)
|
|
226
|
+
rescue Faraday::Error
|
|
227
|
+
raise Transloadit::Exception::RequestFailed, "Transloadit request failed"
|
|
196
228
|
end
|
|
197
229
|
|
|
198
230
|
#
|
data/lib/transloadit/response.rb
CHANGED
|
@@ -1,20 +1,30 @@
|
|
|
1
1
|
require "transloadit"
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
require "delegate"
|
|
5
|
-
|
|
6
|
-
class Transloadit::Response < Delegator
|
|
3
|
+
class Transloadit::Response
|
|
7
4
|
autoload :Assembly, "transloadit/response/assembly"
|
|
8
5
|
|
|
9
6
|
#
|
|
10
|
-
# Creates
|
|
7
|
+
# Creates a response without exposing the underlying HTTP client.
|
|
11
8
|
#
|
|
12
|
-
# @param [
|
|
9
|
+
# @param [String] body the raw response body
|
|
10
|
+
# @param [Hash] headers the response headers
|
|
11
|
+
# @param [Integer] status the HTTP response status
|
|
13
12
|
#
|
|
14
|
-
def initialize(
|
|
15
|
-
|
|
13
|
+
def initialize(body:, headers:, status:)
|
|
14
|
+
@raw_body = body
|
|
15
|
+
@headers = normalize_headers(headers)
|
|
16
|
+
@status = status
|
|
16
17
|
end
|
|
17
18
|
|
|
19
|
+
# @return [Hash] normalized response headers
|
|
20
|
+
attr_reader :headers
|
|
21
|
+
|
|
22
|
+
# @return [Integer] the HTTP response status
|
|
23
|
+
attr_reader :status
|
|
24
|
+
|
|
25
|
+
# RestClient exposed the status through +code+ in previous SDK versions.
|
|
26
|
+
alias_method :code, :status
|
|
27
|
+
|
|
18
28
|
#
|
|
19
29
|
# Returns the attribute from the JSON response.
|
|
20
30
|
#
|
|
@@ -31,7 +41,7 @@ class Transloadit::Response < Delegator
|
|
|
31
41
|
# @return [Hash] the parsed JSON body hash
|
|
32
42
|
#
|
|
33
43
|
def body
|
|
34
|
-
MultiJson.load
|
|
44
|
+
MultiJson.load @raw_body
|
|
35
45
|
end
|
|
36
46
|
|
|
37
47
|
#
|
|
@@ -56,36 +66,28 @@ class Transloadit::Response < Delegator
|
|
|
56
66
|
self
|
|
57
67
|
end
|
|
58
68
|
|
|
59
|
-
protected
|
|
60
|
-
|
|
61
|
-
#
|
|
62
|
-
# The object to delegate method calls to.
|
|
63
|
-
#
|
|
64
|
-
# @return [RestClient::Response]
|
|
65
|
-
#
|
|
66
|
-
def __getobj__
|
|
67
|
-
@response
|
|
68
|
-
end
|
|
69
|
-
|
|
70
69
|
#
|
|
71
|
-
#
|
|
70
|
+
# Replaces this response's HTTP data with another response's data.
|
|
72
71
|
#
|
|
73
|
-
# @param [
|
|
74
|
-
# @return [RestClient::Response] the delegated response
|
|
75
|
-
#
|
|
76
|
-
def __setobj__(response)
|
|
77
|
-
@response = response
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
#
|
|
81
|
-
# Replaces the object this instance delegates to with the one the other
|
|
82
|
-
# object uses.
|
|
83
|
-
#
|
|
84
|
-
# @param [Delegator] other the object whose delegate to use
|
|
72
|
+
# @param [Transloadit::Response] other the response whose data to use
|
|
85
73
|
# @return [Transloadit::Response] this response
|
|
86
74
|
#
|
|
87
75
|
def replace(other)
|
|
88
|
-
|
|
76
|
+
@raw_body = other.raw_body
|
|
77
|
+
@headers = other.headers
|
|
78
|
+
@status = other.status
|
|
89
79
|
self
|
|
90
80
|
end
|
|
81
|
+
|
|
82
|
+
protected
|
|
83
|
+
|
|
84
|
+
attr_reader :raw_body
|
|
85
|
+
|
|
86
|
+
private
|
|
87
|
+
|
|
88
|
+
def normalize_headers(headers)
|
|
89
|
+
headers.to_h.each_with_object({}) do |(name, value), normalized|
|
|
90
|
+
normalized[name.to_s.downcase.tr("-", "_").to_sym] = value
|
|
91
|
+
end
|
|
92
|
+
end
|
|
91
93
|
end
|
data/lib/transloadit/version.rb
CHANGED
data/lib/transloadit.rb
CHANGED
data/test/test_helper.rb
CHANGED
|
@@ -72,3 +72,29 @@ module TransloaditCliHelpers
|
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
Minitest::Test.include(TransloaditCliHelpers)
|
|
75
|
+
|
|
76
|
+
module SingletonMethodOverrideHelpers
|
|
77
|
+
def with_singleton_method(target, name, implementation)
|
|
78
|
+
eigenclass = target.singleton_class
|
|
79
|
+
|
|
80
|
+
backup = "__orig_#{name}_for_test__"
|
|
81
|
+
had_method = eigenclass.method_defined?(name) || eigenclass.private_method_defined?(name)
|
|
82
|
+
eigenclass.send(:alias_method, backup, name) if had_method
|
|
83
|
+
|
|
84
|
+
target.define_singleton_method(name, &implementation)
|
|
85
|
+
yield
|
|
86
|
+
ensure
|
|
87
|
+
eigenclass = target.singleton_class
|
|
88
|
+
if eigenclass.method_defined?(name) || eigenclass.private_method_defined?(name)
|
|
89
|
+
eigenclass.send(:remove_method, name)
|
|
90
|
+
end
|
|
91
|
+
if had_method
|
|
92
|
+
eigenclass.send(:alias_method, name, backup)
|
|
93
|
+
if eigenclass.method_defined?(backup) || eigenclass.private_method_defined?(backup)
|
|
94
|
+
eigenclass.send(:remove_method, backup)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
Minitest::Test.include(SingletonMethodOverrideHelpers)
|
|
@@ -109,7 +109,7 @@ describe Transloadit do
|
|
|
109
109
|
|
|
110
110
|
it "must produce Transloadit-compatible JSON output" do
|
|
111
111
|
fixed_time = Time.utc(2025, 10, 28, 0, 0, 0)
|
|
112
|
-
Time
|
|
112
|
+
with_singleton_method(Time, :now, proc { fixed_time }) do
|
|
113
113
|
_(@transloadit.to_json).must_equal MultiJson.dump(@transloadit.to_hash)
|
|
114
114
|
end
|
|
115
115
|
end
|