251 lines
7.6 KiB
Perl
251 lines
7.6 KiB
Perl
# ==================================================================
|
|
# Gossamer Threads Module Library - http://gossamer-threads.com/
|
|
#
|
|
# GT::Template::Inheritance
|
|
# Author: Scott Beck
|
|
# CVS Info :
|
|
# $Id: Inheritance.pm,v 1.7 2005/02/09 20:51:27 jagerman Exp $
|
|
#
|
|
# Copyright (c) 2004 Gossamer Threads Inc. All Rights Reserved.
|
|
# ==================================================================
|
|
#
|
|
# Description: Provides class methods to deal with template
|
|
# inheritance.
|
|
#
|
|
|
|
package GT::Template::Inheritance;
|
|
# ==================================================================
|
|
|
|
use strict;
|
|
use vars qw($ERRORS);
|
|
use bases 'GT::Base' => '';
|
|
use GT::Template;
|
|
|
|
$ERRORS = { RECURSION => q _Recursive inheritance detected and interrupted: '%s'_ };
|
|
|
|
sub get_all_paths {
|
|
# ----------------------------------------------------------------------------
|
|
my ($class, %opts) = @_;
|
|
|
|
my $file = delete $opts{file};
|
|
my $single = delete $opts{_single};
|
|
$class->fatal(BADARGS => "No file specified to $class->" . ($single ? 'get_path' : 'get_all_paths')) unless defined $file;
|
|
|
|
my $root = delete $opts{path};
|
|
$class->fatal(BADARGS => "No path specified to $class->" . ($single ? 'get_path' : 'get_all_paths')) unless defined $root;
|
|
$class->fatal(BADARGS => "Path $root does not exist or is not a directory") unless -d $root;
|
|
|
|
my $local = exists $opts{local} ? delete $opts{local} : 1;
|
|
my $inheritance = exists $opts{inheritance} ? delete $opts{inheritance} : 1;
|
|
|
|
# Old no-longer-supported option:
|
|
delete @opts{qw/use_inheritance use_local local_inheritance/};
|
|
|
|
$class->fatal(BADARGS => "Unknown arguments: " . join ", ", keys %opts) if keys %opts;
|
|
|
|
my @paths = $class->tree(path => $root, local => $local, inheritance => $inheritance);
|
|
my @files;
|
|
for (@paths) {
|
|
if (-f "$_/$file" and -r _) {
|
|
return "$_/$file" if $single;
|
|
push @files, "$_/$file";
|
|
}
|
|
}
|
|
return if $single;
|
|
return @files;
|
|
}
|
|
|
|
sub get_path {
|
|
# ----------------------------------------------------------------------------
|
|
shift->get_all_paths(@_, _single => 1);
|
|
}
|
|
|
|
sub tree {
|
|
# -----------------------------------------------------------------------------
|
|
my $class = shift;
|
|
my %opts = @_ > 1 ? @_ : (path => shift);
|
|
|
|
my $root = delete $opts{path};
|
|
$class->fatal(BADARGS => "No path specified for $class->tree") unless defined $root;
|
|
$class->fatal(BADARGS => "Path '$root' does not exist or is not a directory") unless -d $root;
|
|
|
|
my $local = exists $opts{local} ? delete $opts{local} : 1;
|
|
my $inheritance = exists $opts{inheritance} ? delete $opts{inheritance} : 1;
|
|
|
|
$class->fatal(BADARGS => "Unknown arguments: " . join ", ", keys %opts) if keys %opts;
|
|
|
|
my @paths;
|
|
push @paths, $root;
|
|
my %encountered = ($root => 1);
|
|
if ($inheritance) {
|
|
for my $path (@paths) {
|
|
my $tplinfo = GT::Template->load_tplinfo($path);
|
|
next if not defined $tplinfo->{inheritance};
|
|
my @inherit = ref $tplinfo->{inheritance} eq 'ARRAY' ? @{$tplinfo->{inheritance}} : $tplinfo->{inheritance};
|
|
|
|
for (@inherit) {
|
|
my $inh = m!^(?:[a-zA-Z]:)?[\\/]! ? $_ : "$path/$_";
|
|
if (length $inh > 500 or $encountered{$inh}++) {
|
|
return $class->fatal(RECURSION => $inh);
|
|
}
|
|
|
|
push @paths, $inh;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($local) {
|
|
for (my $i = 0; $i < @paths; $i++) {
|
|
if (-d "$paths[$i]/local") {
|
|
splice @paths, $i, 0, "$paths[$i]/local";
|
|
$i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return @paths;
|
|
}
|
|
|
|
1;
|
|
|
|
__END__
|
|
|
|
=head1 NAME
|
|
|
|
GT::Template::Inheritance - Provides GT::Template inheritance/local file
|
|
determination.
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
use GT::Template::Inheritance;
|
|
|
|
my $file = GT::Template::Inheritance->get_path(
|
|
file => "foo.htm",
|
|
path => "/path/to/my/template/set"
|
|
);
|
|
|
|
my @files = GT::Template::Inheritance->get_all_paths(
|
|
file => "foo.htm",
|
|
path => "/path/to/my/template/set"
|
|
);
|
|
|
|
my @paths = GT::Template::Inheritance->tree(
|
|
path => "/path/to/my/template/set"
|
|
);
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
GT::Template::Inheritance provides an interface to accessing files for
|
|
GT::Template template parsing and include handling. It supports following
|
|
inheritance directories and respects "local" template directories.
|
|
|
|
|
|
=head2 Inheritance
|
|
|
|
GT::Template inheritance works by looking for a .tplinfo file in the template
|
|
directory (or local/.tplinfo, if it exists). In order for the template
|
|
directory to inherit from another template directory, this file must exist and
|
|
must evaluate to a hash reference containing an C<inheritance> key. The
|
|
following is a possible .tplinfo file contents:
|
|
|
|
{
|
|
inheritance => '../other'
|
|
}
|
|
|
|
The above example would indicate that files in this template set can be
|
|
inherited from the ../other path, relative to the current template set
|
|
directory. The inheritance directory may also contain a full path.
|
|
|
|
=head2 Inheriting from multiple locations
|
|
|
|
You may also inherit from multiple locations by using an array reference for
|
|
the inheritance value:
|
|
|
|
{
|
|
inheritance => ['../other', '/full/path/to/a/third']
|
|
}
|
|
|
|
With the above .tplinfo file, files would be checked for in the current path,
|
|
then C<../other>, then any of C<../other>'s inherited directories, then in
|
|
C<third>, then in any of C<third>'s inherited directories.
|
|
|
|
Also keep in mind that "local" directories, if they exist, will be checked for
|
|
the file before each of their respective directories.
|
|
|
|
Assuming that the initial template path was C</full/path/one>, and assuming
|
|
that C<../other> inherited from C<../other2>, the directories checked would be
|
|
as follows:
|
|
|
|
/full/path/one/local
|
|
/full/path/one
|
|
/full/path/one/../other/local # i.e. /full/path/other/local
|
|
/full/path/one/../other # i.e. /full/path/other
|
|
/full/path/one/../other/../other2/local # i.e. /full/path/other2/local
|
|
/full/path/one/../other/../other2 # i.e. /full/path/other2
|
|
/full/path/to/a/third/local
|
|
/full/path/to/a/third
|
|
|
|
=head1 METHODS
|
|
|
|
All methods in GT::Template::Inheritance are class methods. Each method takes
|
|
a hash of options as an argument.
|
|
|
|
=head2 get_path
|
|
|
|
=head2 get_all_paths
|
|
|
|
These methods are used to obtain the location of the file GT::Template will
|
|
use, taking into account all inherited and "local" template directories. The
|
|
get_path option will return the path to the file that will be included, while
|
|
the get_all_paths option returns the path to B<all> copies of the file found in
|
|
the local/inheritance tree. Both methods take a hash containing the following:
|
|
|
|
=over 4
|
|
|
|
=item file
|
|
|
|
The name of the file desired.
|
|
|
|
=item path
|
|
|
|
The template directory at which to start looking for the above file. Depending
|
|
on the existance of "local" directories and template inheritance, more than
|
|
just this directory will be checked for the file.
|
|
|
|
=item local
|
|
|
|
Optional. Can be passed with a false value to override the checking of "local"
|
|
directories for files.
|
|
|
|
=item inheritance
|
|
|
|
Optional. Can be passed with a false value to override the checking of
|
|
inheritance directories for files.
|
|
|
|
=back
|
|
|
|
=head2 tree
|
|
|
|
This method returns a list of directories that would be searched for a given
|
|
file, in the order they would be searched. It takes the C<path>, C<local>, and
|
|
C<inheritance> options above, but not the C<file> option.
|
|
|
|
=head1 SEE ALSO
|
|
|
|
L<GT::Template>
|
|
|
|
=head1 MAINTAINER
|
|
|
|
Jason Rhinelander
|
|
|
|
=head1 COPYRIGHT
|
|
|
|
Copyright (c) 2005 Gossamer Threads Inc. All Rights Reserved.
|
|
http://www.gossamer-threads.com/
|
|
|
|
=head1 VERSION
|
|
|
|
Revision: $Id: Inheritance.pm,v 1.7 2005/02/09 20:51:27 jagerman Exp $
|
|
|
|
=cut
|