Current File : //var/wcp4/hkaw/public_html/file/private/lib/GT/Template/Inheritance.pm
# ==================================================================
# Gossamer Threads Module Library - http://gossamer-threads.com/
#
#   GT::Template::Inheritance
#   Author: Scott Beck
#   $Id: Inheritance.pm,v 1.3 2002/04/12 22:15:00 jagerman Exp $
#
# Copyright (c) 2002 Gossamer Threads Inc.  All Rights Reserved.
# ==================================================================
#
# Description: Provides class methods to deal with template
#              inheritance.
#

package GT::Template::Inheritance;
# ==================================================================

use strict;

use vars qw($ATTRIBS $ERRORS);
use bases 'GT::Base' => '';

$ERRORS = {
    NOT_FILE  => q _'%s' does not look like a valid filename_,
    RECURSION => q _Recursive inheritance detected and interrupted: '%s'_
};

sub get_all_paths {
# ----------------------------------------------------------------------------
    my ( $class, %opts ) = @_;

    my $file = delete $opts{file};
    $class->fatal( BADARGS => "No file specified for $class->all_files" )
        unless defined $file;
    
    my $root = delete $opts{path};
    $class->fatal( BADARGS => "No path specified for $class->all_files" )
        unless defined $root;
    $class->fatal( BADARGS => "Path $root does not exist or is not a directory" )
        unless -d $root;
    
    my $use_local = delete $opts{use_local};
    $use_local = 1 unless defined $use_local;

    my $use_inheritance = delete $opts{use_inheritance};
    $use_inheritance = 1 unless defined $use_inheritance;

    my $local_inheritance = delete $opts{local_inheritance};
    $local_inheritance = $use_inheritance unless defined $local_inheritance;

    $class->fatal( BADARGS => "Unknown arguments:(". join(", ", keys %opts).")" )
        if keys %opts;

    my @files;
    while () {
        my ($tplinfo, %tplinfo);
        if ($use_local and -f "$root/local/$file" and -r _) {
            push @files, "$root/local/$file";
            if ($local_inheritance and -f "$root/$file" and -r _) {
                push @files, "$root/$file";
            }
        }
        elsif (-f "$root/$file" and -r _) {
            push @files, "$root/$file";
        }

        require GT::Template if $use_inheritance;
        if (
            $use_inheritance and 
            $tplinfo = GT::Template->load_tplinfo($root) and
            my $inherit = $tplinfo->{inheritance}
        )
        {
            if ($inherit =~ m!^(?:[a-zA-Z]:)?[\\/]!) { # Absolute inheritance path
                $root = $inherit;
            }
            else {
                $root .= "/$inherit";
            }
            if (length $root > 150 or $tplinfo{$root}++) { # We've already looked at that directory, or we just have too many relative paths tacked on the end
                $class->error(RECURSION => WARN => $root);
                last; # End the loop - there is no more inheritance since we would just be recursing over what we already have
            }
        }
        else { # No (more) inheritance, so end the loop
            last;
        }
    }
    return @files;
}

sub get_path {
# ----------------------------------------------------------------------------
    my ( $class, %opts ) = @_;
    my $file = delete $opts{file};
    $class->fatal( BADARGS => "No file specified for $class->all_files" )
        unless defined $file;
    
    my $root = delete $opts{path};
    $class->fatal( BADARGS => "No path specified for $class->all_files" )
        unless defined $root;
    $class->fatal( BADARGS => "Path $root does not exist or is not a directory" )
        unless -d $root;
    
    my $use_local = delete $opts{use_local};
    $use_local = 1 unless defined $use_local;

    my $use_inheritance = delete $opts{use_inheritance};
    $use_inheritance = 1 unless defined $use_inheritance;

    $class->fatal( BADARGS => "Unknown arguments:(". join(", ", keys %opts).")" )
        if keys %opts;

    if ( $use_local and -f "$root/local/$file" and -r _ ) {
        return "$root/local/$file";
    }
    elsif ( -f "$root/$file" and -r _ ) {
        return "$root/$file";
    }
    elsif ( $use_inheritance ) {
        my ($tplinfo, %tplinfo);
        require GT::Template;
        while (
            $tplinfo = GT::Template->load_tplinfo($root) and
            my $inherit = $tplinfo->{inheritance}
        )
        {
            if ($inherit =~ m!^(?:[a-zA-Z]:)?[\\/]!) { # Absolute inheritance path
                $root = $inherit;
            }
            else {
                $root .= "/$inherit";
            }
            if ($use_local and -f "$root/local/$file") {
                return "$root/local/$file";
            }
            elsif (-f "$root/$file") {
                return "$root/$file";
            }
            if (length $root > 150 or $tplinfo{$root}++) { # We've already looked at that directory, or we just have too many relative paths tacked on the end
                return $class->warn(RECURSION => "$root/$file");
                # there is no more inheritance since we would just be recursing over what we already have
            }
        }
    }
    return $class->warn(NO_FILE => $file);
}       

1;

__END__

=head1 NAME

GT::Template::Inheritance - Provides class methods to deal with template
inheritance.

=head1 SYNOPSIS

    use GT::Template::Inheritance;

    my $file = GT::Template::Inheritance->get_path(
        file => "foo.htm",
        path => "/path/to/my/template/set",
        use_local => 1,
        use_inheritance => 1
    );

    my @files = GT::Template::Inheritance->get_all_paths(
        file => "foo.htm",
        path => "/path/to/my/template/set",
        use_local => 1,
        use_inheritance => 1,
        local_inheritance => 1
    );

=head1 DESCRIPTION

GT::Template::Inheritance is a simple module with nothing but class methods
to return the path or paths to files following template inheritace files and
locals. See L<GT::Template> for a description of how inheritance and locals
works.

=head1 METHODS

All methods in GT::Template::Inheritance are class methods. Each method takes
a hash of options as an argument.

=head2 get_path

This method returns the path to the proper file given options. The options are
given in the form of a hash.

The following options are required.

=over

=item file

This should be the name of the file you are looking for.

=item path

This should be the path to the template directory you are looking for the file
in.

=back

The following options are not required. If omitted default to on.

=over

=item use_local

This says whether to return the local copy of the file if found rather than
the unmodified copy.

=item use_inheritance

This open specifies whether to search the inheritance tree for the file you
are looking for. The search starts in the C<path> you provided.

=over

=head2 get_all_paths

This method returns all files it finds while looking through inheritance and
or locals.

The following options are required.

=over

=item file

This should be the name of the file you are looking for.

=item path

This should be the path to the template directory you are looking for the file
in.

=back

The following options are not required.

=over

=item use_local

Boolean, should we include files in the local directory if they exist.
Defaults to on.

=item use_inheritance

Boolean, should we search the inheritance tree for files. Defaults to on.

=item local_inheritance

Boolean, should we include both local and root file if they both exist.
Defaults to the value of C<use_inheritance>.

=back

=head1 SEE ALSO

L<GT::Template>

=head1 MAINTAINER

Jason Rhinelander

=head1 COPYRIGHT

Copyright (c) 2002 Gossamer Threads Inc.  All Rights Reserved.
http://www.gossamer-threads.com/

=head1 VERSION

Revision: $Id: Inheritance.pm,v 1.3 2002/04/12 22:15:00 jagerman Exp $

=cut