package Inline::TT;

use strict;
use vars qw($VERSION);
$VERSION = 0.01;

use base qw(Inline);
use IO::File;
use Template::Parser;

sub croak { require Carp; Carp::croak(@_) }

#--------------------------------------------------
# Inline APIs
#--------------------------------------------------

sub register {
    return {
	language => 'TT',
	aliases  => [ qw(tt) ],
	type     => 'interpreted',
	suffix   => 'tt',
    };
}

sub validate { }

sub build {
    my $self = shift;
    my $code = $self->__compile($self->{API}->{code});
    my $path = "$self->{API}->{install_lib}/auto/$self->{API}->{modpname}";
    $self->mkpath($path) unless -d $path;

    my $obj = $self->{API}->{location};
    my $out = IO::File->new("> $obj") or die "$obj: $!";
    $out->print($code);
    $out->close;
}


sub load {
    my $self = shift;
    my $obj  = $self->{API}->{location};
    my $in   = IO::File->new($obj) or die "$obj: $!";
    my $code = do { local $/; <$in> };
    $in->close;

    eval "package $self->{API}->{pkg};$code;";
    croak $@ if $@;
}

sub info { }

#--------------------------------------------------
# private methods
#--------------------------------------------------

sub __compile {
    my($self, $text) = @_;
    my $parser   = Template::Parser->new({ PRE_CHOMP => 1, POST_CHOMP => 1 });
    my $content  = $parser->parse($text) or croak $parser->error;
    my $document = $self->__document($content);

    my $subs;
    for my $block (keys %{$content->{DEFBLOCKS}}) {
	$subs .= <<BLOCK;
sub $block {
    my(\%args) = \@_;
     \$Context->include(\$Context->template('$block'), \\\%args);
}

BLOCK
    }

    return <<CODE;
#------------------------------------------------------------------------
# Compiled template generated by the Inline::TT version $VERSION
#------------------------------------------------------------------------

use Template::Context;
use Template::Document;

my \$Doc = $document
my \$Context = Template::Context->new;
\$Context->visit(\$Doc->{_DEFBLOCKS});

$subs
CODE
    ;
}

sub __document {
    my($self, $content) = @_;

    # just pasted from Template::Document::write_perl_file
    my ($block, $defblocks, $metadata) =
        @$content{ qw( BLOCK DEFBLOCKS METADATA ) };
    my $pkg = "'Template::Document'";

    $defblocks = join('',
                      map { "'$_' => $defblocks->{ $_ },\n" }
                      keys %$defblocks);

    $metadata = join('',
		     map {
			 my $x = $metadata->{ $_ };
			 $x =~ s/(['\\])/\\$1/g;
			 "'$_' => '$x',\n";
		     } keys %$metadata);

    return  <<EOF;
bless {
$metadata
_HOT       => 0,
_BLOCK     => $block,
_DEFBLOCKS => {
$defblocks
},
}, $pkg;
EOF
    ;
}

1;
__END__

=head1 NAME

Inline::TT - use TT BLOCK as your Perl sub

=head1 SYNOPSIS

  use Inline 'TT';

  print add(args => [ 0, 1 ]);                      # 1
  print rubyish(str => "Just another Perl Hacker"); # "Just/another/Ruby/hacker"

  __END__
  __TT__
  [% BLOCK add %]
  [% result = 0 %]
  [% FOREACH arg = args %]
    [% result = result + arg %]
  [% END %]
  [% result %]
  [% END %]

  [% BLOCK rubyish %]
  [% strings = str.split(' ')
     strings.2 = "Ruby"
  %]
  [% strings.join('/') %]
  [% END %]

=head1 DESCRIPTION

Template-Toolkit is not just a Templating Engine. It's a
B<language>. Yep, Inline::TT is a Inline plugin to allow you to code
your Perl subs in TT.

=head1 AUTHOR

Original idea by IKEBE Tomohiro E<lt>ikechin@0xfa.comE<gt>

Code implemented by Tatsuhiko Miyagawa E<lt>miyagawa@bulknews.netE<gt>

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=head1 SEE ALSO

L<Template>, L<Inline>

=cut
