class Parsby::BackedIO
Public Class Methods
Makes a new BackedIO
out of the provided IO, calls the provided blocked and restores the IO on an exception.
# File lib/parsby.rb, line 434 def self.for(io, &b) bio = new io begin b.call bio rescue bio.restore raise end end
Initializes a BackedIO
out of the provided IO object or String. The String will be turned into an IO using StringIO.
# File lib/parsby.rb, line 426 def initialize(io) io = StringIO.new io if io.is_a? String @io = io @backup = Backup.new end
Similar to BackedIO.for
, but it always restores the IO, even when there's no exception.
# File lib/parsby.rb, line 446 def self.peek(io, &b) self.for io do |bio| begin b.call bio ensure bio.restore end end end
Public Instance Methods
# File lib/parsby.rb, line 508 def col backup.col end
Returns current line, including what's to come from read
, without consuming input.
# File lib/parsby.rb, line 528 def current_line load_rest_of_line backup.current_line end
pos == current_line_pos
+ col. This is needed to convert a pos to a col.
# File lib/parsby.rb, line 504 def current_line_pos pos - col end
# File lib/parsby.rb, line 512 def current_line_range start = current_line_pos PosRange.new start, start + current_line.length end
Returns line number of current line. This is 1-indexed.
# File lib/parsby.rb, line 479 def line_number lines_read.length end
# File lib/parsby.rb, line 521 def lines_read load_rest_of_line backup.back_lines.map(&:chomp) end
# File lib/parsby.rb, line 517 def load_rest_of_line with_saved_pos { readline } end
This is to provide transparent delegation to methods of underlying IO.
# File lib/parsby.rb, line 550 def method_missing(m, *args, &b) @io.send(m, *args, &b) end
Like read
, but without consuming.
# File lib/parsby.rb, line 466 def peek(*args) with_saved_pos { read(*args) } end
Delegates pos to inner io, and works around pipes' inability to return pos by getting the length of the innermost BackedIO
.
# File lib/parsby.rb, line 472 def pos @io.pos rescue Errno::ESPIPE backup.pos end
Reads from underlying IO and backs it up.
# File lib/parsby.rb, line 559 def read(*args) @io.read(*args).tap {|r| backup.write r unless r.nil? } end
# File lib/parsby.rb, line 554 def readline(*args) @io.readline(*args).tap {|r| backup.write r unless r.nil? } end
Restore n chars from the backup.
# File lib/parsby.rb, line 534 def restore(n = backup.back_size) # Handle negatives in consideration of #with_saved_pos. if n < 0 read(-n) else backup.back(n).chars.reverse.each {|c| ungetc c} end nil end
# File lib/parsby.rb, line 544 def restore_to(prev_pos) restore(pos - prev_pos) end
# File lib/parsby.rb, line 483 def seek(amount, whence = IO::SEEK_SET) if whence == IO::SEEK_END read restore(-amount) return end new_pos = case whence when IO::SEEK_SET amount when IO::SEEK_CUR pos + amount end if new_pos > pos read new_pos - pos else restore_to new_pos end end
Pass to underlying IO's ungetc and discard a part of the same length from the backup. As specified with different IO classes, the argument should be a single character. To restore from the backup, use restore
.
# File lib/parsby.rb, line 567 def ungetc(c) # Though c is supposed to be a single character, as specified by the # ungetc of different IO objects, let's not assume that when # adjusting the backup. backup.seek(-c.length, IO::SEEK_CUR) @io.ungetc(c) end
# File lib/parsby.rb, line 456 def with_saved_pos(&b) saved = pos begin b.call saved ensure restore_to saved end end
Private Instance Methods
# File lib/parsby.rb, line 577 def backup @backup end