class Parsby::BackedIO

Public Class Methods

for(io, &b) click to toggle source

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
new(io) click to toggle source

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
peek(io, &b) click to toggle source

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

col() click to toggle source
# File lib/parsby.rb, line 508
def col
  backup.col
end
current_line() click to toggle source

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
current_line_pos() click to toggle source

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
current_line_range() click to toggle source
# File lib/parsby.rb, line 512
def current_line_range
  start = current_line_pos
  PosRange.new start, start + current_line.length
end
line_number() click to toggle source

Returns line number of current line. This is 1-indexed.

# File lib/parsby.rb, line 479
def line_number
  lines_read.length
end
lines_read() click to toggle source
# File lib/parsby.rb, line 521
def lines_read
  load_rest_of_line
  backup.back_lines.map(&:chomp)
end
load_rest_of_line() click to toggle source
# File lib/parsby.rb, line 517
def load_rest_of_line
  with_saved_pos { readline }
end
method_missing(m, *args, &b) click to toggle source

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
peek(*args) click to toggle source

Like read, but without consuming.

# File lib/parsby.rb, line 466
def peek(*args)
  with_saved_pos { read(*args) }
end
pos() click to toggle source

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
read(*args) click to toggle source

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
readline(*args) click to toggle source
# File lib/parsby.rb, line 554
def readline(*args)
  @io.readline(*args).tap {|r| backup.write r unless r.nil? }
end
restore(n = backup.back_size) click to toggle source

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
restore_to(prev_pos) click to toggle source
# File lib/parsby.rb, line 544
def restore_to(prev_pos)
  restore(pos - prev_pos)
end
seek(amount, whence = IO::SEEK_SET) click to toggle source
# 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
ungetc(c) click to toggle source

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
with_saved_pos(&b) click to toggle source
# 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

backup() click to toggle source
# File lib/parsby.rb, line 577
def backup
  @backup
end