diff -r fe38422c10a4 -r bab54dae339a chunker/lib/chunker.rb --- a/chunker/lib/chunker.rb Sat Jan 22 01:55:55 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,133 +0,0 @@ -# vim: set nosta noet ts=4 sw=4: - -require 'strscan' -require 'stringio' - -# -# Chunker: A convenience library for parsing __END__ tokens consistently. -# -# == Version -# -# $Id$ -# -# == Author -# -# * Mahlon E. Smith -# -# :include: LICENSE -# - -### Namespace for the datablock parser. -### -module Chunker - - # VCS Revision - VCSRev = %q$Rev$ - - # VCS Id - VCSId = %q$Id$ - - # Package version - VERSION = '1.0.0' - - - ### Parser class for __END__ data blocks. - ### Find each __TOKEN__ within the __END__, and put each into a - ### DATA_TOKEN constant within the namespace that included us. - ### - class DataParser - - # The mark for a DATA block. - END_TOKEN = /^__END__\r?\n/ - - # The mark for a 'sub' block. - CHUNK_TOKEN = /^__([A-Z\_0-9]+)__\r?\n/ - - - ### Constructor: Given a +klass+ and an +io+ to the class file, - ### extract the data blocks and install constants. - ### - def initialize( klass, io ) - io.open if io.closed? - end_string = io.read.split( END_TOKEN, 2 ).last - - @klass = klass - @scanner = StringScanner.new( end_string ) - io.close - - # put each chunk into its own constant - # - if @scanner.check_until( CHUNK_TOKEN ) - self.extract_blocks - - # no sub blocks, put the whole mess into DATA_END - # - else - @klass.const_set( :DATA_END, StringIO.new( end_string ) ) - end - end - - - ######### - protected - ######### - - ### Parse the current +io+ for data blocks, set contents to - ### IO constants in the including class. - ### - def extract_blocks - label = nil - - while @scanner.scan_until( CHUNK_TOKEN ) and ! @scanner.eos? - data = '' - - # First pass, __END__ contents (until next token, instead - # of entire data block.) - # - if label.nil? - label = 'END' - data = @scanner.pre_match - - @scanner.pos = self.next_position - else - label = @scanner[1] - - # Pull the next token text out of the data, set up the next pass - # - if data = @scanner.scan_until( CHUNK_TOKEN ) - data = data[ 0, data.length - @scanner[0].length ] - @scanner.pos = self.next_position - - # No additional blocks - # - else - data = @scanner.rest - end - end - - # Add the IO constant to the class that included me. - @klass.const_set( "DATA_#{label}".to_sym, StringIO.new( data ) ) - end - end - - - ### Return the next scanner position for searching. - ### - def next_position - return @scanner.pos - @scanner[0].length - end - end - - - ### Hook included: Find the file path for how we arrived here, and open - ### it as an IO object. Parse the IO for data block tokens. - ### - def self.included( klass ) - # klass.instance_eval{ __FILE__ } awww, nope. - # __FILE__ won't work here, so we find the filename via caller(). - io = File.open( caller(1).last.sub(/:.*?$/, ''), 'r' ) - - DataParser.new( klass, io ) - end -end -