format_parser 0.2.0 → 0.3.0

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