【问题标题】:How can I handle template dependencies in Template Toolkit?如何在 Template Toolkit 中处理模板依赖项?
【发布时间】:2011-01-30 15:26:54
【问题描述】:

我的静态网页是由大量模板构建的,这些模板使用 Template Toolkit 的“导入”和“包含”相互包含,因此 page.html 看起来像这样:

[% INCLUDE top %]
[% IMPORT middle %]

那么顶部可能包含更多文件。

我有很多这些文件,必须运行它们才能以各种语言(英语、法语等,而不是计算机语言)创建网页。这是一个非常复杂的过程,当更新一个文件时,我希望能够使用 makefile 或类似的东西自动重新制作必要的文件。

有没有像 makedepend 这样的 C 文件工具可以解析模板工具包模板并创建一个依赖列表以在 makefile 中使用?

或者有没有更好的方法来自动化这个过程?

【问题讨论】:

    标签: perl makefile template-toolkit


    【解决方案1】:

    Template Toolkit 带有自己的命令行脚本ttree,用于构建 TT 网站 ala make。

    这是我在 Mac 上的 TT 网站项目中经常使用的 ttree.cfg 文件:

    # directories
    src = ./src
    lib = ./lib
    lib = ./content
    dest = ./html
    
    # pre process these site file
    pre_process = site.tt
    
    # copy these files
    copy = \.(png|gif|jpg)$
    
    # ignore following
    ignore = \b(CVS|RCS)\b
    ignore = ^#
    ignore = ^\.DS_Store$
    ignore = ^._
    
    # other options
    verbose
    recurse
    

    仅运行 ttree -f ttree.cfg 将在 dest 中重建站点,仅更新源(src)或我的库(lib)中更改的内容。

    有关更细粒度的依赖关系,请查看Template Dependencies

    更新 - 这是我通过子类化Template::Provider 来获取依赖列表的尝试:

    {
        package MyProvider;
        use base 'Template::Provider';
    
        # see _dump_cache in Template::Provider
        sub _dump_deps {
            my $self = shift;
    
            if (my $node = $self->{ HEAD }) {
                while ($node) {
                    my ($prev, $name, $data, $load, $next) = @$node;
            
                    say {*STDERR} "$name called from " . $data->{caller}
                        if exists $data->{caller};
            
                    $node = $node->[ 4 ];
                }
            }
        }
    }
    
    
    use Template;
    
    my $provider = MyProvider->new;
    
    my $tt = Template->new({
        LOAD_TEMPLATES => $provider,
    });
    
    $tt->process( 'root.tt', {} ) or die $tt->error;
    
    $provider->_dump_deps;
    

    上面的代码显示了所有调用的依赖项(通过 INCLUDE、INSERT、PROCESS 和 WRAPPER)以及从整个 root.tt 树中调用的位置。因此,您可以从中构建一个ttree 依赖文件。

    /I3az/

    【讨论】:

    • 我在.ttreerc 中发现depend 有点不稳定且不方便,因为依赖列表很长。我应该看看ttree 看看他们是如何处理它的。
    • @Aaahh,它使用Text::ParseWords 来解析依赖关系。现在,这解释了很多 ;-) 无论如何,我认为 OP 想知道他是否可以根据模板文件中的 [%- INCLUDE -%] 等指令自动生成依赖信息。但是,+1 指出 .ttreerc
    • @Sinan:我对依赖位有 2 到 3 个想法,但我觉得最好先把它留到我有具体的东西之前。查看我的更新。
    • 啊! Template::Provider!谢谢你的代码。我曾查看 Template::Parser 试图弄清楚如何做到这一点,但显然我找错了地方。
    • @Sinan:这是优秀 TT 文档稍弱的一个领域。我还查看了Template::ParserTemplate::Directive,然后又查看了Template::Provider(最初查看_fetch 方法,然后才注意到_dump_cache 方法几乎是需要的)。
    【解决方案2】:

    阅读 ttree 文档后,我决定自己创建一些东西。我把它贴在这里,以防它对下一个出现的人有用。但是,这不是通用解决方案,而是仅适用于少数有限情况的解决方案。它适用于这个项目,因为所有文件都在同一个目录中,并且没有重复的包含。我已经在每个例程之前将缺陷记录为 cmets。

    如果有一种简单的方法可以对我错过的 ttree 执行此操作,请告诉我。

    my @dependencies = make_depend ("first_file.html.tmpl");
    
    # Bugs:
    # Insists files end with .tmpl (mine all do)
    # Does not check the final list for duplicates.
    
    sub make_depend
    {
        my ($start_file) = @_;
        die unless $start_file && $start_file =~ /\.tmpl/ && -f $start_file;
        my $dir = $start_file;
        $dir =~ s:/[^/]*$::;
        $start_file =~ s:\Q$dir/::;
        my @found_files;
        find_files ([$start_file], \@found_files, $dir);
        return @found_files;
    }
    
    # Bugs:
    # Doesn't check for including the same file twice.
    # Doesn't allow for a list of directories or subdirectories to find the files.
    # Warning about files which aren't found switched off, due to
    # [% INCLUDE $file %]
    
    sub find_files
    {
        my ($files_ref, $foundfiles_ref, $dir) = @_;
        for my $file (@$files_ref) {
            my $full_name = "$dir/$file";
            if (-f $full_name) {
                push @$foundfiles_ref, $full_name;
                my @includes = get_includes ($full_name);
                if (@includes) {
                    find_files (\@includes, $foundfiles_ref, $dir);
                }
            } else {
    #            warn "$full_name not found";
            }
        }
    }
    
    # Only recognizes two includes, [% INCLUDE abc.tmpl %] and [% INCLUDE "abc.tmpl" %]
    
    sub get_includes
    {
        my ($start_file) = @_;
        my @includes;
        open my $input, "<", $start_file or die "Can't open $start_file: $!";
        while (<$input>) {
            while (/\[\%-?\s+INCLUDE\s+(?:"([^"]+)"|(.*))\s+-?\%\]/g) {
                my $filename = $1 ? $1 : $2;
                push @includes, $filename;
            }
        }
        close $input or die $!;
        return @includes;
    }
    

    【讨论】:

      【解决方案3】:

      如果您关心的只是查找指令中提到的文件名,例如 INCLUDEPROCESSWRAPPER 等,想象一下即使在命令行中使用 sedperl 来生成依赖项.

      但是,如果存在更微妙的依赖关系(例如,您在 HTML 文档中使用 &lt;img&gt; 引用图像,而该图像的大小是使用 Image plugin 计算的,则问题可能会变得更难处理。

      我还没有真正测试过,但类似以下的方法可能会起作用:

      #!/usr/bin/perl
      
      use strict; use warnings;
      
      use File::Find;
      use File::Slurp;
      use Regex::PreSuf;
      
      my ($top) = @ARGV;
      
      my $directive_re = presuf qw( INCLUDE IMPORT PROCESS );
      
      my $re = qr{
          \[%-? \s+ $directive_re \s+ (\S.+) \s+ -?%\]
      }x;
      
      find(\&wanted => $top);
      
      sub wanted {
          return unless /\.html\z/i;
      
          my $doc = read_file $File::Find::name;
          printf "%s : %s\n", $_, join(" \\\n", $doc =~ /$re/g );
      }
      

      【讨论】:

      • 有很多很多依赖项,例如您提到的&lt;img&gt;,但我想至少开始将它们从文件中拉出。我的 makefile 中一直缺少依赖项,然后在编辑模板时构建不会反映更改。
      猜你喜欢
      • 2016-08-10
      • 2015-01-09
      • 2010-09-22
      • 1970-01-01
      • 2011-01-18
      • 2013-01-27
      • 2012-03-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多