[Templates-cvs] cvs commit: TT3/lib/Template Utils.pm

cvs@template-toolkit.org cvs@template-toolkit.org
Tue, 23 Mar 2004 11:05:31 +0000


cvs         04/03/23 11:05:31

  Added:       lib/Template Utils.pm
  Log:
  * Added Template::Utils module
  
  Revision  Changes    Path
  1.1                  TT3/lib/Template/Utils.pm
  
  Index: Utils.pm
  ===================================================================
  #============================================================= -*-perl-*-
  #
  # Template::Utils
  #
  # DESCRIPTION
  #   Module implementing various utility functions that we don't want to 
  #   put in the base class object for reasons of security: things like 
  #   loading Perl modules, reading and writing files, etc., shouldn't be
  #   available to objects exposed in templates.
  #
  # AUTHOR
  #   Andy Wardley   <abw@wardley.org>
  #
  # COPYRIGHT
  #   Copyright (C) 1996-2004 Andy Wardley.  All Rights Reserved.
  #   Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
  #   Copyright (C) 2002-2004 Fotango Ltd.
  #
  #   This module is free software; you can redistribute it and/or
  #   modify it under the same terms as Perl itself.
  #
  # REVISION
  #   $Id: Utils.pm,v 1.1 2004/03/23 11:05:30 abw Exp $
  #
  #========================================================================
  
  package Template::Utils;
  
  use strict;
  use warnings;
  use File::Path;
  use File::Spec;
  use File::Temp;
  use File::Basename;
  
  use Template::Base;
  use vars qw( $VERSION $DEBUG $ERROR );
  use base qw( Template::Base );
  
  $VERSION = sprintf("%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/);
  $DEBUG   = 0 unless defined $DEBUG;
  $ERROR   = '';
  
  
  #------------------------------------------------------------------------
  # load_module($name)
  #
  # Load a Perl module.
  #------------------------------------------------------------------------
  
  sub load_module {
      my ($self, $module) = @_;
      $module  =~ s[::][/]g;
      $module .= '.pm';
      eval { require $module };
      return $@ ? $self->error("failed to load $module: $@") : 1;
  }
  
  
  #------------------------------------------------------------------------
  # load_file($filename)
  #
  # Load the contents of a file, returning it as a reference to a scalar.
  #------------------------------------------------------------------------
  
  sub load_file {
      my ($self, $filename) = @_;
      local $/ = undef;
      local *FH;
  
      open(FH, "<$filename") || return $self->error("$filename: $!");
      my $content = <FH>;
      close(FH);
      
      return \$content;
  }
  
  
  #------------------------------------------------------------------------
  # save_file($file, $output)
  #
  # Writes $output to the file denoted by $file using an intermediate 
  # temporary file which is renamed into place to avoid any race conditions.
  #------------------------------------------------------------------------
  
  sub save_file {
      my ($self, $file, $output) = @_;
      my ($fh, $tmpfile);
  
      # untaint filename
      $file =~ /(.*)/;
      $file = $1;
  
      # determine base directory 
      my $dir = File::Basename::dirname($file);
  
      eval {
          # make the directory if it doesn't already exist
          File::Path::mkpath($dir) unless -d $dir;
  
          # create a temporary file in the same directory 
          ($fh, $tmpfile) = File::Temp::tempfile( DIR => $dir );
          print($fh ref($output) ? $$output : $output) || die $!;
          close($fh);
      };
      return $self->error($@) if $@;
  
      rename($tmpfile, $file)
          || return $self->error($!);
  
      return 1;
  }
  
  
  #------------------------------------------------------------------------
  # file_path($path1, $path2, $path3, ...)
  #
  # Wrapper around File::Spec method to concatenate file path components
  # and return a canonical representation.
  #------------------------------------------------------------------------
  
  sub file_path {
      my $self = shift;
      File::Spec->canonpath(File::Spec->catfile(@_));
  }
  
  
  
  #------------------------------------------------------------------------
  # path($path1, $path2, $path3, ...)
  #
  # Similar to file_path() but always uses '/' as a path separator rather
  # than any OS specific value.
  #------------------------------------------------------------------------
  
  sub path {
      # TODO: this should always use '/' for TT paths, regardless of OS
      my $self = shift;
      File::Spec->catfile(@_);
  }
  
  
  
  
  
  1;
  __END__
  
  =head1 NAME
  
  Template::Utils - utility functions for the Template Toolkit
  
  =head1 SYNOPSIS
  
      use Template::Utils
  
      # supports class methods...
  
      # load a Perl module
      Template::Utils->load_module('Template::Compiler')
          || die Template::Utils->error();  
  
      # load a file
      my $text = Template::Utils->load_file('/tmp/foo')
          || die Template::Utils->error();  
  
      # save a file
      Template::Utils->save_file('/tmp/bar', $text)
          || die Template::Utils->error();  
  
  
      # ...and also object methods
  
      my $utils = Template::Utils->new();
  
      # load a Perl module
      $utils->load_module('Template::Compiler')
          || die $utils->error();  
  
      # load a file
      my $text = $utils->load_file('/tmp/foo')
          || die $utils->error();  
  
      # save a file
      $utils->save_file('/tmp/bar', $text)
          || die $utils->error();  
  
      
  =head1 DESCRIPTION
  
  This module implements a number of useful utility methods.  They can
  be called as class methods:
  
      use Template::Utils;
  
      # load a Perl module
      Template::Utils->load_module('Template::Compiler')
          || die Template::Utils->error();  
  
  Or as object methods:
  
      my $utils = Template::Utils->new();
  
      # load a Perl module
      $utils->load_module('Template::Compiler')
          || die $utils->error();  
  
  =head1 METHODS
  
  =head2 new()
  
  This constructor method creates a new Template::Utils object.
  
      my $utils = Template::Utils->new();
  
  =head2 load_module($modname)
  
  This method loads the Perl module named by the first argument.  Any
  occurrences of C<::> in the name will be converted to C</> and C<.pm>
  will be appended to it to determine the correct file name.  
  
      $utils->load_module('Template::Compiler')
          || die $utils->error();  
  
  In the example above, the module loaded (using Perl's C<require>
  function) is C<Template/TT3/Compiler.pm>.
  
  =head2 load_file($filename)
  
  This method reads the content of the file named by the first argument
  and returns it as a single string.
  
      my $text = $utils->load_file('/tmp/foo')
          || die $utils->error();  
  
  =head2 save_file($filename, $text)
  
  This method writes the text passed as the second argument to the 
  file named by the first.  The text can be passed as a scalar value
  or as a reference to a scalar value.
  
      # pass text
      $utils->save_file('/tmp/bar', $text)
          || die $utils->error();  
  
      # pass reference to text
      $utils->save_file('/tmp/bar', \$text)
          || die $utils->error();  
  
  To avoid any race conditions where two separate processes might 
  attempt to write the same file at the same time, the method writes
  the output to a temporary file and then renames it into place.
  
  =head1 AUTHOR
  
  Andy Wardley  E<lt>abw@wardley.orgE<gt>
  
  =head1 VERSION
  
  $Revision: 1.1 $
  
  =head1 COPYRIGHT
  
    Copyright (C) 1996-2003 Andy Wardley.  All Rights Reserved.
    Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
  
  This module is free software; you can redistribute it and/or
  modify it under the same terms as Perl itself.
  
  =cut
  
  # Local Variables:
  # mode: perl
  # perl-indent-level: 4
  # indent-tabs-mode: nil
  # End:
  #
  # vim: expandtab shiftwidth=4: