format_parser 0.27.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|