format_parser 0.27.0 → 1.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/.github/workflows/main.yml +100 -0
- data/CHANGELOG.md +13 -0
- data/format_parser.gemspec +2 -1
- data/lib/format_parser/version.rb +1 -1
- data/lib/format_parser.rb +3 -2
- data/lib/remote_io.rb +29 -7
- data/spec/integration/active_storage/rails_app.rb +6 -3
- data/spec/remote_fetching_spec.rb +53 -2
- data/spec/remote_io_spec.rb +38 -13
- metadata +24 -4
- data/.travis.yml +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04e71e127d550feb0a5aaa54a27cb68c1671e034a5d309c520e4b81ea385e865
|
4
|
+
data.tar.gz: 4617b5ea41651af01635d16dfba8de00f9765d1f3a092c7ec56170dd0d607495
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f6d059459bcc4813a657bbe6b4eebdbd667d7fb15497ea1cfad2e92e355a68388fd558cc28af4e383f8d909e4a4735d4a485e34d26f1bef7b02e2420650ee0a9
|
7
|
+
data.tar.gz: 990f6e2490a1c38b60e1ce0fcc8f9b3e0b5471ac429a04277171e59a61b0d60d2998834792a7ea124fe474f94446f411620539018ee15bfe176a4d767e1d5919
|
@@ -0,0 +1,100 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on: [push,pull_request]
|
4
|
+
|
5
|
+
env:
|
6
|
+
BUNDLE_PATH: vendor/bundle
|
7
|
+
|
8
|
+
jobs:
|
9
|
+
lint:
|
10
|
+
name: Code Style
|
11
|
+
runs-on: ubuntu-18.04
|
12
|
+
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
|
13
|
+
strategy:
|
14
|
+
matrix:
|
15
|
+
ruby:
|
16
|
+
- 2.7
|
17
|
+
- 2.6
|
18
|
+
- 2.5
|
19
|
+
- jruby
|
20
|
+
steps:
|
21
|
+
- name: Checkout
|
22
|
+
uses: actions/checkout@v2
|
23
|
+
- name: Setup Ruby
|
24
|
+
uses: ruby/setup-ruby@v1
|
25
|
+
with:
|
26
|
+
ruby-version: ${{ matrix.ruby }}
|
27
|
+
- name: Gemfile Cache
|
28
|
+
uses: actions/cache@v2
|
29
|
+
with:
|
30
|
+
path: Gemfile.lock
|
31
|
+
key: ${{ runner.os }}-gemlock-${{ matrix.ruby }}-${{ hashFiles('Gemfile', 'format_parser.gemspec') }}
|
32
|
+
restore-keys: |
|
33
|
+
${{ runner.os }}-gemlock-${{ matrix.ruby }}-
|
34
|
+
- name: Bundle Cache
|
35
|
+
id: cache-gems
|
36
|
+
uses: actions/cache@v2
|
37
|
+
with:
|
38
|
+
path: vendor/bundle
|
39
|
+
key: ${{ runner.os }}-gems-${{ matrix.ruby }}-${{ hashFiles('Gemfile', 'Gemfile.lock', 'format_parser.gemspec') }}
|
40
|
+
restore-keys: |
|
41
|
+
${{ runner.os }}-gems-${{ matrix.ruby }}-
|
42
|
+
${{ runner.os }}-gems-
|
43
|
+
- name: Bundle Install
|
44
|
+
if: steps.cache-gems.outputs.cache-hit != 'true'
|
45
|
+
run: bundle install --jobs 4 --retry 3
|
46
|
+
- name: Rubocop Cache
|
47
|
+
uses: actions/cache@v2
|
48
|
+
with:
|
49
|
+
path: ~/.cache/rubocop_cache
|
50
|
+
key: ${{ runner.os }}-rubocop-${{ hashFiles('.rubocop.yml') }}
|
51
|
+
restore-keys: |
|
52
|
+
${{ runner.os }}-rubocop-
|
53
|
+
- name: Rubocop
|
54
|
+
run: bundle exec rubocop
|
55
|
+
test:
|
56
|
+
name: Specs
|
57
|
+
runs-on: ubuntu-18.04
|
58
|
+
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
|
59
|
+
strategy:
|
60
|
+
matrix:
|
61
|
+
ruby:
|
62
|
+
- 2.7
|
63
|
+
- 2.6
|
64
|
+
- 2.5
|
65
|
+
- jruby
|
66
|
+
experimental: [false]
|
67
|
+
include:
|
68
|
+
- ruby: 3.1
|
69
|
+
experimental: true
|
70
|
+
- ruby: 3.0
|
71
|
+
experimental: true
|
72
|
+
steps:
|
73
|
+
- name: Checkout
|
74
|
+
uses: actions/checkout@v2
|
75
|
+
- name: Setup Ruby
|
76
|
+
uses: ruby/setup-ruby@v1
|
77
|
+
with:
|
78
|
+
ruby-version: ${{ matrix.ruby }}
|
79
|
+
- name: Gemfile Cache
|
80
|
+
uses: actions/cache@v2
|
81
|
+
with:
|
82
|
+
path: Gemfile.lock
|
83
|
+
key: ${{ runner.os }}-gemlock-${{ matrix.ruby }}-${{ hashFiles('Gemfile', 'format_parser.gemspec') }}
|
84
|
+
restore-keys: |
|
85
|
+
${{ runner.os }}-gemlock-${{ matrix.ruby }}-
|
86
|
+
- name: Bundle Cache
|
87
|
+
id: cache-gems
|
88
|
+
uses: actions/cache@v2
|
89
|
+
with:
|
90
|
+
path: vendor/bundle
|
91
|
+
key: ${{ runner.os }}-gems-${{ matrix.ruby }}-${{ hashFiles('Gemfile', 'Gemfile.lock', 'format_parser.gemspec') }}
|
92
|
+
restore-keys: |
|
93
|
+
${{ runner.os }}-gems-${{ matrix.ruby }}-
|
94
|
+
${{ runner.os }}-gems-
|
95
|
+
- name: Bundle Install
|
96
|
+
if: steps.cache-gems.outputs.cache-hit != 'true'
|
97
|
+
run: bundle install --jobs 4 --retry 3
|
98
|
+
- name: RSpec
|
99
|
+
continue-on-error: ${{ matrix.experimental }}
|
100
|
+
run: bundle exec rake parallel:spec
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
## 1.0.0
|
2
|
+
* Dropping support for Ruby 2.2.X, 2.3.X and 2.4.X
|
3
|
+
* MP3: Fix negative length reads in edge cases by bumping `id3tag` version to `v0.14.2`
|
4
|
+
|
5
|
+
## 0.29.1
|
6
|
+
* Fix handling of 200 responses with `parse_http` as well as handling of very small responses which do not need range access
|
7
|
+
|
8
|
+
## 0.29.0
|
9
|
+
* Add option `headers:` to `FormatParser.parse_http`
|
10
|
+
|
11
|
+
## 0.28.0
|
12
|
+
* Change `FormatParser.parse_http` to follow HTTP redirects
|
13
|
+
|
1
14
|
## 0.27.0
|
2
15
|
* Add `#content_type` on `Result` return values which makes sense for the detected filetype
|
3
16
|
|
data/format_parser.gemspec
CHANGED
@@ -32,8 +32,9 @@ Gem::Specification.new do |spec|
|
|
32
32
|
|
33
33
|
spec.add_dependency 'ks', '~> 0.0'
|
34
34
|
spec.add_dependency 'exifr', '~> 1', '>= 1.3.8'
|
35
|
-
spec.add_dependency 'id3tag', '~> 0.14'
|
35
|
+
spec.add_dependency 'id3tag', '~> 0.14', '>= 0.14.2'
|
36
36
|
spec.add_dependency 'faraday', '~> 0.13'
|
37
|
+
spec.add_dependency 'faraday_middleware', '~> 0.14'
|
37
38
|
spec.add_dependency 'measurometer', '~> 1'
|
38
39
|
|
39
40
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
data/lib/format_parser.rb
CHANGED
@@ -88,13 +88,14 @@ module FormatParser
|
|
88
88
|
# given to `.parse`. The accepted keyword arguments are the same as the ones for `parse`.
|
89
89
|
#
|
90
90
|
# @param url[String, URI] the HTTP(S) URL to request the object from using Faraday and `Range:` requests
|
91
|
+
# @param headers[Hash] (optional) the HTTP headers to request the object from using Faraday
|
91
92
|
# @param kwargs the keyword arguments to be delegated to `.parse`
|
92
93
|
# @see {.parse}
|
93
|
-
def self.parse_http(url, **kwargs)
|
94
|
+
def self.parse_http(url, headers: {}, **kwargs)
|
94
95
|
# Do not extract the filename, since the URL
|
95
96
|
# can really be "anything". But if the caller
|
96
97
|
# provides filename_hint it will be carried over
|
97
|
-
parse(RemoteIO.new(url), **kwargs)
|
98
|
+
parse(RemoteIO.new(url, headers: headers), **kwargs)
|
98
99
|
end
|
99
100
|
|
100
101
|
# Parses the file at the given `path` and returns the results as if it were any IO
|
data/lib/remote_io.rb
CHANGED
@@ -24,8 +24,11 @@ class FormatParser::RemoteIO
|
|
24
24
|
end
|
25
25
|
|
26
26
|
# @param uri[URI, String] the remote URL to obtain
|
27
|
-
|
27
|
+
# @param headers[Hash] (optional) the HTTP headers to be used in the HTTP request
|
28
|
+
def initialize(uri, headers: {})
|
28
29
|
require 'faraday'
|
30
|
+
require 'faraday_middleware/response/follow_redirects'
|
31
|
+
@headers = headers
|
29
32
|
@uri = uri
|
30
33
|
@pos = 0
|
31
34
|
@remote_size = false
|
@@ -78,21 +81,40 @@ class FormatParser::RemoteIO
|
|
78
81
|
# We use a GET and not a HEAD request followed by a GET because
|
79
82
|
# S3 does not allow HEAD requests if you only presigned your URL for GETs, so we
|
80
83
|
# combine the first GET of a segment and retrieving the size of the resource
|
81
|
-
|
84
|
+
conn = Faraday.new(headers: @headers) do |faraday|
|
85
|
+
faraday.use FaradayMiddleware::FollowRedirects
|
86
|
+
# we still need the default adapter, more details: https://blog.thecodewhisperer.com/permalink/losing-time-to-faraday
|
87
|
+
faraday.adapter Faraday.default_adapter
|
88
|
+
end
|
89
|
+
response = conn.get(@uri, nil, range: 'bytes=%d-%d' % [range.begin, range.end])
|
82
90
|
|
83
91
|
case response.status
|
84
|
-
when 200
|
92
|
+
when 200
|
93
|
+
# S3 returns 200 when you request a Range that is fully satisfied by the entire object,
|
94
|
+
# we take that into account here. Also, for very tiny responses (and also for empty responses)
|
95
|
+
# the responses are going to be 200 which does not mean we cannot proceed
|
96
|
+
# To have a good check for both of these conditions we need to know whether the ranges overlap fully
|
97
|
+
response_size = response.body.bytesize
|
98
|
+
requested_range_size = range.end - range.begin + 1
|
99
|
+
if response_size > requested_range_size
|
100
|
+
error_message = [
|
101
|
+
"We requested #{requested_range_size} bytes, but the server sent us more",
|
102
|
+
"(#{response_size} bytes) - it likely has no `Range:` support.",
|
103
|
+
"The error occurred when talking to #{@uri})"
|
104
|
+
]
|
105
|
+
raise InvalidRequest.new(response.status, error_message.join("\n"))
|
106
|
+
end
|
107
|
+
[response_size, response.body]
|
108
|
+
when 206
|
85
109
|
# Figure out of the server supports content ranges, if it doesn't we have no
|
86
110
|
# business working with that server
|
87
111
|
range_header = response.headers['Content-Range']
|
88
|
-
raise InvalidRequest.new(response.status, "
|
112
|
+
raise InvalidRequest.new(response.status, "The server replied with 206 status but no Content-Range at #{@uri}") unless range_header
|
89
113
|
|
90
114
|
# "Content-Range: bytes 0-0/307404381" is how the response header is structured
|
91
115
|
size = range_header[/\/(\d+)$/, 1].to_i
|
92
116
|
|
93
|
-
#
|
94
|
-
# we take that into account here. For other servers, 206 is the expected response code.
|
95
|
-
# Also, if we request a _larger_ range than what can be satisfied by the server,
|
117
|
+
# If we request a _larger_ range than what can be satisfied by the server,
|
96
118
|
# the response is going to only contain what _can_ be sent and the status is also going
|
97
119
|
# to be 206
|
98
120
|
return [size, response.body]
|
@@ -53,19 +53,22 @@ end
|
|
53
53
|
require 'minitest/autorun'
|
54
54
|
require 'open-uri'
|
55
55
|
|
56
|
+
fixtures_dir = File.join(File.dirname(__FILE__), '../../fixtures')
|
57
|
+
|
56
58
|
describe User do
|
57
59
|
describe "profile_picture's metadatas" do
|
58
60
|
it 'parse metadatas with format_parser' do
|
61
|
+
fixture_path = fixtures_dir + '/PNG/cat.png'
|
59
62
|
user = User.create
|
60
63
|
user.profile_picture.attach(
|
61
64
|
filename: 'cat.png',
|
62
|
-
io:
|
65
|
+
io: File.open(fixture_path, 'rb')
|
63
66
|
)
|
64
67
|
|
65
68
|
user.profile_picture.analyze
|
66
69
|
|
67
|
-
_(user.profile_picture.metadata[:width_px]).must_equal
|
68
|
-
_(user.profile_picture.metadata[:height_px]).must_equal
|
70
|
+
_(user.profile_picture.metadata[:width_px]).must_equal 600
|
71
|
+
_(user.profile_picture.metadata[:height_px]).must_equal 600
|
69
72
|
_(user.profile_picture.metadata[:color_mode]).must_equal 'rgba'
|
70
73
|
end
|
71
74
|
end
|
@@ -15,18 +15,31 @@ describe 'Fetching data from HTTP remotes' do
|
|
15
15
|
}
|
16
16
|
@server = WEBrick::HTTPServer.new(options)
|
17
17
|
@server.mount '/', WEBrick::HTTPServlet::FileHandler, fixtures_dir
|
18
|
+
@server.mount_proc '/redirect' do |req, res|
|
19
|
+
res.status = 302
|
20
|
+
res.header['Location'] = req.path.sub('/redirect', '')
|
21
|
+
end
|
22
|
+
@server.mount_proc '/empty' do |_req, res|
|
23
|
+
res.status = 200
|
24
|
+
res.body = ''
|
25
|
+
end
|
26
|
+
@server.mount_proc '/tiny' do |_req, res|
|
27
|
+
res.status = 200
|
28
|
+
res.body = File.read(fixtures_dir + '/test.gif')
|
29
|
+
end
|
30
|
+
|
18
31
|
trap('INT') { @server.stop }
|
19
32
|
@server_thread = Thread.new { @server.start }
|
20
33
|
end
|
21
34
|
|
22
|
-
it '
|
35
|
+
it 'works with .parse_http called without any options' do
|
23
36
|
result = FormatParser.parse_http('http://localhost:9399/PNG/anim.png')
|
24
37
|
|
25
38
|
expect(result.format).to eq(:png)
|
26
39
|
expect(result.height_px).to eq(180)
|
27
40
|
end
|
28
41
|
|
29
|
-
it '
|
42
|
+
it 'works with .parse_http called with additional options' do
|
30
43
|
fake_result = double(nature: :audio, format: :aiff)
|
31
44
|
expect_any_instance_of(FormatParser::AIFFParser).to receive(:call).and_return(fake_result)
|
32
45
|
results = FormatParser.parse_http('http://localhost:9399/PNG/anim.png', results: :all)
|
@@ -35,6 +48,18 @@ describe 'Fetching data from HTTP remotes' do
|
|
35
48
|
expect(results).to include(fake_result)
|
36
49
|
end
|
37
50
|
|
51
|
+
it 'is able to cope with a 0-size resource which does not provide Content-Range' do
|
52
|
+
file_information = FormatParser.parse_http('http://localhost:9399/empty')
|
53
|
+
|
54
|
+
expect(file_information).to be_nil
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'is able to cope with a tiny resource which fits into the first requested range completely' do
|
58
|
+
file_information = FormatParser.parse_http('http://localhost:9399/tiny')
|
59
|
+
expect(file_information).not_to be_nil
|
60
|
+
expect(file_information.nature).to eq(:image)
|
61
|
+
end
|
62
|
+
|
38
63
|
it 'parses the animated PNG over HTTP' do
|
39
64
|
file_information = FormatParser.parse_http('http://localhost:9399/PNG/anim.png')
|
40
65
|
expect(file_information).not_to be_nil
|
@@ -91,6 +116,32 @@ describe 'Fetching data from HTTP remotes' do
|
|
91
116
|
end
|
92
117
|
end
|
93
118
|
|
119
|
+
context 'when the server responds with a redirect' do
|
120
|
+
it 'follows the redirect' do
|
121
|
+
file_information = FormatParser.parse_http('http://localhost:9399/redirect/TIFF/test.tif')
|
122
|
+
expect(file_information.format).to eq(:tif)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'sends provided HTTP headers in the request' do
|
127
|
+
# Faraday is required only after calling .parse_http
|
128
|
+
# This line is just to trigger this require, then it's possible to
|
129
|
+
# add an expectation of how Faraday is initialized after.
|
130
|
+
FormatParser.parse_http('invalid_url') rescue nil
|
131
|
+
|
132
|
+
expect(Faraday)
|
133
|
+
.to receive(:new)
|
134
|
+
.with(headers: {'test-header' => 'test-value'})
|
135
|
+
.and_call_original
|
136
|
+
|
137
|
+
file_information = FormatParser.parse_http(
|
138
|
+
'http://localhost:9399//TIFF/test.tif',
|
139
|
+
headers: {'test-header' => 'test-value'}
|
140
|
+
)
|
141
|
+
|
142
|
+
expect(file_information.format).to eq(:tif)
|
143
|
+
end
|
144
|
+
|
94
145
|
after(:all) do
|
95
146
|
@server.stop
|
96
147
|
@server_thread.join(0.5)
|
data/spec/remote_io_spec.rb
CHANGED
@@ -7,7 +7,9 @@ describe FormatParser::RemoteIO do
|
|
7
7
|
rio = described_class.new('https://images.invalid/img.jpg')
|
8
8
|
|
9
9
|
fake_resp = double(headers: {'Content-Range' => '10-109/2577'}, status: 206, body: 'This is the response')
|
10
|
-
|
10
|
+
faraday_conn = instance_double(Faraday::Connection, get: fake_resp)
|
11
|
+
allow(Faraday).to receive(:new).and_return(faraday_conn)
|
12
|
+
expect(faraday_conn).to receive(:get).with('https://images.invalid/img.jpg', nil, range: 'bytes=10-109')
|
11
13
|
|
12
14
|
rio.seek(10)
|
13
15
|
read_result = rio.read(100)
|
@@ -18,7 +20,9 @@ describe FormatParser::RemoteIO do
|
|
18
20
|
rio = described_class.new('https://images.invalid/img.jpg')
|
19
21
|
|
20
22
|
fake_resp = double(headers: {'Content-Range' => '10-109/2577'}, status: 200, body: 'This is the response')
|
21
|
-
|
23
|
+
faraday_conn = instance_double(Faraday::Connection, get: fake_resp)
|
24
|
+
allow(Faraday).to receive(:new).and_return(faraday_conn)
|
25
|
+
expect(faraday_conn).to receive(:get).with('https://images.invalid/img.jpg', nil, range: 'bytes=10-109')
|
22
26
|
|
23
27
|
rio.seek(10)
|
24
28
|
read_result = rio.read(100)
|
@@ -29,7 +33,9 @@ describe FormatParser::RemoteIO do
|
|
29
33
|
rio = described_class.new('https://images.invalid/img.jpg')
|
30
34
|
|
31
35
|
fake_resp = double(headers: {}, status: 403, body: 'Please log in')
|
32
|
-
|
36
|
+
faraday_conn = instance_double(Faraday::Connection, get: fake_resp)
|
37
|
+
allow(Faraday).to receive(:new).and_return(faraday_conn)
|
38
|
+
expect(faraday_conn).to receive(:get).with('https://images.invalid/img.jpg', nil, range: 'bytes=100-199')
|
33
39
|
|
34
40
|
rio.seek(100)
|
35
41
|
expect { rio.read(100) }.to raise_error(/replied with a 403 and refused/)
|
@@ -39,7 +45,9 @@ describe FormatParser::RemoteIO do
|
|
39
45
|
rio = described_class.new('https://images.invalid/img.jpg')
|
40
46
|
|
41
47
|
fake_resp = double(headers: {}, status: 416, body: 'You stepped off the ledge of the range')
|
42
|
-
|
48
|
+
faraday_conn = instance_double(Faraday::Connection, get: fake_resp)
|
49
|
+
allow(Faraday).to receive(:new).and_return(faraday_conn)
|
50
|
+
expect(faraday_conn).to receive(:get).with('https://images.invalid/img.jpg', nil, range: 'bytes=100-199')
|
43
51
|
|
44
52
|
rio.seek(100)
|
45
53
|
expect(rio.read(100)).to be_nil
|
@@ -49,7 +57,9 @@ describe FormatParser::RemoteIO do
|
|
49
57
|
rio = described_class.new('https://images.invalid/img.jpg')
|
50
58
|
|
51
59
|
fake_resp = double(headers: {}, status: 403, body: 'Please log in')
|
52
|
-
|
60
|
+
faraday_conn = instance_double(Faraday::Connection, get: fake_resp)
|
61
|
+
allow(Faraday).to receive(:new).and_return(faraday_conn)
|
62
|
+
expect(faraday_conn).to receive(:get).with('https://images.invalid/img.jpg', nil, range: 'bytes=100-199')
|
53
63
|
|
54
64
|
rio.seek(100)
|
55
65
|
# rubocop: disable Lint/AmbiguousBlockAssociation
|
@@ -60,7 +70,9 @@ describe FormatParser::RemoteIO do
|
|
60
70
|
rio = described_class.new('https://images.invalid/img.jpg')
|
61
71
|
|
62
72
|
fake_resp = double(headers: {}, status: 416, body: 'You jumped off the end of the file maam')
|
63
|
-
|
73
|
+
faraday_conn = instance_double(Faraday::Connection, get: fake_resp)
|
74
|
+
allow(Faraday).to receive(:new).and_return(faraday_conn)
|
75
|
+
expect(faraday_conn).to receive(:get).with('https://images.invalid/img.jpg', nil, range: 'bytes=100-199')
|
64
76
|
|
65
77
|
rio.seek(100)
|
66
78
|
expect(rio.read(100)).to be_nil
|
@@ -69,15 +81,24 @@ describe FormatParser::RemoteIO do
|
|
69
81
|
it 'does not overwrite size when the range cannot be satisfied and the response is 416' do
|
70
82
|
rio = described_class.new('https://images.invalid/img.jpg')
|
71
83
|
|
72
|
-
|
73
|
-
|
84
|
+
fake_resp1 = double(headers: {'Content-Range' => 'bytes 0-0/13'}, status: 206, body: 'a')
|
85
|
+
fake_resp2 = double(headers: {}, status: 416, body: 'You jumped off the end of the file maam')
|
86
|
+
|
87
|
+
faraday_conn = instance_double(Faraday::Connection)
|
88
|
+
allow(Faraday).to receive(:new).and_return(faraday_conn)
|
89
|
+
expect(faraday_conn).to receive(:get)
|
90
|
+
.with('https://images.invalid/img.jpg', nil, range: 'bytes=0-0')
|
91
|
+
.ordered
|
92
|
+
.and_return(fake_resp1)
|
93
|
+
expect(faraday_conn).to receive(:get)
|
94
|
+
.with('https://images.invalid/img.jpg', nil, range: 'bytes=100-199')
|
95
|
+
.ordered
|
96
|
+
.and_return(fake_resp2)
|
97
|
+
|
74
98
|
rio.read(1)
|
75
99
|
|
76
100
|
expect(rio.size).to eq(13)
|
77
101
|
|
78
|
-
fake_resp = double(headers: {}, status: 416, body: 'You jumped off the end of the file maam')
|
79
|
-
expect(Faraday).to receive(:get).with('https://images.invalid/img.jpg', nil, range: 'bytes=100-199').and_return(fake_resp)
|
80
|
-
|
81
102
|
rio.seek(100)
|
82
103
|
expect(rio.read(100)).to be_nil
|
83
104
|
|
@@ -88,7 +109,9 @@ describe FormatParser::RemoteIO do
|
|
88
109
|
rio = described_class.new('https://images.invalid/img.jpg')
|
89
110
|
|
90
111
|
fake_resp = double(headers: {}, status: 502, body: 'Guru meditation')
|
91
|
-
|
112
|
+
faraday_conn = instance_double(Faraday::Connection, get: fake_resp)
|
113
|
+
allow(Faraday).to receive(:new).and_return(faraday_conn)
|
114
|
+
expect(faraday_conn).to receive(:get).with('https://images.invalid/img.jpg', nil, range: 'bytes=100-199')
|
92
115
|
|
93
116
|
rio.seek(100)
|
94
117
|
expect { rio.read(100) }.to raise_error(/replied with a 502 and we might want to retry/)
|
@@ -100,7 +123,9 @@ describe FormatParser::RemoteIO do
|
|
100
123
|
expect(rio.pos).to eq(0)
|
101
124
|
|
102
125
|
fake_resp = double(headers: {'Content-Range' => 'bytes 0-0/13'}, status: 206, body: 'a')
|
103
|
-
|
126
|
+
faraday_conn = instance_double(Faraday::Connection, get: fake_resp)
|
127
|
+
allow(Faraday).to receive(:new).and_return(faraday_conn)
|
128
|
+
expect(faraday_conn).to receive(:get).with('https://images.invalid/img.jpg', nil, range: 'bytes=0-0')
|
104
129
|
rio.read(1)
|
105
130
|
|
106
131
|
expect(rio.pos).to eq(1)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: format_parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Noah Berman
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2022-01-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ks
|
@@ -52,6 +52,9 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0.14'
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: 0.14.2
|
55
58
|
type: :runtime
|
56
59
|
prerelease: false
|
57
60
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -59,6 +62,9 @@ dependencies:
|
|
59
62
|
- - "~>"
|
60
63
|
- !ruby/object:Gem::Version
|
61
64
|
version: '0.14'
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 0.14.2
|
62
68
|
- !ruby/object:Gem::Dependency
|
63
69
|
name: faraday
|
64
70
|
requirement: !ruby/object:Gem::Requirement
|
@@ -73,6 +79,20 @@ dependencies:
|
|
73
79
|
- - "~>"
|
74
80
|
- !ruby/object:Gem::Version
|
75
81
|
version: '0.13'
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: faraday_middleware
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0.14'
|
89
|
+
type: :runtime
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0.14'
|
76
96
|
- !ruby/object:Gem::Dependency
|
77
97
|
name: measurometer
|
78
98
|
requirement: !ruby/object:Gem::Requirement
|
@@ -183,10 +203,10 @@ executables:
|
|
183
203
|
extensions: []
|
184
204
|
extra_rdoc_files: []
|
185
205
|
files:
|
206
|
+
- ".github/workflows/main.yml"
|
186
207
|
- ".gitignore"
|
187
208
|
- ".rspec"
|
188
209
|
- ".rubocop.yml"
|
189
|
-
- ".travis.yml"
|
190
210
|
- CHANGELOG.md
|
191
211
|
- CODE_OF_CONDUCT.md
|
192
212
|
- CONTRIBUTING.md
|
@@ -295,7 +315,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
295
315
|
- !ruby/object:Gem::Version
|
296
316
|
version: '0'
|
297
317
|
requirements: []
|
298
|
-
rubygems_version: 3.
|
318
|
+
rubygems_version: 3.1.6
|
299
319
|
signing_key:
|
300
320
|
specification_version: 4
|
301
321
|
summary: A library for efficient parsing of file metadata
|