require 'pathname' module FixtureFox class Tokenizer # Minimum path to source file. Note that this is a ruby file if the source # was inline attr_reader :file # Array of tokenized lines attr_reader :lines def initialize(file_or_text) @lines = [] # FIXME: Why @dev_proc ? if file_or_text =~ /\s/ if caller[0] =~ /^(.*):(\d+):in `.*/ file, @lineno = $1, $2.to_i - 1 @file = Pathname.new(Pathname.new(file).expand_path).relative_path_from(Pathname.getwd).to_s @dev_proc = lambda { |&block| StringIO.open(file_or_text, &block) } else raise "Oops" end else @lineno = 0 @file = file_or_text @dev_proc = lambda { |&block| File.open(@file, "r", &block) } end end def call # Read source source = @dev_proc.call { |dev| dev.readlines.take_while { |l| l !~ /^__END__\s*$/ } } # Find initial indent while !source.empty? && source.first =~ /^\s*(?:#.*)?$/ source.shift @lineno += 1 end !source.empty? or return [] @initial_indent = source.first[/\A */].size while !source.empty? line = source.shift @lineno += 1 # Ignore blank lines and comments next if line =~ /^\s*(?:#.*)?$/ # Find indent indent = line[/\A */].size - @initial_indent indent >= 0 or error("Illegal indent") # Strip prefixed and suffixed blanks line.strip! # Create if line =~ /^@/ @lines << DirectiveLine.new(@file, @lineno, @initial_indent, indent, line) else @lines << Line.new(@file, @lineno, @initial_indent, indent, line) end end @lines end def dump(long: false) @lines.each { |l| puts l.to_s(long: long) } end def error(msg) raise ParseError.new(@file, @lineno, @initial_indent, msg) end end end