├── .github
└── workflows
│ └── test.yml
├── .gitignore
├── Build.PL
├── Changes
├── HACKING
├── LICENSE
├── META.json
├── README.md
├── author
├── 040_signals_on_loading.t
├── augment.pl
├── bench_compile.pl
├── bench_deserialize.pl
├── cache.pl
├── chtags.pl
├── gen-graph.pl
├── large.pl
├── list_builtins.pl
├── modifiers.pl
├── pptest.pl
├── prof-large-file.pl
├── profile.pl
├── requires.cpanm
├── t_renumber.pl
├── tt.pl
└── while-loop.pl
├── benchmark
├── cascade.pl
├── data_section.pl
├── demo-mt.pl
├── demo-tt.pl
├── expr.pl
├── expr_eq.pl
├── for.pl
├── include.pl
├── interpolate.pl
├── json.pl
├── procs
│ ├── fib.pl
│ ├── function.pl
│ ├── keys.pl
│ ├── map.pl
│ ├── method.pl
│ ├── sort.pl
│ ├── uri_escape.pl
│ └── values.pl
├── template
│ ├── base.mt
│ ├── base.tx
│ ├── child.mt
│ ├── child.tx
│ ├── include.cs
│ ├── include.ht
│ ├── include.mt
│ ├── include.tt
│ ├── include.tx
│ ├── list.cs
│ ├── list.ht
│ ├── list.mst
│ ├── list.mt
│ ├── list.tj
│ ├── list.tt
│ └── list.tx
├── x-poor-env.pl
└── x-rich-env.pl
├── builder
└── MyBuilder.pm
├── cpanfile
├── example
├── amon2.psgi
├── amon2.psgi.gold
├── autolink.pl
├── autolink.pl.gold
├── base.tx
├── bridge.pl
├── bridge.tx
├── cascade.pl
├── cascade.pl.gold
├── cascade.tx
├── chained-scope.pl
├── chained-scope.pl.gold
├── data_section.pl
├── data_section.pl.gold
├── dynamic_functions.pl
├── dynamic_functions.tx
├── err_handler.pl
├── fillinform.pl
├── fillinform.pl.gold
├── form.psgi
├── form.psgi.gold
├── hello.pl
├── hello.pl.gold
├── hello.tmpl
├── hello.tx
├── htmltemplate.pl
├── htparser.pl
├── i18n-data-localize.pl
├── i18n-data-localize.pl.gold
├── i18n.pl
├── i18n.pl.gold
├── list.pl
├── list.pl.gold
├── list.tx
├── locale
│ └── ja.po
├── mojo.psgi
├── mojo.psgi.gold
├── put_js.pl
├── put_js.pl.gold
├── simple.psgi
└── simple.psgi.gold
├── lib
└── Text
│ ├── Xslate.pm
│ └── Xslate
│ ├── Bridge.pm
│ ├── Bridge
│ └── Star.pm
│ ├── Compiler.pm
│ ├── HashWithDefault.pm
│ ├── Manual.pod
│ ├── Manual
│ ├── Builtin.pod
│ ├── Cookbook.pod
│ ├── Debugging.pod
│ └── FAQ.pod
│ ├── PP.pm
│ ├── PP
│ ├── Method.pm
│ ├── Opcode.pm
│ ├── State.pm
│ └── Type
│ │ ├── Macro.pm
│ │ ├── Pair.pm
│ │ └── Raw.pm
│ ├── Parser.pm
│ ├── Runner.pm
│ ├── Symbol.pm
│ ├── Syntax
│ ├── Kolon.pm
│ ├── Metakolon.pm
│ └── TTerse.pm
│ ├── Type
│ └── Raw.pm
│ └── Util.pm
├── minil.toml
├── script
└── xslate
├── src
├── Text-Xslate.xs
├── uri_unsafe.h
├── xslate.h
├── xslate_methods.xs
└── xslate_opcode.inc
├── t
├── 000_load.t
├── 010_internals
│ ├── 001_parse.t
│ ├── 002_compile.t
│ ├── 003_assemble.t
│ ├── 004_magic.t
│ ├── 005_load_file.t
│ ├── 006_errhandler.t
│ ├── 007_compile_errs.t
│ ├── 008_files.t
│ ├── 009_goto_address.t
│ ├── 010_line_number.t
│ ├── 011_missuse.t
│ ├── 012_multilines.t
│ ├── 013_deps_str.t
│ ├── 014_deps_file.t
│ ├── 015_deps_file2.t
│ ├── 016_cached.t
│ ├── 017_render.t
│ ├── 018_opinfo.t
│ ├── 019_runtime_error.t
│ ├── 020_optimize.t
│ ├── 021_edge_cases.t
│ ├── 022_signal.t
│ ├── 023_cachepath.t
│ ├── 024_die_in_macros.t
│ ├── 025_reset_hooks.t
│ ├── 026_issue16_deep_recursion.t
│ ├── 027_infinite_warn.t
│ ├── 028_taint.t
│ ├── 029_large_file.t
│ ├── 030_die_in_funcs.t
│ ├── 031_save_src.t
│ ├── 032_encoding_error.t
│ ├── 033_vpath_cache.t
│ ├── 034_is_code_ref.t
│ ├── 036_merge_hash.t
│ ├── 037_find_file.t
│ ├── 038_suffix.t
│ ├── 039_taint_issue84.t
│ ├── 100_threads.t
│ ├── 200_leaktrace.t
│ └── 300_explicit_pp.t
├── 020_interface
│ ├── 001_parser_option.t
│ ├── 002_myparser.t
│ ├── 003_encoding.t
│ ├── 004_no_vars.t
│ ├── 005_util.t
│ ├── 006_psgi.t
│ ├── 007_data_section.t
│ ├── 008_type.t
│ ├── 009_hash_with_default.t
│ ├── 010_err_encoding.t
│ ├── 011_hwd_w_include_vars.t
│ ├── 012_default_functions.t
│ ├── 013_slurp_template.t
│ ├── 014_customize_option.t
│ ├── 015_render_recursion.t
│ ├── 016_pre_process_handler.t
│ └── 017_validate.t
├── 030_kolon
│ ├── 001_interpolate.t
│ ├── 002_field.t
│ ├── 003_for.t
│ ├── 004_if.t
│ ├── 005_rel_ops.t
│ ├── 006_arith_ops.t
│ ├── 007_log_ops.t
│ ├── 008_literal.t
│ ├── 009_include.t
│ ├── 010_escaped_str.t
│ ├── 011_macro.t
│ ├── 012_cascade.t
│ ├── 013_more_field.t
│ ├── 014_while.t
│ ├── 015_methods.t
│ ├── 016_funcs.t
│ ├── 017_more_macro.t
│ ├── 018_dynamic_filters.t
│ ├── 019_explicit_interpolate.t
│ ├── 020_chomp.t
│ ├── 021_overlay.t
│ ├── 022_given.t
│ ├── 023_bitwise.t
│ ├── 024_localize_vars.t
│ ├── 025_objectliteral.t
│ ├── 026_constant.t
│ ├── 027_lambda.t
│ ├── 028_smartmatch.t
│ ├── 029_blockfilter.t
│ ├── 030_xfuncs.t
│ ├── 031_post_if.t
│ ├── 032_include_bareword.t
│ ├── 033_ov_forloop.t
│ ├── 034_print.t
│ ├── 035_include_w_vars.t
│ ├── 036_foreach_else.t
│ ├── 037_loop_ctl.t
│ ├── 038_custom_esc.t
│ ├── 039_root_vars.t
│ └── 040_external_macro.t
├── 040_tterse
│ ├── 001_parse.t
│ ├── 002_interpolate.t
│ ├── 003_field.t
│ ├── 004_for.t
│ ├── 005_if.t
│ ├── 006_include.t
│ ├── 007_funcs.t
│ ├── 008_methods.t
│ ├── 009_comments.t
│ ├── 010_expr.t
│ ├── 011_objectliterals.t
│ ├── 012_macro.t
│ ├── 013_wrapper.t
│ ├── 014_set.t
│ ├── 015_while.t
│ ├── 016_call.t
│ ├── 017_filter.t
│ ├── 018_process.t
│ ├── 019_switch.t
│ ├── 020_chomp.t
│ ├── 021_fake_use.t
│ ├── 022_post_if.t
│ ├── 023_loop_ctl.t
│ ├── 024_for_else.t
│ ├── 025_macro.t
│ └── 100_not_supported.t
├── 050_builtins
│ ├── 001_builtin_funcs.t
│ ├── 002_autobox.t
│ ├── 003_autobox_w_cb.t
│ └── 004_copied.t
├── 100_plugin
│ ├── 001_import_from.t
│ ├── 002_import.t
│ ├── 003_bridge.t
│ ├── 004_star.t
│ ├── 005_html_builder_module.t
│ └── 100_error.t
├── 200_app
│ ├── 001_hello.t
│ ├── 002_tree.t
│ ├── 003_runner.t
│ ├── 004_encoding.t
│ └── simple
│ │ ├── dont_touch.tx
│ │ ├── goodbye.tx
│ │ └── hello.tx
├── 300_examples
│ ├── 001_basic.t
│ ├── 002_cascade.t
│ ├── 003_metakolon.t
│ └── 004_tterse.t
├── 900_bugs
│ ├── 001_super.t
│ ├── 002_addfunc.t
│ ├── 003_frame_access.t
│ ├── 004_errorhandling.t
│ ├── 005_rec_include.t
│ ├── 006_complex_lex.t
│ ├── 007_uuv.t
│ ├── 008_include_var.t
│ ├── 009_quote_in_comments.t
│ ├── 010_widechar_for_md5.t
│ ├── 011_reserved_words.t
│ ├── 012_ltgt_in_comments.t
│ ├── 013_comments_lineno.t
│ ├── 014_too_large_int.t
│ ├── 015_my_scope.t
│ ├── 016_x_in_tterse.t
│ ├── 017_unallocated.t
│ ├── 018_lvar_in_macro.pl
│ ├── 019_nested_mm.t
│ ├── 020_switch_foo.t
│ ├── 021_cached_enc.t
│ ├── 022_empty_if_block.t
│ ├── 023_deploy_problem.t
│ ├── 024_use_cache.t
│ ├── 025_clobber-macro-args.t
│ ├── 026_issue61.t
│ ├── 027_issue65.t
│ ├── 028_issue68.t
│ ├── 029_fork_and_cache.t
│ ├── 030_issue71.t
│ ├── 031_yappo.t
│ ├── 032_issue79.t
│ ├── 033_ex_safe_render.t
│ ├── 034_hash_key_utf8.t
│ ├── 035_issue81_tiedhash.t
│ ├── 036_vpath_utf8.t
│ ├── 037_text_str_key.t
│ ├── 038_conbine_flaged_utf8_and_other.t
│ ├── 039_issue96.t
│ ├── 040_issue95.t
│ ├── 041_cachedir_other_process.t
│ ├── 042_perl59_issue.t
│ ├── 043_issue107.t
│ ├── 044_empty_result.t
│ ├── 045_issue130.t
│ ├── 046_issue156.t
│ ├── 046_issue88.t
│ ├── 047_undef_concat.t
│ ├── 048_issue172.t
│ └── issue79
│ │ ├── tmpl
│ │ ├── contentA.tt
│ │ ├── contentB.tt
│ │ ├── wrapperA.tt
│ │ └── wrapperB.tt
│ │ └── xslate.pl
├── lib
│ ├── MyBridge2.pm
│ ├── TTSimple.pm
│ ├── Text
│ │ └── Xslate
│ │ │ └── Syntax
│ │ │ └── Foo.pm
│ ├── Util.pm
│ └── UtilNoleak.pm
└── template
│ ├── common.tx
│ ├── config.tt
│ ├── eg
│ ├── base.tx
│ └── child.tx
│ ├── error
│ ├── bad_include.tx
│ ├── bad_method.tx
│ ├── bad_syntax.tx
│ └── bad_tags.tx
│ ├── footer1.tt
│ ├── footer2.tt
│ ├── for.tx
│ ├── func.tx
│ ├── header1.tt
│ ├── header2.tt
│ ├── hello.tt
│ ├── hello.tx
│ ├── hello.tx.mod
│ ├── hello_sjis.tx
│ ├── hello_utf8.tx
│ ├── include.tt
│ ├── include.tx
│ ├── include2.tt
│ ├── include2.tx
│ ├── macro.tt
│ ├── myapp
│ ├── bad_redefine.tx
│ ├── base.tx
│ ├── base.tx.mod
│ ├── cbar.tx
│ ├── cfoo.tx
│ └── derived.tx
│ ├── oi
│ ├── bad_base.tx
│ └── bad_component.tx
│ ├── other
│ └── hello.tx
│ ├── taint.tx
│ ├── wrapper.tt
│ └── wrapper_div.tt
├── tool
├── disasm.pl
├── opcode.PL
├── opcode_for_pp.PL
└── uri_unsafe.PL
└── xt
├── 01_podspell.t
├── 02_pod.t
├── 03_pod-coverage.t
├── 04_synopsis.t
├── 05_vars.t
├── 100_eg_pl.t
├── 101_eg_psgi.t
└── 200_depended.t
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: test
2 |
3 | on:
4 | push:
5 | branches:
6 | - '*'
7 | tags-ignore:
8 | - '*'
9 | pull_request:
10 |
11 | jobs:
12 | linux:
13 | runs-on: ubuntu-latest
14 | strategy:
15 | matrix:
16 | perl-version:
17 | - '5.8-buster'
18 | - '5.10-buster'
19 | - 'latest'
20 | container:
21 | image: perl:${{ matrix.perl-version }}
22 | steps:
23 | - uses: actions/checkout@v2
24 | - run: perl -V
25 | - run: cpanm --installdeps --notest --quiet --with-configure --with-develop .
26 | - run: perl Build.PL
27 | - run: ./Build
28 | - run: ./Build test
29 | windows:
30 | runs-on: windows-latest
31 | steps:
32 | - uses: actions/checkout@v2
33 | - run: perl -V
34 | - run: cpanm --installdeps --notest --quiet --with-configure --with-develop .
35 | - run: perl Build.PL
36 | - run: perl Build
37 | - run: perl Build test
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | Text-Xslate-*
2 | .xslate_cache/
3 | !.gitignore
4 | !.shipit
5 | !.proverc
6 | *~
7 | *.o
8 | *.obj
9 | *.bs
10 | *.def
11 | Makefile*
12 | !Makefile.PL
13 | *blib
14 | META.yml
15 | MYMETA.*
16 | inc/
17 | *.out
18 | *.bak
19 | ppport.h
20 | xshelper.h
21 | nytprof*
22 | cover_db*
23 | *.gcda
24 | *.gcno
25 | *.gcov
26 | *.stackdump
27 | *.c
28 | *.txc
29 | *.ttc
30 | *.cache
31 | xslate_ops.h
32 | lib/Text/Xslate/PP/Const.pm
33 | /Build
34 | /_build
35 | /lib/Text/Xslate.xs
36 | /src/xs_version.h
37 |
--------------------------------------------------------------------------------
/HACKING:
--------------------------------------------------------------------------------
1 | NOTES FOR HACKERS
2 |
3 | Easy evaluation:
4 | $ xslate -e 'Hello, <: $ARGV[0] :> world!' Xslate
5 |
6 | Debugging options ($ENV{XSLATE}; or --debug for xslate(1)):
7 | dump=proto Output preprocessed proto templates
8 | dump=token Output token sequence
9 | dump=denote Output code denotation
10 | dump=gen Output code generation
11 | dump=ast Output abstract syntax tree
12 | dump=asm Output xslate assembly
13 | dump=asm:ix Output xslate assembly with indexes
14 | dump=pp Output Perl code PP::Booster generates
15 | optimize=0 Suppress optimization
16 | pp=verbose Make error messages verbose (by Carp->import('verbose'))
17 |
18 | Parser's terminology:
19 | arity Symbol class; used while compiling
20 | bp Binding power; or operator precedence
21 | nud Null denotation; processing values and prefix operators
22 | led Left denotation; processing infix and postfix operators
23 | std Statement denotation; processing statements
24 |
25 | Callbacks: functios, methods, and macros
26 | tx_call_sv() is a thin wrapper to Perl_call_sv()
27 | tx_funcall() tries to call Perl fuctions
28 | tx_proccall() tries to call macros, or fallback to tx_funcall()
29 | tx_methodcall() tries to call Perl methods, or fallback to tx_proccall()
30 |
--------------------------------------------------------------------------------
/author/040_signals_on_loading.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use Text::Xslate;
6 | use Time::HiRes qw(sleep alarm);
7 |
8 | note $$;
9 |
10 | for (1..10) {
11 | my $tx = Text::Xslate->new();
12 |
13 | eval {
14 | local $SIG{ALRM} = sub { die "TIMEOUT" };
15 | alarm(0.010);
16 | $tx->render_string(q{: while true {} });
17 | };
18 | $@ =~ /TIMEOUT/ or note $@;
19 | }
20 |
21 | pass "program finished";
22 |
23 | done_testing;
24 |
--------------------------------------------------------------------------------
/author/augment.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Text::Xslate;
4 |
5 | my %template = (
6 | 'base' => <<'T',
7 | : block hello -> {
8 | Hello, <: inner :>!
9 | : }
10 | T
11 |
12 | 'child' => <<'T',
13 | : cascade 'base'
14 | : augment hello -> { "Augment" }
15 | T
16 | );
17 |
18 | my $tx = Text::Xslate->new(
19 | path => \%template,
20 | cache => 0,
21 | );
22 | print $tx->render('child');
23 |
--------------------------------------------------------------------------------
/author/bench_compile.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Benchmark qw(:all);
4 |
5 | use Text::Xslate;
6 |
7 | my $tx = Text::Xslate->new();
8 | my $tt = Text::Xslate->new(syntax => 'TTerse');
9 |
10 | my $x = <<'T';
11 | List:
12 | : for $data ->($item) {
13 | * <:= $item.title :>
14 | * <:= $item.title :>
15 | * <:= $item.title :>
16 | : }
17 | T
18 |
19 | my $y = <<'T';
20 | List:
21 | [% FOREACH item IN data -%]
22 | * [% item.title %]
23 | * [% item.title %]
24 | * [% item.title %]
25 | [% END -%]
26 | T
27 |
28 | print "Parser: Kolon v.s. TTerse\n";
29 | cmpthese 0, {
30 | kolon => sub { $tx->compile($x) },
31 | tterse => sub { $tt->compile($y) },
32 | };
33 |
--------------------------------------------------------------------------------
/author/bench_deserialize.pl:
--------------------------------------------------------------------------------
1 | #!perl
2 | use strict;
3 | use Benchmark qw(:all);
4 |
5 | BEGIN{ $ENV{PERL_JSON_BACKEND} = 'JSON::PP' }
6 |
7 | use Data::Serializer::JSON;
8 | use Data::Serializer::Storable;
9 | use Data::Serializer::Data::Dumper;
10 |
11 | use Test::More tests => 3;
12 |
13 | my $asm = [
14 | map { [$_ => 42, undef, undef] } ('aa' .. 'zz')
15 | ];
16 | print scalar @{$asm}, "\n";
17 |
18 | my $j = Data::Serializer::JSON->serialize($asm);
19 | my $s = Data::Serializer::Storable->serialize($asm);
20 | my $d = Data::Serializer::Data::Dumper->serialize($asm);
21 |
22 | {
23 | is_deeply(Data::Serializer::JSON->deserialize($j), $asm);
24 | is_deeply(Data::Serializer::Storable->deserialize($s), $asm);
25 | is_deeply(Data::Serializer::Data::Dumper->deserialize($d), $asm);
26 | }
27 |
28 | cmpthese timethese -1 => {
29 | json => sub { Data::Serializer::JSON->deserialize($j) },
30 | storable => sub { Data::Serializer::Storable->deserialize($s) },
31 | datadumper => sub { Data::Serializer::Data::Dumper->deserialize($d) },
32 | };
33 |
34 |
--------------------------------------------------------------------------------
/author/cache.pl:
--------------------------------------------------------------------------------
1 | use strict;
2 | use Text::Xslate;
3 | use Benchmark qw/ :all /;
4 | use Path::Class qw/ file /;
5 | END{ unlink "test.tx" }
6 | file("test.tx")->openw->print(q{[% FOR i IN list %] [% i %] [% END %]});
7 |
8 | my $tx = Text::Xslate->new( syntax => "TTerse" );
9 | print $tx->VERSION, "\n";
10 | timethese 0, {
11 | tx => sub {
12 | $tx->render("test.tx", { list => [ 1 .. 100 ] });
13 | },
14 | };
15 |
--------------------------------------------------------------------------------
/author/chtags.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use File::Find;
4 | use Fatal qw(open close);
5 |
6 | sub wanted {
7 | return if not -f $_;
8 |
9 | print "$_\n";
10 |
11 | my $name = $_;
12 |
13 | open my $in, '<', $name;
14 | open my $out, '>', $name . ".tmp";
15 | while(<$in>) {
16 | s/^([ \t]*) \Q?/$1:/xms;
17 | s/\Q/<:/xmsg;
18 | s/\Q?>/:>/xmsg;
19 | print $out $_;
20 | }
21 | close $in;
22 | close $out;
23 |
24 | rename "$name.tmp" => $name;
25 | }
26 |
27 | find({
28 | wanted => \&wanted,
29 | }, qw(t lib example benchmark));
30 |
31 |
--------------------------------------------------------------------------------
/author/large.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Text::Xslate;
4 |
5 | my $file = shift(@ARGV) or die "No templae file supplied";
6 |
7 | my $tx = Text::Xslate->new(
8 | path => 'author',
9 | cache => 0,
10 | );
11 |
12 | $tx->render($file);
13 |
14 |
--------------------------------------------------------------------------------
/author/list_builtins.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Text::Xslate;
4 |
5 | my $tx = Text::Xslate->new();
6 |
7 | print join("\n", sort keys %{ $tx->{function} }), "\n";
8 |
9 |
--------------------------------------------------------------------------------
/author/modifiers.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use 5.010;
3 | use strict;
4 | {
5 | package Base;
6 | use Any::Moose;
7 |
8 | sub foo { say "Base::foo" }
9 |
10 | package Role;
11 | use Any::Moose '::Role';
12 |
13 | before foo => sub { say "Role::before" };
14 | after foo => sub { say "Role::after" };
15 |
16 | package Derived;
17 | use Any::Moose;
18 | extends 'Base';
19 | with 'Role';
20 |
21 | before foo => sub { say "Derived::before" };
22 | after foo => sub { say "Derived::after" };
23 | }
24 |
25 | Derived->foo;
26 |
--------------------------------------------------------------------------------
/author/pptest.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | BEGIN{ $ENV{XSLATE} ||= 'pp=booster;dump=pp;' }
3 |
4 | use strict;
5 | use Text::Xslate;
6 |
7 | my $tx = Text::Xslate->new();
8 |
9 | $tx->render_string( <<'CODE', {} );
10 | : macro foo -> $arg {
11 | Hello <:= $arg :>!
12 | : }
13 | : foo($value)
14 | CODE
15 |
--------------------------------------------------------------------------------
/author/prof-large-file.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use File::Temp;
4 | use File::Basename;
5 |
6 | my $N = 500;
7 |
8 | my $tmp = File::Temp->new(
9 | UNLINK => 0,
10 | DIR => 'author',
11 | SUFFIX => '.tt',
12 | );
13 | $tmp->unlink_on_destroy(1);
14 |
15 | my $tmpl = <<'XML';
16 |
17 | [% aaa %]
18 | [% bbb %]
19 |
20 | XML
21 |
22 | print $tmp "\n";
23 |
24 | for my $i(1 .. $N) {
25 | print $tmp $tmpl;
26 | }
27 |
28 | print $tmp "\n";
29 | close $tmp;
30 |
31 | system($^X, 'author/large.pl', basename($tmp)) == 0
32 | or die "Failed to exec"; # wake up
33 |
34 | system($^X, '-d:NYTProf', 'author/large.pl', basename($tmp)) == 0
35 | or die "Failed to exec";
36 |
37 |
38 |
--------------------------------------------------------------------------------
/author/profile.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Text::Xslate;
4 |
5 | use UNIVERSAL(); # makes NYTProf happy
6 |
7 | {
8 | package BlogEntry;
9 | use Mouse;
10 | has title => (is => 'rw');
11 | has body => (is => 'rw');
12 | }
13 |
14 | my($cache, $n) = @ARGV;
15 | $cache //= 1;
16 | $n //= 100;
17 |
18 | my @blog_entries = map{ BlogEntry->new($_) } (
19 | {
20 | title => 'Entry one',
21 | body => 'This is my first entry.',
22 | },
23 | {
24 | title => 'Entry two',
25 | body => 'This is my second entry.',
26 | },
27 | ) x 10;
28 | for(1 .. $n) {
29 | my $tx = Text::Xslate->new(
30 | path => ["./benchmark/template"],
31 | cache => $cache,
32 | );
33 |
34 | $tx->render('child.tx', { blog_entries => \@blog_entries });
35 | }
36 |
37 | print $INC{'Text/Xslate/Compiler.pm'} ? "compiled.\n" : "cached.\n";
38 |
--------------------------------------------------------------------------------
/author/requires.cpanm:
--------------------------------------------------------------------------------
1 | # for configure
2 | Module::Install
3 | Module::Install::XSUtil
4 | Module::Install::AuthorTests
5 | Module::Install::TestTarget
6 | Module::Install::Repository
7 |
8 | # for testing
9 | Test::Vars
10 | Test::Synopsis
11 | Test::Spellunker
12 | Test::LeakTrace
13 | Plack
14 | IPC::Run
15 |
16 | # for benchmarks
17 | Text::MicroTemplate::Extended
18 | Text::ClearSilver
19 | HTML::Template
20 | HTML::Template::Pro
21 | Template
22 |
23 | # for examples
24 | Data::Section::Simple
25 | HTML::FillInForm
26 | HTML::FillInForm::Lite
27 | HTML::Shakan
28 | URI::Find
29 | Mojolicious
30 | MojoX::Renderer::Xslate
31 | JavaScript::Value::Escape
32 | Locale::Maketext::Lexicon
33 | Data::Localize
34 | File::Which
35 | Amon2::Lite
36 | Catalyst::View::Xslate
37 |
38 |
--------------------------------------------------------------------------------
/author/t_renumber.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | # re-number test files
3 | use strict;
4 |
5 | my $dir = shift(@ARGV) or die "Usage: $0 test-dir\n";
6 | $dir =~ s{/$}{};
7 | -d $dir or die "No such directory: $dir\n";
8 |
9 | my $i = 0;
10 | foreach my $dir (sort { ($a =~ /(\d+)_\w+\.t$/)[0] <=> ($b =~ /(\d+)_\w+\.t$/)[0] } <$dir/*.t>) {
11 | my $n = ($dir =~ /(\d+)_\w+\.t$/)[0];
12 | last if $n >= 100;
13 |
14 | (my $newdir = $dir) =~ s/(\d+)(_\w+\.t)$/ sprintf '%03d%s', ++$i, $2 /xmse;
15 |
16 | next if $dir eq $newdir;
17 |
18 | printf "%-36s => %-36s\n", $dir, $newdir;
19 | rename $dir => $newdir or die "Cannot rename $dir to $newdir: $!";
20 | }
21 |
--------------------------------------------------------------------------------
/author/tt.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Template;
4 | use Smart::Comments;
5 |
6 | my $t = Template->new();
7 |
8 | $t->process(\<<'T', {}, \my $x) or die $t->error, "\n";
9 | A
10 | [%- component -%]
11 | B
12 | T
13 | ### $x
14 |
--------------------------------------------------------------------------------
/author/while-loop.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | BEGIN{ $ENV{XSLATE} ||= 'dump=asm;' }
3 |
4 | use strict;
5 | use Text::Xslate;
6 |
7 | my $tx = Text::Xslate->new(
8 | function => { f => sub { undef } },
9 | );
10 |
11 | print $tx->render_string(<<'TX', { x => shift });
12 | : macro add -> $x, $y { $x + $y }
13 | : while(true) {
14 | : if(add(1, 2) > 0) { }
15 | : }
16 | TX
17 |
--------------------------------------------------------------------------------
/benchmark/demo-mt.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 |
4 | use Text::Xslate;
5 | use Text::MicroTemplate::File;
6 |
7 | use Time::HiRes qw(time);
8 | use FindBin qw($Bin);
9 |
10 | use Config; printf "Perl/%vd %s\n", $^V, $Config{archname};
11 | foreach my $mod(qw(Text::Xslate Text::MicroTemplate)){
12 | print $mod, '/', $mod->VERSION, "\n";
13 | }
14 | my $path = "$Bin/template";
15 |
16 | my $mt = Text::MicroTemplate::File->new(
17 | include_path => [$path],
18 | use_cache => 2,
19 | );
20 | my $tx = Text::Xslate->new(
21 | path => [$path],
22 | cache_dir => '.xslate_cache',
23 | cache => 2,
24 | );
25 |
26 | my %vars = (
27 | data => [
28 | ({ title => 'Programming Perl'}) x 100,
29 | ]
30 | );
31 | {
32 | my $out = $mt->render_file('list.mt', \%vars);
33 | $tx->render('list.tx', \%vars) eq $out or die $out;
34 | }
35 |
36 | $| = 1;
37 |
38 | print "Text::MicrTemplate's render_file() x 1000\n";
39 | my $start = time();
40 | foreach (1 .. 1000) {
41 | print $_, "\r";
42 | my $out = $mt->render_file('list.mt', \%vars);
43 | }
44 | print "\n";
45 | my $mt_used = time() - $start;
46 | printf "Used: %.03f sec.\n", $mt_used;
47 |
48 | print "Text::Xslate's render() x 1000\n";
49 | $start = time();
50 | foreach (1 .. 1000) {
51 | print $_, "\r";
52 | my $out = $tx->render('list.tx', \%vars);
53 | }
54 | print "\n";
55 | my $tx_used = time() - $start;
56 | printf "Used: %.03f sec.\n", $tx_used;
57 |
58 | printf "In this benchmark, Xslate is about %.01f times faster than Text::MicroTemplate.\n",
59 | $mt_used / $tx_used;
60 |
--------------------------------------------------------------------------------
/benchmark/demo-tt.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 |
4 | use Text::Xslate;
5 | use Template;
6 |
7 | use Time::HiRes qw(time);
8 | use FindBin qw($Bin);
9 |
10 | use Config; printf "Perl/%vd %s\n", $^V, $Config{archname};
11 | foreach my $mod(qw(Text::Xslate Template)){
12 | print $mod, '/', $mod->VERSION, "\n";
13 | }
14 |
15 | my $file = 'list.tt';
16 |
17 | my $tt = Template->new(
18 | INCLUDE_PATH => ["$Bin/template"],
19 | COMPILE_EXT => '.out',
20 | );
21 | my $tx = Text::Xslate->new(
22 | syntax => 'TTerse',
23 | path => ["$Bin/template"],
24 | cache_dir => '.xslate_cache',
25 | cache => 2,
26 | );
27 |
28 | my %vars = (
29 | data => [
30 | ({ title => 'Programming Perl'}) x 100,
31 | ]
32 | );
33 | {
34 | my $out;
35 | $tt->process($file, \%vars, \$out);
36 | $tx->render($file, \%vars) eq $out
37 | or die $tx->render($file, \%vars), "\n", $out;
38 | }
39 |
40 | $| = 1;
41 |
42 | print "Template-Toolkit's process() x 1000\n";
43 | my $start = time();
44 | foreach (1 .. 1000) {
45 | print $_, "\r";
46 | $tt->process($file, \%vars, \my $out);
47 | }
48 | print "\n";
49 | my $tt_used = time() - $start;
50 | printf "Used: %.03f sec.\n", $tt_used;
51 |
52 | print "Text::Xslate's render() x 1000\n";
53 | $start = time();
54 | foreach (1 .. 1000) {
55 | print $_, "\r";
56 | my $out = $tx->render($file, \%vars);
57 | }
58 | print "\n";
59 | my $tx_used = time() - $start;
60 | printf "Used: %.03f sec.\n", $tx_used;
61 |
62 | printf "In this benchmark, Xslate is about %.01f times faster than Template-Tookit.\n",
63 | $tt_used / $tx_used;
64 |
--------------------------------------------------------------------------------
/benchmark/expr.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 |
4 | use Text::Xslate;
5 | use Text::MicroTemplate qw(build_mt);
6 |
7 | use Benchmark qw(:all);
8 | use Config; printf "Perl/%vd %s\n", $^V, $Config{archname};
9 | use Test::More;
10 |
11 | foreach my $mod(qw(Text::Xslate Text::MicroTemplate)){
12 | print $mod, '/', $mod->VERSION, "\n";
13 | }
14 |
15 | my $n = shift(@ARGV) || 100;
16 |
17 | my %vpath = (
18 | expr => "Hello, <:= \$value + 1 :> world!\n" x $n,
19 | );
20 |
21 | my $tx = Text::Xslate->new(
22 | path => \%vpath,
23 | cache_dir => '.xslate_cache',
24 | cache => 2,
25 | );
26 |
27 | my $mt = build_mt(qq{Hello, = \$_[0]->{value} + 1 ?> world!\n} x $n);
28 |
29 | my $subst_tmpl = qq{Hello, %value% world!\n} x $n;
30 |
31 | my $vars = {
32 | value => '41',
33 | };
34 |
35 | {
36 | plan tests => 2;
37 | my $expected = $tx->render(expr => $vars);
38 | is $mt->($vars), $expected, 'MT';
39 |
40 | my $body = [$subst_tmpl];
41 | $body->[0] =~ s/%(\w+)%/ $vars->{$1} + 1 /eg;
42 | is $body->[0], $expected, 's///g';
43 | }
44 |
45 | # suppose PSGI response body
46 | cmpthese -1 => {
47 | xslate => sub {
48 | my $body = [$tx->render(expr => $vars)];
49 | return;
50 | },
51 | mt => sub {
52 | my $body = [$mt->($vars)];
53 | return;
54 | },
55 | 's///g' => sub {
56 | my $body = [$subst_tmpl];
57 | $body->[0] =~ s/%(\w+)%/ $vars->{$1} + 1 /eg;
58 | return;
59 | },
60 | };
61 |
62 |
--------------------------------------------------------------------------------
/benchmark/expr_eq.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 |
4 | use Text::Xslate;
5 | use Text::MicroTemplate qw(build_mt);
6 |
7 | use Benchmark qw(:all);
8 | use Config; printf "Perl/%vd %s\n", $^V, $Config{archname};
9 | use Test::More;
10 |
11 | foreach my $mod(qw(Text::Xslate Text::MicroTemplate)){
12 | print $mod, '/', $mod->VERSION, "\n";
13 | }
14 |
15 | my $n = shift(@ARGV) || 100;
16 |
17 | my %vpath = (
18 | expr_eq => "Hello, <:= \$value == 42 ? 'Xslate' : 'unlikely' :> world!\n" x $n,
19 | );
20 |
21 | my $tx = Text::Xslate->new(
22 | path => \%vpath,
23 | cache_dir => '.xslate_cache',
24 | cache => 2,
25 | );
26 |
27 | my $mt = build_mt(qq{Hello, = \$_[0]->{value} == 42 ? 'Xslate' : 'unlikely' ?> world!\n} x $n);
28 |
29 | my $subst_tmpl = qq{Hello, %value% world!\n} x $n;
30 |
31 | my $vars = {
32 | value => '41',
33 | };
34 |
35 | {
36 | plan tests => 2;
37 | my $expected = $tx->render(expr_eq => $vars);
38 | is $mt->($vars), $expected, 'MT';
39 |
40 | my $body = [$subst_tmpl];
41 | $body->[0] =~ s/%(\w+)%/ $vars->{$1} == 42 ? 'Xslate' : 'unlikely' /eg;
42 | is $body->[0], $expected, 's///g';
43 | }
44 | # suppose PSGI response body
45 |
46 | cmpthese -1 => {
47 | xslate => sub {
48 | my $body = [$tx->render(expr_eq => $vars)];
49 | return;
50 | },
51 | mt => sub {
52 | my $body = [$mt->($vars)];
53 | return;
54 | },
55 | 's///g' => sub {
56 | my $body = [$subst_tmpl];
57 | $body->[0] =~ s/%(\w+)%/ $vars->{$1} + 1 /eg;
58 | return;
59 | },
60 | };
61 |
62 |
--------------------------------------------------------------------------------
/benchmark/json.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 |
4 | use Text::Xslate;
5 | use JSON::XS;
6 |
7 | use Benchmark qw(:all);
8 | use Config; printf "Perl/%vd %s\n", $^V, $Config{archname};
9 |
10 | foreach my $mod(qw(Text::Xslate JSON::XS)){
11 | print $mod, '/', $mod->VERSION, "\n";
12 | }
13 |
14 | my $n = shift(@ARGV) || 10;
15 |
16 | my %vpath = (
17 | json => <<'TX',
18 |
19 | : for $books ->($item) {
20 | - <:= $item.title :> (<: $item.author :>)
21 | : }
22 |
23 | TX
24 | );
25 |
26 | my $tx = Text::Xslate->new(
27 | path => \%vpath,
28 | cache_dir => '.xslate_cache',
29 | cache => 2,
30 | );
31 |
32 | my $json = JSON::XS->new();
33 |
34 | my %vars = (
35 | books => [(
36 | { title => 'Islands in the stream',
37 | author => 'Ernest Hemingway' },
38 | { title => 'Beautiful code',
39 | author => 'Brian Kernighan, Jon Bentley, et. al.' },
40 | { title => q{Atkinson and Hilgard's Introduction to Psychology With Infotrac}, # '
41 | author => 'Edward E. Smith, et. al.' },
42 | { title => 'Programming Perl',
43 | author => 'Larry Wall, et.al.' },
44 | { title => 'Compilers: Principles, Techniques, and Tools',
45 | author => 'Alfred V. Aho, et. al.' },
46 | ) x $n],
47 | );
48 |
49 | if(0) {
50 | print $tx->render(json => \%vars);
51 | print $json->encode(\%vars);
52 | }
53 |
54 | cmpthese -1 => {
55 | xslate => sub {
56 | my $body = $tx->render(json => \%vars);
57 | return;
58 | },
59 | json => sub {
60 | my $body = $json->encode(\%vars);
61 | return;
62 | },
63 | };
64 |
--------------------------------------------------------------------------------
/benchmark/procs/fib.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 |
4 | use Text::Xslate;
5 | use Text::MicroTemplate qw(build_mt);
6 |
7 | use Benchmark qw(:all);
8 | use Config; printf "Perl/%vd %s\n", $^V, $Config{archname};
9 | use Test::More;
10 |
11 | foreach my $mod(qw(Text::Xslate Text::MicroTemplate)){
12 | print $mod, '/', $mod->VERSION, "\n";
13 | }
14 | my $n = shift(@ARGV) || 10;
15 |
16 | my %vpath = (
17 | fib => <<'TX',
18 | : macro fib -> $n {
19 | : $n <= 1 ? 1 : fib($n - 1) + fib($n - 2);
20 | : }
21 | : fib($x);
22 | TX
23 | );
24 |
25 | my $tx = Text::Xslate->new(
26 | path => \%vpath,
27 | cache_dir => '.xslate_cache',
28 | cache => 2,
29 | );
30 |
31 | my $mt = build_mt(<<'MT');
32 | ? sub fib {
33 | ? my($n) = @_;
34 | ? $n <= 1 ? 1 : fib($n - 1) + fib($n - 2);
35 | ? }
36 | ?= fib($_[0]->{x})
37 | MT
38 |
39 | my $vars = {
40 | x => $n,
41 | };
42 |
43 | {
44 | plan tests => 1;
45 | my $out = $mt->($vars);
46 | chomp $out;
47 | is $out, $tx->render(fib => $vars), 'MT'
48 | or die;
49 | }
50 | # suppose PSGI response body
51 | print "fib($n) = ", $tx->render(fib => $vars), "\n";
52 | cmpthese -1 => {
53 | xslate => sub {
54 | my $body = [$tx->render(fib => $vars)];
55 | return;
56 | },
57 | mt => sub {
58 | my $body = [$mt->($vars)];
59 | return;
60 | },
61 | };
62 |
63 |
--------------------------------------------------------------------------------
/benchmark/procs/function.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 |
4 | use Text::Xslate;
5 | use Text::MicroTemplate qw(build_mt);
6 |
7 | use Benchmark qw(:all);
8 | use Config; printf "Perl/%vd %s\n", $^V, $Config{archname};
9 |
10 | foreach my $mod(qw(Text::Xslate Text::MicroTemplate)){
11 | print $mod, '/', $mod->VERSION, "\n";
12 | }
13 |
14 | my $n = shift(@ARGV) || 100;
15 |
16 | my %vpath = (
17 | function => <<'TX' x $n,
18 | Hello, <:= $lang | uc :> world!
19 | TX
20 | );
21 | my $tx = Text::Xslate->new(
22 | path => \%vpath,
23 | cache_dir => '.xslate_cache',
24 | cache => 2,
25 |
26 | function => { uc => sub { uc $_[0] } },
27 | );
28 |
29 | my $mt = build_mt("Hello, = uc(\$_[0]->{lang}) ?> world!\n" x $n);
30 |
31 | my $subst_tmpl = qq{Hello, %lang% world!\n} x $n;
32 |
33 | my $vars = {
34 | lang => 'Template',
35 | };
36 |
37 | $tx->render(function => $vars) eq $mt->($vars)
38 | or die $tx->render(function => $vars);
39 |
40 | # suppose PSGI response body
41 |
42 | cmpthese -1 => {
43 | xslate => sub {
44 | my $body = [$tx->render(function => $vars)];
45 | return;
46 | },
47 | mt => sub {
48 | my $body = [$mt->($vars)];
49 | return;
50 | },
51 | 's///g' => sub {
52 | my $body = [$subst_tmpl];
53 | $body->[0] =~ s/%(\w+)%/uc($vars->{$1})/eg;
54 | return;
55 | },
56 | };
57 |
58 |
--------------------------------------------------------------------------------
/benchmark/procs/keys.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 |
4 | use Text::Xslate;
5 | use Text::MicroTemplate qw(build_mt);
6 |
7 | use Benchmark qw(:all);
8 | use Config; printf "Perl/%vd %s\n", $^V, $Config{archname};
9 | use Test::More;
10 |
11 | foreach my $mod(qw(Text::Xslate Text::MicroTemplate)){
12 | print $mod, '/', $mod->VERSION, "\n";
13 | }
14 |
15 | my $n = shift(@ARGV) || 10;
16 |
17 | my %vpath = (
18 | keys => <<'TX' x $n,
19 | : for $h.keys() -> $k {
20 | [<: $k :>]
21 | : }
22 | TX
23 | );
24 |
25 | my $tx = Text::Xslate->new(
26 | path => \%vpath,
27 | cache_dir => '.xslate_cache',
28 | cache => 2,
29 | );
30 |
31 | my $mt = build_mt(<<'T' x $n);
32 | ? for my $k(sort keys %{ $_[0]->{h} }) {
33 | [= $k ?>]
34 | ? }
35 | T
36 |
37 | my $subst_tmpl = qq{Hello, %value% world!\n} x $n;
38 |
39 | my $vars = {
40 | h => { %ENV },
41 | };
42 |
43 | {
44 | plan tests => 1;
45 | is $mt->($vars), $tx->render(keys => $vars), 'MT'
46 | or exit(1);
47 | }
48 |
49 | # suppose PSGI response body
50 | cmpthese -1 => {
51 | xslate => sub {
52 | my $body = [$tx->render(keys => $vars)];
53 | return;
54 | },
55 | mt => sub {
56 | my $body = [$mt->($vars)];
57 | return;
58 | },
59 | };
60 |
61 |
--------------------------------------------------------------------------------
/benchmark/procs/map.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 |
4 | use Text::Xslate;
5 | use Text::MicroTemplate qw(build_mt);
6 |
7 | use Benchmark qw(:all);
8 | use Config; printf "Perl/%vd %s\n", $^V, $Config{archname};
9 | use Test::More;
10 |
11 | foreach my $mod(qw(Text::Xslate Text::MicroTemplate)){
12 | print $mod, '/', $mod->VERSION, "\n";
13 | }
14 |
15 | my $n = shift(@ARGV) || 10;
16 |
17 | my %vpath = (
18 | map => <<'TX' x $n,
19 | : for $data.map(-> $x { $x + 1 }) -> $v {
20 | [<: $v :>]
21 | : }
22 | TX
23 | );
24 |
25 | my $tx = Text::Xslate->new(
26 | path => \%vpath,
27 | cache_dir => '.xslate_cache',
28 | cache => 2,
29 | );
30 |
31 | my $mt = build_mt(<<'T' x $n);
32 | ? {
33 | ? my $data = $_[0]->{data};
34 | ? for my $v(map{ $_ + 1 } @{$data}) {
35 | [= $v ?>]
36 | ? }
37 | ? }
38 | T
39 |
40 | my $vars = {
41 | data => [ 1 .. 100 ],
42 | };
43 |
44 | {
45 | plan tests => 1;
46 | is $mt->($vars), $tx->render(map => $vars), 'MT'
47 | or exit(1);
48 | }
49 | # suppose PSGI response body
50 | cmpthese -1 => {
51 | xslate => sub {
52 | my $body = [$tx->render(map => $vars)];
53 | return;
54 | },
55 | mt => sub {
56 | my $body = [$mt->($vars)];
57 | return;
58 | },
59 | };
60 |
61 |
--------------------------------------------------------------------------------
/benchmark/procs/sort.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 |
4 | use Text::Xslate;
5 | use Text::MicroTemplate qw(build_mt);
6 |
7 | use Benchmark qw(:all);
8 | use Config; printf "Perl/%vd %s\n", $^V, $Config{archname};
9 | use Test::More;
10 |
11 | foreach my $mod(qw(Text::Xslate Text::MicroTemplate)){
12 | print $mod, '/', $mod->VERSION, "\n";
13 | }
14 |
15 | my $n = shift(@ARGV) || 10;
16 |
17 | my %vpath = (
18 | sort => <<'TX' x $n,
19 | : for $data.sort(-> $a, $b { $a.value <=> $b.value }) -> $v {
20 | [<: $v.value :>]
21 | : }
22 | TX
23 | );
24 |
25 | my $tx = Text::Xslate->new(
26 | path => \%vpath,
27 | cache_dir => '.xslate_cache',
28 | cache => 2,
29 | );
30 |
31 | my $mt = build_mt(<<'T' x $n);
32 | ? {
33 | ? my $data = $_[0]->{data};
34 | ? for my $v(sort { $a->{value} <=> $b->{value} } @{$data}) {
35 | [= $v->{value} ?>]
36 | ? }
37 | ? }
38 | T
39 |
40 | my $vars = {
41 | data => [ map { +{ value => $_ } } reverse 1 .. 100 ],
42 | };
43 |
44 | {
45 | plan tests => 1;
46 | is $mt->($vars), $tx->render(sort => $vars), 'MT'
47 | or exit(1);
48 | }
49 | # suppose PSGI response body
50 | print q{Benchmark of sort-by-values ($a.sort( -> $a, $b { $a.value <=> $b.value })):}, "\n";
51 | cmpthese -1 => {
52 | xslate => sub {
53 | my $body = [$tx->render(sort => $vars)];
54 | return;
55 | },
56 | mt => sub {
57 | my $body = [$mt->($vars)];
58 | return;
59 | },
60 | };
61 |
62 |
--------------------------------------------------------------------------------
/benchmark/procs/uri_escape.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 |
4 | use Text::Xslate;
5 |
6 | use URI::Escape;
7 | use URI::Escape::XS;
8 |
9 | use Benchmark qw(:all);
10 | use Config; printf "Perl/%vd %s\n", $^V, $Config{archname};
11 |
12 | foreach my $mod(qw(Text::Xslate URI::Escape URI::Escape::XS)){
13 | print $mod, '/', $mod->VERSION, "\n";
14 | }
15 |
16 | my $n = shift(@ARGV) || 100;
17 |
18 | my %vpath = (
19 | builtin_uri => <<'TX' x $n,
20 | Hello, <: $lang | uri :> world!
21 | TX
22 | uri_escape_pp => <<'TX' x $n,
23 | Hello, <: $lang | uri_pp :> world!
24 | TX
25 |
26 | uri_escape_xs => <<'TX' x $n,
27 | Hello, <: $lang | uri_xs :> world!
28 | TX
29 |
30 | );
31 | my $tx = Text::Xslate->new(
32 | path => \%vpath,
33 | cache_dir => '.xslate_cache',
34 | cache => 2,
35 |
36 | function => {
37 | uri_pp => \&uri_escape,
38 | uri_xs => \&encodeURIComponent,
39 | },
40 | );
41 |
42 | my $vars = {
43 | lang => '/Text::Xslate/',
44 | };
45 |
46 | {
47 | use Test::More;
48 | plan tests => 2;
49 | is $tx->render(uri_escape_pp => $vars), $tx->render(builtin_uri => $vars), 'URI::Escape';
50 | is $tx->render(uri_escape_xs => $vars), $tx->render(builtin_uri => $vars), 'URI::Escape:XS';
51 | }
52 |
53 | # suppose PSGI response body
54 | cmpthese -1 => {
55 | builtin => sub {
56 | my $body = [$tx->render(builtin_uri => $vars)];
57 | },
58 | 'URI::Escape' => sub {
59 | my $body = [$tx->render(uri_escape_pp => $vars)];
60 | },
61 | 'URI::Escape::XS' => sub {
62 | my $body = [$tx->render(uri_escape_xs => $vars)];
63 | },
64 | };
65 |
66 |
--------------------------------------------------------------------------------
/benchmark/procs/values.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 |
4 | use Text::Xslate;
5 | use Text::MicroTemplate qw(build_mt);
6 |
7 | use Benchmark qw(:all);
8 | use Config; printf "Perl/%vd %s\n", $^V, $Config{archname};
9 | use Test::More;
10 |
11 | foreach my $mod(qw(Text::Xslate Text::MicroTemplate)){
12 | print $mod, '/', $mod->VERSION, "\n";
13 | }
14 |
15 | my $n = shift(@ARGV) || 10;
16 |
17 | my %vpath = (
18 | values => <<'TX' x $n,
19 | : for $h.values() -> $v {
20 | [<: $v :>]
21 | : }
22 | TX
23 | );
24 |
25 | my $tx = Text::Xslate->new(
26 | path => \%vpath,
27 | cache_dir => '.xslate_cache',
28 | cache => 2,
29 | );
30 |
31 | my $mt = build_mt(<<'T' x $n);
32 | ? {
33 | ? my $h = $_[0]->{h};
34 | ? for my $v(map{ $h->{$_ } } sort keys %{ $h }) {
35 | [= $v ?>]
36 | ? }
37 | ? }
38 | T
39 |
40 | my $subst_tmpl = qq{Hello, %value% world!\n} x $n;
41 |
42 | my $vars = {
43 | h => { %ENV },
44 | };
45 |
46 | {
47 | plan tests => 1;
48 | is $mt->($vars), $tx->render(values => $vars), 'MT'
49 | or exit(1);
50 | }
51 | # suppose PSGI response body
52 | cmpthese -1 => {
53 | xslate => sub {
54 | my $body = [$tx->render(values => $vars)];
55 | return;
56 | },
57 | mt => sub {
58 | my $body = [$mt->($vars)];
59 | return;
60 | },
61 | };
62 |
63 |
--------------------------------------------------------------------------------
/benchmark/template/base.mt:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 | block title => sub { ?>My amazing site }; ?>
7 |
8 |
9 |
10 |
18 |
19 |
20 | block content => sub { } ?>
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/benchmark/template/base.tx:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 | <: block title -> { :>My amazing site<: } :>
7 |
8 |
9 |
10 |
18 |
19 |
20 | <: block content -> { ; } :>
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/benchmark/template/child.mt:
--------------------------------------------------------------------------------
1 | ? extends "base"
2 |
3 | block title => sub { ?>My amazing blog }; ?>
4 |
5 | ? block content => sub {
6 | ? for my $entry(@$blog_entries) {
7 | = $entry->title ?>
8 | = $entry->body ?>
9 | ? }
10 | ? };
11 |
--------------------------------------------------------------------------------
/benchmark/template/child.tx:
--------------------------------------------------------------------------------
1 | : cascade base
2 |
3 | <: around title ->{ :>My amazing blog<: } :>
4 |
5 | : around content -> {
6 | : for $blog_entries -> ($entry) {
7 | <:= $entry.title :>
8 | <:= $entry.body :>
9 | : } # end for
10 | : } # end content
11 |
--------------------------------------------------------------------------------
/benchmark/template/include.cs:
--------------------------------------------------------------------------------
1 | Include:
2 |
--------------------------------------------------------------------------------
/benchmark/template/include.ht:
--------------------------------------------------------------------------------
1 | Include:
2 |
3 |
--------------------------------------------------------------------------------
/benchmark/template/include.mt:
--------------------------------------------------------------------------------
1 | Include:
2 | ?= include "list", @_
3 |
--------------------------------------------------------------------------------
/benchmark/template/include.tt:
--------------------------------------------------------------------------------
1 | Include:
2 | [% INCLUDE "list.tt" -%]
3 |
--------------------------------------------------------------------------------
/benchmark/template/include.tx:
--------------------------------------------------------------------------------
1 | Include:
2 | : include "list.tx"
3 |
--------------------------------------------------------------------------------
/benchmark/template/list.cs:
--------------------------------------------------------------------------------
1 | List:
2 |
3 | *
4 | *
5 | *
6 |
7 |
--------------------------------------------------------------------------------
/benchmark/template/list.ht:
--------------------------------------------------------------------------------
1 | List:
2 |
3 | *
4 | *
5 | *
6 |
7 |
--------------------------------------------------------------------------------
/benchmark/template/list.mst:
--------------------------------------------------------------------------------
1 | List:
2 | $ loop(data) { $
3 | * $=h:title$
4 | * $=h:title$
5 | * $=h:title$
6 | $ } $
7 |
--------------------------------------------------------------------------------
/benchmark/template/list.mt:
--------------------------------------------------------------------------------
1 | List:
2 | ? for my $item(@{ $_[0]->{data} }) {
3 | * = $item->{title} ?>
4 | * = $item->{title} ?>
5 | * = $item->{title} ?>
6 | ? }
7 |
--------------------------------------------------------------------------------
/benchmark/template/list.tj:
--------------------------------------------------------------------------------
1 | List:
2 | {data} }) { ?>
3 | * [= $item->{title} =]
4 | * [= $item->{title} =]
5 | * [= $item->{title} =]
6 |
7 |
--------------------------------------------------------------------------------
/benchmark/template/list.tt:
--------------------------------------------------------------------------------
1 | List:
2 | [% FOREACH item IN data -%]
3 | * [% item.title | html %]
4 | * [% item.title | html %]
5 | * [% item.title | html %]
6 | [% END -%]
7 |
--------------------------------------------------------------------------------
/benchmark/template/list.tx:
--------------------------------------------------------------------------------
1 | List:
2 | : for $data ->($item) {
3 | * <:= $item.title :>
4 | * <:= $item.title :>
5 | * <:= $item.title :>
6 | : }
7 |
--------------------------------------------------------------------------------
/cpanfile:
--------------------------------------------------------------------------------
1 | requires 'perl', '5.008001';
2 | requires 'Mouse', 'v2.5.0';
3 | requires 'Data::MessagePack', '0.38';
4 | requires 'parent', '0.221';
5 | requires 'Scalar::Util', '1.14';
6 |
7 | # fix local $SIG{__DIE__} + eval problems
8 | requires 'Encode', '2.26';
9 | requires 'Storable', '2.15';
10 |
11 | on configure => sub {
12 | requires 'Devel::PPPort', '3.33';
13 | requires 'Module::Build::XSUtil';
14 | requires 'version', '0.9913';
15 | };
16 |
17 | on test => sub {
18 | requires 'Test::More', '0.98';
19 | requires 'Test::Requires';
20 | requires 'File::Copy::Recursive';
21 | requires 'File::Path', '2.07';
22 | };
23 |
24 | on develop => sub {
25 | requires 'Test::LeakTrace';
26 | requires 'Devel::StackTrace';
27 | requires 'Data::Section::Simple';
28 | };
29 |
--------------------------------------------------------------------------------
/example/amon2.psgi:
--------------------------------------------------------------------------------
1 | #!perl
2 | use strict;
3 | use warnings;
4 |
5 | use Amon2::Lite;
6 |
7 | get '/' => sub {
8 | my ($c) = @_;
9 | $c->render('index.tt');
10 | };
11 | get '/hello' => sub {
12 | my ($c) = @_;
13 | $c->render('index.tt', { name => 'Amon2' });
14 | };
15 |
16 | sub res_404 {
17 | my($c) = @_;
18 | use Data::Dumper;
19 | die Dumper($c);
20 | }
21 |
22 | __PACKAGE__->to_app();
23 |
24 | __DATA__
25 |
26 | @@ index.tt
27 |
28 |
29 | Hello, [% name // 'Xslate' %] world!
30 |
31 |
--------------------------------------------------------------------------------
/example/amon2.psgi.gold:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello, Amon2 world!
4 |
5 |
--------------------------------------------------------------------------------
/example/autolink.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Text::Xslate qw(html_builder html_escape);
4 | use URI::Find 20100505;
5 |
6 | my $text = <<'EOT';
7 |
8 | EOT
9 |
10 | my $finder = URI::Find->new(sub {
11 | my($obj_uri, $orig_uri) = @_;
12 | my $safe_uri = html_escape($orig_uri);
13 | return qq|$safe_uri|;
14 | });
15 |
16 | my $tx = Text::Xslate->new(
17 | function => {
18 | autolink => html_builder {
19 | my($text) = @_;
20 | $finder->find(\$text, \&html_escape);
21 | return $text;
22 | },
23 | },
24 | );
25 |
26 | print $tx->render_string(<<'T', { text => $text });
27 | : $text | autolink
28 | T
29 |
--------------------------------------------------------------------------------
/example/autolink.pl.gold:
--------------------------------------------------------------------------------
1 | <http://example.com/?a=10&b=20>
2 |
--------------------------------------------------------------------------------
/example/base.tx:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 | <: block title -> { :>My amazing site<: } :>
7 |
8 |
9 |
10 |
18 |
19 |
20 | : block content -> { ; }
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/example/bridge.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Text::Xslate;
4 | use FindBin qw($Bin);
5 |
6 | {
7 | package MyBridge;
8 |
9 | use parent qw(Text::Xslate::Bridge);
10 |
11 | use Scalar::Util qw(looks_like_number);
12 | use List::Util qw(sum);
13 |
14 | __PACKAGE__->bridge(
15 | scalar => {
16 | looks_like_number => \&_scalar_looks_like_number,
17 | length => \&_scalar_length,
18 | },
19 | array => {
20 | sum => \&_array_sum,
21 | },
22 | hash => {
23 | delete_keys => \&_hash_delete_keys,
24 | },
25 |
26 | );
27 |
28 | sub _scalar_looks_like_number {
29 | looks_like_number($_[0]);
30 | }
31 |
32 | sub _scalar_length {
33 | defined $_[0] ? length $_[0] : 0;
34 | }
35 |
36 | sub _array_sum {
37 | defined $_[0] ? sum @{$_[0]} : 0;
38 | }
39 |
40 | sub _hash_delete_keys {
41 | my %hash = %{+shift};
42 | delete $hash{$_} for @_;
43 | return \%hash;
44 | }
45 | }
46 |
47 | my $tx = Text::Xslate->new(
48 | module => [qw(MyBridge)],
49 | path => $Bin,
50 | );
51 |
52 | print $tx->render('bridge.tx');
53 |
--------------------------------------------------------------------------------
/example/bridge.tx:
--------------------------------------------------------------------------------
1 | : my $num = 100;
2 | : my $str = 'abc';
3 | : my $array = [1,2,4,8,16];
4 | : my $hash = {a => 1, b => 2, c => 3, d => 4};
5 |
6 | : $num ~ ' is a number' if $num.looks_like_number();
7 |
8 | : $str ~ ' is a string' if !$str.looks_like_number();
9 |
10 | : $str ~ ' length is ' ~ $str.length();
11 |
12 | : 'sum of ' ~ $array.join(',') ~ ' is ' ~ $array.sum();
13 |
14 | : my $reduced = $hash.delete_keys('b', 'd');
15 |
16 | After keys b and d have been deleted, the hash is:
17 | : for $reduced.kv() -> $pair {
18 | <: $pair.key :> = <: $pair.value :>
19 | : };
20 |
--------------------------------------------------------------------------------
/example/cascade.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Text::Xslate;
4 | use FindBin qw($Bin);
5 |
6 | {
7 | package BlogEntry;
8 | use Mouse;
9 | has title => (is => 'rw');
10 | has body => (is => 'rw');
11 | }
12 |
13 | my @blog_entries = map{ BlogEntry->new($_) } (
14 | {
15 | title => 'Entry one',
16 | body => 'This is my first entry.',
17 | },
18 | {
19 | title => 'Entry two',
20 | body => 'This is my second entry.',
21 | },
22 | );
23 |
24 | my $path = $Bin;
25 | my $tx = Text::Xslate->new(
26 | path => [$path],
27 | cache_dir => '.eg_cache',
28 | );
29 |
30 | print $tx->render('cascade.tx', { blog_entries => \@blog_entries });
31 |
--------------------------------------------------------------------------------
/example/cascade.pl.gold:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 | My amazing blog
7 |
8 |
9 |
10 |
16 |
17 |
18 |
Entry one
19 |
This is my first entry.
20 |
Entry two
21 |
This is my second entry.
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/example/cascade.tx:
--------------------------------------------------------------------------------
1 | : cascade base
2 |
3 | <: around title ->{ :>My amazing blog<: } :>
4 |
5 | : around content -> {
6 | : for $blog_entries -> ($entry) {
7 | <:= $entry.title :>
8 | <:= $entry.body :>
9 | : } # end for
10 | : } # end content
11 |
--------------------------------------------------------------------------------
/example/chained-scope.pl:
--------------------------------------------------------------------------------
1 | #!perl
2 | use strict;
3 | use warnings;
4 | use Text::Xslate;
5 |
6 | my %vpath = (
7 | 'foo.tx' => 'Hello, <: $a ~ $b :> world!' . "\n",
8 | 'bar.tx' => ': include foo { __ROOT__.merge({ b => " with Kolon"}) }',
9 | );
10 |
11 | my $tx = Text::Xslate->new(
12 | cache => 0,
13 | path => \%vpath,
14 | );
15 |
16 | print $tx->render('bar.tx', { a => 'Xslate' });
17 |
18 |
--------------------------------------------------------------------------------
/example/chained-scope.pl.gold:
--------------------------------------------------------------------------------
1 | Hello, Xslate with Kolon world!
2 |
--------------------------------------------------------------------------------
/example/data_section.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 |
4 | use Text::Xslate;
5 | use Data::Section::Simple;
6 |
7 | my $tx = Text::Xslate->new(
8 | path => [ Data::Section::Simple->new()->get_data_section() ],
9 | cache_dir => '.eg_cache',
10 | );
11 |
12 | print $tx->render('child.tx');
13 |
14 | __DATA__
15 |
16 | @@ base.tx
17 |
18 |
19 | <: block body -> { :>default body<: } :>
20 |
21 |
22 | @@ child.tx
23 | : cascade base;
24 | : override body -> {
25 | child body
26 | : } # endblock body
27 |
--------------------------------------------------------------------------------
/example/data_section.pl.gold:
--------------------------------------------------------------------------------
1 |
2 |
3 | child body
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/example/dynamic_functions.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Text::Xslate;
4 | use FindBin qw($Bin);
5 |
6 | {
7 | package MyBridge;
8 |
9 | use parent qw(Text::Xslate::Bridge);
10 |
11 | __PACKAGE__->bridge(
12 | function => {my_func => \&_my_func},
13 | scalar => {my_func => \&_scalar},
14 | hash => {my_func => \&_hash},
15 | array => {my_func => \&_array},
16 | );
17 |
18 | sub _scalar {
19 | my $obj = shift;
20 | _my_func(@_)->($obj);
21 | };
22 |
23 | sub _hash {
24 | my $obj = shift;
25 | _my_func(@_)->(map {$_, $obj->{$_}} keys %$obj);
26 | };
27 |
28 | sub _array {
29 | my $obj = shift;
30 | _my_func(@_)->(@$obj);
31 | };
32 |
33 | sub _my_func {
34 | my @outer_args = @_;
35 | sub {
36 | my (@inner_args) = @_;
37 | join(', ', @outer_args, @inner_args) . "\n";
38 | }
39 | }
40 | }
41 |
42 | my $tx = Text::Xslate->new(
43 | module => [qw(MyBridge)],
44 | path => $Bin,
45 | );
46 |
47 | print $tx->render('dynamic_functions.tx');
48 |
--------------------------------------------------------------------------------
/example/dynamic_functions.tx:
--------------------------------------------------------------------------------
1 | Block syntax:
2 | : block my_block | my_func(foo => 'bar') -> {'baz, qux'}
3 |
4 | Subroutine syntax:
5 | : my_func(foo => 'bar')('baz, qux');
6 |
7 | Filter syntax:
8 | : 'baz, qux' | my_func(foo => 'bar')
9 |
10 | Scalar object syntax:
11 | : 'baz, qux'.my_func(foo => 'bar')
12 |
13 | Hash object syntax:
14 | : {baz => 'qux'}.my_func(foo => 'bar')
15 |
16 | Array object syntax:
17 | : ['baz', 'qux'].my_func(foo => 'bar')
18 |
--------------------------------------------------------------------------------
/example/err_handler.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Text::Xslate;
4 | my %vpath = (
5 | hello => 'Hello, <: $lang :> world!' . "\n",
6 | );
7 | my $tx = Text::Xslate->new(
8 | cache => 0,
9 | path => \%vpath,
10 | verbose => 2,
11 | warn_handler => sub { Text::Xslate->print('[[', @_, ']]') },
12 | );
13 |
14 | print $tx->render('hello', { lang => "Xslate" });
15 | print $tx->render('hello', { });
16 |
17 |
--------------------------------------------------------------------------------
/example/fillinform.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Text::Xslate;
4 | use HTML::FillInForm::Lite 1.09;
5 |
6 | my $tx = Text::Xslate->new(
7 | html_builder_module => [ 'HTML::FillInForm::Lite' => [qw(fillinform)] ],
8 | cache_dir => '.eg_cache',
9 | );
10 |
11 | my %vars = (
12 | q => { foo => "" },
13 | );
14 | print $tx->render_string(<<'T', \%vars);
15 | FillInForm:
16 | : block form | fillinform($q) -> {
17 |
20 | : }
21 | T
22 |
--------------------------------------------------------------------------------
/example/fillinform.pl.gold:
--------------------------------------------------------------------------------
1 | FillInForm:
2 |
5 |
--------------------------------------------------------------------------------
/example/form.psgi.gold:
--------------------------------------------------------------------------------
1 |
2 |
3 | Using Form Builder
4 |
5 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/example/hello.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Text::Xslate;
4 | use FindBin qw($Bin);
5 |
6 | my $path = $Bin;
7 | my $tx = Text::Xslate->new(
8 | path => [$path],
9 | cache_dir => '.eg_cache',
10 | );
11 |
12 | print $tx->render('hello.tx', { });
13 | print $tx->render('hello.tx', { lang => "Xslate" });
14 |
15 |
--------------------------------------------------------------------------------
/example/hello.pl.gold:
--------------------------------------------------------------------------------
1 | Hello, Perl world!
2 | Hello, Xslate world!
3 |
--------------------------------------------------------------------------------
/example/hello.tmpl:
--------------------------------------------------------------------------------
1 | Hello, world!
2 |
3 |
--------------------------------------------------------------------------------
/example/hello.tx:
--------------------------------------------------------------------------------
1 | Hello, <: $lang // "Perl" :> world!
2 |
--------------------------------------------------------------------------------
/example/htmltemplate.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | # TODO
3 | use strict;
4 |
5 | use Text::Xslate;
6 |
7 | my $tx = Text::Xslate->new(
8 | syntax => 'HTMLTemplate',
9 | cache => 0,
10 | );
11 |
12 | print $tx->render('example/hello.tmpl', { lang => 'HTML::Template' });
13 |
14 |
--------------------------------------------------------------------------------
/example/htparser.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | # TODO
3 | use strict;
4 |
5 | use Text::Xslate;
6 | use File::Slurp qw(slurp);
7 | use HTML::Template::Parser;
8 | use HTML::Template::Parser::TreeWriter::TextXslate::Metakolon;
9 |
10 | my $htparser = HTML::Template::Parser->new();
11 | my $ast = $htparser->parse(slurp 'example/hello.tmpl');
12 |
13 | my $writer = HTML::Template::Parser::TreeWriter::TextXslate::Metakolon->new;
14 | my $source = $writer->write($ast);
15 |
16 | my $tx = Text::Xslate->new(
17 | syntax => 'Metakolon',
18 | cache => 0,
19 | );
20 |
21 | print $tx->render_string($source, { lang => 'HTML::Template' });
22 |
23 |
--------------------------------------------------------------------------------
/example/i18n-data-localize.pl:
--------------------------------------------------------------------------------
1 | #!perl
2 | use strict;
3 | use warnings;
4 | use utf8;
5 |
6 | use Text::Xslate;
7 | use Text::Xslate::Util qw(html_escape html_builder);
8 | use Data::Localize;
9 | use Data::Localize::Gettext;
10 | use FindBin qw($Bin);
11 | use Encode ();
12 |
13 | my $i18n = Data::Localize->new(
14 | auto => 1,
15 | languages => ['ja'],
16 | );
17 | $i18n->add_localizer(
18 | class => 'Gettext',
19 | path => "$Bin/locale/*.po",
20 | );
21 |
22 | my $xslate = Text::Xslate->new(
23 | syntax => 'TTerse',
24 | function => {
25 | l => sub {
26 | return $i18n->localize(@_);
27 | },
28 | l_raw => html_builder {
29 | my $format = shift;
30 | my @args = map { html_escape($_) } @_;
31 | return $i18n->localize($format, @args);
32 | },
33 | },
34 | );
35 |
36 | my %param = (location => ''); # user inputs
37 | my $body = $xslate->render_string(<<'TEMPLATE', \%param);
38 | [% l_raw('Hello!
') %]
39 | [% l_raw('I am in %1
', $location) %]
40 | TEMPLATE
41 |
42 | print Encode::encode_utf8($body);
43 |
44 |
--------------------------------------------------------------------------------
/example/i18n-data-localize.pl.gold:
--------------------------------------------------------------------------------
1 | こんにちは!
2 | 私は <Tokyo> にいます
3 |
--------------------------------------------------------------------------------
/example/i18n.pl:
--------------------------------------------------------------------------------
1 | #!perl
2 | use strict;
3 | use warnings;
4 | use utf8;
5 |
6 | use Text::Xslate;
7 | use Text::Xslate::Util qw(html_escape html_builder);
8 | use Encode ();
9 |
10 | {
11 | package MyApp::I18N;
12 | use FindBin qw($Bin);
13 | use parent 'Locale::Maketext';
14 | use Locale::Maketext::Lexicon {
15 | '*' => [Gettext => "$Bin/locale/*.po"],
16 | _auto => 1,
17 | _decode => 1,
18 | _style => 'gettext',
19 | };
20 | }
21 |
22 | my $i18n = MyApp::I18N->get_handle('ja');
23 |
24 | my $xslate = Text::Xslate->new(
25 | syntax => 'TTerse',
26 | function => {
27 | l => sub {
28 | return $i18n->maketext(@_);
29 | },
30 | l_raw => html_builder {
31 | my $format = shift;
32 | my @args = map { html_escape($_) } @_;
33 | return $i18n->maketext($format, @args);
34 | },
35 | },
36 | );
37 |
38 | my %param = (location => ''); # user inputs
39 | my $body = $xslate->render_string(<<'TEMPLATE', \%param);
40 | [% l_raw('Hello!
') %]
41 | [% l_raw('I am in %1
', $location) %]
42 | TEMPLATE
43 |
44 | print Encode::encode_utf8($body);
45 |
46 |
--------------------------------------------------------------------------------
/example/i18n.pl.gold:
--------------------------------------------------------------------------------
1 | こんにちは!
2 | 私は <Tokyo> にいます
3 |
--------------------------------------------------------------------------------
/example/list.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Text::Xslate;
4 | use FindBin qw($Bin);
5 | use File::Find;
6 |
7 | my $path = $Bin;
8 | my $tx = Text::Xslate->new(
9 | path => [$path],
10 | cache_dir => '.eg_cache',
11 | );
12 |
13 | # preload templates
14 | find sub {
15 | if(/\.tx$/) {
16 | my $file = $File::Find::name;
17 | $file =~ s/\Q$path\E .//xsm;
18 | $tx->load_file($file);
19 | }
20 | }, $path;
21 |
22 | print $tx->render('list.tx', {data => [
23 | { title => 'Islands in the stream' },
24 | { title => 'Programming Perl' },
25 | { title => 'River out of Eden' },
26 | { title => 'Beautiful code' },
27 | ]});
28 |
29 |
--------------------------------------------------------------------------------
/example/list.pl.gold:
--------------------------------------------------------------------------------
1 | List:
2 | -------------------------------
3 | 1. Islands in the stream
4 | -------------------------------
5 | 2. Programming Perl
6 | -------------------------------
7 | 3. River out of Eden
8 | -------------------------------
9 | 4. Beautiful code
10 | -------------------------------
11 |
--------------------------------------------------------------------------------
/example/list.tx:
--------------------------------------------------------------------------------
1 | List:
2 | : for $data ->($item) {
3 | : if $~item.is_first {
4 | -------------------------------
5 | : }
6 | <: $~item.count :>. <: $item.title :>
7 | -------------------------------
8 | : }
9 |
--------------------------------------------------------------------------------
/example/locale/ja.po:
--------------------------------------------------------------------------------
1 | # for example/i18n.pl
2 | msgid ""
3 | msgstr ""
4 | "Project-Id-Version: Xslate I18N example\n"
5 | "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
6 | "PO-Revision-Date: 2011-11-02 12:00-0900\n"
7 | "Last-Translator: Fuji Goro\n"
8 | "Language-Team: Jaapanese\n"
9 | "MIME-Version: 1.0\n"
10 | "Content-Type: text/plain; charset=UTF-8\n"
11 | "Content-Transfer-Encoding: 8bit\n"
12 |
13 | msgid "Hello!
"
14 | msgstr "こんにちは!
"
15 |
16 | msgid "I am in %1
"
17 | msgstr "私は %1 にいます
"
18 |
19 |
--------------------------------------------------------------------------------
/example/mojo.psgi:
--------------------------------------------------------------------------------
1 | #!perl
2 | package HelloMojo;
3 | use strict;
4 | use warnings;
5 | use Mojolicious 1.0;
6 |
7 | use Mojolicious::Lite;
8 | #use MojoX::Renderer::Xslate; # this is automatically loaded
9 |
10 | plugin 'xslate_renderer';
11 |
12 | get '/' => 'index';
13 | get '/:name' => 'index';
14 |
15 | app->start;
16 |
17 | __DATA__
18 | @@ index.html.tx
19 |
20 |
21 | Hello, <: $c.req.param('lang') // "Xslate" :> world!
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/example/mojo.psgi.gold:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello, Xslate world!
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/example/put_js.pl:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Text::Xslate;
4 |
5 | my $tx = Text::Xslate->new(
6 | module => ['JavaScript::Value::Escape' => [qw(js)]],
7 | );
8 |
9 | my %params = (
10 | user_input => '',
11 | );
12 |
13 | print $tx->render_string(<<'T', \%params);
14 |
18 | T
19 |
20 |
--------------------------------------------------------------------------------
/example/put_js.pl.gold:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/example/simple.psgi:
--------------------------------------------------------------------------------
1 | #!psgi -w
2 | use strict;
3 | use Text::Xslate;
4 | use Plack::Request;
5 |
6 | my %vpath = (
7 | 'hello.tx' => <<'TX',
8 |
9 |
10 |
11 | hello
12 |
13 |
14 |
18 | Hello, <: $lang :> world!
19 |
20 |
21 | TX
22 | );
23 |
24 | my $tx = Text::Xslate->new(
25 | path => \%vpath,
26 | cache_dir => '.eg_cache',
27 | );
28 |
29 | sub app {
30 | my($env) = @_;
31 | my $req = Plack::Request->new($env);
32 | my $res = $req->new_response(
33 | 200,
34 | [content_type => 'text/html; charset=utf-8'],
35 | );
36 | my %vars = (
37 | lang => $req->param('lang') || '',
38 | );
39 | my $body = $tx->render('hello.tx', \%vars);
40 | utf8::encode($body);
41 | $res->body($body);
42 | return $res->finalize();
43 | }
44 |
45 | return \&app;
46 |
--------------------------------------------------------------------------------
/example/simple.psgi.gold:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | hello
5 |
6 |
7 |
11 | Hello, <Xslate> world!
12 |
13 |
14 |
--------------------------------------------------------------------------------
/lib/Text/Xslate/HashWithDefault.pm:
--------------------------------------------------------------------------------
1 | package Text::Xslate::HashWithDefault;
2 | use strict;
3 |
4 | use Tie::Hash;
5 | our @ISA = qw(Tie::ExtraHash);
6 |
7 | sub TIEHASH {
8 | my($class, $storage, $default) = @_;
9 | return bless [ $storage, $default ], $class;
10 | }
11 |
12 | sub FETCH {
13 | my($self, $key) = @_;
14 | if(exists $self->[0]{$key}) {
15 | return $self->[0]{$key};
16 | }
17 | else {
18 | return ref($self->[1]) eq 'CODE'
19 | ? $self->[1]->($key)
20 | : $self->[1];
21 | }
22 | }
23 |
24 | 1;
25 | __END__
26 |
27 | =head1 NAME
28 |
29 | Text::Xslate::HashWithDefault - Helper class to fill in default values
30 |
31 | =head1 SYNOPSIS
32 |
33 | use Text::Xslate::Util qw(hash_with_default);
34 |
35 | my $hash_ref = hash_with_default({ }, sub { "FILLME('@_')" });
36 | print $hash_ref->{foo}; # FILLME('foo')
37 |
38 | =head1 DESCRIPTION
39 |
40 | This is a helper class to provide C functionality,
41 | which is useful for debugging.
42 |
43 | See L for details.
44 |
45 | =cut
46 |
47 |
--------------------------------------------------------------------------------
/lib/Text/Xslate/Manual.pod:
--------------------------------------------------------------------------------
1 |
2 | =head1 NAME
3 |
4 | Text::Xslate::Manual - Xslate users manual
5 |
6 | =head1 TABLE OF CONTENTS
7 |
8 | L - Perl Interface to the Xslate template engine
9 |
10 | L - The default template syntax
11 |
12 | L - A Template Toolkit compatible syntax
13 |
14 | L - Builtin methods and filters/functions
15 |
16 | L - The Xslate cookbook
17 |
18 | L - Frequently asked questions and answers
19 |
20 | L - How to debug Xslate templates
21 |
22 | =head1 NOTES
23 |
24 | Xslate manual pages are not yet completed. Patches are welcome.
25 |
26 | =head1 SEE ALSO
27 |
28 | L - Xslate repositories
29 |
30 | =cut
31 |
32 |
--------------------------------------------------------------------------------
/lib/Text/Xslate/PP/Type/Macro.pm:
--------------------------------------------------------------------------------
1 | package Text::Xslate::PP::Type::Macro;
2 | use Mouse;
3 | use warnings FATAL => 'recursion';
4 |
5 | use overload
6 | '&{}' => \&as_code_ref,
7 | fallback => 1,
8 | ;
9 |
10 | has name => (
11 | is => 'ro',
12 | isa => 'Str',
13 |
14 | required => 1,
15 | );
16 |
17 | has addr => (
18 | is => 'ro',
19 | isa => 'Int',
20 |
21 | required => 1,
22 | );
23 |
24 | has nargs => (
25 | is => 'rw',
26 | isa => 'Int',
27 |
28 | default => 0,
29 | );
30 |
31 | has outer => (
32 | is => 'rw',
33 | isa => 'Int',
34 |
35 | default => 0,
36 | );
37 |
38 | has state => (
39 | is => 'rw',
40 | isa => 'Object',
41 |
42 | required => 1,
43 | weak_ref => 1,
44 | );
45 |
46 | sub as_code_ref {
47 | my($self) = @_;
48 |
49 | return sub {
50 | my $st = $self->state;
51 | push @{$st->{SP}}, [@_];
52 | $st->proccall($self);
53 | };
54 | }
55 |
56 | no Mouse;
57 | __PACKAGE__->meta->make_immutable;
58 | __END__
59 |
60 | =head1 NAME
61 |
62 | Text::Xslate::PP::Type::Macro - Text::Xslate macro object in pure Perl
63 |
64 | =head1 DESCRIPTION
65 |
66 | This module is used by Text::Xslate::PP internally.
67 |
68 | =head1 SEE ALSO
69 |
70 | L
71 |
72 | L
73 |
74 | =cut
75 |
--------------------------------------------------------------------------------
/lib/Text/Xslate/PP/Type/Pair.pm:
--------------------------------------------------------------------------------
1 | package Text::Xslate::PP::Type::Pair;
2 | use Mouse;
3 |
4 | has [qw(key value)] => (
5 | is => 'rw',
6 | required => 1,
7 | );
8 |
9 | no Mouse;
10 | __PACKAGE__->meta->make_immutable();
11 | __END__
12 |
13 | =head1 NAME
14 |
15 | Text::Xslate::PP::Type::Pair - Text::Xslate builtin pair type in pure Perl
16 |
17 | =head1 DESCRIPTION
18 |
19 | This module is used by Text::Xslate::PP internally.
20 |
21 | =head1 SEE ALSO
22 |
23 | L
24 |
25 | L
26 |
27 | =cut
28 |
--------------------------------------------------------------------------------
/lib/Text/Xslate/Syntax/Metakolon.pm:
--------------------------------------------------------------------------------
1 | package Text::Xslate::Syntax::Metakolon;
2 | use Mouse;
3 |
4 | extends qw(Text::Xslate::Parser);
5 |
6 | # [% ... %] and %% ...
7 | sub _build_line_start { '%%' }
8 | sub _build_tag_start { '[%' }
9 | sub _build_tag_end { '%]' }
10 |
11 | no Mouse;
12 | __PACKAGE__->meta->make_immutable();
13 |
14 | __END__
15 |
16 | =head1 NAME
17 |
18 | Text::Xslate::Syntax::Metakolon - The same as Kolon but using [% ... %] tags
19 |
20 | =head1 SYNOPSIS
21 |
22 | use Text::Xslate;
23 | my $tx = Text::Xslate->new(
24 | syntax => 'Metakolon',
25 | );
26 |
27 | print $tx->render_string(
28 | 'Hello, [% $dialect %] world!',
29 | { dialect => 'Metakolon' }
30 | );
31 |
32 | =head1 DESCRIPTION
33 |
34 | Metakolon is the same as Kolon except for using C<< [% ... %] >> tags and
35 | C<< %% ... >> line code, instead of C<< <: ... :> >> and C<< : ... >>.
36 |
37 | This may be useful when you want to produce Xslate templates by itself.
38 |
39 | See L for details.
40 |
41 | =head1 SEE ALSO
42 |
43 | L
44 |
45 | =cut
46 |
--------------------------------------------------------------------------------
/lib/Text/Xslate/Type/Raw.pm:
--------------------------------------------------------------------------------
1 | package Text::Xslate::Type::Raw;
2 | # the package is implemented intentionally in Text::Xslate
3 | require Text::Xslate;
4 | 1
5 | __END__
6 |
7 | =head1 NAME
8 |
9 | Text::Xslate::Type::Raw - The raw string representation
10 |
11 | =head1 DESCRIPTION
12 |
13 | This class represents raw strings so that Xslate does not escape them.
14 |
15 | Note that you cannot extend this class.
16 |
17 | =head1 METHODS
18 |
19 | =head2 new
20 |
21 | create a new instance
22 |
23 | =head2 as_string
24 |
25 | this method is overload to string.
26 |
27 | print Text::Xslate::Type::Raw->new('raw_string')->as_string
28 | print Text::Xslate::Type::Raw->new('raw_string') # the same, because of overload
29 |
30 |
31 | =cut
32 |
--------------------------------------------------------------------------------
/minil.toml:
--------------------------------------------------------------------------------
1 | name = "Text-Xslate"
2 | module_maker = "ModuleBuild"
3 | allow_pureperl = 1
4 | badges = ["github-actions/test"]
5 |
6 | [build]
7 | build_class = "builder::MyBuilder"
8 |
--------------------------------------------------------------------------------
/t/000_load.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 |
3 | use strict;
4 | use Test::More tests => 7;
5 |
6 | BEGIN { use_ok 'Text::Xslate' }
7 | BEGIN { use_ok 'Text::Xslate::Compiler' }
8 | BEGIN { use_ok 'Text::Xslate::Parser' }
9 | BEGIN { use_ok 'Text::Xslate::Syntax::Kolon' }
10 | BEGIN { use_ok 'Text::Xslate::Syntax::Metakolon' }
11 | BEGIN { use_ok 'Text::Xslate::Syntax::TTerse' }
12 | BEGIN { use_ok 'Text::Xslate::Type::Raw' }
13 |
14 | diag "Testing Text::Xslate/$Text::Xslate::VERSION";
15 | if(Text::Xslate->isa('Text::Xslate::PP')) {
16 | diag "Backend: PP";
17 | }
18 | else {
19 | diag "Backend: XS";
20 | }
21 | diag '$ENV{XSLATE}=', $ENV{XSLATE} || '';
22 |
23 |
--------------------------------------------------------------------------------
/t/010_internals/001_parse.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 |
3 | use strict;
4 | use Test::More;
5 |
6 | use Text::Xslate::Parser;
7 | use Text::Xslate::Util qw(p);
8 |
9 | my $debug = 0;
10 |
11 | my $parser = Text::Xslate::Parser->new();
12 | isa_ok $parser, 'Text::Xslate::Parser';
13 |
14 | my @data = (
15 | [''],
16 | ['Hello, world!', qr/"Hello, world!"/],
17 | ['Hello, <:= $lang :> world!', qr/ \$lang \b/xms, qr/"Hello, "/, qr/" world!"/],
18 | ['aaa <:= $bbb :> ccc <:= $ddd :>', qr/aaa/, qr/\$bbb/, qr/ccc/, qr/\$ddd/],
19 |
20 | ['<: for $data ->($item) { print $item; } :>', qr/\b for \b/xms, qr/\$data\b/, qr/\$item/ ],
21 |
22 | [":
", qr{:
}],
23 | [" :
", qr{ :
}],
24 |
25 | [<<'T', qr/foo/, qr/item/, qr/data/],
26 | : macro foo ->($x, $y) {
27 | : for $x -> ($item) {
28 | <: $item :>
29 | : }
30 | : }
31 | : for $data -> ($item) {
32 | : foo($item)
33 | : }
34 | T
35 |
36 | [<<'T'],
37 | : if $foo {
38 | bar
39 | : }
40 | : else {
41 | baz
42 | : }
43 | T
44 |
45 | [';' x 10],
46 |
47 | [<<'T'],
48 | : my $foo = {
49 | : bar => 42,
50 | : };
51 | T
52 | );
53 |
54 | foreach my $d(@data) {
55 | my($str, @patterns) = @{$d};
56 |
57 | note($str) if $debug;
58 | my $code = eval { p($parser->parse($str)) };
59 | note($code) if $debug;
60 |
61 | ok $code, 'parse'
62 | or diag $@;
63 |
64 | foreach my $pat(@patterns) {
65 | like $code, $pat;
66 | }
67 | }
68 |
69 | done_testing;
70 |
--------------------------------------------------------------------------------
/t/010_internals/002_compile.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 |
3 | use strict;
4 | use Test::More;
5 |
6 | use Text::Xslate::Compiler;
7 | use Text::Xslate::Util qw(p);
8 |
9 | my $c = Text::Xslate::Compiler->new();
10 |
11 | isa_ok $c, 'Text::Xslate::Compiler';
12 |
13 | my @data = (
14 | ['Hello, world!', qr/Hello, world!/],
15 | ['Hello, <:= $lang :> world!', qr/\b lang \b/xms, qr/Hello, /, qr/ world!/],
16 | ['aaa <:= $bbb :> ccc <:= $ddd :>', qr/aaa/, qr/\b bbb \b/xms, qr/ccc/, qr/\b ddd \b/xms],
17 |
18 | ['<: for $data ->($item) { print $item; } :>', qr/\b for /xms, qr/\b data \b/xms ],
19 |
20 | ['<: "foo" :>:<: "bar" :>', qr/ foo /xms, qr/ bar /xms, qr/ : /xms ],
21 | );
22 |
23 | foreach my $d(@data) {
24 | my($str, @patterns) = @{$d};
25 |
26 | my $code = p($c->compile($str));
27 | #note($code);
28 |
29 | foreach my $pat(@patterns) {
30 | like $code, $pat, $str;
31 | }
32 | }
33 |
34 | done_testing;
35 |
--------------------------------------------------------------------------------
/t/010_internals/003_assemble.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | # The purpose of this test is to ensure that _assemble() ends successfully.
3 |
4 | use strict;
5 | use Test::More tests => 4;
6 |
7 | use Text::Xslate;
8 |
9 | my %vpath = (
10 | hello => 'Hello, world!',
11 | );
12 |
13 |
14 | for my $n(1 .. 2) {
15 | my $tx = Text::Xslate->new(cache => 0, path => \%vpath);
16 | eval {
17 | $tx->load_file('hello');
18 | };
19 | is $@, '', "assemble inside of eval {} ($n)";
20 |
21 | $tx = Text::Xslate->new(cache => 0, path => \%vpath);
22 | $tx->load_file('hello');
23 | pass "assemble outside of eval {} ($n)";
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/t/010_internals/006_errhandler.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 |
3 | use strict;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 |
8 | my $warn = '';
9 | my $die = '';
10 | my $tx = Text::Xslate->new(
11 | verbose => 2,
12 | warn_handler => sub{ $warn = "@_" },
13 | die_handler => sub{ $die = "@_" },
14 | );
15 |
16 | is $tx->render_string(
17 | 'Hello, <:= $lang :> world!',
18 | { lang => undef }), "Hello, world!", "error handler" for 1 .. 2;
19 |
20 | like $warn, qr/\b nil \b/xms, 'warnings are produced';
21 | like $warn, qr/Xslate/;
22 | like $warn, qr//;
23 | is $die, '';
24 |
25 | $warn = '';
26 | $die = '';
27 |
28 | eval {
29 | is $tx->render_string(
30 | ': include "no/such/path" ',
31 | { lang => undef }), "Hello, world!", "error handler" for 1 .. 2;
32 | };
33 |
34 | is $warn, '';
35 | like $die, qr{no/such/path}, 'the error handler was called';
36 | like $die, qr/Xslate/;
37 | like $@, qr{no/such/path}, 'errors are thrown, anyway';
38 | like $@, qr/Xslate/;
39 |
40 | done_testing;
41 |
--------------------------------------------------------------------------------
/t/010_internals/009_goto_address.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | # NOTE: the optimizer could break goto addresses
3 |
4 | use strict;
5 | use Test::More;
6 |
7 | use Text::Xslate;
8 | use Text::Xslate::Util qw(p);
9 |
10 | my $tx = Text::Xslate->new();
11 |
12 | my @data = (
13 | [<<'T', " [foo]\n" . " [foo]\n"],
14 | : if($value == "foo") {
15 | [<:= $value :>]
16 | [<:= $value :>]
17 | : }
18 | : else {
19 | [<:= $value :>]
20 | [<:= $value :>]
21 | : }
22 | T
23 |
24 | [<<'T', " [foo]\n" . " [foo]\n"],
25 | : if($value == "bar") {
26 | [<:= $value :>]
27 | [<:= $value :>]
28 | : }
29 | : else {
30 | [<:= $value :>]
31 | [<:= $value :>]
32 | : }
33 | T
34 |
35 | [<<'T', " [*foo]\n" . " [*foo]\n"],
36 | : if($value == "foo") {
37 | [<:= "*" ~ $value :>]
38 | [<:= "*" ~ $value :>]
39 | : }
40 | : else {
41 | [<:= "*" ~ $value :>]
42 | [<:= "*" ~ $value :>]
43 | : }
44 | T
45 |
46 | [<<'T', " [*foo]\n" . " [*foo]\n"],
47 | : if($value == "bar") {
48 | [<:= "*" ~ $value :>]
49 | [<:= "*" ~ $value :>]
50 | : }
51 | : else {
52 | [<:= "*" ~ $value :>]
53 | [<:= "*" ~ $value :>]
54 | : }
55 | T
56 | [<<'T', "\ntrue\n\n"],
57 | <: if 1 { :>
58 | true
59 | <: } else { :>
60 | false
61 | <: } :>
62 | T
63 | [<<'T', "\nfalse\n\n"],
64 | <: if 0 { :>
65 | true
66 | <: } else { :>
67 | false
68 | <: } :>
69 | T
70 |
71 | );
72 |
73 |
74 | foreach my $pair(@data) {
75 | my($in, $out) = @$pair;
76 |
77 | my %vars = (
78 | value => 'foo',
79 | );
80 | is $tx->render_string($in, \%vars), $out
81 | or diag( p($tx->render(\%vars)) );
82 | }
83 |
84 | done_testing;
85 |
--------------------------------------------------------------------------------
/t/010_internals/013_deps_str.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 |
3 | use strict;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 | use FindBin qw($Bin);
8 | use File::Copy qw(copy move);
9 | use File::Path qw(rmtree);
10 |
11 | use lib "t/lib";
12 | use Util;
13 |
14 | my $base = path . "/myapp/base.tx";
15 | END{
16 | move "$base.save" => $base if -e "$base.save";
17 |
18 | rmtree cache_dir;
19 | }
20 |
21 | note 'for strings';
22 |
23 | utime $^T-120, $^T-120, $base;
24 |
25 | my $tx = Text::Xslate->new(path => [path], cache_dir => cache_dir);
26 |
27 | #use Data::Dumper; print Dumper $tx;
28 |
29 | $tx->load_string(":cascade myapp::base");
30 | is $tx->render('', {lang => 'Xslate'}), <<'T';
31 | HEAD
32 | Hello, Xslate world!
33 | FOOT
34 | T
35 |
36 | move $base => "$base.save";
37 | copy "$base.mod" => $base;
38 |
39 | utime $^T+60, $^T+60, $base;
40 |
41 | $tx->load_string(":cascade myapp::base");
42 | is $tx->render('', {lang => 'Foo'}), <<'T';
43 | HEAD
44 | Modified version of base.tx
45 | FOOT
46 | T
47 |
48 | move "$base.save" => $base;
49 | utime $^T+120, $^T+120, $base;
50 |
51 | $tx->load_string(":cascade myapp::base");
52 | is $tx->render('', {lang => 'Perl'}), <<'T';
53 | HEAD
54 | Hello, Perl world!
55 | FOOT
56 | T
57 |
58 | done_testing;
59 |
--------------------------------------------------------------------------------
/t/010_internals/014_deps_file.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 |
3 | use strict;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 | use File::Copy qw(copy move);
8 | use File::Path qw(rmtree);
9 |
10 | use lib "t/lib";
11 | use Util;
12 |
13 | my $base = path . "/myapp/base.tx";
14 | my $derived = path . "/myapp/derived.tx";
15 | rmtree cache_dir;
16 | END{
17 | move "$base.save" => $base if -e "$base.save";
18 |
19 | rmtree cache_dir;
20 | }
21 |
22 | note 'for files';
23 |
24 | utime $^T - 120, $^T - 120, $base, $derived;
25 |
26 | my $tx = Text::Xslate->new(path => [path], cache_dir => cache_dir);
27 |
28 | #use Data::Dumper; print Dumper $tx;
29 |
30 | is $tx->render('myapp/derived.tx', {lang => 'Xslate'}), <<'T', 'original' for 1 .. 2;
31 | HEAD
32 | D-BEFORE
33 | Hello, Xslate world!
34 | D-AFTER
35 | FOOT
36 | T
37 |
38 | move $base => "$base.save";
39 | copy "$base.mod" => $base;
40 |
41 | utime $^T+60, $^T+60, $base;
42 | note "modify $base";
43 |
44 | is $tx->render('myapp/derived.tx', {lang => 'Foo'}), <<'T', 'modified' for 1 .. 2;
45 | HEAD
46 | D-BEFORE
47 | Modified version of base.tx
48 | D-AFTER
49 | FOOT
50 | T
51 |
52 | move "$base.save" => $base;
53 | utime $^T+120, $^T+120, $base;
54 | note "modify $base again";
55 |
56 | is $tx->render('myapp/derived.tx', {lang => 'Perl'}), <<'T', 'again' for 1 .. 2;
57 | HEAD
58 | D-BEFORE
59 | Hello, Perl world!
60 | D-AFTER
61 | FOOT
62 | T
63 |
64 | done_testing;
65 |
--------------------------------------------------------------------------------
/t/010_internals/015_deps_file2.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 |
3 | use strict;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 | use File::Copy qw(copy move);
8 | use File::Path qw(rmtree);
9 | use File::Spec;
10 | use lib "t/lib";
11 | use Util;
12 |
13 | rmtree cache_dir;
14 |
15 | my $base;
16 | my $derived;
17 | my $base_c;
18 | my $derived_c;
19 | BEGIN {
20 | my $tx = Text::Xslate->new(path => [path], cache_dir => cache_dir);
21 |
22 | my $fi = $tx->find_file('myapp/base.tx');
23 | $base = $fi->{fullpath};
24 | $base_c = $fi->{cachepath};
25 |
26 | $fi = $tx->find_file('myapp/derived.tx');
27 | $derived = $fi->{fullpath};
28 | $derived_c = $fi->{cachepath};
29 | }
30 |
31 | END{
32 | move "$base.save" => $base if -e "$base.save";
33 |
34 | rmtree cache_dir;
35 | }
36 |
37 |
38 | note 'for files';
39 |
40 | utime $^T - 120, $^T - 120, $base, $derived;
41 |
42 | {
43 | # compile and cache template files.
44 | my $tx = Text::Xslate->new(path => [path], cache_dir => cache_dir);
45 | $tx->render($_, {lang => 'Perl'}) for 'myapp/derived.tx';
46 | }
47 |
48 | utime $^T - 60, $^T - 60, $base_c, $derived_c;
49 | note " cache files have been created at 60 seconds ago.";
50 |
51 | my $tx = Text::Xslate->new(path => [path], cache_dir => cache_dir);
52 |
53 | move $base => "$base.save";
54 | copy "$base.mod" => $base;
55 |
56 | utime $^T, $^T, $base;
57 | note "modify $base just now";
58 |
59 | is $tx->render('myapp/derived.tx', {lang => 'Foo'}), <<'T', "modified($_)" for 1 .. 2;
60 | HEAD
61 | D-BEFORE
62 | Modified version of base.tx
63 | D-AFTER
64 | FOOT
65 | T
66 |
67 | done_testing;
68 |
--------------------------------------------------------------------------------
/t/010_internals/016_cached.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 |
3 | use strict;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 | use File::Path;
8 | use File::Temp 'tempfile';
9 | use Config;
10 |
11 | use lib "t/lib";
12 | use Util ();
13 |
14 | my $path = Util::path();
15 | my $cache_dir = Util::cache_dir;
16 | rmtree($cache_dir);
17 | END{ rmtree($cache_dir) }
18 |
19 | my ($tempfh, $tempname) = tempfile(UNLINK => 1);
20 | print {$tempfh} <<'EOT';
21 | use strict;
22 | use warnings;
23 | use Text::Xslate;
24 | use lib "t/lib";
25 | use Util;
26 | my($path, $cache_dir) = @ARGV;
27 | my $tx = Text::Xslate->new(
28 | path => [$path, { 'foo.tx' => 'Hello' } ],
29 | cache_dir => $cache_dir,
30 | );
31 | $tx->load_file('myapp/derived.tx');
32 | $tx->load_file('foo.tx');
33 | EOT
34 | close $tempfh;
35 |
36 | # XXX: @INC is too long to pass a command, so we need to give it via %ENV
37 | $ENV{PERL5LIB} = join $Config{path_sep}, @INC;
38 | is system($^X, $tempname, $path, $cache_dir), 0, 'compile' or die "failed to compile";
39 |
40 | ok -d $cache_dir;
41 |
42 | for my $cache(1 .. 2) {
43 | my $tx = Text::Xslate->new(
44 | path => [$path, { 'foo.tx' => 'Hello' } ],
45 | cache_dir => $cache_dir,
46 | cache => $cache,
47 | );
48 |
49 | for(1 .. 2) {
50 | like $tx->render('myapp/derived.tx', { lang => 'Xslate' }),
51 | qr/Hello, Xslate world!/, "cache => $cache (render/path)";
52 |
53 | is $tx->render('foo.tx'), 'Hello', 'render/vpath';
54 |
55 | ok !exists $INC{'Text/Xslate/Compiler.pm'}, 'Text::Xslate::Compiler is not loaded';
56 | }
57 | #note(explain($tx->{_cache_path}));
58 | }
59 |
60 | done_testing;
61 |
--------------------------------------------------------------------------------
/t/010_internals/018_opinfo.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 |
3 | use strict;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 | use lib "t/lib";
8 | use Util;
9 | use File::Path qw(rmtree);
10 |
11 | rmtree(cache_dir);
12 | END{ rmtree(cache_dir) }
13 |
14 | my $warn;
15 |
16 | my $tx = Text::Xslate->new(
17 | verbose => 2,
18 | warn_handler => sub{ $warn .= join '', @_ },
19 | path => path,
20 | cache_dir => cache_dir,
21 | cache => 1,
22 | );
23 |
24 | $warn = '';
25 | eval {
26 | $tx->render_string(<<'T');
27 | : cascade oi::bad_base
28 | T
29 | };
30 | is $@, '', 'exception';
31 | like $warn, qr{ \b bad_base\.tx \b }xms;
32 | like $warn, qr{ \b bad_code_foo \b }xms;
33 |
34 | $warn = '';
35 | eval {
36 | $tx->render_string(<<'T');
37 | : cascade oi::bad_base with oi::bad_component
38 | T
39 | };
40 | is $@, '', 'exception';
41 | like $warn, qr{ \b bad_code_foo \b .+ \b bad_base\.tx \b }xms, 'warn (for base)';
42 | like $warn, qr{ \b bad_code_bar \b .+ \b bad_component\.tx \b }xms, 'warn (for component)';
43 |
44 | done_testing;
45 |
--------------------------------------------------------------------------------
/t/010_internals/021_edge_cases.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use Text::Xslate;
6 |
7 | my $tx = Text::Xslate->new();
8 |
9 | my @data = (
10 | ['<: "foo\tbar\n" :>', "foo\tbar\n"],
11 | [q{<: 'foo\tbar\n' :>}, 'foo\tbar\n'],
12 | [q{<: ' & " \' ' :>}, ' & " ' '],
13 | [q{<: "<: 'foo' :>" :>}, "<: 'foo' :>"],
14 |
15 | [q{foo<:# this is a comment :>bar}, "foobar"],
16 | [q{<:$lang:> foo<:# this is a comment :>bar <:$lang:>}, "Xslate foobar Xslate"],
17 | [q{foo<:
18 | :>bar}, "foobar"],
19 | [q{foo<: # this is a comment
20 | $lang :>bar}, "fooXslatebar"],
21 |
22 | # edge-cases
23 | [q{: $lang}, 'Xslate'],
24 | [q{<: $lang :>:}, 'Xslate:' ],
25 |
26 | [<<'T', <<'X' ],
27 | <: $lang :>
28 | : "foo\n"
29 | T
30 | Xslate
31 | foo
32 | X
33 |
34 | [<<'T', <<'X' ],
35 | <: $lang :>: 42
36 | T
37 | Xslate: 42
38 | X
39 |
40 | [<<'T', 42 ],
41 | : for [42] -> $it {
42 | : $it
43 | : }
44 | T
45 |
46 | # from Template::Benchmark
47 | [<<'T' x 10, <<'X' x 10],
48 | <: for $hash.keys() ->($k) { :><:= $k :><:= ":" :> <:= $hash[ $k ] :><: } :>
49 | T
50 | age: 43name: Larry Nomates
51 | X
52 |
53 | );
54 |
55 | my %vars = (
56 | lang => 'Xslate',
57 | foo => "",
58 | hash => { name => 'Larry Nomates', age => 43, },
59 | );
60 | foreach my $pair(@data) {
61 | my($in, $out) = @$pair;
62 | is $tx->render_string($in, \%vars), $out
63 | or diag $in;
64 | }
65 |
66 | done_testing;
67 |
--------------------------------------------------------------------------------
/t/010_internals/022_signal.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 | use Text::Xslate;
5 |
6 | plan skip_all => 'disable on Windows with older perl(<5.14.2)' if $^O eq 'MSWin32' && $] < 5.014002;
7 |
8 | my $tx = Text::Xslate->new();
9 | $tx->render_string(''); # load related modules
10 |
11 | eval {
12 | local $SIG{ALRM} = sub { die "TIMEOUT" };
13 | alarm(1);
14 | $tx->render_string(q{: while true {} });
15 | };
16 |
17 | like $@, qr/TIMEOUT/;
18 |
19 | done_testing;
20 |
--------------------------------------------------------------------------------
/t/010_internals/023_cachepath.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 |
3 | use strict;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 | use Text::Xslate::Util qw();
8 | use File::Path;
9 | use lib "t/lib";
10 | use Util;
11 |
12 | rmtree(cache_dir);
13 | END{ rmtree(cache_dir) }
14 |
15 | package FooOverloadingObjectDir;
16 | use overload
17 | q{""} => sub { return ${shift()} },
18 | fallback => 1,
19 | ;
20 | sub new { bless \"$_[1]" => $_[0] }
21 |
22 | package main;
23 |
24 |
25 | {
26 | my $tx1 = Text::Xslate->new(
27 | path => [FooOverloadingObjectDir->new(path), { 'foo.tx' => 'Hello' } ],
28 | cache_dir => cache_dir,
29 | cache => 2,
30 | );
31 | my $tx2 = Text::Xslate->new(
32 | path => [FooOverloadingObjectDir->new(path . '/other'), { 'foo.tx' => 'Hello' } ],
33 | cache_dir => cache_dir,
34 | cache => 2,
35 | );
36 |
37 | # different path's cachepath is different too
38 | isnt $tx1->find_file('hello.tx')->{cachepath},
39 | $tx2->find_file('hello.tx')->{cachepath};
40 | }
41 |
42 |
43 | done_testing;
44 |
--------------------------------------------------------------------------------
/t/010_internals/024_die_in_macros.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use Text::Xslate;
6 |
7 | my %vpath = (
8 | "base.tx" => <<'T',
9 | : block main -> {}
10 | T
11 |
12 | "derived.tx" => <<'T',
13 | : cascade base
14 | : around main -> {
15 | <: $o.foo :>
16 | : }
17 | T
18 |
19 | "block.tx" => <<'T',
20 | : block main -> {
21 | <: $o.foo :>
22 | : }
23 | T
24 |
25 | );
26 |
27 | {
28 | package Foo;
29 | sub new { bless {} => shift }
30 | sub foo {
31 | die "foo";
32 | }
33 | package Bar;
34 | sub new { bless {} => shift }
35 | sub bar {
36 | eval { die "bar" };
37 | }
38 | }
39 |
40 | my $tx = Text::Xslate->new(path => \%vpath, cache => 0, verbose => 0);
41 |
42 | ok $tx->render('block.tx', { o => Foo->new }), 'block';
43 | ok $tx->render('block.tx', { o => Bar->new }), 'block';
44 |
45 |
46 | ok $tx->render('derived.tx', { o => Foo->new }), 'cascade';
47 | ok $tx->render('derived.tx', { o => Bar->new }), 'cascade';
48 |
49 | is $tx->render_string('Hello, world!'), 'Hello, world!', 'render_string() works';
50 |
51 | done_testing;
52 |
--------------------------------------------------------------------------------
/t/010_internals/025_reset_hooks.t:
--------------------------------------------------------------------------------
1 | #!perl
2 | use strict;
3 | use warnings;
4 |
5 | use Test::More tests => 20;
6 | use Text::Xslate;
7 |
8 | sub reset_diehook {
9 | local $SIG{__DIE__} = sub { die @_ };
10 | return 42;
11 | }
12 |
13 | sub reset_warnhook {
14 | local $SIG{__WARN__} = sub { warn @_ };
15 | return 42;
16 | }
17 |
18 | {
19 | my $tx = Text::Xslate->new(function => {
20 | reset_diehook => \&reset_diehook,
21 | reset_warnhook => \&reset_warnhook,
22 | });
23 |
24 | for ( 1 .. 10 ) {
25 | is $tx->render_string( '[<: reset_diehook() :>]' ), '[42]';
26 | is $tx->render_string( '[<: reset_warnhook() :>]' ), '[42]';
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/t/010_internals/026_issue16_deep_recursion.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 | use Text::Xslate;
5 |
6 | my $tx = Text::Xslate->new(
7 | cache => 0,
8 | syntax => 'TTerse',
9 | path => {
10 | wrap_begin => '[% WRAPPER "base" %]',
11 | wrap_end => '[% END %]',
12 |
13 | header => 'Header' . "\n",
14 | base => '[% INCLUDE "header" %]Hello, [% content %] world!' . "\n",
15 | content => 'Xslate',
16 | },
17 | header => ['wrap_begin'],
18 | footer => ['wrap_end'],
19 | );
20 |
21 | is $tx->render_string(q{Xslate}), <<'X';
22 | Header
23 | Hello, Xslate world!
24 | X
25 |
26 | is $tx->render('content'), <<'X';
27 | Header
28 | Hello, Xslate world!
29 | X
30 |
31 | done_testing;
32 |
--------------------------------------------------------------------------------
/t/010_internals/027_infinite_warn.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use Text::Xslate;
6 |
7 | my %vpath = (
8 | 'runner.tx' => <<'T',
9 | :include "test.tx";
10 | T
11 | 'test.tx' => <<'T',
12 | : $test()[0];
13 | T
14 | );
15 |
16 | my $err_buf = '';
17 | close STDERR;
18 | open STDERR, '>', \$err_buf;
19 |
20 | my $tx = Text::Xslate->new(cache => 0, path => \%vpath);
21 |
22 | is $tx->render('runner.tx', {test => sub {warn "WARNING";['OK'] }}), 'OK';
23 | like $err_buf, qr/\b WARNING \b/xms;
24 |
25 | done_testing;
26 |
--------------------------------------------------------------------------------
/t/010_internals/029_large_file.t:
--------------------------------------------------------------------------------
1 | #!perl
2 | use strict;
3 | use warnings;
4 |
5 | use Test::More;
6 | use Text::Xslate;
7 | use File::Temp ();
8 | note 'preparing...';
9 | my $temp = File::Temp->new(DIR => '.');
10 | $temp->unlink_on_destroy(1);
11 |
12 | $temp->print("Hello, world!\n") for 1 .. 1024*5;
13 | $temp->close();
14 | note 'prepared';
15 |
16 | foreach (1 .. 2) {
17 | note $_;
18 | my $tx = Text::Xslate->new(
19 | cache => 1,
20 | cache_dir => '.xslate_cache',
21 | );
22 | eval {
23 | $tx->render($temp->filename);
24 | };
25 | ok !$@ or note $@;
26 | }
27 |
28 |
29 | done_testing;
30 |
--------------------------------------------------------------------------------
/t/010_internals/030_die_in_funcs.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 | use Text::Xslate;
5 |
6 | {
7 | package Foo;
8 | use Mouse;
9 |
10 | has bar => (
11 | is => 'rw',
12 | isa => 'Int',
13 | );
14 | }
15 |
16 | my $tx = Text::Xslate->new(
17 | module => [qw(Carp) => [qw(confess croak)] ],
18 | warn_handler => sub { die @_ },
19 | );
20 |
21 | eval {
22 | $tx->render_string('<: croak("foo") :>');
23 | };
24 | like $@, qr/foo/, 'croak in functions';
25 |
26 | eval {
27 | $tx->render_string('<: confess("bar") :>');
28 | };
29 | like $@, qr/bar/, 'confess in templates';
30 |
31 | eval {
32 | $tx->render_string('<: $foo.bar("xyzzy") :>', { foo => Foo->new });
33 | };
34 | like $@, qr/Validation failed/, 'confess in templates';
35 | done_testing;
36 |
37 |
--------------------------------------------------------------------------------
/t/010_internals/031_save_src.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use if exists $INC{'Text/Xslate.pm'},
4 | 'Test::More', skip_all => 'Text::Xslate has been loaded';
5 | use Test::More;
6 | BEGIN{ $ENV{XSLATE} ||= ''; $ENV{XSLATE} .= ':save_src' }
7 |
8 | use Text::Xslate;
9 | use File::Spec;
10 | use lib "t/lib";
11 | use Util;
12 |
13 | my $tx = Text::Xslate->new(
14 | path => [{ foo => 'Hello, <: "" :>world!' }, path],
15 | cache => 0,
16 | );
17 |
18 | note 'from file';
19 | is $tx->render('hello.tx', { lang => 'Xslate' } ), "Hello, Xslate world!\n";
20 | is $tx->{source}{File::Spec->catfile(path, 'hello.tx')},
21 | "Hello, <:= \$lang :> world!\n"
22 | or diag(explain($tx->{source}));
23 |
24 | note 'from hash';
25 | is $tx->render('foo'), 'Hello, world!';
26 | is $tx->{source}{foo}, 'Hello, <: "" :>world!'
27 | or diag(explain($tx->{source}));
28 |
29 | note 'from ';
30 | is $tx->render_string('<: 1 + 41 :>'), 42;
31 | is $tx->{source}{''}, '<: 1 + 41 :>';
32 |
33 | done_testing;
34 |
--------------------------------------------------------------------------------
/t/010_internals/032_encoding_error.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More skip_all => 'TODO: the behaviours of PP and XS does not match';
4 | use Text::Xslate;
5 | use File::Path qw(rmtree);
6 | use utf8;
7 |
8 | use lib "t/lib";
9 | use Util;
10 | BEGIN{ rmtree(cache_dir) }
11 | END { rmtree(cache_dir) }
12 |
13 | my $str = 'エクスレイト';
14 | utf8::encode($str);
15 |
16 | my $tx = Text::Xslate->new(
17 | path => [path],
18 | cache_dir => cache_dir,
19 | cache => 0,
20 | );
21 |
22 | diag $tx->render('hello_utf8.tx', { name => $str });
23 | diag $tx->render('hello_utf8.tx', { name => $str });
24 | pass;
25 |
26 | done_testing;
27 |
28 |
--------------------------------------------------------------------------------
/t/010_internals/033_vpath_cache.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use warnings;
4 | use Test::More;
5 | use File::Path qw(rmtree);
6 | use File::Basename;
7 |
8 | use constant CACHE_DIR => basename(__FILE__);
9 | BEGIN { rmtree(CACHE_DIR) }
10 | END { rmtree(CACHE_DIR) }
11 |
12 | use Text::Xslate;
13 |
14 | my $compile_called = 0;
15 | {
16 | package MyEngine;
17 | our @ISA = qw(Text::Xslate);
18 |
19 | sub compile {
20 | my($self, @args) = @_;
21 | ::note 'compile!';
22 | $compile_called++;
23 | return $self->SUPER::compile(@args);
24 | }
25 | }
26 |
27 | my $phase = 0;
28 | foreach my $i(0, 1) {
29 | my %vpath = (
30 | hello => 'hello#' . $i,
31 | );
32 |
33 | my $tx = MyEngine->new(
34 | cache_dir => CACHE_DIR,
35 | path => [\%vpath],
36 | );
37 | foreach my $j(0, 1) {
38 | note "# $i-$j";
39 |
40 | is $tx->render('hello'), 'hello#' . $i;
41 |
42 | if($phase == 0) {
43 | is $compile_called, 1, 'compiling at first time';
44 | }
45 | elsif($phase == 1) {
46 | is $compile_called, 1, 'using cache, not compiled';
47 | }
48 | elsif($phase == 2) {
49 | is $compile_called, 2, 're-compiled because %vpath changed';
50 | }
51 | elsif($phase == 3) {
52 | is $compile_called, 2, 'using cache';
53 | }
54 | else {
55 | fail 'something failed';
56 | }
57 | $phase++;
58 | }
59 | }
60 |
61 | done_testing;
62 |
63 |
--------------------------------------------------------------------------------
/t/010_internals/038_suffix.t:
--------------------------------------------------------------------------------
1 | #!perl
2 | use strict;
3 | use warnings;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 |
8 | BEGIN {
9 | package Text::Xslate::Syntax::Custom;
10 | use Mouse;
11 | extends 'Text::Xslate::Parser';
12 |
13 | sub init_symbols {
14 | my $self = shift;
15 |
16 | $self->SUPER::init_symbols(@_);
17 |
18 | $self->symbol('suffix')->set_nud($self->can('nud_suffix'));
19 | }
20 |
21 | sub nud_suffix {
22 | my $self = shift;
23 | my ($symbol) = @_;
24 |
25 | return $symbol->clone(arity => 'suffix'),
26 | }
27 |
28 | package Text::Xslate::Compiler::Custom;
29 | use Mouse;
30 | extends 'Text::Xslate::Compiler';
31 |
32 | sub _generate_suffix {
33 | my $self = shift;
34 | my ($node) = @_;
35 |
36 | return (
37 | $self->opcode('suffix'),
38 | );
39 | }
40 |
41 | package Text::Xslate::Custom;
42 | use base 'Text::Xslate';
43 |
44 | sub options {
45 | my $class = shift;
46 |
47 | my $options = $class->SUPER::options(@_);
48 |
49 | $options->{compiler} = 'Text::Xslate::Compiler::Custom';
50 | $options->{syntax} = 'Custom';
51 |
52 | return $options;
53 | }
54 | }
55 |
56 | my $tx = Text::Xslate::Custom->new(suffix => '.mustache');
57 |
58 | is(
59 | $tx->render_string(
60 | ': suffix;',
61 | {}
62 | ),
63 | '.mustache',
64 | "got the right suffix"
65 | );
66 |
67 | done_testing;
68 |
--------------------------------------------------------------------------------
/t/010_internals/039_taint_issue84.t:
--------------------------------------------------------------------------------
1 | #!perl -wT
2 |
3 | use strict;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 | use File::Path;
8 | use Scalar::Util qw(tainted);
9 | use Cwd qw(getcwd);
10 |
11 | my $cwd;
12 | my $cache_dir;
13 | tainted($cwd) and die "cwd is tainted";
14 |
15 | BEGIN{
16 | $cwd = getcwd();
17 | if ($cwd =~ /(.+)/) {
18 | $cwd = $1;
19 | }
20 | $cache_dir = $cwd . '/xxx_test_taint_issue84';
21 | }
22 | END{ rmtree($cache_dir) }
23 |
24 | tainted($cache_dir) and die "cache_dir is tainted";
25 |
26 |
27 | for (1 .. 2) {
28 | my $tx = Text::Xslate->new(
29 | path => [$cwd . '/t/template'],
30 | cache_dir => $cache_dir,
31 | cache => 1,
32 | );
33 |
34 | for(1 .. 2) {
35 | is $tx->render('hello.tx', { lang => 'Xslate'}),
36 | "Hello, Xslate world!\n";
37 | utime time()+rand(100), time()+rand(100), "$cwd/t/template/hello.tx";
38 | }
39 | }
40 |
41 | done_testing;
42 |
--------------------------------------------------------------------------------
/t/010_internals/300_explicit_pp.t:
--------------------------------------------------------------------------------
1 | #!perl
2 | # Explicit use of PP version
3 |
4 | use strict;
5 | use Test::More tests => 5;
6 |
7 | BEGIN {
8 | use_ok 'Text::Xslate::PP';
9 | use_ok 'Text::Xslate', qw(escaped_string);
10 | }
11 |
12 |
13 | use B;
14 |
15 | ok( !B::svref_2object(Text::Xslate->can('render'))->XSUB, 'render() is not an xsub' );
16 |
17 | eval {
18 | my $tx = Text::Xslate->new();
19 |
20 | is $tx->render_string('Hello, <: $lang :> world!', { lang => escaped_string('') }),
21 | "Hello, world!";
22 | };
23 | is $@, '';
24 |
25 | done_testing;
26 |
--------------------------------------------------------------------------------
/t/020_interface/002_myparser.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 |
3 | use strict;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 | use lib "t/lib";
8 |
9 | # moniker
10 | my $tx1 = Text::Xslate->new(syntax => 'Foo');
11 | # fq name
12 | my $tx2 = Text::Xslate->new(syntax => 'Text::Xslate::Syntax::Foo');
13 |
14 | my @data = (
15 | ['Hello, <%= $lang %> world!' => 'Hello, Xslate world!'],
16 | ['Hello, <%= $foo %> world!' => 'Hello, <bar> world!'],
17 | [q{foo <%= $lang
18 | %> bar} => "foo Xslate bar"],
19 |
20 | # no default
21 | ['Hello, <: $lang :> world!' => 'Hello, <: $lang :> world!'],
22 | [':= $lang', ':= $lang'],
23 |
24 | # no line code
25 | ['%= $lang', '%= $lang'],
26 | );
27 |
28 | foreach my $pair(@data) {
29 | my($in, $out) = @$pair;
30 | my %vars = (lang => 'Xslate', foo => "");
31 |
32 | is $tx1->render_string($in, \%vars), $out, $in;
33 | is $tx2->render_string($in, \%vars), $out, $in;
34 | }
35 |
36 | done_testing;
37 |
--------------------------------------------------------------------------------
/t/020_interface/004_no_vars.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 |
3 | use strict;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 |
8 | use lib "t/lib";
9 | use Util;
10 |
11 | my $tx = Text::Xslate->new();
12 |
13 | is $tx->render_string("Hello, world!"), "Hello, world!";
14 | is $tx->render_string("Hello, world!", undef), "Hello, world!";
15 |
16 | done_testing;
17 |
--------------------------------------------------------------------------------
/t/020_interface/007_data_section.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 |
3 | use strict;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 | use lib "t/lib";
8 | use Util;
9 |
10 | use File::Path qw(rmtree);
11 |
12 | rmtree(cache_dir);
13 | END{ rmtree(cache_dir) }
14 |
15 | my %vpath = (
16 | 'foo.tx' => 'Hello, <: $lang :> world!',
17 |
18 | 'base.tx' => <<'T',
19 |
20 | <: block body -> { :>default body<: } :>
21 |
22 | T
23 |
24 | 'child.tx' => <<'T',
25 | : cascade base;
26 | : override body -> {
27 | child body
28 | : } # endblock body
29 | T
30 | );
31 |
32 | for my $cache(0 .. 2) {
33 | note "cache => $cache";
34 | my $tx = Text::Xslate->new(
35 | path => [ \%vpath, path ],
36 | cache_dir => cache_dir,
37 | cache => $cache,
38 | );
39 |
40 | is $tx->render('foo.tx', { lang => 'Xslate' }), 'Hello, Xslate world!', "(1)";
41 | is $tx->render('foo.tx', { lang => 'Perl' }), 'Hello, Perl world!', "(2)";
42 |
43 | is $tx->render('child.tx'), <<'X' for 1 .. 2;
44 |
45 | child body
46 |
47 |
48 | X
49 |
50 | is $tx->render('hello.tx', { lang => 'Xslate' }), "Hello, Xslate world!\n", "for real files";
51 |
52 |
53 | # reload
54 | local $vpath{'foo.tx'} = 'Modified';
55 | $tx = Text::Xslate->new(
56 | path => \%vpath,
57 | cache_dir => cache_dir,
58 | cache => $cache,
59 | );
60 | is $tx->render('foo.tx', { lang => 'Xslate' }), 'Modified', 'reloaded';
61 | }
62 |
63 | done_testing;
64 |
--------------------------------------------------------------------------------
/t/020_interface/008_type.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 |
3 | use strict;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 | use lib "t/lib";
8 | use Util;
9 | use File::Path qw(rmtree);
10 |
11 | rmtree(cache_dir);
12 | END{ rmtree(cache_dir) }
13 |
14 | my $tx = Text::Xslate->new(
15 | path => path,
16 | cache_dir => cache_dir,
17 | type => 'text',
18 | );
19 |
20 | my @set = (
21 | [<<'T', { value => "" }, <<'X', 'type => "text"'],
22 | Hello, <: $value :>!
23 | T
24 | Hello, !
25 | X
26 | );
27 |
28 | foreach my $d(@set) {
29 | my($in, $vars, $out, $msg) = @$d;
30 | is $tx->render_string($in, $vars), $out, $msg or diag $in;
31 | }
32 |
33 | is $tx->render('hello.tx', { lang => '' }),
34 | "Hello, world!\n";
35 |
36 | $tx = Text::Xslate->new(
37 | path => path,
38 | cache_dir => cache_dir,
39 | type => 'html',
40 | );
41 | is $tx->render('hello.tx', { lang => '' }),
42 | "Hello, <Xslate> world!\n", "type => 'html'";
43 |
44 | $tx = Text::Xslate->new(
45 | path => path,
46 | cache_dir => cache_dir,
47 | type => 'xml',
48 | );
49 | is $tx->render('hello.tx', { lang => '' }),
50 | "Hello, <Xslate> world!\n", "type => 'xml'";
51 |
52 | done_testing;
53 |
--------------------------------------------------------------------------------
/t/020_interface/009_hash_with_default.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 | use Text::Xslate;
5 | use Text::Xslate::Util qw(hash_with_default);
6 |
7 | my $tx = Text::Xslate->new(
8 | cache => 0,
9 | );
10 |
11 | my $vars = hash_with_default {}, 'FILLME';
12 |
13 | is $tx->render_string(<<'T', $vars), "Hello, FILLME world!\n";
14 | Hello, <: $oops :> world!
15 | T
16 |
17 | is $tx->render_string(<<'T', $vars), "FILLME, FILLME, FILLME\n";
18 | <: $a :>, <: $b :>, <: $c :>
19 | T
20 |
21 | $vars = hash_with_default {}, sub { "FILLME/@_" };
22 |
23 | is $tx->render_string(<<'T', $vars), "Hello, FILLME/oops world!\n";
24 | Hello, <: $oops :> world!
25 | T
26 |
27 | is $tx->render_string(<<'T', $vars), "FILLME/a, FILLME/b, FILLME/c\n";
28 | <: $a :>, <: $b :>, <: $c :>
29 | T
30 |
31 | done_testing;
32 |
33 |
--------------------------------------------------------------------------------
/t/020_interface/010_err_encoding.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 | use Text::Xslate;
5 | use lib "t/lib";
6 | use Util;
7 | use utf8;
8 |
9 | binmode Test::More->builder->output, ":utf8";
10 | binmode Test::More->builder->failure_output, ":utf8";
11 | binmode Test::More->builder->todo_output, ":utf8";
12 |
13 | my $warn = '';
14 |
15 | my $tx = Text::Xslate->new(
16 | cache => 0,
17 | path => [path],
18 | verbose => 2,
19 | warn_handler => sub {
20 | $warn .= "@_";
21 | },
22 | );
23 |
24 | like $tx->render('hello_utf8.tx'), qr/こんにちは/;
25 | like $warn, qr/こんにちは/;
26 |
27 | eval {
28 | $tx->render_string('<: こんにちは'); # syntax error
29 | };
30 | note $@;
31 | like $@, qr/\<\: こんにちは/, 'wide characters in error messages';
32 |
33 | done_testing;
34 |
35 |
--------------------------------------------------------------------------------
/t/020_interface/011_hwd_w_include_vars.t:
--------------------------------------------------------------------------------
1 | #!perl
2 | use strict;
3 | use warnings;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 | use Text::Xslate::Util qw(hash_with_default);
8 |
9 | my $tx = Text::Xslate->new(
10 | path => [{ 'dish.tx' => '{[% food %]}' } ],
11 | cache => 0,
12 | syntax => 'TTerse',
13 | verbose => 2,
14 | );
15 |
16 | my $_var = { food => 'rakkyo' };
17 | my $var;
18 | my $tmpl =<render_string($tmpl, $var), '{gyoza}';
27 |
28 | $var = hash_with_default($_var, sub { qq{*FILLME ($_[0])*} });
29 | is $tx->render_string($tmpl, $var), '{gyoza}';
30 |
31 | done_testing;
32 |
33 |
--------------------------------------------------------------------------------
/t/020_interface/012_default_functions.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 | use Text::Xslate;
5 |
6 | {
7 | package MyXslate;
8 | use parent qw(Text::Xslate);
9 |
10 | sub default_functions {
11 | return {
12 | foo => sub { 'bar' },
13 | blessed => sub { 42 },
14 | };
15 | }
16 | }
17 |
18 | my $tx = MyXslate->new(
19 | module => [qw(Scalar::Util) => [qw(blessed)]],
20 | );
21 |
22 | is $tx->render_string('<: foo() :>'), 'bar';
23 | is $tx->render_string('<: blessed($o) :>', { o => bless {}, 'XYZ' }), 'XYZ';
24 |
25 |
26 | done_testing;
27 |
28 |
--------------------------------------------------------------------------------
/t/020_interface/013_slurp_template.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use utf8;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 | use Encode ();
8 |
9 | use File::Path qw(rmtree);
10 | use lib "t/lib";
11 | use Util;
12 | rmtree(cache_dir);
13 | END{ rmtree(cache_dir) }
14 |
15 | {
16 | package MyTemplate;
17 | our @ISA = qw(Text::Xslate);
18 |
19 | sub slurp_template {
20 | my($self, $input_layer, $fullpath) = @_;
21 |
22 | my $content = $self->SUPER::slurp_template($input_layer, $fullpath);
23 | return Encode::encode('cp932', $content);
24 | }
25 | }
26 |
27 | my $p = Encode::encode('cp932', 'エクスレート');
28 |
29 | for(1 .. 2) {
30 | my $tx = MyTemplate->new(
31 | path => [path],
32 | cache_dir => cache_dir,
33 | );
34 |
35 |
36 | is $tx->render('hello_utf8.tx', { name => $p }),
37 | Encode::encode('cp932', "こんにちは! エクスレート!\n");
38 |
39 | is $tx->render('hello_utf8.tx', { name => $p }),
40 | Encode::encode('cp932', "こんにちは! エクスレート!\n");
41 | }
42 | done_testing;
43 |
44 |
45 |
--------------------------------------------------------------------------------
/t/020_interface/015_render_recursion.t:
--------------------------------------------------------------------------------
1 | #!perl
2 | # recursive call of render()
3 | # related to issue #65 but there are no problems.
4 | #
5 | use strict;
6 | use warnings;
7 | use Test::More;
8 |
9 | use Text::Xslate;
10 |
11 | my %vpath = (
12 | foo => <<'T',
13 | : for [42] -> $i {
14 | : render('bar');
15 | : }
16 | T
17 |
18 | bar => <<'T',
19 | Hello, world!
20 | T
21 | );
22 |
23 | my $tx;
24 | $tx = Text::Xslate->new(
25 | cache => 0,
26 | path => [\%vpath],
27 |
28 | function => {
29 | render => sub {
30 | return $tx->render(@_);
31 | },
32 | },
33 | );
34 |
35 | is $tx->render('foo'), "Hello, world!\n";
36 |
37 | done_testing;
38 |
39 |
--------------------------------------------------------------------------------
/t/020_interface/016_pre_process_handler.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use utf8;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 | use Encode ();
8 |
9 | use File::Path qw(rmtree);
10 | use lib "t/lib";
11 | use Util;
12 | rmtree(cache_dir);
13 | END{ rmtree(cache_dir) }
14 |
15 | my $p = Encode::encode('cp932', 'エクスレート');
16 |
17 | for(1 .. 2) {
18 | my $tx = Text::Xslate->new(
19 | path => [path],
20 | cache_dir => cache_dir,
21 | pre_process_handler => sub { Encode::encode('cp932', $_[0]) },
22 | );
23 |
24 |
25 | is $tx->render('hello_utf8.tx', { name => $p }),
26 | Encode::encode('cp932', "こんにちは! エクスレート!\n");
27 |
28 | is $tx->render('hello_utf8.tx', { name => $p }),
29 | Encode::encode('cp932', "こんにちは! エクスレート!\n");
30 | }
31 | done_testing;
32 |
--------------------------------------------------------------------------------
/t/020_interface/017_validate.t:
--------------------------------------------------------------------------------
1 | #!perl
2 | use strict;
3 | use warnings;
4 | use Test::More;
5 | use File::Temp qw(tempdir);
6 |
7 | use Text::Xslate;
8 |
9 | my %vpath = (
10 | ok0 => <<'T',
11 | Hello, world!
12 | T
13 |
14 | ok1=> <<'T',
15 | Hello, <: $xslate :> world!
16 | T
17 |
18 | ng0=> <<'T',
19 | Hello, <: $xslate world!
20 | T
21 |
22 | ng1=> <<'T',
23 | Hello, <: $xslate ??? :> world!
24 | T
25 | );
26 |
27 | my $tx = Text::Xslate->new(
28 | path => [\%vpath],
29 | cache_dir => tempdir(CLEANUP => 1),
30 | );
31 |
32 | foreach my $name (qw(ok0 ok1)) {
33 | eval { $tx->validate($name) };
34 | ok !$@, $name;
35 | note $@ if $@;
36 | }
37 |
38 | foreach my $name (qw(ng0 ng1)) {
39 | eval { $tx->validate($name) };
40 | ok $@, $name;
41 | note $@ if $@;
42 | }
43 |
44 | done_testing;
45 |
--------------------------------------------------------------------------------
/t/030_kolon/001_interpolate.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use Text::Xslate;
6 | use Text::Xslate::Util qw(p);
7 |
8 | my $tx = Text::Xslate->new();
9 |
10 | my @data = (
11 | ['Hello, world!' => 'Hello, world!'],
12 | ['Hello, <: $lang :> world!' => 'Hello, Xslate world!'],
13 | ['Hello, <: $foo :> world!' => 'Hello, <bar> world!'],
14 | ['<: $lang :> <: $foo :> <: $lang :> <: $foo :>' => 'Xslate <bar> Xslate <bar>'],
15 | [q{<:$lang:>}, 'Xslate'],
16 | [q{foo <:= $lang
17 | :> bar} => "foo Xslate bar"],
18 | [q{<: print $lang :>} => "Xslate"],
19 | [q{<:print $lang:>} => "Xslate"],
20 | [q{<:print$lang:>} => "Xslate"],
21 | [q{<:print $lang, "\n":>} => "Xslate\n"],
22 |
23 | [q{<:print "<", $lang, ">":>} => "<Xslate>"],
24 | [q{<:print_raw "<", $lang, ">":>} => ""],
25 | );
26 |
27 | my %vars = (lang => 'Xslate', foo => "");
28 | my $vars_str = p(\%vars);
29 | foreach my $pair(@data) {
30 | my($in, $out) = @$pair;
31 |
32 | #diag $in;
33 | is $tx->render_string($in, \%vars), $out or diag $in;
34 |
35 | is p(\%vars), $vars_str, 'vars are not changed';
36 | }
37 |
38 | done_testing;
39 |
--------------------------------------------------------------------------------
/t/030_kolon/009_include.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 |
3 | use strict;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 | use lib "t/lib";
8 | use Util;
9 |
10 | my $tx = Text::Xslate->new(cache => 0, path => [path]);
11 |
12 | for(1 .. 2) { # to test including depth
13 | for(1 .. 100){
14 | is $tx->render('include.tx', { lang => "Xslate" }),
15 | "include:\n" . "Hello, Xslate world!\n", "index.tx ($_)";
16 |
17 | is $tx->render('include2.tx', { file => "hello.tx", lang => "Xslate" }),
18 | "include2:\n" . "Hello, Xslate world!\n", 'index2.tx (literal)';
19 |
20 | is $tx->render('include2.tx', { file => "include.tx", lang => "Xslate" }),
21 | "include2:\n" . "include:\n" . "Hello, Xslate world!\n", 'index2.tx (var)';
22 | }
23 |
24 | eval {
25 | $tx->render('include2.tx', { file => "include2.tx", lang => "Xslate" });
26 | };
27 | like $@, qr/\bXslate\b/xms, "recursion";
28 | like $@, qr/too \s+ deep/xms, "recursion";
29 | }
30 |
31 | done_testing;
32 |
--------------------------------------------------------------------------------
/t/030_kolon/013_more_field.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use Text::Xslate;
6 |
7 | my $tx = Text::Xslate->new();
8 |
9 | my @data = (
10 | ['<:= $var[ $foo && "bar" ] :>', 'BAR'],
11 | ['<:= $var[ $foo || "bar" ] :>', 'FOO'],
12 |
13 | ['<:= $var[ "foo" && "bar" ] :>', 'BAR'],
14 | ['<:= $var[ "foo" || "bar" ] :>', 'FOO'],
15 |
16 | ['<:= $var[ $foo == "foo" ? "bar" : "baz" ] :>', 'BAR'],
17 | ['<:= $var[ $foo != "foo" ? "bar" : "baz" ] :>', 'BAZ'],
18 |
19 | ['<:= $ary[ 0+0 ] :>', 10],
20 | ['<:= $ary[ 0+1 ] :>', 20],
21 | ['<:= $ary[ 1+1 ] :>', 30],
22 |
23 | ['<:= $ary[ 0-0 ] :>', 10],
24 | ['<:= $ary[ 2-1 ] :>', 20],
25 | ['<:= $ary[ 3-1 ] :>', 30],
26 |
27 | ['<:= $ary[ +0 ] :>', 10],
28 | ['<:= $ary[ -0 ] :>', 10],
29 |
30 | ['<:= $ary[ +0.0 ] :>', 10],
31 | ['<:= $ary[ -0.0 ] :>', 10],
32 |
33 | ['<:= $var[ $ary[3] ] :>', "FOO"],
34 | );
35 |
36 | foreach my $pair(@data) {
37 | my($in, $out) = @$pair;
38 |
39 | my %vars = (
40 | var => { foo => 'FOO', bar => 'BAR', baz => "BAZ" },
41 |
42 | ary => [10, 20, 30, "foo"],
43 |
44 | foo => 'foo',
45 | );
46 |
47 | is $tx->render_string($in, \%vars), $out or diag $in;
48 | }
49 |
50 | done_testing;
51 |
--------------------------------------------------------------------------------
/t/030_kolon/018_dynamic_filters.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use Text::Xslate;
6 |
7 | use FindBin qw($Bin);
8 |
9 | sub mk_indent {
10 | my($prefix) = @_;
11 |
12 | return sub {
13 | my($str) = @_;
14 | $str =~ s/^/$prefix/xmsg;
15 | return $str;
16 | }
17 | }
18 |
19 | my $tx = Text::Xslate->new(
20 | function => {
21 | indent => \&mk_indent,
22 | },
23 | );
24 |
25 | my @set = (
26 | [ q{<: $value | indent("> ") :>}, { value => 'Xslate' }
27 | => '> Xslate' ],
28 |
29 | [ q{<: $value | indent("> ") :>}, { value => "Xslate\nPerl\n" }
30 | => "> Xslate\n> Perl\n" ],
31 |
32 | [ q{: $value | indent("| ") }, { value => "Xslate\nPerl\n" }
33 | => "| Xslate\n| Perl\n" ],
34 |
35 | [ q{: indent("* ")($value) }, { value => "Xslate\nPerl\n" }
36 | => "* Xslate\n* Perl\n" ],
37 | );
38 |
39 | foreach my $d(@set) {
40 | my($in, $vars, $out, $msg) = @$d;
41 | is $tx->render_string($in, $vars), $out, $msg or diag $in;;
42 | }
43 |
44 | done_testing;
45 |
--------------------------------------------------------------------------------
/t/030_kolon/019_explicit_interpolate.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use Text::Xslate;
6 |
7 | my $tx = Text::Xslate->new();
8 |
9 | my @data = (
10 | ['Hello, world!' => 'Hello, world!'],
11 | ['Hello, <:= $lang :> world!' => 'Hello, Xslate world!'],
12 | ['Hello, <:= $foo :> world!' => 'Hello, <bar> world!'],
13 | ['<:= $lang :> <:= $foo :> <:= $lang :> <:= $foo :>' => 'Xslate <bar> Xslate <bar>'],
14 | [q{foo <:= $lang
15 | :> bar} => "foo Xslate bar"],
16 | [q{<: print $lang :>} => "Xslate"],
17 | [q{<:print $lang:>} => "Xslate"],
18 | [q{<:print $lang, "\n":>} => "Xslate\n"],
19 | [q{<:print "<", $lang, ">":>} => "<Xslate>"],
20 | [q{<:print_raw "<", $lang, ">":>} => ""],
21 |
22 | ['<:= "foo\tbar\n" :>', "foo\tbar\n"],
23 | [q{<:= 'foo\tbar\n' :>}, 'foo\tbar\n'],
24 | [q{<:= ' & " \' ' :>}, ' & " ' '],
25 |
26 | [q{foo<:# this is a comment :>bar}, "foobar"],
27 | [q{<:=$lang:> foo<:# this is a comment :>bar <:=$lang:>}, "Xslate foobar Xslate"],
28 | [q{foo<:
29 | :>bar}, "foobar"],
30 | [q{foo<: # this is a comment
31 | $lang :>bar}, "fooXslatebar"],
32 | );
33 |
34 | foreach my $pair(@data) {
35 | my($in, $out) = @$pair;
36 | my %vars = (lang => 'Xslate', foo => "");
37 |
38 | is $tx->render_string($in, \%vars), $out or diag $in;
39 | }
40 |
41 | done_testing;
42 |
--------------------------------------------------------------------------------
/t/030_kolon/020_chomp.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use Text::Xslate;
6 |
7 | my $tx = Text::Xslate->new();
8 |
9 | my @data = (
10 | [<<'T', "A[foo]\nB\n", "prechomp(1)"],
11 | A
12 | <:- "[foo]" :>
13 | B
14 | T
15 |
16 | [<<'T', " A[foo]\n B\n", "prechomp(2)"],
17 | A
18 | <:- "[foo]" :>
19 | B
20 | T
21 |
22 | [<<'T', "A\n[foo]B\n", "postchomp(1)"],
23 | A
24 | <: "[foo]" -:>
25 | B
26 | T
27 |
28 | [<<'T', " A\n [foo] B\n", "postchomp(2)"],
29 | A
30 | <: "[foo]" -:>
31 | B
32 | T
33 |
34 |
35 | [<<'T', "A[foo]B\n", "both(1)"],
36 | A
37 | <:- "[foo]" -:>
38 | B
39 | T
40 |
41 | [<<'T', " A[foo] B\n", "both(2)"],
42 | A
43 | <:- "[foo]" -:>
44 | B
45 | T
46 |
47 | );
48 |
49 | foreach my $pair(@data) {
50 | my($in, $out, $msg) = @$pair;
51 | my %vars = (lang => 'Xslate', foo => "");
52 | is $tx->render_string($in, \%vars), $out, $msg or diag $in;
53 | }
54 |
55 | done_testing;
56 |
--------------------------------------------------------------------------------
/t/030_kolon/023_bitwise.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use Text::Xslate;
6 |
7 | my $tx = Text::Xslate->new();
8 |
9 | my @data = (
10 | ['<: 0x011 +| 0x100 :>', 0x111 ],
11 | ['<: $value0 +| 0x111 :>', 0x111 ],
12 | ['<: $value0x201 +| 0x111 :>', 0x311 ],
13 | ['<: 0x111 +| $value0x201 :>', 0x311 ],
14 |
15 | ['<: 0x011 +& 0x010 :>', 0x010 ],
16 | ['<: $value0 +& 0x111 :>', 0x000 ],
17 | ['<: $value0x201 +& 0x111 :>', 0x001 ],
18 | ['<: 0x111 +& $value0x201 :>', 0x001 ],
19 |
20 | ['<: 0x00101 +^ 0x00100 :>', 0x00001 ],
21 | ['<: 0x10100 +^ 0x10000 :>', 0x00100 ],
22 | ['<: $value0 +^ 0x111 :>', 0x111 ],
23 | ['<: $value0x201 +^ 0x111 :>', 0x310 ],
24 | ['<: 0x111 +^ $value0x201 :>', 0x310 ],
25 |
26 | ['<: +^0 :>', ~0, 'const'],
27 | ['<: +^0x201 :>', ~0x201, 'const'],
28 | ['<: +^$value0 :>', ~0, 'var'],
29 | ['<: +^$value0x201 :>', ~0x201, 'var'],
30 | );
31 |
32 | my %vars = (
33 | value0 => 0,
34 | value0x201 => 0x201,
35 | );
36 | foreach my $d(@data) {
37 | my($in, $out, $msg) = @$d;
38 |
39 | is $tx->render_string($in, \%vars), $out, $msg
40 | or diag $in;
41 | }
42 |
43 | done_testing;
44 |
--------------------------------------------------------------------------------
/t/030_kolon/027_lambda.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 |
3 | use strict;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 | use Text::Xslate::Compiler;
8 | use Text::Xslate::Util qw(p);
9 |
10 | my $tx = Text::Xslate->new();
11 |
12 | my @set = (
13 | [<<'T', {}, <<'X'],
14 | <: -> $x { $x + 10 }(0) :>
15 | <: -> $x { $x + 10 }(1) :>
16 | <: -> $x { $x + 10 }(2) :>
17 | T
18 | 10
19 | 11
20 | 12
21 | X
22 | [<<'T', {}, <<'X'],
23 | <: my $y = 10; -> $x { $x + $y }(15) :>
24 | T
25 | 25
26 | X
27 |
28 | [<<'T', {}, <<'X'],
29 | <: my $add10 = -> $x { $x + 10 }; $add10(20) :>
30 | T
31 | 30
32 | X
33 |
34 | [<<'T', {}, <<'X'],
35 | <: constant add10 = -> $x { $x + 10 }; add10(20) :>
36 | T
37 | 30
38 | X
39 |
40 | [<<'T', {}, <<'X'],
41 | : for [1, 2, 3] -> $v {
42 | <: my $addv = -> $x { $x + $v }; $addv(20) :>
43 | : }
44 | T
45 | 21
46 | 22
47 | 23
48 | X
49 |
50 |
51 | );
52 |
53 | foreach my $d(@set) {
54 | my($in, $vars, $out, $msg) = @$d;
55 |
56 | is $tx->render_string($in, $vars), $out, $msg
57 | or diag($in);
58 | }
59 |
60 |
61 | done_testing;
62 |
--------------------------------------------------------------------------------
/t/030_kolon/030_xfuncs.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use Text::Xslate;
6 |
7 | my $tx = Text::Xslate->new(
8 | function => {
9 | 'array::count' => sub {
10 | my($a, $cb) = @_;
11 | return scalar grep { $cb->($_) } @{$a};
12 | },
13 | },
14 | );
15 |
16 | my @data = (
17 | [<<'T', <<'X'],
18 | : macro upper50 -> $x { $x >= 50 }
19 | <: $a.count(upper50) :>
20 | T
21 | 50
22 | X
23 | [<<'T', <<'X'],
24 | <: $a.count(-> $x { $x >= 0 }) :>
25 | <: $a.count(-> $x { $x >= 50 }) :>
26 | <: $a.count(-> $x { $x >= 100 }) :>
27 | <: $a.count(-> $x { $x == nil }) :>
28 | <: $a.count(-> $x { $x == 42 }) :>
29 | T
30 | 100
31 | 50
32 | 0
33 | 0
34 | 1
35 | X
36 | );
37 |
38 | my %vars = (
39 | a => [ 0 .. 99 ],
40 | );
41 | foreach my $d(@data) {
42 | my($in, $out, $msg) = @$d;
43 |
44 | is $tx->render_string($in, \%vars), $out, $msg
45 | or diag $in;
46 | }
47 |
48 | done_testing;
49 |
--------------------------------------------------------------------------------
/t/030_kolon/031_post_if.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use Text::Xslate;
6 | use lib "t/lib";
7 | use Util;
8 |
9 | my $tx = Text::Xslate->new(
10 | cache => 0,
11 | path => [path],
12 | );
13 |
14 | my @data = (
15 | [<<'T', <<'X'],
16 | [<: "foo" if true :>]
17 | T
18 | [foo]
19 | X
20 |
21 | [<<'T', <<'X'],
22 | [<: "foo" if false :>]
23 | T
24 | []
25 | X
26 |
27 | [<<'T', <<'X'],
28 | [<: "foo" if $a[0] == 0 :>]
29 | T
30 | [foo]
31 | X
32 |
33 | [<<'T', <<'X'],
34 | [<: "foo" if $a[0] == 1 :>]
35 | T
36 | []
37 | X
38 |
39 | [<<'T', <<'X', 'include-if'],
40 | : include "hello.tx" if true
41 | : include "hello.tx" if true
42 | T
43 | Hello, Xslate world!
44 | Hello, Xslate world!
45 | X
46 |
47 | [<<'T', <<'X'],
48 | : include "hello.tx" if false
49 | : include "hello.tx" if false
50 | T
51 | X
52 |
53 | );
54 |
55 | my %vars = (
56 | lang => 'Xslate',
57 | a => [ 0 .. 99 ],
58 | );
59 | foreach my $d(@data) {
60 | my($in, $out, $msg) = @$d;
61 |
62 | is $tx->render_string($in, \%vars), $out, $msg
63 | or diag $in;
64 | }
65 |
66 | done_testing;
67 |
--------------------------------------------------------------------------------
/t/030_kolon/032_include_bareword.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 | use Text::Xslate;
5 |
6 | my %vpath = (
7 | 'hello.tx' => 'Hello, world!',
8 | );
9 |
10 | my $tx = Text::Xslate->new(
11 | path => \%vpath,
12 | cache => 0,
13 | );
14 |
15 | is $tx->render('hello.tx'), 'Hello, world!';
16 | is $tx->render_string(<render_string(< 'Hello, world!',
26 | );
27 |
28 | $tx = Text::Xslate->new(
29 | path => \%vpath,
30 | cache => 0,
31 | suffix => '.html',
32 | );
33 |
34 | is $tx->render_string(<new(
8 | function => {
9 | myprint => sub { Text::Xslate->print(@_) },
10 | mysay => sub { Text::Xslate->print(@_, "\n") },
11 | },
12 |
13 | warn_handler => sub { Text::Xslate->print(@_) },
14 | verbose => 2,
15 | );
16 |
17 | is $tx->render_string('[<: myprint() :>]'), '[]';
18 | is $tx->render_string('[<: myprint("") :>]'),
19 | '[<foo>]';
20 | is $tx->render_string('[<: myprint("", "") :>]'),
21 | '[<foo><bar>]';
22 |
23 | is $tx->render_string('[<: mysay() :>]'), "[\n]";
24 | is $tx->render_string('[<: mysay("") :>]'),
25 | "[<foo>\n]";
26 | is $tx->render_string('[<: mysay("", "") :>]'),
27 | "[<foo><bar>\n]";
28 |
29 | like $tx->render_string("<: nil :>"), qr/nil/;
30 | like $tx->render_string("<: nil :>"), qr/<string>/;
31 |
32 | done_testing;
33 |
34 |
--------------------------------------------------------------------------------
/t/030_kolon/035_include_w_vars.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 |
3 | use strict;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 |
8 | my %vpath = (
9 | foo => ': include "bar" { $baz }',
10 | bar => 'Hello, <: $lang :> world!',
11 | );
12 |
13 | my $tx = Text::Xslate->new(
14 | cache => 0,
15 | path => \%vpath,
16 | verbose => 2,
17 | warn_handler => sub { die @_ },
18 | );
19 |
20 | is $tx->render(foo => { baz => { lang => 'Xslate' } }),
21 | 'Hello, Xslate world!';
22 |
23 | is $tx->render(foo => { baz => { lang => 'Template' } }),
24 | 'Hello, Template world!';
25 |
26 | is $tx->render_string(':include "bar" { $baz }; $lang',
27 | { baz => { lang => 'Xslate' }, lang => '!!' }),
28 | 'Hello, Xslate world!!!';
29 |
30 | is $tx->render_string(':include "bar" { $baz.merge({ lang => "Xslate"}) }; $lang',
31 | { baz => { }, lang => '!!' }),
32 | 'Hello, Xslate world!!!';
33 |
34 | eval { $tx->render_string(': include "bar" { a => 42, "b" }' ) };
35 | like $@, qr/pairs/;
36 |
37 | eval { $tx->render_string(': include "bar" { 42 }' ) };
38 | like $@, qr/must be a HASH reference/;
39 |
40 | eval { $tx->render('foo', { baz => { }, lang => 'XXX'} ) };
41 | like $@, qr/nil/;
42 |
43 | done_testing;
44 |
--------------------------------------------------------------------------------
/t/030_kolon/036_foreach_else.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 |
3 | use strict;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 |
8 | my %vpath = (
9 | );
10 |
11 | my $tx = Text::Xslate->new(
12 | cache => 0,
13 | path => \%vpath,
14 | verbose => 2,
15 | warn_handler => sub { die @_ },
16 | );
17 |
18 | is $tx->render_string(<<'T'), <<'X';
19 | : for [42] -> $it {
20 | * <:$it:>
21 | : }
22 | : else {
23 | nothing
24 | : }
25 | T
26 | * 42
27 | X
28 |
29 | is $tx->render_string(<<'T'), <<'X';
30 | : for [] -> $it {
31 | * <:$it:>
32 | : }
33 | : else {
34 | nothing
35 | : }
36 | T
37 | nothing
38 | X
39 |
40 | is $tx->render_string(<<'T'), <<'X';
41 | : for nil -> $it {
42 | * <:$it:>
43 | : }
44 | : else {
45 | nothing
46 | : }
47 | T
48 | nothing
49 | X
50 |
51 | done_testing;
52 |
--------------------------------------------------------------------------------
/t/030_kolon/037_loop_ctl.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 |
3 | use strict;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 |
8 | my %vpath = (
9 | );
10 |
11 | my $tx = Text::Xslate->new(
12 | cache => 0,
13 | path => \%vpath,
14 | verbose => 2,
15 | warn_handler => sub { die @_ },
16 | );
17 |
18 | note 'for';
19 | is $tx->render_string(<<'T'), <<'X' or die;
20 | : for [42, 43, 44] -> $it {
21 | : last if $it == 43;
22 | * <:$it:>
23 | : }
24 | : else {
25 | nothing
26 | : }
27 | T
28 | * 42
29 | X
30 |
31 | is $tx->render_string(<<'T'), <<'X' or die;
32 | : for [42, 43, 44] -> $it {
33 | : next if $it == 43;
34 | * <:$it:>
35 | : }
36 | : else {
37 | nothing
38 | : }
39 | T
40 | * 42
41 | * 44
42 | X
43 |
44 | note 'while';
45 | my $iter = do{ my @a = (42, 43, 44); sub { shift @a } };
46 | is $tx->render_string(<<'T', { iter => $iter }), <<'X';
47 | : while $iter() -> $it {
48 | : next if $it == 43;
49 | * <:$it:>
50 | : }
51 | T
52 | * 42
53 | * 44
54 | X
55 |
56 | $iter = do{ my @a = (42, 43, 44); sub { shift @a } };
57 | is $tx->render_string(<<'T', { iter => $iter }), <<'X';
58 | : while $iter() -> $it {
59 | : last if $it == 43;
60 | * <:$it:>
61 | : }
62 | T
63 | * 42
64 | X
65 |
66 | $iter = do{ my @a = (42, 43, 44); sub { shift @a } };
67 | is $tx->render_string(<<'T', { iter => $iter }), <<'X';
68 | : while $iter() -> $it {
69 | * <:$it:>
70 | : last if $it == 43;
71 | : }
72 | T
73 | * 42
74 | * 43
75 | X
76 |
77 | eval { $tx->render_string(': last') };
78 | like $@, qr/Use of loop control statement \(last\)/;
79 |
80 | eval { $tx->render_string(': next') };
81 | like $@, qr/Use of loop control statement \(next\)/;
82 |
83 | done_testing;
84 |
--------------------------------------------------------------------------------
/t/030_kolon/039_root_vars.t:
--------------------------------------------------------------------------------
1 | #!perl
2 | use strict;
3 | use warnings;
4 | use Test::More;
5 | use Text::Xslate;
6 |
7 | my $tx = Text::Xslate->new();
8 |
9 | is $tx->render_string('<: __ROOT__["foo"] :>', { foo => 42 }), '42';
10 | is $tx->render_string('<: __ROOT__.foo :>', { foo => 42 }), '42';
11 |
12 | is $tx->render_string(
13 | '<: __ROOT__.merge({ foo => "bar"}).foo ~ __ROOT__.foo :>', { foo => 42 }),
14 | 'bar42';
15 |
16 | done_testing;
17 |
18 |
--------------------------------------------------------------------------------
/t/030_kolon/040_external_macro.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | #
3 | # global macros
4 | #
5 | use strict;
6 | use Test::More skip_all => 'external macros are not yet implemented';
7 |
8 | use Text::Xslate;
9 |
10 | my %vpath = (
11 | 'macro/common.tx' => <<'T',
12 | : macro hello -> {
13 | Hello, world!
14 | : }
15 | T
16 |
17 | 'foo.tx' => <<'T',
18 | : import macro::common;
19 | : hello()
20 | T
21 | );
22 |
23 | my $tx = Text::Xslate->new(
24 | path => \%vpath,
25 | );
26 |
27 | is $tx->render('foo.tx'), "Hello, world!\n";
28 |
29 | done_testing;
30 |
31 |
--------------------------------------------------------------------------------
/t/040_tterse/001_parse.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use Text::Xslate::Syntax::TTerse;
6 | use Text::Xslate::Util qw(p);
7 |
8 | my $parser = Text::Xslate::Syntax::TTerse->new();
9 |
10 | my @data = (
11 | ['Hello, world!' => qr/Hello, world!/],
12 | ['Hello, [% lang %] world!' => qr/Hello/, qr/\b lang \b/xms, qr/world/],
13 | ['Hello, [% foo %] world!' => qr/\b foo \b/xms],
14 | ['Hello, [% lang %] [% foo %] world!', qr/\b lang \b/xms, qr/\b foo \b/xms],
15 |
16 | [<<'T', qr/\b foo \b/xms, qr/\b if \b/xms],
17 | [% IF foo %]
18 | This is true
19 | [% END %]
20 | T
21 | [<<'T', qr/\b foo \b/xms, qr/\b if \b/xms],
22 | [% IF foo %]
23 | This is true
24 | [% ELSE %]
25 | This is false
26 | [% END %]
27 | T
28 |
29 | [<<'T', qr/\b item \b/xms, qr/\b foo \b/xms, qr/\b for \b/xms],
30 | [% FOREACH item IN foo %]
31 | This is true
32 | [% END %]
33 | T
34 |
35 | );
36 |
37 | foreach my $d(@data) {
38 | my($str, @patterns) = @{$d};
39 |
40 | #note($str);
41 | my $code = p($parser->parse($str));
42 | #note($code);
43 |
44 | foreach my $pat(@patterns) {
45 | like $code, $pat;
46 | }
47 | }
48 |
49 | done_testing;
50 |
--------------------------------------------------------------------------------
/t/040_tterse/002_interpolate.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use lib "t/lib";
6 | use TTSimple;
7 |
8 | my @data = (
9 | ['Hello, world!' => 'Hello, world!'],
10 | ['Hello, [% lang %] world!' => 'Hello, Xslate world!'],
11 | ['Hello, [% foo %] world!' => 'Hello, <bar> world!'],
12 | ['Hello, [% lang %] [% foo %] world!'
13 | => 'Hello, Xslate <bar> world!'],
14 |
15 | ['Hello, [% $lang %] world!' => 'Hello, Xslate world!'],
16 | ['Hello, [% ${lang} %] world!' => 'Hello, Xslate world!'],
17 | ['Hello, [% ${ lang } %] world!' => 'Hello, Xslate world!'],
18 |
19 | ['Hello, [% $no_such_field %] world!' => 'Hello, world!', 'nil as empty'],
20 | ['Hello, [% $no_such_field or "Default" %] world!' => 'Hello, Default world!', 'empty or default'],
21 |
22 | ['[% $IF %]', 'This is IF' ],
23 | ['[% +IF %]', 'This is IF' ],
24 |
25 | ['[% GET lang %]', 'Xslate'],
26 | ['[% get lang %]', 'Xslate'],
27 | ['[% get IF %]', 'This is IF'],
28 | );
29 |
30 | my %vars = (
31 | lang => 'Xslate',
32 | foo => "",
33 | '$lang' => 'XXX',
34 | IF => 'This is IF',
35 | );
36 |
37 | foreach my $pair(@data) {
38 | my($in, $out, $msg) = @$pair;
39 |
40 | is render_str($in, \%vars), $out, $msg
41 | or diag $in;
42 | }
43 |
44 | done_testing;
45 |
--------------------------------------------------------------------------------
/t/040_tterse/006_include.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 |
3 | use strict;
4 | use Test::More;
5 |
6 | use lib "t/lib";
7 | use TTSimple;
8 |
9 | is render_file('include.tt', { lang => "Xslate" }),
10 | "include:\n" . "Hello, Xslate world!\n";
11 |
12 | is render_file('include2.tt', { file => "hello.tt", lang => "Xslate" }),
13 | "include2:\n" . "Hello, Xslate world!\n";
14 |
15 | is render_file('include2.tt', { file => "include.tt", lang => "Xslate" }),
16 | "include2:\n" . "include:\n" . "Hello, Xslate world!\n";
17 |
18 | is render_str(<<'T', { lang => "Xslate" }), <<'X';
19 | [% INCLUDE "hello.tt" WITH lang = "TTerse" -%]
20 | Hello, [% lang %] world!
21 | T
22 | Hello, TTerse world!
23 | Hello, Xslate world!
24 | X
25 |
26 | is render_str(<<'T', { lang => "Xslate" }), <<'X';
27 | [% INCLUDE "hello.tt" WITH
28 | pi = 3.14
29 | lang = "TTerse" -%]
30 | Hello, [% lang %] world!
31 | T
32 | Hello, TTerse world!
33 | Hello, Xslate world!
34 | X
35 |
36 | is render_str(<<'T', { lang => "Xslate" }), <<'X';
37 | [% INCLUDE "hello.tt" WITH pi = 3.14, lang = "TTerse" -%]
38 | Hello, [% lang %] world!
39 | T
40 | Hello, TTerse world!
41 | Hello, Xslate world!
42 | X
43 |
44 | is render_str(<<'T', { lang => "Xslate" }), <<'X', 'lower-cased';
45 | [% include "hello.tt" with pi = 3.14, lang = "TTerse" -%]
46 | Hello, [% lang %] world!
47 | T
48 | Hello, TTerse world!
49 | Hello, Xslate world!
50 | X
51 |
52 | #is render_str(<<'T', { lang => "Xslate" }), <<'X', 'WITH is optional';
53 | #[% INCLUDE "hello.tt" pi = 3.14, lang = "TTerse" -%]
54 | #Hello, [% lang %] world!
55 | #T
56 | #Hello, TTerse world!
57 | #Hello, Xslate world!
58 | #X
59 |
60 | done_testing;
61 |
--------------------------------------------------------------------------------
/t/040_tterse/008_methods.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use Text::Xslate;
6 |
7 | my $tx = Text::Xslate->new(
8 | syntax => 'TTerse',
9 | cache => 0,
10 | );
11 |
12 | {
13 | package Obj;
14 | use Mouse;
15 |
16 | sub join :method {
17 | my($self, $sep, @args) = @_;
18 | return join $sep, @args;
19 | }
20 |
21 | sub ok { 42 }
22 |
23 | sub switch { 'switch' }
24 | sub CASE { 'CASE' }
25 | }
26 |
27 | my @data = (
28 | [ <<'T', <<'X', "method call without args" ],
29 | [% obj.ok() %]
30 | T
31 | 42
32 | X
33 |
34 | [ <<'T', <<'X', "method call" ],
35 | [% obj.join(".") %]
36 | T
37 |
38 | X
39 |
40 | [ <<'T', <<'X', "method call" ],
41 | [% obj.join(".", "foo", "bar") %]
42 | T
43 | foo.bar
44 | X
45 |
46 | [ <<'T', <<'X', "method call" ],
47 | [% obj.join(".", "foo", "bar", "baz") %]
48 | T
49 | foo.bar.baz
50 | X
51 |
52 | [ <<'T', <<'X', "keywords as fields/methods" ],
53 | [% obj.switch %]
54 | [% obj.switch() %]
55 | [% obj.CASE %]
56 | [% obj.CASE() %]
57 | T
58 | switch
59 | switch
60 | CASE
61 | CASE
62 | X
63 |
64 | );
65 |
66 | foreach my $d(@data) {
67 | my($in, $out, $msg) = @$d;
68 |
69 | my %vars = (
70 | obj => Obj->new,
71 | );
72 | is $tx->render_string($in, \%vars), $out, $msg or diag $in;
73 | }
74 |
75 | done_testing;
76 |
--------------------------------------------------------------------------------
/t/040_tterse/009_comments.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use lib "t/lib";
6 | use TTSimple;
7 |
8 | my @data = (
9 | [ <<'T', <<'X', ],
10 | A[%# foo %]B
11 | T
12 | AB
13 | X
14 |
15 | [ <<'T', <<'X', ],
16 | A[%#
17 | foo
18 | %]B
19 | T
20 | AB
21 | X
22 |
23 | [ <<'T', <<'X', ],
24 | A[%#
25 | [foo]
26 | [bar]
27 | [baz]
28 | %]B
29 | T
30 | AB
31 | X
32 | );
33 |
34 | foreach my $d(@data) {
35 | my($in, $out, $msg) = @$d;
36 |
37 | my %vars = ();
38 | is render_str($in, \%vars), $out, $msg or diag $in;
39 | }
40 |
41 | done_testing;
42 |
--------------------------------------------------------------------------------
/t/040_tterse/010_expr.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use lib "t/lib";
6 | use TTSimple;
7 |
8 | my @data = (
9 | ['Hello, [% lang or "Perl" %] world!' => 'Hello, Xslate world!'],
10 | ['Hello, [% empty or "Perl" %] world!' => 'Hello, Perl world!'],
11 |
12 | ['Hello, [% "foo" _ "bar" %] world!' => 'Hello, foobar world!'],
13 |
14 | ['[% ( NOT value == 10 ) ? "true" : "false" %]', "false" ],
15 | ['[% (NOT value AND (value == 10)) ? "true" : "false" %]', "false" ],
16 | ['[% (NOT( value == 10 )) ? "true" : "false" %]', "false", ],
17 |
18 | ['[% (value == 10 AND value == 10) ? "true" : "false" %]', "true" ],
19 | ['[% (value == 10) AND (value == 10) ? "true" : "false" %]', "true" ],
20 |
21 | ['[% (value == 10 AND value == 10 OR value == 10) ? "true" : "false" %]', "true" ],
22 | ['[% ((value == 10) AND (value == 10) OR (value == 10)) ? "true" : "false" %]', "true" ],
23 | ['[% (value == 10 AND value == 10 OR value == 11) ? "true" : "false" %]', "true" ],
24 | ['[% (((value == 10) AND (value == 10)) OR (value == 11)) ? "true" : "false" %]', "true" ],
25 |
26 | # TTerse specific features
27 | ['[% 0x110 +& 0x101 %]', 0x100, undef, 1 ],
28 | );
29 |
30 | my %vars = (
31 | lang => 'Xslate',
32 | foo => "",
33 | '$lang' => 'XXX',
34 | value => 10,
35 | );
36 | foreach my $d(@data) {
37 | my($in, $out, $msg, $is_tterse_specific) = @$d;
38 |
39 | last if $is_tterse_specific;
40 | is render_str($in, \%vars), $out, $msg
41 | or diag $in;
42 | }
43 |
44 | done_testing;
45 |
--------------------------------------------------------------------------------
/t/040_tterse/011_objectliterals.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use lib "t/lib";
6 | use TTSimple;
7 |
8 | my @data = (
9 | [<<'T', <<'X'],
10 | %% FOR i IN [1, 2, 3]
11 | [% i %]
12 | %% END
13 | T
14 | 1
15 | 2
16 | 3
17 | X
18 |
19 | [<<'T', <<'X'],
20 | [% { a => 1, b => 2, c => 3 }.a %]
21 | [% { a => 1, b => 2, c => 3 }.b %]
22 | [% { a => 1, b => 2, c => 3 }.c %]
23 | T
24 | 1
25 | 2
26 | 3
27 | X
28 |
29 | [<<'T', <<'X', 'with literals'],
30 | [% { "if" => 42 }.if %]
31 | [% { "not" => 43 }.not %]
32 | [% { "for" => 44 }.for %]
33 | [% { "FOR" => 45 }.FOR %]
34 | T
35 | 42
36 | 43
37 | 44
38 | 45
39 | X
40 |
41 |
42 | [<<'T', <<'X', 'with keywords'],
43 | [% { if => 42 }.if %]
44 | [% { not => 43 }.not %]
45 | [% { for => 44 }.for %]
46 | [% { FOR => 45 }.FOR %]
47 | T
48 | 42
49 | 43
50 | 44
51 | 45
52 | X
53 |
54 | );
55 |
56 | foreach my $pair(@data) {
57 | my($in, $out, $msg) = @$pair;
58 |
59 | my %vars = (lang => 'Xslate', foo => "", '$lang' => 'XXX');
60 |
61 | is render_str($in, \%vars), $out, $msg
62 | or diag $in;
63 | }
64 |
65 | done_testing;
66 |
--------------------------------------------------------------------------------
/t/040_tterse/012_macro.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use lib "t/lib";
6 | use TTSimple;
7 |
8 | my @data = (
9 | [<<'T', <<'X'],
10 | [% MACRO foo BLOCK -%]
11 | Hello, [% lang %] world!
12 | [% END -%]
13 | [% foo() -%]
14 | T
15 | Hello, Xslate world!
16 | X
17 |
18 | [<<'T', <<'X'],
19 | [% MACRO foo(lang) BLOCK -%]
20 | foo [% lang %] bar
21 | [% END -%]
22 | [%- foo(42) -%]
23 | Hello, [% lang %] world!
24 | T
25 | foo 42 bar
26 | Hello, Xslate world!
27 | X
28 |
29 | [<<'T', <<'X'],
30 | [% MACRO add(a, b) BLOCK -%]
31 | [% a + b %]
32 | [% END -%]
33 | [%- add(10, 32) -%]
34 | T
35 | 42
36 | X
37 |
38 | );
39 |
40 | foreach my $pair(@data) {
41 | my($in, $out, $msg) = @$pair;
42 |
43 | my %vars = (lang => 'Xslate', foo => "", '$lang' => 'XXX');
44 |
45 | is render_str($in, \%vars), $out, $msg
46 | or diag $in;
47 | }
48 |
49 | done_testing;
50 |
--------------------------------------------------------------------------------
/t/040_tterse/016_call.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use lib "t/lib";
6 | use TTSimple;
7 | use Text::Xslate::Util qw(p);
8 |
9 | my @data = (
10 | [<<'T', <<'X'],
11 | foo
12 | [% CALL lang -%]
13 | [% CALL foo.bar -%]
14 | bar
15 | T
16 | foo
17 | bar
18 | X
19 |
20 | [<<'T', <<'X', 'lower cased'],
21 | foo
22 | [% call lang -%]
23 | [% call foo.bar -%]
24 | bar
25 | T
26 | foo
27 | bar
28 | X
29 |
30 | );
31 |
32 | my %vars = (lang => 'Xslate', foo => { bar => 43 });
33 |
34 | foreach my $d(@data) {
35 | my($in, $out, $msg) = @$d;
36 |
37 | is render_str($in, \%vars), $out, $msg
38 | or diag $in;
39 | }
40 |
41 | done_testing;
42 |
--------------------------------------------------------------------------------
/t/040_tterse/020_chomp.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use lib "t/lib";
6 | use TTSimple;
7 |
8 | my @data = (
9 | [<<'T', 'Xslate' ],
10 | [%- lang -%]
11 | T
12 |
13 | [<<'T', <<'X' ],
14 | - [%- lang -%] -
15 | T
16 | - Xslate -
17 | X
18 |
19 | [<<'T', <<'X' ],
20 | *
21 | [%- lang -%]
22 | *
23 | T
24 | *Xslate *
25 | X
26 |
27 | [<<'T', <<'X' ],
28 | *
29 |
30 | [%- lang -%]
31 |
32 | *
33 | T
34 | *
35 | Xslate
36 | *
37 | X
38 |
39 | [<<'T', <<'X' ],
40 |
41 | [%- lang -%]
42 |
43 | T
44 | Xslate
45 | X
46 |
47 | [<<'T', <<'X' ],
48 |
49 | [%- lang -%]
50 |
51 | T
52 | Xslate
53 | X
54 |
55 | [<<'T', <<'X' ],
56 |
57 | [%- lang -%]
58 |
59 | T
60 | Xslate
61 | X
62 |
63 | [<<'T', <<'X' ],
64 |
65 | [%- lang -%]
66 |
67 | T
68 | Xslate
69 | X
70 |
71 |
72 | # http://github.com/gfx/p5-Text-Xslate/issues#issue/12
73 | #['Hello, [%~ "Xslate" ~%] world!', 'Hello,Xslateworld!'],
74 | );
75 |
76 | my %vars = (
77 | lang => 'Xslate',
78 | void => '',
79 |
80 | value => 10,
81 | );
82 | foreach my $d(@data) {
83 | my($in, $out, $msg) = @$d;
84 | is render_str($in, \%vars), $out, $msg or diag($in);
85 | }
86 |
87 | done_testing;
88 |
--------------------------------------------------------------------------------
/t/040_tterse/021_fake_use.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::Requires qw(Template::Plugin::Math);
4 | use Test::More;
5 |
6 | use lib "t/lib";
7 | use TTSimple;
8 |
9 | use Template::Plugin::String;
10 |
11 | # XXX: TTerse does not support plugins (i.e. USE directive), but grokes
12 | # the USE keyword as an alias to 'CALL', which takes expressions.
13 |
14 | my @data = (
15 | [<<'T', <<'X'],
16 | [% USE Math -%]
17 | [% Math.abs(-100) %]
18 | [% Math.abs( 100) %]
19 | T
20 | 100
21 | 100
22 | X
23 |
24 | [<<'T', <<'X'],
25 | [% USE String -%]
26 | [% s = String.new("foo") -%]
27 | [% s.upper %]
28 | [% s.repeat(2) %]
29 | T
30 | FOO
31 | FOOFOO
32 | X
33 |
34 | );
35 |
36 | my %vars = (
37 | lang => 'Xslate',
38 | void => '',
39 |
40 | value => 10,
41 |
42 | Math => Template::Plugin::Math->new(), # as a namespace
43 | String => Template::Plugin::String->new(), # as a prototype
44 | );
45 | foreach my $d(@data) {
46 | my($in, $out, $msg) = @$d;
47 | is render_str($in, \%vars), $out, $msg or diag($in);
48 | }
49 |
50 | done_testing;
51 |
--------------------------------------------------------------------------------
/t/040_tterse/022_post_if.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use lib "t/lib";
6 | use TTSimple;
7 |
8 | my @data = (
9 | [<<'T', <<'X', 'post if'],,
10 | {[% "foo" IF 1 %]}
11 | {[% "bar" IF 1 %]}
12 | T
13 | {foo}
14 | {bar}
15 | X
16 |
17 | [<<'T', <<'X'],
18 | {[% "foo" IF 0 %]}
19 | {[% "bar" IF 0 %]}
20 | T
21 | {}
22 | {}
23 | X
24 |
25 | [<<'T', <<'X', 'post unless'],
26 | {[% "foo" UNLESS 0 %]}
27 | {[% "bar" UNLESS 0 %]}
28 | T
29 | {foo}
30 | {bar}
31 | X
32 |
33 | [<<'T', <<'X'],
34 | {[% "foo" UNLESS 1 %]}
35 | {[% "bar" UNLESS 1 %]}
36 | T
37 | {}
38 | {}
39 | X
40 |
41 |
42 | [<<'T', <<'X', 'include if'],
43 | [% INCLUDE "hello.tt" IF 1 -%]
44 | [% INCLUDE "hello.tt" IF 1 -%]
45 | T
46 | Hello, Xslate world!
47 | Hello, Xslate world!
48 | X
49 |
50 | [<<'T', <<'X'],
51 | [% INCLUDE "hello.tt" IF 0 -%]
52 | [% INCLUDE "hello.tt" IF 0 -%]
53 | T
54 | X
55 | );
56 |
57 | my %vars = (
58 | lang => 'Xslate',
59 | value => 10,
60 | );
61 | foreach my $d(@data) {
62 | my($in, $out, $msg) = @$d;
63 | is render_str($in, \%vars), $out, $msg or diag($in);
64 | }
65 |
66 | done_testing;
67 |
--------------------------------------------------------------------------------
/t/040_tterse/023_loop_ctl.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 |
3 | use strict;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 |
8 | my %vpath = (
9 | );
10 |
11 | my $tx = Text::Xslate->new(
12 | syntax => 'TTerse',
13 | cache => 0,
14 | path => \%vpath,
15 | verbose => 2,
16 | warn_handler => sub { die @_ },
17 | );
18 |
19 | note 'for';
20 | is $tx->render_string(<<'T'), <<'X' or die;
21 | %% for it in [42, 43, 44]
22 | %% last if it == 43
23 | * [% it %]
24 | %% end
25 | T
26 | * 42
27 | X
28 |
29 | is $tx->render_string(<<'T'), <<'X' or die;
30 | %% for it in [42, 43, 44]
31 | %% NEXT if it == 43
32 | * [% it %]
33 | %% END
34 | T
35 | * 42
36 | * 44
37 | X
38 |
39 | note 'while';
40 | my $iter = do{ my @a = (42, 43, 44); sub { shift @a } };
41 | is $tx->render_string(<<'T', { iter => $iter }), <<'X';
42 | %% while it = iter()
43 | %% NEXT if it == 43
44 | * [% it %]
45 | %% END
46 | T
47 | * 42
48 | * 44
49 | X
50 |
51 | $iter = do{ my @a = (42, 43, 44); sub { shift @a } };
52 | is $tx->render_string(<<'T', { iter => $iter }), <<'X';
53 | %% while it = iter()
54 | %% LAST if it == 43
55 | * [% it %]
56 | %% END
57 | T
58 | * 42
59 | X
60 |
61 | $iter = do{ my @a = (42, 43, 44); sub { shift @a } };
62 | is $tx->render_string(<<'T', { iter => $iter }), <<'X';
63 | %% while it = iter()
64 | * [% it %]
65 | %% LAST if it == 43
66 | %% END
67 | T
68 | * 42
69 | * 43
70 | X
71 |
72 | done_testing;
73 |
--------------------------------------------------------------------------------
/t/040_tterse/024_for_else.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use warnings;
4 |
5 | use Test::More;
6 | use Text::Xslate;
7 |
8 | my $tx = Text::Xslate->new(syntax => 'TTerse');
9 |
10 | is $tx->render_string(<<'T'), <<'X';
11 | %% for i in [42]
12 | {[% i %]}
13 | %% else
14 | empty
15 | %% end
16 | T
17 | {42}
18 | X
19 |
20 | is $tx->render_string(<<'T'), <<'X';
21 | %% for i in []
22 | {[% i %]}
23 | %% else
24 | empty
25 | %% end
26 | T
27 | empty
28 | X
29 |
30 | is $tx->render_string(<<'T', { y => 'y' }), <<'X';
31 | %% FOR i IN []
32 | {[% i %]}
33 | %% ELSE
34 | empt[% $y %]
35 | %% END
36 | T
37 | empty
38 | X
39 |
40 | done_testing;
41 |
42 |
--------------------------------------------------------------------------------
/t/040_tterse/025_macro.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use warnings;
4 |
5 | use Test::More;
6 | use Text::Xslate;
7 |
8 | my $tx = Text::Xslate->new(syntax => 'TTerse', macro => ['t/template/macro.tt']);
9 |
10 | is $tx->render_string(<<'T'), <<'X';
11 | {[% foo() %]}
12 | T
13 | {foo}
14 | X
15 |
16 | done_testing;
17 |
18 |
--------------------------------------------------------------------------------
/t/040_tterse/100_not_supported.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use lib "t/lib";
6 | use TTSimple;
7 |
8 | my @data = (
9 | [<<'T'],
10 | [% PERL %]
11 | print "Hello, world"\n";
12 | [% PERL %]
13 | T
14 |
15 | [<<'T'],
16 | [% TRY %]
17 | print "Hello, world"\n";
18 | [% END %]
19 | T
20 | );
21 |
22 | my %vars = (
23 | lang => 'Xslate',
24 | void => '',
25 |
26 | value => 10,
27 | );
28 | foreach my $d(@data) {
29 | my($in, $out, $msg) = @$d;
30 | eval { render_str($in, \%vars) };
31 | note $@;
32 | like $@, qr/not supported/;
33 | }
34 |
35 | done_testing;
36 |
--------------------------------------------------------------------------------
/t/050_builtins/004_copied.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 |
3 | use strict;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 | use Text::Xslate::Compiler;
8 |
9 | my $tx = Text::Xslate->new(
10 | function => {
11 | 'array::inc' => sub {
12 | my($a, $i) = @_;
13 | $a->[$i]++;
14 | return $a;
15 | },
16 | }
17 | );
18 |
19 | my @a = (42);
20 | is $tx->render_string(q{<: $a.merge(3).inc(0).join(',') :>}, { a => \@a}),
21 | '43,3';
22 | is_deeply \@a, [42];
23 |
24 | is $tx->render_string(q{<: $a.merge(3).inc(1).join(',') :>}, { a => \@a}),
25 | '42,4';
26 |
27 | my %h = (foo => 42);
28 | is $tx->render_string(q{<: $h.keys().inc(0).join(',') :>}, { h => \%h}),
29 | do{ my $x = 'foo'; $x++; $x };
30 | is_deeply \%h, { foo => 42 };
31 |
32 | is $tx->render_string(q{<: $h.values().inc(0).join(',') :>}, { h => \%h}),
33 | '43';
34 | is_deeply \%h, { foo => 42 };
35 |
36 | done_testing;
37 |
--------------------------------------------------------------------------------
/t/100_plugin/001_import_from.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use Text::Xslate::Util qw(import_from);
6 |
7 | for(1 .. 2) {
8 | my $f = import_from("Scalar::Util" => [qw(blessed looks_like_number)]);
9 |
10 | is_deeply $f, {
11 | blessed => \&Scalar::Util::blessed,
12 | looks_like_number => \&Scalar::Util::looks_like_number,
13 | };
14 |
15 | $f = import_from(
16 | "Carp",
17 | "Data::Dumper" => [qw(Dumper)],
18 | );
19 |
20 | is_deeply $f, {
21 | Dumper => \&Data::Dumper::Dumper,
22 | carp => \&Carp::carp,
23 | croak => \&Carp::croak,
24 | confess => \&Carp::confess,
25 | };
26 |
27 | # for constants
28 | $f = import_from(
29 | "Fcntl" => [qw(:flock)],
30 | );
31 |
32 | ok exists $f->{LOCK_EX} or diag explain($f);
33 | is $f->{LOCK_EX}->(), Fcntl::LOCK_EX(), 'constant';
34 | is $f->{LOCK_SH}->(), Fcntl::LOCK_SH(), 'constant';
35 | }
36 |
37 |
38 | done_testing;
39 |
--------------------------------------------------------------------------------
/t/100_plugin/005_html_builder_module.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use Text::Xslate;
6 |
7 | {
8 | package My::HTML::Builder;
9 | use parent qw(Exporter);
10 | our @EXPORT = qw(foo);
11 | sub foo {
12 | return "
";
13 |
14 | }
15 | $INC{'My/HTML/Builder.pm'} = __FILE__;
16 | }
17 |
18 | my $tx = Text::Xslate->new(
19 | html_builder_module => [
20 | 'My::HTML::Builder',
21 | ],
22 | );
23 |
24 | my @set = (
25 | [
26 | '<: foo() :>',
27 | { },
28 | "
",
29 | 'My::HTML::Builder returns a aprt of HTML'
30 | ],
31 | );
32 |
33 | foreach my $d(@set) {
34 | my($in, $vars, $out, $msg) = @$d;
35 | is $tx->render_string($in, $vars), $out, $msg;
36 | }
37 |
38 | done_testing;
39 |
--------------------------------------------------------------------------------
/t/100_plugin/100_error.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use Text::Xslate;
6 |
7 | use warnings FATAL => 'all';
8 |
9 | eval {
10 | Text::Xslate->new(
11 | module => [ 'Text::Xslate::No::Such::Module' ],
12 | );
13 | };
14 |
15 | like $@, qr/Failed to import/;
16 | like $@, qr{Can't locate Text/Xslate/No/Such/Module.pm};
17 |
18 | eval {
19 | Text::Xslate->new(
20 | module => [ '(^_^)' ],
21 | );
22 | };
23 |
24 | like $@, qr/Invalid module name/;
25 |
26 | done_testing;
27 |
--------------------------------------------------------------------------------
/t/200_app/001_hello.t:
--------------------------------------------------------------------------------
1 | use strict;
2 | use Test::More (tests => 8);
3 | use File::Path ();
4 | use FindBin qw($Bin);
5 |
6 | use constant CACHE_DIR => '.xslate/app1';
7 | sub clean {
8 | File::Path::rmtree( $Bin . "/out" );
9 | File::Path::rmtree( CACHE_DIR );
10 | }
11 | clean();
12 | END{
13 | clean();
14 | }
15 |
16 | system $^X, (map { "-I$_" } @INC), "script/xslate",
17 | '--suffix', 'tx=txt',
18 | sprintf('--dest=%s/out', $Bin),
19 | '--cache_dir=' . CACHE_DIR,
20 | '--verbose=1',
21 | '--cache=2',
22 | sprintf('%s/simple/hello.tx', $Bin),
23 | ;
24 |
25 | is $?, 0, "command executed successfully (1)";
26 |
27 | ok -d CACHE_DIR, 'cache directory created';
28 |
29 | ok -f sprintf('%s/out/hello.txt', $Bin), 'correct file generated';
30 |
31 | my $fh;
32 | ok open($fh, '<', sprintf('%s/out/hello.txt', $Bin)), 'file opened';
33 |
34 | my $content = do { local $/; <$fh> };
35 |
36 | like $content, qr/Hello, Perl world!/;
37 |
38 | system $^X, (map { "-I$_" } @INC), "script/xslate",
39 | '--suffix', 'tx=txt',
40 | sprintf('--dest=%s/out', $Bin),
41 | '--cache_dir=' . CACHE_DIR,
42 | '--define=lang=Xslate',
43 | '--cache=2',
44 | sprintf('%s/simple/hello.tx', $Bin),
45 | ;
46 |
47 | is $?, 0, "command executed successfully (2)";
48 |
49 | ok open($fh, '<', sprintf('%s/out/hello.txt', $Bin)), 'file opened';
50 |
51 | $content = do { local $/; <$fh> };
52 |
53 | like $content, qr/Hello, Xslate world!/;
54 |
--------------------------------------------------------------------------------
/t/200_app/002_tree.t:
--------------------------------------------------------------------------------
1 | use strict;
2 | use Test::More (tests => 8);
3 | use File::Path ();
4 | use FindBin qw($Bin);
5 |
6 | sub clean {
7 | File::Path::rmtree( ".app_cache2" );
8 | File::Path::rmtree( ".tree_out" );
9 | }
10 |
11 | clean();
12 | END{
13 | clean();
14 | }
15 |
16 | system $^X, (map { "-I$_" } @INC), "script/xslate",
17 | '--suffix', 'tx=txt',
18 | '--cache_dir=.xslate_cache/app2',
19 | '--dest=.tree_out',
20 | '--ignore=dont_touch',
21 | "$Bin/simple",
22 | ;
23 |
24 | if (is $?, 0, "command executed successfully") {
25 | {
26 | ok -f '.tree_out/hello.txt', 'correct file generated';
27 | my $fh;
28 | ok open($fh, '<', '.tree_out/hello.txt'), 'file opened';
29 |
30 | my $content = do { local $/; <$fh> };
31 | like $content, qr/Hello, Perl world!/;
32 | }
33 |
34 | {
35 | ok -f '.tree_out/goodbye.txt', 'correct file generated';
36 | my $fh;
37 | ok open($fh, '<', '.tree_out/goodbye.txt'), 'file opened';
38 |
39 | my $content = do { local $/; <$fh> };
40 | like $content, qr/Goodbye, Cruel world!/;
41 | }
42 |
43 | {
44 | ok !-f '.tree_out/dont_touch.tx', '--ignore works';
45 | }
46 | }
47 |
48 |
49 |
--------------------------------------------------------------------------------
/t/200_app/004_encoding.t:
--------------------------------------------------------------------------------
1 | #!perl
2 | use strict;
3 | use warnings;
4 | use utf8;
5 |
6 | use Test::More;
7 | use SelectSaver;
8 | use Text::Xslate::Runner;
9 |
10 | use Encode qw(encode decode);
11 |
12 | sub capture(&) {
13 | my($block) = @_;
14 |
15 | my $s = '';
16 |
17 | {
18 | open my $out, '>', \$s;
19 | my $saver = SelectSaver->new($out);
20 | $block->();
21 | }
22 | return $s;
23 | }
24 |
25 | my $app = Text::Xslate::Runner->new(
26 | define => { name => '' },
27 | cache_dir => '.xslate_cache/app3',
28 | );
29 | is capture { $app->run('t/template/hello_utf8.tx') },
30 | encode("UTF-8", "こんにちは! <Xslate>!\n");
31 |
32 | $app->output_encoding('Shift_JIS');
33 | is capture { $app->run('t/template/hello_utf8.tx') },
34 | encode("Shift_JIS", "こんにちは! <Xslate>!\n");
35 |
36 | $app->input_encoding('Shift_JIS');
37 | $app->output_encoding('utf-8');
38 | is capture { $app->run('t/template/hello_sjis.tx') },
39 | encode("UTF-8", "こんにちは! <Xslate>!\n");
40 |
41 | $app->input_encoding('Shift_JIS');
42 | $app->output_encoding('Shift_JIS');
43 | is capture { $app->run('t/template/hello_sjis.tx') },
44 | encode("Shift_JIS", "こんにちは! <Xslate>!\n");
45 |
46 | done_testing;
47 |
--------------------------------------------------------------------------------
/t/200_app/simple/dont_touch.tx:
--------------------------------------------------------------------------------
1 | Thiis file will be ignored by the --ignore option.
2 |
--------------------------------------------------------------------------------
/t/200_app/simple/goodbye.tx:
--------------------------------------------------------------------------------
1 | Goodbye, <: $world_type // "Cruel" :> world!
--------------------------------------------------------------------------------
/t/200_app/simple/hello.tx:
--------------------------------------------------------------------------------
1 | Hello, <: $lang // "Perl" :> world!
--------------------------------------------------------------------------------
/t/300_examples/001_basic.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use Text::Xslate;
6 |
7 | my $tx = Text::Xslate->new(syntax => 'Kolon');
8 |
9 | my $tmpl;
10 |
11 | $tmpl = <<'TX';
12 | Hello, <: $dialect :> world!
13 | TX
14 |
15 | is $tx->render_string($tmpl, { dialect => 'Kolon' }), "Hello, Kolon world!\n", "Hello, world";
16 |
17 | $tmpl = <<'TX';
18 | : if $var == nil {
19 | $var is nil.
20 | : }
21 | : else if $var != "foo" {
22 | $var is not nil nor "foo".
23 | : }
24 | : else {
25 | $var is "foo".
26 | : }
27 | TX
28 |
29 | is $tx->render_string($tmpl, { var => undef }), " \$var is nil.\n";
30 | is $tx->render_string($tmpl, { var => 0 }), qq{ \$var is not nil nor "foo".\n};
31 | is $tx->render_string($tmpl, { var => "foo" }), qq{ \$var is "foo".\n};
32 |
33 | $tmpl = <<'TX';
34 | : if( $var >= 1 && $var <= 10 ) {
35 | $var is 1 .. 10
36 | : }
37 | TX
38 |
39 | is $tx->render_string($tmpl, { var => 5 }), " \$var is 1 .. 10\n";
40 | is $tx->render_string($tmpl, { var => 0 }), "";
41 | is $tx->render_string($tmpl, { var => 11 }), "";
42 |
43 | $tmpl = <<'TX';
44 | := $var.value == nil ? "nil" : $var.value
45 | TX
46 |
47 | is $tx->render_string($tmpl, { var => {} }), "nil";
48 | is $tx->render_string($tmpl, { var => { value => "" }}), "<foo>";
49 |
50 | $tmpl = <<'TX';
51 | : for $data ->($item) {
52 | [<:= $item + 5 :>]
53 | : } # end for
54 | TX
55 |
56 | is $tx->render_string($tmpl, { data => [1 .. 100] }),
57 | join('', map{ sprintf "[%d]\n", $_ + 5 } 1 .. 100);
58 |
59 |
60 | done_testing;
61 |
--------------------------------------------------------------------------------
/t/300_examples/002_cascade.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use Text::Xslate;
6 | use lib "t/lib";
7 | use Util;
8 |
9 | {
10 | package BlogEntry;
11 | use Mouse;
12 | has title => (is => 'rw');
13 | has body => (is => 'rw');
14 | }
15 |
16 | my @blog_entries = map{ BlogEntry->new($_) } (
17 | {
18 | title => 'Entry one',
19 | body => 'This is my first entry.',
20 | },
21 | {
22 | title => 'Entry two',
23 | body => 'This is my second entry.',
24 | },
25 | );
26 |
27 | my $tx = Text::Xslate->new(
28 | cache => 0,
29 | path => [path],
30 | );
31 |
32 | my $gold = <<'T';
33 |
35 |
36 |
37 |
38 | My amazing blog
39 |
40 |
41 |
42 |
48 |
49 |
50 |
Entry one
51 |
This is my first entry.
52 |
Entry two
53 |
This is my second entry.
54 |
55 |
56 |
57 | T
58 |
59 | is $tx->render('eg/child.tx', { blog_entries => \@blog_entries }), $gold, 'example/cascade.pl'
60 | for 1 .. 2;
61 |
62 |
63 | done_testing;
64 |
--------------------------------------------------------------------------------
/t/300_examples/003_metakolon.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use Text::Xslate;
6 |
7 | my $tx = Text::Xslate->new(syntax => 'Metakolon');
8 |
9 | my $tmpl;
10 |
11 | $tmpl = <<'TX';
12 | Hello, [% $dialect %] world!
13 | TX
14 |
15 | is $tx->render_string($tmpl, { dialect => 'Kolon' }), "Hello, Kolon world!\n", "Hello, world";
16 |
17 | $tmpl = <<'TX';
18 | %% if $var == nil {
19 | $var is nil.
20 | %% }
21 | %% else if $var != "foo" {
22 | $var is not nil nor "foo".
23 | %% }
24 | %% else {
25 | $var is "foo".
26 | %% }
27 | TX
28 |
29 | is $tx->render_string($tmpl, { var => undef }), " \$var is nil.\n";
30 | is $tx->render_string($tmpl, { var => 0 }), qq{ \$var is not nil nor "foo".\n};
31 | is $tx->render_string($tmpl, { var => "foo" }), qq{ \$var is "foo".\n};
32 |
33 | $tmpl = <<'TX';
34 | %% if( $var >= 1 && $var <= 10 ) {
35 | $var is 1 .. 10
36 | %% }
37 | TX
38 |
39 | is $tx->render_string($tmpl, { var => 5 }), " \$var is 1 .. 10\n";
40 | is $tx->render_string($tmpl, { var => 0 }), "";
41 | is $tx->render_string($tmpl, { var => 11 }), "";
42 |
43 | $tmpl = <<'TX';
44 | %%= $var.value == nil ? "nil" : $var.value
45 | TX
46 |
47 | is $tx->render_string($tmpl, { var => {} }), "nil";
48 | is $tx->render_string($tmpl, { var => { value => "" }}), "<foo>";
49 |
50 | $tmpl = <<'TX';
51 | %% for $data ->($item) {
52 | [[%= $item + 5 %]]
53 | %% } # end for
54 | TX
55 |
56 | is $tx->render_string($tmpl, { data => [1 .. 100] }),
57 | join('', map{ sprintf "[%d]\n", $_ + 5 } 1 .. 100);
58 |
59 |
60 | done_testing;
61 |
--------------------------------------------------------------------------------
/t/300_examples/004_tterse.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use Test::More;
4 |
5 | use Text::Xslate;
6 |
7 | my $tx = Text::Xslate->new(syntax => 'TTerse');
8 |
9 | my $tmpl;
10 |
11 | $tmpl = <<'TX';
12 | Hello, [% dialect %] world!
13 | TX
14 |
15 | is $tx->render_string($tmpl, { dialect => 'Kolon' }), "Hello, Kolon world!\n", "Hello, world";
16 |
17 | $tmpl = <<'TX';
18 | [% IF var == nil -%]
19 | $var is nil.
20 | [% ELSIF var != "foo" -%]
21 | $var is not nil nor "foo".
22 | [% ELSE -%]
23 | $var is "foo".
24 | [% END -%]
25 | TX
26 |
27 | is $tx->render_string($tmpl, { var => undef }), " \$var is nil.\n";
28 | is $tx->render_string($tmpl, { var => 0 }), qq{ \$var is not nil nor "foo".\n};
29 | is $tx->render_string($tmpl, { var => "foo" }), qq{ \$var is "foo".\n};
30 |
31 | $tmpl = <<'TX';
32 | [% IF var >= 1 && var <= 10 -%]
33 | $var is 1 .. 10
34 | [% END -%]
35 | TX
36 |
37 | is $tx->render_string($tmpl, { var => 5 }), " \$var is 1 .. 10\n";
38 | is $tx->render_string($tmpl, { var => 0 }), "";
39 | is $tx->render_string($tmpl, { var => 11 }), "";
40 |
41 | $tmpl = <<'TX';
42 | [% var.value == nil ? "nil" : var.value -%]
43 | TX
44 |
45 | is $tx->render_string($tmpl, { var => {} }), "nil";
46 | is $tx->render_string($tmpl, { var => { value => "" }}), "<foo>";
47 |
48 | $tmpl = <<'TX';
49 | [% FOREACH item IN data -%]
50 | [[% item + 5 %]]
51 | [% END -%]
52 | TX
53 |
54 | is $tx->render_string($tmpl, { data => [1 .. 100] }),
55 | join('', map{ sprintf "[%d]\n", $_ + 5 } 1 .. 100);
56 |
57 |
58 | done_testing;
59 |
--------------------------------------------------------------------------------
/t/900_bugs/001_super.t:
--------------------------------------------------------------------------------
1 | #!perl -w
2 | use strict;
3 | use warnings;
4 | use Test::More;
5 |
6 | use Text::Xslate;
7 |
8 | my %vpath = (
9 | 'component.tx' => <<'T',
10 | : around body -> {
11 |
12 |
13 | Welcome
14 |
15 | : super
16 |
17 |
18 | : }
19 | T
20 |
21 | 'main.tx' => <<'T',
22 | : cascade with component
23 |
24 | : block body -> {
25 | <: $message :>
26 | This page was generated from the template
27 | : }
28 | T
29 | );
30 |
31 | my $tx = Text::Xslate->new(path => \%vpath, cache => 0);
32 | my $out = $tx->render('main.tx', { message => 'OK'});
33 | like $out, qr//;
34 | like $out, qr/