Class: AudioTag::ID3::StreamReader

Inherits:
Object
  • Object
show all
Defined in:
lib/audio_tag/id3/stream_reader.rb

Overview

Wrapper for native IO stream objects that defines a consistent reading interface.

Bang methods indicate that the read operation is not idempotent, as calling them will result in the stream position being advanced. Non-bang methods are idempotent, as they reset the stream position after reading meaning the net effect on the stream position is 0.

Direct Known Subclasses

StreamSection

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(stream) ⇒ StreamReader

Returns a new instance of StreamReader.



13
14
15
# File 'lib/audio_tag/id3/stream_reader.rb', line 13

def initialize(stream)
  @stream = stream
end

Instance Attribute Details

#streamObject (readonly)

Returns the value of attribute stream.



11
12
13
# File 'lib/audio_tag/id3/stream_reader.rb', line 11

def stream
  @stream
end

Instance Method Details

#read(length) ⇒ Object



21
22
23
24
25
26
27
# File 'lib/audio_tag/id3/stream_reader.rb', line 21

def read(length)
  pos = stream.pos

  read!(length)
ensure
  stream.seek(pos)
end

#read!(length) ⇒ Object



17
18
19
# File 'lib/audio_tag/id3/stream_reader.rb', line 17

def read!(length)
  stream.read(length) || raise
end

#read_byteObject



45
46
47
# File 'lib/audio_tag/id3/stream_reader.rb', line 45

def read_byte
  read_bytes(1).first || raise
end

#read_byte!Object



41
42
43
# File 'lib/audio_tag/id3/stream_reader.rb', line 41

def read_byte!
  read_bytes!(1).first || raise
end

#read_bytes(length) ⇒ Object



33
34
35
36
37
38
39
# File 'lib/audio_tag/id3/stream_reader.rb', line 33

def read_bytes(length)
  pos = stream.pos

  read_bytes!(length)
ensure
  stream.seek(pos)
end

#read_bytes!(length) ⇒ Object



29
30
31
# File 'lib/audio_tag/id3/stream_reader.rb', line 29

def read_bytes!(length)
  stream.read(length)&.bytes || raise
end

#read_bytes_until(byte) ⇒ Object



83
84
85
86
87
88
89
# File 'lib/audio_tag/id3/stream_reader.rb', line 83

def read_bytes_until(byte)
  pos = stream.pos

  read_bytes_until!(byte)
ensure
  stream.seek(pos)
end

#read_bytes_until!(byte, consume_delimiter: true) ⇒ Object

Uses instance method rather than stream.eof? directly as this can be overridden in child classes to prevent read*_until methods extending past the end of a settable limit.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/audio_tag/id3/stream_reader.rb', line 68

def read_bytes_until!(byte, consume_delimiter: true)
  [].tap do |bytes|
    until end_of_stream?
      next_byte = stream.getbyte

      if next_byte == byte
        stream.ungetbyte(1) unless consume_delimiter
        break
      end

      bytes << next_byte
    end
  end
end

#read_until(byte) ⇒ Object



61
62
63
# File 'lib/audio_tag/id3/stream_reader.rb', line 61

def read_until(byte)
  read_bytes_until(byte).pack("c*")
end

#read_until!(byte, consume_delimiter: true) ⇒ Object

Reads the stream up to the specified byte, for example a null delimiter. The given byte is not included in the output, but the stream is advanced to the position after it unless the consume_delimiter flag is false.

This is useful for extracting string fragments until a delimiter without including it in the extracted fragment nor the start of the next.



57
58
59
# File 'lib/audio_tag/id3/stream_reader.rb', line 57

def read_until!(byte, consume_delimiter: true)
  read_bytes_until!(byte, consume_delimiter:).pack("c*")
end