home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / tsw / TSW_3.4.0.exe / Apache2 / perl / Directory.pm < prev    next >
Encoding:
Perl POD Document  |  2004-01-30  |  11.5 KB  |  411 lines

  1. #============================================================= -*-Perl-*-
  2. #
  3. # Template::Plugin::Directory
  4. #
  5. # DESCRIPTION
  6. #   Plugin for encapsulating information about a file system directory.
  7. #
  8. # AUTHORS
  9. #   Michael Stevens <michael@etla.org>, with some mutilations from 
  10. #   Andy Wardley <abw@kfs.org>.
  11. #
  12. # COPYRIGHT
  13. #   This module is free software; you can redistribute it and/or
  14. #   modify it under the same terms as Perl itself.
  15. #
  16. # REVISION
  17. #   $Id: Directory.pm,v 2.64 2004/01/13 16:20:38 abw Exp $
  18. #
  19. #============================================================================
  20.  
  21. package Template::Plugin::Directory;
  22.  
  23. require 5.004;
  24.  
  25. use strict;
  26. use Cwd;
  27. use File::Spec;
  28. use Template::Plugin::File;
  29. use vars qw( $VERSION );
  30. use base qw( Template::Plugin::File );
  31.  
  32. $VERSION = sprintf("%d.%02d", q$Revision: 2.64 $ =~ /(\d+)\.(\d+)/);
  33.  
  34.  
  35. #------------------------------------------------------------------------
  36. # new(\%config)
  37. #
  38. # Constructor method.
  39. #------------------------------------------------------------------------
  40.  
  41. sub new {
  42.     my $config = ref($_[-1]) eq 'HASH' ? pop(@_) : { };
  43.     my ($class, $context, $path) = @_;
  44.  
  45.     return $class->throw('no directory specified')
  46.     unless defined $path and length $path;
  47.  
  48.     my $self = $class->SUPER::new($context, $path, $config);
  49.     my ($dir, @files, $name, $item, $abs, $rel, $check);
  50.     $self->{ files } = [ ];
  51.     $self->{ dirs  } = [ ];
  52.     $self->{ list  } = [ ];
  53.     $self->{ _dir  } = { };
  54.  
  55.     # don't read directory if 'nostat' or 'noscan' set
  56.     return $self if $config->{ nostat } || $config->{ noscan };
  57.  
  58.     $self->throw("$path: not a directory")
  59.     unless $self->{ isdir };
  60.  
  61.     $self->scan($config);
  62.  
  63.     return $self;
  64. }
  65.  
  66.  
  67. #------------------------------------------------------------------------
  68. # scan(\%config)
  69. #
  70. # Scan directory for files and sub-directories.
  71. #------------------------------------------------------------------------
  72.  
  73. sub scan {
  74.     my ($self, $config) = @_;
  75.     $config ||= { };
  76.     local *DH;
  77.     my ($dir, @files, $name, $abs, $rel, $item);
  78.     
  79.     # set 'noscan' in config if recurse isn't set, to ensure Directories
  80.     # created don't try to scan deeper
  81.     $config->{ noscan } = 1 unless $config->{ recurse };
  82.  
  83.     $dir = $self->{ abs };
  84.     opendir(DH, $dir) or return $self->throw("$dir: $!");
  85.  
  86.     @files = readdir DH;
  87.     closedir(DH) 
  88.     or return $self->throw("$dir close: $!");
  89.  
  90.     my ($path, $files, $dirs, $list) = @$self{ qw( path files dirs list ) };
  91.     @$files = @$dirs = @$list = ();
  92.  
  93.     foreach $name (sort @files) {
  94.     next if $name =~ /^\./;
  95.     $abs = File::Spec->catfile($dir, $name);
  96.     $rel = File::Spec->catfile($path, $name);
  97.  
  98.     if (-d $abs) {
  99.         $item = Template::Plugin::Directory->new(undef, $rel, $config);
  100.         push(@$dirs, $item);
  101.     }
  102.     else {
  103.         $item = Template::Plugin::File->new(undef, $rel, $config);
  104.         push(@$files, $item);
  105.     }
  106.     push(@$list, $item);
  107.     $self->{ _dir }->{ $name } = $item;
  108.     }
  109.  
  110.     return '';
  111. }
  112.  
  113.  
  114. #------------------------------------------------------------------------
  115. # file($filename)
  116. #
  117. # Fetch a named file from this directory.
  118. #------------------------------------------------------------------------
  119.  
  120. sub file {
  121.     my ($self, $name) = @_;
  122.     return $self->{ _dir }->{ $name };
  123. }
  124.  
  125.  
  126. #------------------------------------------------------------------------
  127. # present($view)
  128. #
  129. # Present self to a Template::View
  130. #------------------------------------------------------------------------
  131.  
  132. sub present {
  133.     my ($self, $view) = @_;
  134.     $view->view_directory($self);
  135. }
  136.  
  137.  
  138. #------------------------------------------------------------------------
  139. # content($view)
  140. # Present directory content to a Template::View.
  141. #------------------------------------------------------------------------
  142.  
  143. sub content {
  144.     my ($self, $view) = @_;
  145.     return $self->{ list } unless $view;
  146.     my $output = '';
  147.     foreach my $file (@{ $self->{ list } }) {
  148.     $output .= $file->present($view);
  149.     }
  150.     return $output;
  151. }
  152.  
  153.  
  154. #------------------------------------------------------------------------
  155. # throw($msg)
  156. #
  157. # Throw a 'Directory' exception.
  158. #------------------------------------------------------------------------
  159.  
  160. sub throw {
  161.     my ($self, $error) = @_;
  162.     die (Template::Exception->new('Directory', $error));
  163. }
  164.  
  165. __END__
  166.  
  167.  
  168. #------------------------------------------------------------------------
  169. # IMPORTANT NOTE
  170. #   This documentation is generated automatically from source
  171. #   templates.  Any changes you make here may be lost.
  172. #   The 'docsrc' documentation source bundle is available for download
  173. #   from http://www.template-toolkit.org/docs.html and contains all
  174. #   the source templates, XML files, scripts, etc., from which the
  175. #   documentation for the Template Toolkit is built.
  176. #------------------------------------------------------------------------
  177.  
  178. =head1 NAME
  179.  
  180. Template::Plugin::Directory - Plugin for generating directory listings
  181.  
  182. =head1 SYNOPSIS
  183.  
  184.     [% USE dir = Directory(dirpath) %]
  185.  
  186.     # files returns list of regular files
  187.     [% FOREACH file = dir.files %]
  188.        [% file.name %] [% file.path %] ...
  189.     [% END %]
  190.  
  191.     # dirs returns list of sub-directories
  192.     [% FOREACH subdir = dir.dirs %]
  193.        [% subdir.name %] [% subdir.path %] ...
  194.     [% END %]
  195.  
  196.     # list returns both interleaved in order
  197.     [% FOREACH item = dir.list %]
  198.        [% IF item.isdir %]
  199.       Directory: [% item.name %]
  200.        [% ELSE 
  201.           File: [% item.name %]
  202.        [% END %]
  203.     [% END %]
  204.  
  205.     # define a VIEW to display dirs/files
  206.     [% VIEW myview %]
  207.        [% BLOCK file %]
  208.        File: [% item.name %]
  209.        [% END %]
  210.  
  211.        [% BLOCK directory %]
  212.        Directory: [% item.name %] 
  213.        [% item.content(myview) | indent -%]
  214.        [% END %]
  215.     [% END %]
  216.  
  217.     # display directory content using view
  218.     [% myview.print(dir) %]
  219.  
  220. =head1 DESCRIPTION
  221.  
  222. This Template Toolkit plugin provides a simple interface to directory
  223. listings.  It is derived from the Template::Plugin::File module and
  224. uses Template::Plugin::File object instances to represent files within
  225. a directory.  Sub-directories within a directory are represented by
  226. further Template::Plugin::Directory instances.
  227.  
  228. The constructor expects a directory name as an argument.
  229.  
  230.     [% USE dir = Directory('/tmp') %]
  231.  
  232. It then provides access to the files and sub-directories contained within 
  233. the directory.
  234.  
  235.     # regular files (not directories)
  236.     [% FOREACH file = dir.files %]
  237.        [% file.name %]
  238.     [% END %]
  239.  
  240.     # directories only
  241.     [% FOREACH file = dir.dirs %]
  242.        [% file.name %]
  243.     [% END %]
  244.  
  245.     # files and/or directories
  246.     [% FOREACH file = dir.list %]
  247.        [% file.name %] ([% file.isdir ? 'directory' : 'file' %])
  248.     [% END %]
  249.  
  250.     [% USE Directory('foo/baz') %]
  251.  
  252. The plugin constructor will throw a 'Directory' error if the specified
  253. path does not exist, is not a directory or fails to stat() (see
  254. L<Template::Plugin::File>).  Otherwise, it will scan the directory and
  255. create lists named 'files' containing files, 'dirs' containing
  256. directories and 'list' containing both files and directories combined.
  257. The 'nostat' option can be set to disable all file/directory checks
  258. and directory scanning.
  259.  
  260. Each file in the directory will be represented by a
  261. Template::Plugin::File object instance, and each directory by another
  262. Template::Plugin::Directory.  If the 'recurse' flag is set, then those
  263. directories will contain further nested entries, and so on.  With the
  264. 'recurse' flag unset, as it is by default, then each is just a place
  265. marker for the directory and does not contain any further content
  266. unless its scan() method is explicitly called.  The 'isdir' flag can
  267. be tested against files and/or directories, returning true if the item
  268. is a directory or false if it is a regular file.
  269.  
  270.     [% FOREACH file = dir.list %]
  271.        [% IF file.isdir %]
  272.           * Directory: [% file.name %]
  273.        [% ELSE %]
  274.           * File: [% file.name %]
  275.        [% END %]
  276.     [% END %]
  277.  
  278. This example shows how you might walk down a directory tree, displaying 
  279. content as you go.  With the recurse flag disabled, as is the default, 
  280. we need to explicitly call the scan() method on each directory, to force
  281. it to lookup files and further sub-directories contained within. 
  282.  
  283.     [% USE dir = Directory(dirpath) %]
  284.     * [% dir.path %]
  285.     [% INCLUDE showdir %]
  286.  
  287.     [% BLOCK showdir -%]
  288.       [% FOREACH file = dir.list -%]
  289.         [% IF file.isdir -%]
  290.         * [% file.name %]
  291.           [% file.scan -%]
  292.       [% INCLUDE showdir dir=file FILTER indent(4) -%]
  293.         [% ELSE -%]
  294.         - [% f.name %]
  295.         [% END -%]
  296.       [% END -%]
  297.      [% END %]
  298.  
  299. This example is adapted (with some re-formatting for clarity) from
  300. a test in F<t/directry.t> which produces the following output:
  301.  
  302.     * test/dir
  303.         - file1
  304.         - file2
  305.         * sub_one
  306.             - bar
  307.             - foo
  308.         * sub_two
  309.             - waz.html
  310.             - wiz.html
  311.         - xyzfile
  312.  
  313. The 'recurse' flag can be set (disabled by default) to cause the
  314. constructor to automatically recurse down into all sub-directories,
  315. creating a new Template::Plugin::Directory object for each one and 
  316. filling it with any further content.  In this case there is no need
  317. to explicitly call the scan() method.
  318.  
  319.     [% USE dir = Directory(dirpath, recurse=1) %]
  320.        ...
  321.  
  322.         [% IF file.isdir -%]
  323.         * [% file.name %]
  324.       [% INCLUDE showdir dir=file FILTER indent(4) -%]
  325.         [% ELSE -%]
  326.            ...
  327.  
  328. From version 2.01, the Template Toolkit provides support for views.
  329. A view can be defined as a VIEW ... END block and should contain 
  330. BLOCK definitions for files ('file') and directories ('directory').
  331.  
  332.     [% VIEW myview %]
  333.     [% BLOCK file %]
  334.        - [% item.name %]
  335.     [% END %]
  336.     
  337.     [% BLOCK directory %]
  338.        * [% item.name %]
  339.          [% item.content(myview) FILTER indent %]
  340.     [% END %]
  341.     [% END %]
  342.  
  343. Then the view print() method can be called, passing the
  344. Directory object as an argument.
  345.  
  346.     [% USE dir = Directory(dirpath, recurse=1) %]
  347.     [% myview.print(dir) %]
  348.  
  349. When a directory is presented to a view, either as [% myview.print(dir) %]
  350. or [% dir.present(view) %], then the 'directory' BLOCK within the 'myview' 
  351. VIEW is processed, with the 'item' variable set to alias the Directory object.
  352.  
  353.     [% BLOCK directory %]
  354.        * [% item.name %]
  355.          [% item.content(myview) FILTER indent %]
  356.     [% END %]
  357.  
  358. The directory name is first printed and the content(view) method is
  359. then called to present each item within the directory to the view.
  360. Further directories will be mapped to the 'directory' block, and files
  361. will be mapped to the 'file' block.
  362.  
  363. With the recurse option disabled, as it is by default, the 'directory'
  364. block should explicitly call a scan() on each directory.
  365.  
  366.     [% VIEW myview %]
  367.     [% BLOCK file %]
  368.        - [% item.name %]
  369.     [% END %]
  370.     
  371.     [% BLOCK directory %]
  372.        * [% item.name %]
  373.      [% item.scan %]
  374.          [% item.content(myview) FILTER indent %]
  375.     [% END %]
  376.     [% END %]
  377.  
  378.     [% USE dir = Directory(dirpath) %]
  379.     [% myview.print(dir) %]
  380.  
  381. =head1 TODO
  382.  
  383. Might be nice to be able to specify accept/ignore options to catch
  384. a subset of files.
  385.  
  386. =head1 AUTHORS
  387.  
  388. Michael Stevens E<lt>michael@etla.orgE<gt> wrote the original Directory plugin
  389. on which this is based.  Andy Wardley E<lt>abw@wardley.orgE<gt> split it into 
  390. separate File and Directory plugins, added some extra code and documentation
  391. for VIEW support, and made a few other minor tweaks.
  392.  
  393. =head1 VERSION
  394.  
  395. 2.64, distributed as part of the
  396. Template Toolkit version 2.13, released on 30 January 2004.
  397.  
  398.  
  399.  
  400. =head1 COPYRIGHT
  401.  
  402. This module is free software; you can redistribute it and/or
  403. modify it under the same terms as Perl itself.
  404.  
  405. =head1 SEE ALSO
  406.  
  407. L<Template::Plugin|Template::Plugin>, L<Template::Plugin::File|Template::Plugin::File>, L<Template::View|Template::View>
  408.  
  409.