format_parser 0.2.0 → 0.3.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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -0
  3. data/.travis.yml +1 -0
  4. data/README.md +14 -11
  5. data/format_parser.gemspec +11 -10
  6. data/lib/care.rb +9 -17
  7. data/lib/format_parser.rb +11 -13
  8. data/lib/format_parser/version.rb +1 -1
  9. data/lib/io_constraint.rb +3 -3
  10. data/lib/io_utils.rb +4 -10
  11. data/lib/parsers/aiff_parser.rb +9 -10
  12. data/lib/parsers/dpx_parser.rb +42 -42
  13. data/lib/parsers/dsl.rb +2 -2
  14. data/lib/parsers/exif_parser.rb +3 -8
  15. data/lib/parsers/fdx_parser.rb +3 -3
  16. data/lib/parsers/gif_parser.rb +3 -5
  17. data/lib/parsers/jpeg_parser.rb +4 -8
  18. data/lib/parsers/moov_parser.rb +8 -6
  19. data/lib/parsers/moov_parser/decoder.rb +105 -122
  20. data/lib/parsers/mp3_parser.rb +36 -46
  21. data/lib/parsers/mp3_parser/id3_v1.rb +7 -13
  22. data/lib/parsers/mp3_parser/id3_v2.rb +6 -6
  23. data/lib/parsers/png_parser.rb +5 -12
  24. data/lib/parsers/psd_parser.rb +2 -2
  25. data/lib/parsers/tiff_parser.rb +10 -12
  26. data/lib/parsers/wav_parser.rb +3 -3
  27. data/lib/read_limiter.rb +3 -7
  28. data/lib/remote_io.rb +3 -6
  29. data/spec/care_spec.rb +10 -10
  30. data/spec/file_information_spec.rb +1 -3
  31. data/spec/format_parser_spec.rb +6 -6
  32. data/spec/io_utils_spec.rb +7 -7
  33. data/spec/parsers/exif_parser_spec.rb +2 -3
  34. data/spec/parsers/gif_parser_spec.rb +1 -1
  35. data/spec/parsers/jpeg_parser_spec.rb +0 -1
  36. data/spec/parsers/moov_parser_spec.rb +2 -3
  37. data/spec/parsers/png_parser_spec.rb +1 -1
  38. data/spec/parsers/tiff_parser_spec.rb +0 -1
  39. data/spec/parsers/wav_parser_spec.rb +3 -3
  40. data/spec/read_limiter_spec.rb +0 -1
  41. data/spec/remote_fetching_spec.rb +34 -20
  42. data/spec/remote_io_spec.rb +20 -21
  43. data/spec/spec_helper.rb +2 -2
  44. metadata +19 -4
@@ -2,15 +2,15 @@ require 'spec_helper'
2
2
 
3
3
  describe Care do
4
4
  describe Care::Cache do
5
- let(:source) { StringIO.new("Hello there, this is our little caching reader") }
5
+ let(:source) { StringIO.new('Hello there, this is our little caching reader') }
6
6
 
7
7
  it 'performs correct reads at various offsets' do
8
8
  cache = Care::Cache.new(3)
9
- expect(cache.byteslice(source, 0, 3)).to eq("Hel")
10
- expect(cache.byteslice(source, 0, 7)).to eq("Hello t")
11
- expect(cache.byteslice(source, 1, 7)).to eq("ello th")
12
- expect(cache.byteslice(source, 11, 8)).to eq(", this i")
13
- expect(cache.byteslice(source, 12, 12)).to eq(" this is our")
9
+ expect(cache.byteslice(source, 0, 3)).to eq('Hel')
10
+ expect(cache.byteslice(source, 0, 7)).to eq('Hello t')
11
+ expect(cache.byteslice(source, 1, 7)).to eq('ello th')
12
+ expect(cache.byteslice(source, 11, 8)).to eq(', this i')
13
+ expect(cache.byteslice(source, 12, 12)).to eq(' this is our')
14
14
  expect(cache.byteslice(source, 120, 12)).to be_nil
15
15
  end
16
16
 
@@ -23,10 +23,10 @@ describe Care do
23
23
 
24
24
  it 'can be cleared' do
25
25
  cache = Care::Cache.new(3)
26
- expect(cache.byteslice(source, 0, 3)).to eq("Hel")
27
- expect(cache.instance_variable_get("@pages")).not_to be_empty
26
+ expect(cache.byteslice(source, 0, 3)).to eq('Hel')
27
+ expect(cache.instance_variable_get('@pages')).not_to be_empty
28
28
  cache.clear
29
- expect(cache.instance_variable_get("@pages")).to be_empty
29
+ expect(cache.instance_variable_get('@pages')).to be_empty
30
30
  end
31
31
 
32
32
  it 'fits all the reads into one if the input fits into one page' do
@@ -67,7 +67,7 @@ describe Care do
67
67
  @recorded_calls ||= []
68
68
  @recorded_calls << [io, at, n_bytes]
69
69
  # Pretend reads always succeed and return the requisite number of bytes
70
- "x" * n_bytes
70
+ 'x' * n_bytes
71
71
  end
72
72
  end
73
73
 
@@ -1,8 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe FormatParser::Image do
4
-
5
- context "File data checks" do
4
+ context 'File data checks' do
6
5
  it 'succeeds with relevant attributes' do
7
6
  result = described_class.new(format: :jpg, width_px: 42, height_px: 10, image_orientation: 1)
8
7
  expect(result.nature).to eq(:image)
@@ -12,5 +11,4 @@ describe FormatParser::Image do
12
11
  expect(result.image_orientation).to eq(1)
13
12
  end
14
13
  end
15
-
16
14
  end
@@ -3,12 +3,12 @@ require 'spec_helper'
3
3
  describe FormatParser do
4
4
  it 'returns nil when trying to parse an empty IO' do
5
5
  d = StringIO.new('')
6
- expect(FormatParser.parse(d)).to be_empty
6
+ expect(FormatParser.parse(d)).to be_nil
7
7
  end
8
8
 
9
9
  it 'returns nil when parsing an IO no parser can make sense of' do
10
10
  d = StringIO.new(Random.new.bytes(1))
11
- expect(FormatParser.parse(d)).to be_empty
11
+ expect(FormatParser.parse(d)).to be_nil
12
12
  end
13
13
 
14
14
  describe 'with fuzzing' do
@@ -26,24 +26,24 @@ describe FormatParser do
26
26
  let(:audio) { FormatParser::Audio.new(format: :aiff, num_audio_channels: 1) }
27
27
  let(:image) { FormatParser::Image.new(format: :dpx, width_px: 1, height_px: 1) }
28
28
 
29
- context '#parse called without any option' do
29
+ context '#parse called hash options' do
30
30
  before do
31
31
  expect_any_instance_of(FormatParser::AIFFParser).to receive(:call).and_return(audio)
32
32
  expect_any_instance_of(FormatParser::DPXParser).to receive(:call).and_return(image)
33
33
  end
34
34
 
35
- subject { FormatParser.parse(blob) }
35
+ subject { FormatParser.parse(blob, results: :all) }
36
36
 
37
37
  it { is_expected.to include(image) }
38
38
  it { is_expected.to include(audio) }
39
39
  end
40
40
 
41
- context '#parse called with hash options' do
41
+ context '#parse called without hash options' do
42
42
  before do
43
43
  expect_any_instance_of(FormatParser::DPXParser).to receive(:call).and_return(image)
44
44
  end
45
45
 
46
- subject { FormatParser.parse(blob, formats: [:dpx], returns: :one) }
46
+ subject { FormatParser.parse(blob) }
47
47
 
48
48
  it { is_expected.to eq(image) }
49
49
  end
@@ -1,8 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe "IOUtils" do
4
- let(:io) {File.open(fixtures_dir + '/test.jpg', 'rb')}
5
- include FormatParser::IOUtils
3
+ describe 'IOUtils' do
4
+ let(:io) { File.open(fixtures_dir + '/test.jpg', 'rb') }
5
+ include FormatParser::IOUtils
6
6
 
7
7
  describe '#safe_read' do
8
8
  it 'raises if the requested bytes are past the EOF' do
@@ -16,12 +16,12 @@ describe "IOUtils" do
16
16
  expect {
17
17
  safe_read(io, 1_000_000)
18
18
  }.to raise_error(FormatParser::IOUtils::InvalidRead)
19
- end
19
+ end
20
20
  end
21
21
 
22
22
  describe '#safe_skip' do
23
23
  it 'raises on a negative skip byte amount' do
24
- fake_io = double()
24
+ fake_io = double
25
25
  expect {
26
26
  safe_skip(fake_io, -5)
27
27
  }.to raise_error(FormatParser::IOUtils::InvalidRead)
@@ -29,12 +29,12 @@ describe "IOUtils" do
29
29
 
30
30
  it 'uses #pos if available on the object' do
31
31
  fake_io = double(pos: 11)
32
- expect(fake_io).to receive(:seek).with(11+5)
32
+ expect(fake_io).to receive(:seek).with(11 + 5)
33
33
  safe_skip(fake_io, 5)
34
34
  end
35
35
 
36
36
  it 'uses #read if no #pos is available on the object' do
37
- fake_io = double()
37
+ fake_io = double
38
38
  expect(fake_io).to receive(:read).with(5).and_return('x' * 5)
39
39
  safe_skip(fake_io, 5)
40
40
  end
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe FormatParser::EXIFParser do
4
-
5
4
  # ORIENTATIONS = [
6
5
  # :top_left,
7
6
  # :top_right,
@@ -23,7 +22,7 @@ describe FormatParser::EXIFParser do
23
22
 
24
23
  expect(parser.orientation).to be_kind_of(Symbol)
25
24
  # Filenames in this dir correspond with the orientation of the file
26
- expect(filename.include?(parser.orientation.to_s)).to be true
25
+ expect(filename.include?(parser.orientation.to_s)).to be true
27
26
  end
28
27
  end
29
28
  end
@@ -38,7 +37,7 @@ describe FormatParser::EXIFParser do
38
37
 
39
38
  expect(parser.orientation).to be_kind_of(Symbol)
40
39
  # Filenames in this dir correspond with the orientation of the file
41
- expect(filename.include?(parser.orientation.to_s)).to be true
40
+ expect(filename.include?(parser.orientation.to_s)).to be true
42
41
  end
43
42
  end
44
43
  end
@@ -23,7 +23,7 @@ describe FormatParser::GIFParser do
23
23
 
24
24
  describe 'is able to correctly parse our own examples' do
25
25
  it 'is able to parse the animated GIF' do
26
- gif_path = fixtures_dir + "GIF/anim.gif"
26
+ gif_path = fixtures_dir + 'GIF/anim.gif'
27
27
 
28
28
  parsed = subject.call(File.open(gif_path, 'rb'))
29
29
  expect(parsed).not_to be_nil
@@ -32,5 +32,4 @@ describe FormatParser::JPEGParser do
32
32
  end
33
33
  end
34
34
  end
35
-
36
35
  end
@@ -1,8 +1,7 @@
1
- # coding: utf-8
1
+
2
2
  require 'spec_helper'
3
3
 
4
4
  describe FormatParser::MOOVParser do
5
-
6
5
  def deep_print_atoms(atoms, output, swimlanes = [])
7
6
  return unless atoms
8
7
 
@@ -12,7 +11,7 @@ describe FormatParser::MOOVParser do
12
11
  vert = '│'
13
12
  cdn = '┬'
14
13
  n_atoms = atoms.length
15
-
14
+
16
15
  atoms.each_with_index do |atom, i|
17
16
  is_last_child = i == (n_atoms - 1)
18
17
  has_children = atom.children && atom.children.any?
@@ -20,7 +20,7 @@ describe FormatParser::PNGParser do
20
20
  end
21
21
 
22
22
  it 'is able to parse an animated PNG' do
23
- gif_path = fixtures_dir + "PNG/anim.png"
23
+ gif_path = fixtures_dir + 'PNG/anim.png'
24
24
 
25
25
  parsed = subject.call(File.open(gif_path, 'rb'))
26
26
  expect(parsed).not_to be_nil
@@ -33,5 +33,4 @@ describe FormatParser::TIFFParser do
33
33
  end
34
34
  end
35
35
  end
36
-
37
36
  end
@@ -12,7 +12,7 @@ describe FormatParser::WAVParser do
12
12
  end
13
13
  end
14
14
 
15
- it "returns correct info about pcm files" do
15
+ it 'returns correct info about pcm files' do
16
16
  parse_result = subject.call(File.open(__dir__ + '/../fixtures/WAV/c_8kmp316.wav', 'rb'))
17
17
 
18
18
  expect(parse_result.nature).to eq(:audio)
@@ -23,7 +23,7 @@ describe FormatParser::WAVParser do
23
23
  expect(parse_result.media_duration_seconds).to be_within(0.01).of(13.81)
24
24
  end
25
25
 
26
- it "returns correct info about pcm files with more channels" do
26
+ it 'returns correct info about pcm files with more channels' do
27
27
  parse_result = subject.call(File.open(__dir__ + '/../fixtures/WAV/c_39064__alienbomb__atmo-truck.wav', 'rb'))
28
28
 
29
29
  expect(parse_result.nature).to eq(:audio)
@@ -34,7 +34,7 @@ describe FormatParser::WAVParser do
34
34
  expect(parse_result.media_duration_seconds).to be_within(0.01).of(3.69)
35
35
  end
36
36
 
37
- it "returns correct info about non pcm files" do
37
+ it 'returns correct info about non pcm files' do
38
38
  parse_result = subject.call(File.open(__dir__ + '/../fixtures/WAV/c_11k16bitpcm.wav', 'rb'))
39
39
 
40
40
  expect(parse_result.nature).to eq(:audio)
@@ -41,5 +41,4 @@ describe FormatParser::ReadLimiter do
41
41
  reader.read(1)
42
42
  }.to raise_error(/bytes budget \(512\) exceeded/)
43
43
  end
44
-
45
44
  end
@@ -6,52 +6,67 @@ describe 'Fetching data from HTTP remotes' do
6
6
  log_file ||= StringIO.new
7
7
  log = WEBrick::Log.new(log_file)
8
8
  options = {
9
- :Port => 9399,
10
- :Logger => log,
11
- :AccessLog => [
12
- [ log, WEBrick::AccessLog::COMMON_LOG_FORMAT ],
13
- [ log, WEBrick::AccessLog::REFERER_LOG_FORMAT ]
14
- ]
9
+ Port: 9399,
10
+ Logger: log,
11
+ AccessLog: [
12
+ [log, WEBrick::AccessLog::COMMON_LOG_FORMAT],
13
+ [log, WEBrick::AccessLog::REFERER_LOG_FORMAT]
14
+ ]
15
15
  }
16
16
  @server = WEBrick::HTTPServer.new(options)
17
17
  @server.mount '/', WEBrick::HTTPServlet::FileHandler, fixtures_dir
18
- trap("INT") { @server.stop }
18
+ trap('INT') { @server.stop }
19
19
  @server_thread = Thread.new { @server.start }
20
20
  end
21
21
 
22
+ it '#parse_http is called without any option' do
23
+ result = FormatParser.parse_http('http://localhost:9399/PNG/anim.png')
24
+
25
+ expect(result.format).to eq(:png)
26
+ expect(result.height_px).to eq(180)
27
+ end
28
+
29
+ it '#parse_http is called with hash options' do
30
+ expect_any_instance_of(FormatParser::AIFFParser).to receive(:call).and_return(:audio)
31
+ result = FormatParser.parse_http('http://localhost:9399/PNG/anim.png', results: :all)
32
+
33
+ expect(result.include?(:audio)).to be true
34
+ expect(result.count).to eq(2)
35
+ end
36
+
22
37
  it 'parses the animated PNG over HTTP' do
23
38
  file_information = FormatParser.parse_http('http://localhost:9399/PNG/anim.png')
24
39
  expect(file_information).not_to be_nil
25
- expect(file_information.first.nature).to eq(:image)
40
+ expect(file_information.nature).to eq(:image)
26
41
  end
27
42
 
28
43
  it 'parses the JPEGs exif data' do
29
44
  file_information = FormatParser.parse_http('http://localhost:9399/exif-orientation-testimages/jpg/top_left.jpg')
30
45
  expect(file_information).not_to be_nil
31
- expect(file_information.first.nature).to eq(:image)
32
- expect(file_information.first.format).to eq(:jpg)
33
- expect(file_information.first.orientation).to eq(:top_left)
46
+ expect(file_information.nature).to eq(:image)
47
+ expect(file_information.format).to eq(:jpg)
48
+ expect(file_information.orientation).to eq(:top_left)
34
49
  end
35
50
 
36
51
  it 'parses the TIFFs exif data' do
37
52
  file_information = FormatParser.parse_http('http://localhost:9399/TIFF/test.tif')
38
53
  expect(file_information).not_to be_nil
39
- expect(file_information.first.nature).to eq(:image)
40
- expect(file_information.first.format).to eq(:tif)
41
- expect(file_information.first.orientation).to eq(:top_left)
54
+ expect(file_information.nature).to eq(:image)
55
+ expect(file_information.format).to eq(:tif)
56
+ expect(file_information.orientation).to eq(:top_left)
42
57
  end
43
58
 
44
59
  describe 'is able to correctly parse orientation for all remote JPEG EXIF examples from FastImage' do
45
60
  Dir.glob(fixtures_dir + '/exif-orientation-testimages/jpg/*.jpg').each do |jpeg_path|
46
61
  filename = File.basename(jpeg_path)
47
62
  it "is able to parse #{filename}" do
48
- remote_jpeg_path = jpeg_path.gsub(fixtures_dir, "http://localhost:9399")
63
+ remote_jpeg_path = jpeg_path.gsub(fixtures_dir, 'http://localhost:9399')
49
64
  file_information = FormatParser.parse_http(remote_jpeg_path)
50
65
  expect(file_information).not_to be_nil
51
66
 
52
- expect(file_information.first.orientation).to be_kind_of(Symbol)
67
+ expect(file_information.orientation).to be_kind_of(Symbol)
53
68
  # Filenames in this dir correspond with the orientation of the file
54
- expect(filename.include?(file_information.first.orientation.to_s)).to be true
69
+ expect(filename.include?(file_information.orientation.to_s)).to be true
55
70
  end
56
71
  end
57
72
  end
@@ -60,15 +75,14 @@ describe 'Fetching data from HTTP remotes' do
60
75
  Dir.glob(fixtures_dir + '/**/*.*').sort.each do |fixture_path|
61
76
  filename = File.basename(fixture_path)
62
77
  it "parses #{filename} without raising any errors" do
63
- remote_fixture_path = fixture_path.gsub(fixtures_dir, "http://localhost:9399")
78
+ remote_fixture_path = fixture_path.gsub(fixtures_dir, 'http://localhost:9399')
64
79
  # Some of the fixtures are in dirs with spaces
65
- cleaned_remote_fixture_path = remote_fixture_path.gsub(" ", "%20")
80
+ cleaned_remote_fixture_path = remote_fixture_path.gsub(' ', '%20')
66
81
  FormatParser.parse_http(cleaned_remote_fixture_path)
67
82
  end
68
83
  end
69
84
  end
70
85
 
71
-
72
86
  after(:all) do
73
87
  @server.stop
74
88
  @server_thread.join(0.5)
@@ -1,14 +1,13 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe FormatParser::RemoteIO do
4
-
5
4
  it_behaves_like 'an IO object compatible with IOConstraint'
6
5
 
7
6
  it 'returns the partial content when the server supplies a 206 status' do
8
- rio = described_class.new("https://images.invalid/img.jpg")
9
-
7
+ rio = described_class.new('https://images.invalid/img.jpg')
8
+
10
9
  fake_resp = double(headers: {'Content-Range' => '10-109/2577'}, status: 206, body: 'This is the response')
11
- expect(Faraday).to receive(:get).with("https://images.invalid/img.jpg", nil, range: "bytes=10-109").and_return(fake_resp)
10
+ expect(Faraday).to receive(:get).with('https://images.invalid/img.jpg', nil, range: 'bytes=10-109').and_return(fake_resp)
12
11
 
13
12
  rio.seek(10)
14
13
  read_result = rio.read(100)
@@ -16,10 +15,10 @@ describe FormatParser::RemoteIO do
16
15
  end
17
16
 
18
17
  it 'returns the entire content when the server supplies the Content-Range response but sends a 200 status' do
19
- rio = described_class.new("https://images.invalid/img.jpg")
20
-
18
+ rio = described_class.new('https://images.invalid/img.jpg')
19
+
21
20
  fake_resp = double(headers: {'Content-Range' => '10-109/2577'}, status: 200, body: 'This is the response')
22
- expect(Faraday).to receive(:get).with("https://images.invalid/img.jpg", nil, range: "bytes=10-109").and_return(fake_resp)
21
+ expect(Faraday).to receive(:get).with('https://images.invalid/img.jpg', nil, range: 'bytes=10-109').and_return(fake_resp)
23
22
 
24
23
  rio.seek(10)
25
24
  read_result = rio.read(100)
@@ -27,36 +26,36 @@ describe FormatParser::RemoteIO do
27
26
  end
28
27
 
29
28
  it 'raises a specific error for all 4xx responses except 416' do
30
- rio = described_class.new("https://images.invalid/img.jpg")
31
-
29
+ rio = described_class.new('https://images.invalid/img.jpg')
30
+
32
31
  fake_resp = double(headers: {}, status: 403, body: 'Please log in')
33
- expect(Faraday).to receive(:get).with("https://images.invalid/img.jpg", nil, range: "bytes=100-199").and_return(fake_resp)
32
+ expect(Faraday).to receive(:get).with('https://images.invalid/img.jpg', nil, range: 'bytes=100-199').and_return(fake_resp)
34
33
 
35
34
  rio.seek(100)
36
35
  expect { rio.read(100) }.to raise_error(/replied with a 403 and refused/)
37
36
  end
38
37
 
39
38
  it 'returns a nil when the range cannot be satisfied and the response is 416' do
40
- rio = described_class.new("https://images.invalid/img.jpg")
41
-
39
+ rio = described_class.new('https://images.invalid/img.jpg')
40
+
42
41
  fake_resp = double(headers: {}, status: 416, body: 'You jumped off the end of the file maam')
43
- expect(Faraday).to receive(:get).with("https://images.invalid/img.jpg", nil, range: "bytes=100-199").and_return(fake_resp)
42
+ expect(Faraday).to receive(:get).with('https://images.invalid/img.jpg', nil, range: 'bytes=100-199').and_return(fake_resp)
44
43
 
45
44
  rio.seek(100)
46
45
  expect(rio.read(100)).to be_nil
47
46
  end
48
47
 
49
48
  it 'does not overwrite size when the range cannot be satisfied and the response is 416' do
50
- rio = described_class.new("https://images.invalid/img.jpg")
49
+ rio = described_class.new('https://images.invalid/img.jpg')
51
50
 
52
51
  fake_resp = double(headers: {'Content-Range' => 'bytes 0-0/13'}, status: 206, body: 'a')
53
- expect(Faraday).to receive(:get).with("https://images.invalid/img.jpg", nil, range: "bytes=0-0").and_return(fake_resp)
52
+ expect(Faraday).to receive(:get).with('https://images.invalid/img.jpg', nil, range: 'bytes=0-0').and_return(fake_resp)
54
53
  rio.read(1)
55
54
 
56
55
  expect(rio.size).to eq(13)
57
56
 
58
57
  fake_resp = double(headers: {}, status: 416, body: 'You jumped off the end of the file maam')
59
- expect(Faraday).to receive(:get).with("https://images.invalid/img.jpg", nil, range: "bytes=100-199").and_return(fake_resp)
58
+ expect(Faraday).to receive(:get).with('https://images.invalid/img.jpg', nil, range: 'bytes=100-199').and_return(fake_resp)
60
59
 
61
60
  rio.seek(100)
62
61
  expect(rio.read(100)).to be_nil
@@ -65,22 +64,22 @@ describe FormatParser::RemoteIO do
65
64
  end
66
65
 
67
66
  it 'raises a specific error for all 5xx responses' do
68
- rio = described_class.new("https://images.invalid/img.jpg")
69
-
67
+ rio = described_class.new('https://images.invalid/img.jpg')
68
+
70
69
  fake_resp = double(headers: {}, status: 502, body: 'Guru meditation')
71
- expect(Faraday).to receive(:get).with("https://images.invalid/img.jpg", nil, range: "bytes=100-199").and_return(fake_resp)
70
+ expect(Faraday).to receive(:get).with('https://images.invalid/img.jpg', nil, range: 'bytes=100-199').and_return(fake_resp)
72
71
 
73
72
  rio.seek(100)
74
73
  expect { rio.read(100) }.to raise_error(/replied with a 502 and we might want to retry/)
75
74
  end
76
75
 
77
76
  it 'maintains and exposes #pos' do
78
- rio = described_class.new("https://images.invalid/img.jpg")
77
+ rio = described_class.new('https://images.invalid/img.jpg')
79
78
 
80
79
  expect(rio.pos).to eq(0)
81
80
 
82
81
  fake_resp = double(headers: {'Content-Range' => 'bytes 0-0/13'}, status: 206, body: 'a')
83
- expect(Faraday).to receive(:get).with("https://images.invalid/img.jpg", nil, range: "bytes=0-0").and_return(fake_resp)
82
+ expect(Faraday).to receive(:get).with('https://images.invalid/img.jpg', nil, range: 'bytes=0-0').and_return(fake_resp)
84
83
  rio.read(1)
85
84
 
86
85
  expect(rio.pos).to eq(1)