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

cvs@template-toolkit.org cvs@template-toolkit.org
Thu, 04 Dec 2003 15:12:34 +0000


cvs         03/12/04 15:12:31

  Added:       lib/Template/TT3 Factory.pm
  Log:
  added Template::TT3::Factory
  
  Revision  Changes    Path
  1.1                  TT3/lib/Template/TT3/Factory.pm
  
  Index: Factory.pm
  ===================================================================
  #============================================================= -*-perl-*-
  #
  # Template::TT3::Factory
  #
  # DESCRIPTION
  #   Factory module for loading and instantiating other Template modules.
  #
  # AUTHOR
  #   Andy Wardley  <abw@wardley.org>
  #
  # 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.
  #
  # REVISION
  #   $Id: Factory.pm,v 1.1 2003/12/04 15:12:31 abw Exp $
  #
  # TODO
  #   * if module entry can be a string or hash table, then module() could
  #     return either, leaving the caller to work out which.  Perhaps it 
  #     should automatically fold strings (module names) into hash arrays
  #     of the form { module => $module_name }
  #
  #========================================================================
  
  package Template::TT3::Factory;
  
  use strict;
  use warnings;
  use Template::TT3::Base;
  use Template::TT3::Utils;
  use vars qw( $VERSION $DEBUG $ERROR $WARNING $UTILS $MODULES );
  use base qw( Template::TT3::Base );
  
  $VERSION = sprintf("%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/);
  $DEBUG   = 0 unless defined $DEBUG;
  $ERROR   = '';
  $UTILS   = 'Template::TT3::Utils';
  $MODULES = { };
  
  
  
  #------------------------------------------------------------------------
  # init({ name => $module, name => $module, ... })
  #
  # Initialisation method which builds a factory table mapping names to 
  # modules, by merging any $MODULES hash defined in the derived class
  # package with any extra definitions passed in as arguments.
  #------------------------------------------------------------------------
  
  sub init {
      my ($self, $config) = @_;
      my $class = ref $self || $self;
  
      # merge $MODULES class hash and MODULES (or modules) config hash
      my $classmods = do {
          no strict 'refs';
          ${"$class\::MODULES"} || { };
      };
      my $configmods = $config->{ modules } 
                    || $config->{ MODULES } 
                    || { };
  
      $self->{ modules } = {
          %$classmods, 
          %$configmods,
      };
      $self->{ loaded  } = { };
  
      # set utility class
      $self->{ utils } = $config->{ utils }
                      || $UTILS;
  
      $self->debug("init() => $self\n") if $DEBUG;
  
      return $self;
  }
  
  
  #------------------------------------------------------------------------
  # module($name)
  # module($name, $module)
  # 
  # Accessor/mutator method for managing the internal module lookup table
  # that maps generic names to specific module implementations.  Returns
  # the current module package name for a named item when called with one 
  # argument, or updates it when called with two. 
  #------------------------------------------------------------------------
  
  sub module {
      my ($self, $name, $module) = @_;
      my $class = ref($self) || $self;
      my ($modmod, $utils);
  
      my $mods = ref $self ? $self->{ modules } : do {
          no strict 'refs';
          ${"$class\::MODULES"} || { };
      };
  
      if (defined($module)) {
          # update table with new module
          $mods->{ $name } = $module;
          return $module;
      }
      else {
          $module = $mods->{ $name }
              || return $self->error("module not found: $name");
      }
  
      # load relevant module if we haven't already done so
      unless ($self->{ loaded }->{ $name }) {
          
          if (UNIVERSAL::isa($module, 'HASH')) {
              # if 'module' isn't defined in the hash then the
              # user doesn't want us to load a module for this class
              $modmod = $module->{ module };
          }
          else {
              $modmod = $module;
          }
  
          if ($modmod) {
              # delegate to Utils class
              $utils = $self->{ utils } 
                  || return $self->error('no utility class defined');
  
              $utils->load_module($modmod)
                  || return $self->error($utils->error());
          }
  
          $self->{ loaded }->{ $name } = $module;
      }
  
      # TODO: should this always return a hash (or string?)
      return $module;
  }
  
  
  sub class {
      my ($self, $name) = @_;
      my $module = $self->module($name) || return;
      my $modclass;
  
      if (UNIVERSAL::isa($module, 'HASH')) {
          # if 'class' isn't defined in the hash then we
          # look for 'module', or fail
          $modclass = $module->{ class } || $module->{ module } 
              || return $self->error("no class or module defined for $name");
      }
      else {
          $modclass = $module;
      }
      return $modclass;
  }
  
  
  sub create {
      my ($self, $module, @args) = @_;
      my $class = $self->class($module) || return;
      my $object;
      
      eval {
          # call the class constructor method
          $self->debug("calling $class->new(", join(', ', @args), ")\n") if $DEBUG;
          $object = $class->new(@args)
              || $self->error("failed to create $class object", 
                              UNIVERSAL::can($class, 'error') 
                              ? (': ', $class->error) : ());
      };
      if ($@) {
          chomp($@);
          return $self->error("failed to create $class object: $@");
      };
      return $object;
  }
  
  
  # TT
  #
  # sub object { }
  # 
  # sub preload { }
  # 
  # sub isa { }
  
  # # Webkit
  # 
  # sub instance { }    # can be a singleton
  # 
  # sub construct { }
  # 
  
  1;
  __END__
  
  =head1 NAME
  
  Template::TT3::Factory - load and instantiate other Template modules
  
  =head1 SYNOPSIS
  
      use Template::TT3::Factory
  
      # TODO
  
  =head1 DESCRIPTION
  
  # TODO
  
  =head1 METHODS
  
  =head2 method1()
  
  # TODO
  
  =head2 method2()
  
  # TODO
  
  =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.
  
  =head1 SEE ALSO
  
  # TODO
  
  =cut
  
  # Local Variables:
  # mode: perl
  # perl-indent-level: 4
  # indent-tabs-mode: nil
  # End:
  #
  # vim: expandtab shiftwidth=4: