Template::Ast - Processing ASTs for Perl Template Toolkit


Template-Ast documentation Contained in the Template-Ast distribution.

Index


Code Index:

NAME

Top

Template::Ast - Processing ASTs for Perl Template Toolkit

SYNOPSIS

Top

    use Template::Ast;

    # Rebuild AST stored in file:
    $ast = Template::Ast->read('foo.ast') or
        die Template::Ast->error();

    # Writing existing AST to file:
    $ast = { Marry => [24, 'F'], John => [21, 'M'] };
    Template::Ast->write($ast, 'foo.ast') or
        die Template::Ast->error();

    $ast = Template::Ast->merge([1,2,3], undef);  # [1,2,3]
    $ast = Template::Ast->merge(undef, [1,2,3]);  # [1,2,3]
    $ast = Template::Ast->merge(undef, undef);    # undef

    $ast = Template::Ast->merge({A=>1,B=>2}, ['C']);  # ['C']
    $ast = Template::Ast->merge([1,2,3], [5,6]);      # [5,6]
    $ast = Template::Ast->merge([{A=>1},2], 5);       # 5

    $ast = Template::Ast->merge({A=>1,B=>2}, {C=>3});  # {A=>1,B=>2,C=>3}
    $ast = Template::Ast->merge({A=>1,B=>2}, {B=>3});  # {A=>1,B=>3}

    # {A=>1,B=>2}
    $ast = Template::Ast->merge({A=>1,B=>undef}, {A=>undef,B=>2});

    Template::Ast->merge(
        {A=>1,B=>{C=>1,D=>2}},
        {B=>{C=>1,D=>3,E=>4}}
    );  # {A=>1,B=>{C=>1,D=>3,E=>4}}

    Template::Ast->merge(
        {A=>1,B=>{C=>[1,2]}},
        {B=>{C=>[3,4]}}
    );  # {A=>1,B=>{C=>[3,4]}}

    print Template::Ast->dump([$vars], ['vars']);

DESCRIPTION

Top

ASTs are essential in the programming model based on Perl Template Toolkit. This module provides some easy interface to do the dirty work involved in AST handling. The term AST used here are referred to any Perl referece pointed to a complex data structure, such as a nested hash, a nested array, or such.

METHODS

Top

Template::Ast->read($filename)

This method reads the specified file, evals the code contained in it, and returns the result back. It is important to note that the file needn't be generated by the Template::Ast-write> method. The code should be generated in the form used by Data::Dumper, and the variable name used is not important for it will be ignored completely by Template::Ast. The following AST specs are all okay (but they can't appear in a single file simultaneously:

    $vars = { John => 3, Mary => [1, 2, {age => 5}] }

    $ast =
        [ 'item1',
          'item2',
          'item3',
        ];

    { [1,2], [3,4], { a => 1, b => 2} }

    [ 1, 2, 3, 4]

The read static method will return undef when an error occurs. In case of a failure, you should check the error info via the ->error() method.

Template::Ast->write($ast, $filename)

The write method writes the given AST $ast, to the file $filename, utilizing Data::Dumper internally. It returns undef if it encounters an error, and replies 1 otherwise. Always invoke the ->error() method when you fail to write the AST.

Template::Ast->merge($ast1, $ast2)

This method merges $ast2 to $ast1, and returns the final AST. The arguments passed to the method stay unchanged during the merging process.

The merging rule used here is a little hard to explain and may be completely not what you expect, but it is still very useful in many cases. The algorithm is as follows:

  • If one of the two ASTs is undef, The result will be exactly the same as other one. In the case that both ASTs are undef, undef will be returned. Here are some samples:

        Template::Ast->merge($ref, undef);     # $ref
        Template::Ast->merge(undef, $ref);     # $ref
        Template::Ast->merge(undef, undef);    # undef
    
    
  • If $ast1 and $ast2 are not both hash refs, the result will simply be $ast2 provided that $ast2 is not undef.

        Template::Ast->merge({A=>1,B=>2}, ['C']);  # ['C']
        Template::Ast->merge([1,2,3], [5,6]);      # [5,6]
        Template::Ast->merge([{A=>1},2], 5);       # 5
    
    
  • If $ast1 and $ast2 are both hash refs, The key-value pairs that appear in %$ast2 but not in %$ast1 will be added to %$ast1, forming the final result. If a key is shared by both %$ast1 and %$ast2, the corresponding values of both hashes will the treated as two sub-ASTs, and be merged recursively, the resulting sub-AST will be assigned to the hash of the final AST. Here are some examples:

        Template::Ast->merge({A=>1,B=>2}, {C=>3});  # {A=>1,B=>2,C=>3}
        Template::Ast->merge({A=>1,B=>2}, {B=>3});  # {A=>1,B=>3}
    
    


        Template::Ast->merge(
            {A=>1,B=>{C=>1,D=>2}},
            {B=>{C=>1,D=>3,E=>4}}
        );  # {A=>1,B=>{C=>1,D=>3,E=>4}}
    
    


        Template::Ast->merge(
            {A=>1,B=>{C=>[1,2]}},
            {B=>{C=>[3,4]}}
        );  # {A=>1,B=>{C=>[3,4]}}
    
    

As you may have noticed, the merging rule is completely "hash-oriented". No merging but substitution will happen if the two ASTs are arrays or scalars. This may look strange at the first glance, but is quite reasonable for most AST-TT applications.

You will doubtlessly need you own version of AST merging rule. In that case, it is recommended to override the ->merge() method via class inheritance.

Template::Ast->error()

It returns the most recent error info stored in the module, mostly set by the other static methods of Template::Ast.

Template::Ast->dump(...)

Simple interface to the Data::Dumper->Dump method. It accepts exactly the same arguments as the latter.

SEE ALSO

Top

Template, Data::Dumper

AUTHOR

Top

Agent Zhang, <agent2002@126.com>

COPYRIGHT AND LICENSE

Top


Template-Ast documentation Contained in the Template-Ast distribution.

#: Template/Ast.pm
#: Facilities to handle the Perl AST data structures that
#:   fits the TT template file
#: Template-Ast v0.01
#: 2005-07-15 2005-07-17

package Template::Ast;

use 5.008001;
use strict;
use warnings;
use Data::Dumper;

our $VERSION = '0.01';

our $error;

# Rebuild the AST stored in the given file:
sub read {
    shift if @_ > 1;
    my $fname = shift;
    my $fh;
    unless (open $fh, $fname) {
        $error = "file error - Can't open $fname for reading: $!\n";
        return undef;
    }
    my $code;
    {
        local $/;
        $code = <$fh>;
        close $fh;
    }
    $code =~ s/^\s*[\$\w]+\s*=\s*//os;
    my $ast = eval $code;
    if ($@) {
        $error = "file error - The AST contained in $fname is invalid: $@\n";
        return undef;
    }
    return $ast;
}

# Write the given AST to disk file:
sub write {
    shift if @_ > 2;
    my ($ast, $fname) = @_;
    my $fh;
    unless (open $fh, ">$fname") {
        $error = "file error - Can't open $fname for writing: $!\n";
        return undef;
    }
    my $code = Data::Dumper->Dump([$ast], ['ast']);
    print $fh $code;
    close $fh;
    return 1;
}

# Merging two ASTs together:
sub merge {
    shift if @_ > 2;
    my ($ast1, $ast2) = @_;
    unless (defined $ast1) { return $ast2 }
    unless (defined $ast2) { return $ast1 }
    unless (ref($ast1) and ref($ast1) eq 'HASH' and
            ref($ast2) and ref($ast2) eq 'HASH') {
        return $ast2;
    }
    my %ast1 = %$ast1;
    my %ast2 = %$ast2;
    foreach my $key (keys %ast2) {
        if (defined $ast1{$key}) { # share the same key:
            $ast1{$key} = merge($ast1{$key}, $ast2{$key});
        } else {
            $ast1{$key} = $ast2{$key};
        }
    }
    return \%ast1;
}

# Return the error info stored in the package:
sub error {
    return $error;
}

# Simple interface to Data::Dumper->Dump
sub dump {
    shift;
    return Data::Dumper->Dump(@_);
}

1;
__END__