class Cog::Helpers::FileScanner
@api developer Helper for scanning files for embed expansions
Attributes
@return [Fixnum] line number where mark! was called or -1 if mark! was not called
@return [MatchData, nil] match data for the last matched pattern
Public Class Methods
@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
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
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
@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
@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
@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
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
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
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
@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
# File lib/cog/helpers/file_scanner.rb, line 73 def unmark! @mark = nil @marked_line_number = -1 end
# File lib/cog/helpers/file_scanner.rb, line 62 def win_fudge (@f.lineno - 1) * @win_fudge end
Private Instance Methods
# 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
# File lib/cog/helpers/file_scanner.rb, line 175 def tmp_filename @tmp_filename ||= "#{@filename}.tmp" end