class Cog::Helpers::FileScanner

@api developer Helper for scanning files for embed expansions

Attributes

marked_line_number[R]

@return [Fixnum] line number where mark! was called or -1 if mark! was not called

match[R]

@return [MatchData, nil] match data for the last matched pattern

Public Class Methods

new(filename) click to toggle source

@api developer

# File lib/cog/helpers/file_scanner.rb, line 18
def initialize(filename)
  @filename = filename
  @f = File.open filename, 'r'
  @f = @f.binmode if @f.respond_to?(:binmode)
  @lines = []
  @mark = nil
  @cap_begin_pos = nil
  @cap_end_pos = nil
  @cap_end_lineno = nil
  @match = nil # The last match object
  @win_fudge = if RUBY_PLATFORM =~ /(mswin|mingw)/
    x = @f.readline.end_with? "\r\n"
    @f.seek 0
    @f.lineno = 0
    x ? 0 : 1
  else
    0
  end
end
scan(filename, pattern, opt={}, &block) click to toggle source

Opens the given file for scanning. @param filename [String] path to the file which will be scanned @param pattern [Regexp] a pattern to test for @option opt [Fixnum] :occurrence (0) 0 for the first, 1 for the second, and so on @yieldparam scanner [FileScanner] a file scanner @yieldreturn [Object] @return [Object,nil] the return value of the block, or nil if the pattern was not found

# File lib/cog/helpers/file_scanner.rb, line 51
def self.scan(filename, pattern, opt={}, &block)
  s = new filename
  val = if s.read_until pattern, opt[:occurrence] || 0
    block.call s
  else
    nil
  end
  s.close
  val
end

Public Instance Methods

capture_until(pattern, opt={}) click to toggle source

Advances the file until the given pattern is encountered and captures lines as it reads. The line which matches the pattern will not be captured. Captured lines can later be recovered with captured_text @param pattern [Regexp] a pattern to test for @option opt [Array<Regexp>, Regexp] :but_not (nil) if a line matching any of the provided patterns is found before the desired pattern :bad_pattern_found will be thrown @return [Boolean] whether or not the pattern was found

# File lib/cog/helpers/file_scanner.rb, line 113
def capture_until(pattern, opt={})
  @cap_begin_pos = @f.pos - win_fudge
  but_not = opt[:but_not] || []
  but_not = [but_not] unless but_not.is_a?(Array)
  while line = @f.readline
    but_not.each do |bad_pattern|
      if bad_pattern =~ line
        return false
      end
    end
    return true if line =~ pattern
    @lines << line
    @cap_end_pos = @f.pos # win_fudge not needed here
    @cap_end_lineno = @f.lineno
  end
rescue EOFError
  false
end
captured_text() click to toggle source

@return [String] text captured during capture_until. The last newline is stripped

# File lib/cog/helpers/file_scanner.rb, line 133
def captured_text
  x = @lines.join('')
  x
end
close() click to toggle source

@api developer Closes the scanned file, if it is not already closed

# File lib/cog/helpers/file_scanner.rb, line 40
def close
  @f.close unless @f.closed?
end
insert_at_mark(value) click to toggle source

@param value [String] value to be inserted into the file at the current position @return [Boolean] whether or not the operation succeeded

# File lib/cog/helpers/file_scanner.rb, line 159
def insert_at_mark(value)
  return false if @mark.nil?
  @f.seek 0
  @f.lineno = 0
  tmp.write @f.read(@mark)
  tmp.write value
  @f.readline # discard original
  tmp.write @f.read
  tmp.close
  close
  FileUtils.mv tmp_filename, @filename
  true
end
mark!() click to toggle source

Remember this position. A later call to insert_at_mark will insert at this marked position @return [nil]

# File lib/cog/helpers/file_scanner.rb, line 68
def mark!
  @mark = @f.pos - win_fudge
  @marked_line_number = @f.lineno + 1
end
read_until(pattern, n=0) click to toggle source

Advances the file until the (n+1)th occurence of the given pattern is encountered, or the end of the file is reached @param pattern [Regexp] a pattern to test for @param n [Fixnum] 0 for the first, 1 for the second, and so on @return [Boolean] whether or not a match was found. Use {#match} to retrieve the match data

# File lib/cog/helpers/file_scanner.rb, line 85
def read_until(pattern, n=0)
  i = 0
  mark!
  while (line = @f.readline) && i <= n
    if @match = pattern.match(line)
      return true if i == n
      i += 1
    end
    mark!
  end
rescue EOFError
  unmark!
  false
end
readline_matches?(pattern) click to toggle source

Advances the file by one line @param pattern [Regexp] a pattern to test for @return [Boolean] whether or not the next line matched the pattern

# File lib/cog/helpers/file_scanner.rb, line 103
def readline_matches?(pattern)
  !!(@f.readline =~ pattern)
rescue EOFError
  false
end
replace_captured_text(value, opt={}) click to toggle source

@param value [String] value to replace the captured_text with @param opt [Boolean] :once (false) if once, the cog delimiters will be removed @return [Boolean] whether or not the operation succeeded

# File lib/cog/helpers/file_scanner.rb, line 141
def replace_captured_text(value, opt={})
  return false if @cap_begin_pos.nil? || @cap_end_pos.nil?
  @f.seek 0
  @f.lineno = 0
  tmp.write @f.read(opt[:once] ? @mark : @cap_begin_pos)
  tmp.write value
  @f.seek @cap_end_pos
  @f.lineno = @cap_end_lineno
  @f.readline if opt[:once]
  tmp.write @f.read
  tmp.close
  close
  FileUtils.mv tmp_filename, @filename
  true
end
unmark!() click to toggle source
# File lib/cog/helpers/file_scanner.rb, line 73
def unmark!
  @mark = nil
  @marked_line_number = -1
end
win_fudge() click to toggle source
# File lib/cog/helpers/file_scanner.rb, line 62
def win_fudge
  (@f.lineno - 1) * @win_fudge
end

Private Instance Methods

tmp() click to toggle source
# File lib/cog/helpers/file_scanner.rb, line 179
def tmp
  unless @tmp
    @tmp = File.open(tmp_filename, 'w')
    @tmp = @tmp.binmode if @tmp.respond_to?(:binmode)
  end
  @tmp
end
tmp_filename() click to toggle source
# File lib/cog/helpers/file_scanner.rb, line 175
def tmp_filename
  @tmp_filename ||= "#{@filename}.tmp"
end