[Templates-cvs] cvs commit: TT3/t base.t handler.t

cvs@template-toolkit.org cvs@template-toolkit.org
Wed, 10 Nov 2004 18:24:33 +0000


cvs         04/11/10 18:24:33

  Modified:    t        base.t handler.t
  Log:
  * minor updates
  
  Revision  Changes    Path
  1.11      +17 -3     TT3/t/base.t
  
  Index: base.t
  ===================================================================
  RCS file: /template-toolkit/TT3/t/base.t,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- base.t	2004/03/25 09:56:35	1.10
  +++ base.t	2004/11/10 18:24:33	1.11
  @@ -9,7 +9,7 @@
   # This is free software; you can redistribute it and/or modify it
   # under the same terms as Perl itself.
   #
  -# $Id: base.t,v 1.10 2004/03/25 09:56:35 abw Exp $
  +# $Id: base.t,v 1.11 2004/11/10 18:24:33 abw Exp $
   #
   #========================================================================
   
  @@ -18,7 +18,7 @@
   
   use lib qw( ./lib ../lib );
   use Template::Base;
  -use Test::More tests => 99;
  +use Test::More tests => 105;
   
   # run with -d flag to enable debugging, e.g. perl base.t -d
   $Template::Base::DEBUG = grep(/^--?d(ebug)?/, @ARGV);
  @@ -198,9 +198,23 @@
   use base qw( Foo );
   use vars qw( $BAR );
   $BAR = 'Bar Var';
  +our $BAZ = 'Baz Var';
   
  -
   package main;
  +
  +is( Foo->pkgvar('FOO'), 'Foo Var', 
  +    'got FOO var from Foo class method' );
  +is( Bar->pkgvar('FOO'), 'Foo Var', 
  +    'got FOO var from Bar class method' );
  +is( Foo->pkgvar('BAR'), 'Foo Bar', 
  +    'got BAR var from Bar class method' );
  +is( Bar->pkgvar('BAR'), 'Bar Var', 
  +    'got BAR var from Bar class method' );
  +is( Foo->pkgvar( BAZ => 'default BAZ'), 'default BAZ', 
  +    'got default BAZ var from Bar class method' );
  +is( Bar->pkgvar('BAZ'), 'Baz Var', 
  +    'got BAZ var from Bar class method' );
  +
   
   my $foo = Foo->new() || die Foo->error();
   ok( $foo, 'created a foo' );
  
  
  
  1.4       +295 -506  TT3/t/handler.t
  
  Index: handler.t
  ===================================================================
  RCS file: /template-toolkit/TT3/t/handler.t,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- handler.t	2004/03/25 16:26:50	1.3
  +++ handler.t	2004/11/10 18:24:33	1.4
  @@ -2,14 +2,14 @@
   #
   # t/handler.t
   #
  -# Test the Template::TT3::Handler.pm module.
  +# Test the Template::Handler.pm module.
   #
   # Written by Andy Wardley <abw@wardley.org>
   #
   # This is free software; you can redistribute it and/or modify it
   # under the same terms as Perl itself.
   #
  -# $Id: handler.t,v 1.3 2004/03/25 16:26:50 abw Exp $
  +# $Id: handler.t,v 1.4 2004/11/10 18:24:33 abw Exp $
   #
   #========================================================================
   
  @@ -17,658 +17,447 @@
   use warnings;
   
   use lib qw( ./lib ../lib );
  -use Test::More skip_all => 'all tests: sorry, these tests are broken'; 
  -use Template::TT3::Handler;
  -use Template::TT3::Generator::Debug;
  -use Template::TT3::Constants qw( :chomp );
  -use Test::More tests => 139;
  +use Template::Handler;
  +use Template::Constants qw( :chomp :actions );
  +use Template::Test;
   
  +plan(46);
  +
   my $DEBUG = 
  -$Template::TT3::Handler::DEBUG = 
  +$Template::Handler::DEBUG = 
   grep /^--?d(ebug)?$/, @ARGV;
   
  -my $pkg = 'Template::TT3::Handler';
  -my $handler = $pkg->new( );
  -
  -ok( $handler, 'created handler' );
   
   
   #------------------------------------------------------------------------
  -# test start_scanner(), end_scanner() and scanner()
  +# new()
   #------------------------------------------------------------------------
   
  -ok( ! defined $handler->scanner(), 
  -    'no scanner' );
  +my $pkg = 'Template::Handler';
   
  -is( $handler->error(), 'no scanners currently bound to handler', 
  -    'no scanner error' );
  +my ($pending, $rollback);
  +my $handler = $pkg->new( );
  +ok( $handler, 'created empty handler' );
   
  -ok( $handler->start_scanner('foo'), 
  -    'started scan with foo' );
  +$handler = $pkg->new( events => {
  +    text => ACCEPT
  +});
   
  -is( $handler->scanner(), 'foo', 
  -    'scanner is foo' );
  +ok( $handler, 'created handler with events' );
   
  -ok( $handler->end_scanner('foo'), 
  -    'ended scan with foo' );
  +sub hmatch {
  +    my ($expect, $message) = @_;
  +    is( ${$handler->content->[-1]->[1]}, $expect, $message);
  +}
   
  -ok( ! defined $handler->scanner(), 
  -    'still no scanner' );
  +sub is_text_expr {
  +    my ($expr, $expect, $message) = @_;
  +    $message ||= $expect;
  +    is( $expr->[0], 'text', "$message (text expr)" );
  +    is( ${$expr->[1]}, $expect, "$message (text matches)" );
  +}
   
  -is( $handler->error(), 'no scanners currently bound to handler', 
  -    'still no scanner error' );
   
   
   #------------------------------------------------------------------------
  -# nested scanners
  +# event(), commit(), pending() and rollback()
   #------------------------------------------------------------------------
  -
  -ok( $handler->start_scanner('ding'), 
  -    'started scan with ding' );
  -
  -is( $handler->scanner(), 'ding', 
  -    'scanner is ding' );
  -
  -ok( $handler->start_scanner('dang'), 
  -    'started scan with dang' );
  -
  -is( $handler->scanner(), 'dang', 
  -    'scanner is dang' );
  -
  -ok( $handler->start_scanner('dong'), 
  -    'started scan with dong' );
   
  -is( $handler->scanner(), 'dong', 
  -    'scanner is dong' );
  +ok( $handler->text('the cat sat on the mat'), 'text event' );
   
  -my $scanners = $handler->scanners();
  +# check content was added
  +hmatch('the cat sat on the mat', 'text added');
   
  -is( $scanners->[0], 'ding', 
  -    'scanner 0 is ding' );
  +# check pending item is returned
  +$pending = $handler->pending();
   
  -is( $scanners->[1], 'dang', 
  -    'scanner 1 is dang' );
  +# check it contains the correct text
  +is_text_expr($pending, 'the cat sat on the mat', 'pending item' );
   
  -is( $scanners->[2], 'dong', 
  -    'scanner 2 is dong' );
  +# check item is still in content
  +hmatch('the cat sat on the mat', 'text still there');
   
  -ok( $handler->end_scanner('dong'), 
  -    'ended scan with dong' );
  +# check rollback returns item and removes it from content
  +$rollback = $handler->rollback();
   
  -is( $handler->scanner(), 'dang', 
  -    'scanner is dang' );
  +is_text_expr($rollback, 'the cat sat on the mat', 'pending item' );
   
  -ok( $handler->end_scanner(),     # no scanner to check against, should be ok
  -    'ended scan with dang' );
  +# check pending() reports nothing
  +ok( ! defined $handler->pending(), 'no pending item left' );
   
  -is( $handler->scanner(), 'ding', 
  -    'scanner is ding' );
  +# add more text
  +ok( $handler->text('the cat is back on the mat' ), 'more text' );
   
  -ok( $handler->end_scanner('ding'),
  -    'ended scan with ding' );
  +# check content was added
  +hmatch('the cat is back on the mat', 'more text added');
   
  -ok( ! defined $handler->scanner(), 
  -    'no more scanners' );
  +# check pending item is returned
  +is_text_expr( $handler->pending(), 'the cat is back on the mat', 
  +    'another pending item' );
   
  +# now commit
  +$handler->commit();
   
  -#------------------------------------------------------------------------
  -# end_scanner() scanner comparison
  -#------------------------------------------------------------------------
  +# check pending() reports nothing
  +ok( ! defined $handler->pending(), 'no pending item after commit' );
   
  -ok( $handler->start_scanner('foo')->start_scanner('bar'), 'foo bar' );
  +# check rollback() does nothing
  +ok( ! defined $handler->rollback(), 'no rollback after commit' );
   
  -is( $handler->scanner(), 'bar', 
  -    'scanner is bar' );
  +# check content still there
  +hmatch('the cat is back on the mat', 'more text still there');
   
  -ok( ! defined $handler->end_scanner('ooops'),
  -    'end scan oops' );
  +# add more text and commit directly
  +ok( $handler->text('the cat has left the mat', commit => 1),
  +    'commit text' );
   
  -is( $handler->error(), 'scanner mismatch at end of scan', 
  -    'scanner mismatch error' );
  +# check content is there
  +hmatch('the cat has left the mat', 'commit text still there');
   
  -is( $handler->scanner(), 'foo', 
  -    'scanner is foo, regardless' );
  +# check pending() reports nothing
  +ok( ! defined $handler->pending(), 'no pending item after auto-commit' );
   
  -ok( $handler->end_scanner(), 
  -    'ended scanner foo' );
  +# check rollback() does nothing
  +ok( ! defined $handler->rollback(), 'no rollback after auto-commit' );
   
   
   
   #------------------------------------------------------------------------
  -# test start_source(), end_source(), source(), sources() and source_data()
  +# next_text() and prev_text()
   #------------------------------------------------------------------------
  -
  -ok( ! defined $handler->source_name(), 
  -    'no source' );
  -
  -is( $handler->error(), 'no source documents currently bound to handler', 
  -    'no source error' );
  -
  -ok( $handler->start_source('foo'), 
  -    'started source with foo' );
   
  -is( $handler->source_name(), 'foo', 
  -    'source name is foo' );
  -
  -is( $handler->name(), 'foo', 
  -    'name is foo' );
  -
  -ok( $handler->end_source('foo'), 
  -    'ended source with foo' );
  -
  -ok( ! defined $handler->source_name(), 
  -    'still no source' );
  +sub chomp_leading {
  +    my ($handler, $textref, $flag) = @_;
  +    $flag ||= CHOMP_REMOVE;
  +    $flag = ($flag == CHOMP_COLLAPSE ? ' ' : '');
   
  -is( $handler->error(), 'no source documents currently bound to handler', 
  -    'still no source error' );
  +    $handler->debug("chomping leading whitespace [$$textref]\n") if $DEBUG;
  +    $$textref =~ s/^\s+/$flag/;
  +    $handler->debug("chomped leading whitespace [$$textref]\n") if $DEBUG;
  +    return 1;
  +}
   
  -ok( $handler->start_source('wiz'), 
  -    'started source with wiz' );
   
  -is( $handler->source_name(), 'wiz', 
  -    'source is wiz' );
  +sub chomp_trailing {
  +    my ($handler, $textref, $flag) = @_;
  +    $flag ||= CHOMP_REMOVE;
  +    $flag = ($flag == CHOMP_COLLAPSE ? ' ' : '');
   
  -my $data = $handler->source_data();
  -ok( $data, 'got source data' );
  +    $handler->debug("chomping trailing whitespace [$$textref]\n") if $DEBUG;
  +    $$textref =~ s/\s+$/$flag/;
  +    $handler->debug("chomped trailing whitespace [$$textref]\n") if $DEBUG;
  +    return 1;
  +}
   
  -is( $data->{ name }, 'wiz',
  -    'source name is wiz' );
   
  -ok( $handler->start_source('waz', { pi => 3.14 }), 
  -    'started source with waz' );
  +sub text_event {
  +    my ($text, $expect, $message) = @_;
   
  -$data = $handler->source_data();
  -ok( $data, 'got waz source data' );
  +    my $srcmsg = $text;
  +    for ($srcmsg) {
  +        s/^\s*//;
  +        s/\s*$//;
  +    }
   
  -is( $data->{ name }, 'waz',
  -    'source name is waz' );
  +    ok( $handler->text($text), $srcmsg);
  +    is( ${$handler->content->[-1]->[1]}, $expect, $message);
  +}
   
  -is( $data->{ pi }, 3.14,
  -    'pi is 3.14' );
   
  -is( $handler->sources()->[0]->[0], 'wiz',
  -    'bottom source is wiz' );
  +# no hooks at first
  +text_event('  unmodified text  ', '  unmodified text  ', 'no change');
   
  -is( $handler->sources()->[-1]->[0], 'waz',
  -    'top source is waz' );
  +# add a hook to chomp leading whitespace
  +ok( $handler->next_text( \&chomp_leading ),
  +    'set next hook handler to remove leading' );
   
  -ok( $handler->end_source('waz'), 
  -    'ended source with waz' );
  +text_event('  the cat  ', 'the cat  ', 'chomped leading');
   
  -ok( $handler->end_source('wiz'), 
  -    'ended source with waz' );
   
  +# check the hook has been removed
  +text_event('  sat on  ', '  sat on  ', 'revert to unchomped leading');
   
   
  -#------------------------------------------------------------------------
  -# nested sources
  -#------------------------------------------------------------------------
  +# add a hook to collapse leading whitespace
  +ok( $handler->next_text( \&chomp_leading, CHOMP_COLLAPSE ),
  +    'set next text hook to collapse leading' );
   
  -ok( $handler->start_source('ding'), 
  -    'started source with ding' );
  +text_event('  the mat  ', ' the mat  ', 'collapsed leading');
   
  -is( $handler->source_name(), 'ding', 
  -    'source is ding' );
   
  -ok( $handler->start_source('dang'), 
  -    'started source with dang' );
  +# add hook to remove trailing whitespace
  +ok( $handler->next_text( \&chomp_trailing ),
  +    'set next text hook to remove trailing' );
   
  -is( $handler->source_name(), 'dang', 
  -    'source is dang' );
  +text_event('  another cat  ', '  another cat', 'chomped trailing');
  +text_event('  sat on  ', '  sat on  ', 'revert to unchomped trailing');
   
  -ok( $handler->start_source('dong'), 
  -    'started source with dong' );
   
  -is( $handler->source_name(), 'dong', 
  -    'source is dong' );
  +# add hook to collapse trailing whitespace
  +ok( $handler->next_text( \&chomp_trailing, CHOMP_COLLAPSE ),
  +    'set next text hook to collapse trailing' );
   
  -ok( $handler->end_source('dong'), 
  -    'ended source with dong' );
  +text_event('  the mat  ', '  the mat ', 'collapsed trailing');
   
  -is( $handler->source_name(), 'dang', 
  -    'source is dang' );
   
  -ok( $handler->end_source(),     # no source to check against, should be ok
  -    'ended source with dang' );
  +# same again with hook_prev()
   
  -is( $handler->source_name(), 'ding', 
  -    'source is ding' );
  +$handler->text('  yet another cat  ');
   
  -ok( $handler->end_source('ding'),
  -    'ended source with ding' );
  +ok( $handler->prev_text( \&chomp_leading ),
  +    'set prev hook handler to remove leading' );
   
  -ok( ! defined $handler->source_name(), 
  -    'no more sources' );
  +hmatch('yet another cat  ', 'chomped prev leading');
   
  +$handler->text(" \n sat once again \n ");
   
  -#------------------------------------------------------------------------
  -# end_source() source comparison
  -#------------------------------------------------------------------------
  +ok( $handler->prev_text( \&chomp_leading, CHOMP_COLLAPSE ),
  +    'set prev hook handler to remove leading' );
   
  -ok( $handler->start_source('foo')->start_source('bar'), 'foo bar' );
  +hmatch(" sat once again \n ", 'collapsed prev leading');
   
  -is( $handler->source_name(), 'bar', 
  -    'source is bar' );
  +$handler->text(" \t\r\n upon another mat \t\r\n ");
   
  -ok( ! defined $handler->end_source('ooops'),
  -    'end source oops' );
  +ok( $handler->prev_text( \&chomp_trailing ),
  +    'set prev text hook to chomp trailing' );
   
  -is( $handler->error(), 'document mismatch at end of source', 
  -    'source mismatch error' );
  +hmatch(" \t\r\n upon another mat", 'chomped prev trailing');
   
  -is( $handler->source_name(), 'foo', 
  -    'source is foo, regardless' );
  +$handler->text(" \t\r\n and shat \t\r\n ");
   
  -ok( $handler->end_source('foo'), 
  -    'ended foo source' );
  +ok( $handler->prev_text( \&chomp_trailing, CHOMP_COLLAPSE ),
  +    'set prev text hook to collapse trailing' );
   
  -ok( ! defined $handler->source_name(),
  -    'no more foo source' );
  +hmatch(" \t\r\n and shat ", 'collapsed prev trailing');
   
   
  -#------------------------------------------------------------------------
  -# line() and location()
  -#------------------------------------------------------------------------
  -
  -ok( ! defined $handler->line(), 'no current line' );
   
  -is( $handler->error(), 'no scanners currently bound to handler',
  -    'no scanners line error' );
  +# check that chomp_leading() and chomp_trailing() both work with 
  +# text references
   
  -ok( ! defined $handler->location(),
  -    'undefined location' );
  +my ($text, $result);
  +$text = '  the cat sat on the mat  ';
   
  -is( $handler->error(), 'no location information available',
  -    'no location error' );
  +ok( $handler->next_text( \&chomp_leading ),
  +    'text ref leading' );
   
  -ok( $handler->start_scanner('foo'),
  -    'added scanner foo' );
  +$handler->text(\$text);
  +$result = $handler->content->[-1]->[1];
  +is($$result, 'the cat sat on the mat  ', 'chomped text ref leading');
  +is($text, 'the cat sat on the mat  ', 'original text ref modified');
   
  -ok( ! defined $handler->location(),
  -    'undefined location' );
   
  -is( $handler->error(), 'no location information available',
  -    'still no location error' );
  +$text = '  the cat sat on the mat  ';
   
  -ok( ! defined $handler->line(), 'still no current line' );
  +ok( $handler->next_text(\&chomp_trailing),
  +    'text ref trailing' );
   
  -is( $handler->error(), 'scanner does not report line numbers',
  -    'no scanner line number error' );
  +$handler->text(\$text);
  +$result = $handler->content->[-1]->[1];
  +is($$result, '  the cat sat on the mat', 'chomped text ref trailing');
  +is($text, '  the cat sat on the mat', 'original text ref modified again');
   
  -ok( $handler->end_scanner('foo'),
  -    'ended scanner foo' );
   
   
   #------------------------------------------------------------------------
  -package My::Scanner;
  -use Template::TT3::Base;
  -use base qw( Template::TT3::Base );
  -
  -sub init {
  -    my ($self, $config) = @_;
  -    $self->{ line } = $config->{ line };
  -    return $self;
  -}
  -
  -sub line {
  -    my $self = shift;
  -    if (@_) {
  -        return ($self->{ line } = shift);
  -    }
  -    elsif (defined $self->{ line }) {
  -        return $self->{ line };
  -    }
  -    else {
  -        return $self->error('no line number set');
  -    }
  -}
  -
  -package main;
  -
  -my $scanner = My::Scanner->new();
  -
  -ok( $handler->start_scanner($scanner),
  -    'added custom scanner' );
  -
  -ok( ! defined $handler->line(), 'and still no current line' );
  -
  -is( $handler->error(), 'no line number set',
  -    'no line number set error' );
  -
  -
  -ok( ! defined $handler->source_name(),
  -    'still no more foo source' );
  +# start_block(), end_block()
  +#------------------------------------------------------------------------
   
  -$scanner->line(0);
  +$handler = $pkg->new( type => 'template' );
   
  -is( $handler->line(), 0, 
  -    'line zero' );
  +ok( $handler, 'created block handler' );
   
  -is( $handler->location(), 'line 0',
  -    'location line zero' );
  -        
  -$scanner->line(10);
  +ok( $handler->text('hello world'), 'hello world' );
   
  -is( $handler->line(), 10, 
  -    'line ten' );
  +ok( $handler = $handler->start_block( wrapper => 'filename', 'params' ),
  +    'started wrapper block' );
   
  -is( $handler->location(), 'line 10',
  -    'location is line 10' );
  +is( $handler->type(), 'wrapper', 'handler is a wrapper' );
   
  -ok( $handler->start_source('tenline'),
  -    'set source to tenline' );
  +ok( $handler->text('some wrapper text'), 'some wrapper text' );
  +ok( $handler->text('more wrapper text'), 'more wrapper text' );
   
  -is( $handler->location(), 'tenline line 10',
  -    'location is tenline line 10' );
  +ok( $handler = $handler->end_block('wrapper'),
  +    'ended wrapper block' );
   
  -ok( $handler->end_scanner(),
  -    'ended scanner' );
  +ok( $handler->type('template'), 'back to the template handler' );
   
  -is( $handler->location(), 'tenline',
  -    'location is tenline' );
  +ok( $pending = $handler->pending(), 'got pending item' );
  +is( $pending->[0], 'wrapper', 'pending item is the wrapper' );
  +is( $pending->[1], 'filename', 'wrapper filename' );
  +is( $pending->[2], 'params', 'wrapper params' );
  +is( ref $pending->[3], 'ARRAY', 'wrapper body is an array' );
  +is( scalar @{$pending->[3]}, 2, 'two items in wrapper body' );
  +is_text_expr($pending->[3]->[0], 'some wrapper text');
  +is_text_expr($pending->[3]->[1], 'more wrapper text');
   
   
   #------------------------------------------------------------------------
  -# start(), end(), start_block(), end_block() and add()
  +# test next_block() with if...else...end
   #------------------------------------------------------------------------
  -
  -ok( $handler->start(),
  -    'started handler' );
  -
  -ok( $handler->directive( text => 'hello world' ),
  -    'added text hello' );
  -
  -ok( $handler->directive( text => 'goodbye cruel world' ),
  -    'added text goodbye' );
  -
  -#ok( $handler->directive( wrap => 'tortilla' ),
  -#    'added a tortilla wrap' );
  -
  -$handler->dump_stack('about to add tortilla wrap') if $DEBUG;
  -
  -ok( $handler->start_block( wrap => 'tortilla' ),
  -    'started tortilla wrap' );
  -
  -$handler->dump_stack('started tortilla wrap block') if $DEBUG;
  -
  -ok( $handler->directive( meat => 'chicken' ),
  -    'added some chicken' );
  -
  -ok( $handler->directive( cheese => 'swiss' ),
  -    'added some swiss cheese' );
  -
  -$handler->dump_stack('about to end tortilla wrap block') if $DEBUG;
  -
  -ok( $handler->end_block(),
  -    'ended tortilla wrap block' );
  -
  -$handler->dump_stack('ended tortilla wrap block') if $DEBUG;
  -
  -ok( $handler->directive( text => 'another brick in the wall' ),
  -    'added another brick' );
   
  -my $result = $handler->end() || die $handler->error();
  -ok( $result, 'got result' );
  +$handler = $pkg->new( type => 'template' );
  +ok( $handler = $handler->text('hello'), 'initial text' );
  +ok( $handler = $handler->start_block('if'), 'start if' );
  +ok( $handler = $handler->text('if text'), 'if text' );
  +ok( $handler = $handler->next_block('if'), 'else next block' );
  +ok( $handler = $handler->text('else text'), 'else text' );
  +ok( $handler = $handler->end_block('if'), 'end if' );
  +$result = $handler->end_block();
   
  -is( $result->[0], 'template', 
  -    'template type' );
  +is( $result->[0], 'template', 'template block type' );
  +is_text_expr($result->[1]->[0], 'hello' );
  +is( $result->[1]->[1]->[0], 'if', 'if block type' );
  +is_text_expr($result->[1]->[1]->[1]->[0], 'if text' );
  +is_text_expr($result->[1]->[1]->[2]->[0], 'else text' );
  +#print $handler->dump_item($result);
   
  -is( $result->[1]->[0], 'text', 
  -    'text type hello' );
  -
  -is( $result->[1]->[1], 'hello world', 
  -    'text message hello' );
  -
  -is( $result->[2]->[0], 'text', 
  -    'text type goodbye' );
  -
  -is( $result->[2]->[1], 'goodbye cruel world', 
  -    'text message goodbye' );
  -
  -is( $result->[3]->[0], 'wrap', 
  -    'wrap type' );
  -
  -is( $result->[3]->[1], 'tortilla', 
  -    'tortilla wrap' );
  -
  -is( $result->[3]->[2]->[0], 'block', 
  -    'tortilla block' );
  -
  -is( $result->[3]->[2]->[1]->[0], 'meat', 
  -    'tortilla meat' );
  -
  -is( $result->[3]->[2]->[1]->[1], 'chicken', 
  -    'tastes like chicken' );
  -
  -
  -is( $result->[3]->[2]->[2]->[0], 'cheese', 
  -    'tortilla cheese' );
  -
  -is( $result->[3]->[2]->[2]->[1], 'swiss', 
  -    'swiss cheese' );
  -
  -
  -print $handler->dump_list($result) if $DEBUG;
  -
  -
   #------------------------------------------------------------------------
  -# start_block(), next_block(), end_block()
  +# test next_block() with if...elsif...else...end (dangling blocks)
   #------------------------------------------------------------------------
  -
  -$handler = $pkg->new();
  -$handler->start();
  -
  -ok( $handler->text('first line'), 
  -    'added first line' );
  -
  -$handler->dump_stack('about to start if block') if $DEBUG;
  -
  -ok( $handler->start_block( if => 'true' ),
  -    'started if block' );
  -
  -ok( $handler->text('true block'), 
  -    'added true line' );
  -
  -$handler->dump_stack('before elsif') if $DEBUG;
  -
  -ok( $handler->next_block( elsif => 'half-true' ),
  -    'started half-true block' );
  -
  -ok( $handler->text('half-true block'), 
  -    'added half-true line' );
  -
  -$handler->dump_stack('between elsifs') if $DEBUG;
  -
  -ok( $handler->next_block( elsif => 'false' ),
  -    'started false block' );
  -
  -ok( $handler->text('false block'), 
  -    'added false line' );
  -
  -ok( $handler->next_block('else'),
  -    'started else block' );
  -
  -ok( $handler->text('undecided'), 
  -    'added undecided line' );
  -
  -$handler->dump_stack('about to end if block') if $DEBUG;
  -
  -ok( $handler->end_block('if') || die($handler->error()),
  -    'ended if block' );
  -
  -$handler->dump_stack('about to end') if $DEBUG;
  -
  -$result = $handler->end();
  -
  -is( $result->[0], 'template', 
  -    'got a template result' );
  -
  -is ( $result->[1]->[0], 'text',
  -     'first item is text' );
  -
  -is ( ${$result->[1]->[1]}, 'first line',
  -     'first line is correct' );
  -
  -my $if = $result->[2];
  -
  -is ( $if->[0], 'if',
  -     'second item is if' );
  -
  -is ( $if->[1], 'true',
  -     'if true' );
  -
  -is ( $if->[2]->[0], 'block',
  -     'true block' );
  -
  -is ( $if->[2]->[1]->[0], 'text',
  -     'true text' );
  -
  -is ( ${$if->[2]->[1]->[1]}, 'true block',
  -     'true block' );
  -
  -my $elsif = $if->[3];
  -
  -is ( $elsif->[0], 'elsif',
  -     'third item is elsif' );
   
  -is ( $elsif->[1], 'half-true',
  -     'elsif half-true' );
  +$handler = $pkg->new( type => 'template' );
  +ok( $handler = $handler->text('hello again'), 'more initial text' );
  +ok( $handler = $handler->start_block(if => 'x'), 'start if again' );
  +ok( $handler = $handler->text('more if text'), 'more if text' );
   
  -is ( $elsif->[2]->[0], 'block',
  -     'half-true block' );
  +# elsif y => else { if y ... }
  +ok( $handler = $handler->next_block('if'), 
  +    'first elsif next block' );
  +ok( $handler = $handler->start_block([if=>'y'], dangling => 1), 
  +    'first elsif start block' );
  +ok( $handler = $handler->text('first elsif text'), 
  +    'first elsif text' );
   
  -is ( $elsif->[2]->[1]->[0], 'text',
  -     'half-true text' );
  +# elsif z => else { if z ... }
  +ok( $handler = $handler->next_block('if'), 
  +    'second elsif next block' );
  +ok( $handler = $handler->start_block([if=>'z'], dangling => 1), 
  +    'second elsif start block' );
  +ok( $handler = $handler->text('second elsif text'), 
  +    'second elsif text' );
   
  -is ( ${$elsif->[2]->[1]->[1]}, 'half-true block',
  -     'half-true block' );
  +ok( $handler = $handler->end_block('for'), 
  +    'end elsif' );
   
  -$elsif = $if->[4];
  +$result = $handler->end_block();
   
  -is ( $elsif->[0], 'elsif',
  -     'fourth item is elsif' );
  +#is( $result->[0], 'template', 'template block type' );
  +#is_text_expr($result->[1]->[0], 'hello' );
  +#is( $result->[1]->[1]->[0], 'if', 'if block type' );
  +#is_text_expr($result->[1]->[1]->[1]->[0], 'if text' );
  +#is_text_expr($result->[1]->[1]->[2]->[0], 'else text' );
  +print $handler->dump_item($result);
   
  -is ( $elsif->[1], 'false',
  -     'elsif false' );
   
  -is ( $elsif->[2]->[0], 'block',
  -     'false block' );
   
  -is ( $elsif->[2]->[1]->[0], 'text',
  -     'false text' );
  +__END__
   
  -is ( ${$elsif->[2]->[1]->[1]}, 'false block',
  -     'false block' );
  +# old stuff (before early nov) follows, now implemented with start_block()
  +# et al
   
  -
  -
  -print $handler->dump_list($result) if $DEBUG;
  -
  -if ($DEBUG) {
  -    my $generator = Template::TT3::Generator::Debug->new();
  -    
  -    my $output = $generator->generate($result)
  -        || die $generator->error();
  -    
  -    print STDERR $output;
  -}
  -
  -exit();   ## EXIT FOR DEBUGGING ##
  -
  -
  -
   #------------------------------------------------------------------------
  -# next_text() and prev_text()
  +# expand() and reduce()
   #------------------------------------------------------------------------
   
  -ok( $handler->start(),
  -    'restarted handler' );
  +# first try manual control
   
  -ok( $handler->next_text( \&chomp_leading ),
  -    'set next hook handler to remove leading' );
  +$handler = $pkg->new( events => {
  +    text => ACCEPT
  +});
   
  -ok( $handler->text('  the cat  '),
  -    'the cat' );
  +$handler->event( text => 'The cat sat on the mat' );
   
  -ok( $handler->text('  sat on  '),
  -    'sat on' );
  +$handler = $handler->expand([ for => 'x' ], {
  +    events => {
  +        text => ACCEPT,             # TODO: move out and inherit
  +        end  => REDUCE,
  +    },
  +});
   
  -ok( $handler->next_text( \&chomp_leading, CHOMP_COLLAPSE ),
  -    'set next text hook to collapse leading' );
  -
  -ok( $handler->text('  the mat  '),
  -    'the mat' );
  -
  -ok( $handler->next_text( \&chomp_trailing ),
  -    'set next text hook to remove trailing' );
  +$handler->event( text => 'The dog sat on the log' );
   
  -ok( $handler->text('  the cat  '),
  -    'another cat' );
  +$handler = $handler->reduce();
   
  -ok( $handler->prev_text( \&chomp_leading ),
  -    'set prev text hook to remove trailing' );
  +is( $handler->content->[-1][0], 'for', 'nested for block' );
  +is( $handler->content->[-1][-1][-1][-1], 
  +    'The dog sat on the log', 'nested for block text on manual control' );
   
  -ok( $handler->text('  sat on  '),
  -    'also sat on' );
  +#print $handler->dump();
   
  -ok( $handler->prev_text( \&chomp_leading, CHOMP_COLLAPSE ),
  -    'set prev text hook to collapse leading' );
  -
  -ok( $handler->next_text( \&chomp_trailing, CHOMP_COLLAPSE ),
  -    'set next hook handler to collapse trailing' );
   
  -ok( $handler->text('  the mat  '),
  -    'another the mat' );
  +# now on auto-pilot
   
  -$result = $handler->end();
  +$handler = $pkg->new( events => {
  +    text => ACCEPT,
  +    for   => {
  +        events => {
  +            text => ACCEPT,
  +            end  => REDUCE,
  +        },
  +    },
  +});
   
  -is( $result->[0], 'template',
  -    'a template - what a result!' );
  +$handler->event( text => 'The cat sat on the mat' );
  +$handler = $handler->event( for => 'x' );
  +$handler->event( text => 'The dog sat on the log' );
  +$handler = $handler->event( end => 'for' );
   
  -foreach my $n (1..6) {
  -    is( $result->[$n]->[0], 'text',
  -        "item $n is text" );
  -}
  +is( $handler->content->[-1][-1][-1][-1], 
  +    'The dog sat on the log', 'nested for block text on auto-pilot' );
   
  -is( ${ $result->[1]->[1] }, 'the cat  ',
  -    'chomped cat' );
  +#print $handler->dump();
   
  -is( ${ $result->[2]->[1] }, '  sat on  ',
  -    'unchomped sat' );
   
  -is( ${ $result->[3]->[1] }, ' the mat  ',
  -    'collapsed mat' );
  +#------------------------------------------------------------------------
  +# extend()
  +#------------------------------------------------------------------------
   
  -is( ${ $result->[4]->[1] }, 'the cat',
  -    'another chomped cat' );
   
  -is( ${ $result->[5]->[1] }, ' sat on  ',
  -    'another unchomped sat' );
  +# now on auto-pilot
   
  -is( ${ $result->[6]->[1] }, '  the mat ',
  -    'another collapsed mat' );
  +$handler = $pkg->new( events => {
  +    text => ACCEPT,
  +    if   => {
  +        action => EXPAND,
  +        events => {
  +            text  => ACCEPT,
  +            elsif => {
  +                action => EXPAND,
  +                events => {
  +                    elsif => EXTEND,
  +                    else  => EXTEND,
  +                },
  +            },
  +            else  => {
  +                action => EXPAND,
  +                events => {
  +                    elsif => EXTEND,
  +                    else  => EXTEND,
  +                },
  +            },
  +            end   => REDUCE,
  +        },
  +    },
  +});
   
  -# print $handler->dump_list($result) if $DEBUG;
  +$handler = $handler->event( text => 'The ant sat on the plant' );
  +$handler = $handler->event( if => 'x' );
  +$handler = $handler->event( text => 'The bee sat on the knee' );
  +#print $handler->dump();
  +#print "\n\n----------\n\n";
  +$handler = $handler->event( elsif => 'y' );
  +$handler = $handler->event( text => 'The cat sat on the mat' );
  +#print $handler->dump();
   
  +$handler = $handler->event( elsif => 'z' );
  +$handler = $handler->event( text => 'The dog sat on the log' );
  +$handler = $handler->event( else => '' );
  +$handler = $handler->event( text => 'The elk sat on the whelk' );
  +$handler = $handler->event( end => '' );
   
  -sub chomp_leading {
  -    my ($handler, $textref, $flag) = @_;
  -    $flag ||= CHOMP_REMOVE;
  -    $flag = ($flag == CHOMP_COLLAPSE ? ' ' : '');
   
  -    $handler->debug("chomping leading whitespace [$$textref]\n") if $DEBUG;
  -    $$textref =~ s/^\s+/$flag/;
  -    $handler->debug("chomped leading whitespace [$$textref]\n") if $DEBUG;
  -    return 1;
  -}
  +print $handler->dump();
   
  -sub chomp_trailing {
  -    my ($handler, $textref, $flag) = @_;
  -    $flag ||= CHOMP_REMOVE;
  -    $flag = ($flag == CHOMP_COLLAPSE ? ' ' : '');
  +__END__
   
  -    $handler->debug("chomping trailing whitespace [$$textref]\n") if $DEBUG;
  -    $$textref =~ s/\s+$/$flag/;
  -    $handler->debug("chomped trailing whitespace [$$textref]\n") if $DEBUG;
  -    return 1;
  -}