├── t ├── lib │ ├── TestApp │ │ ├── root │ │ │ ├── foo.tt │ │ │ └── bar.tt │ │ └── View │ │ │ └── Jemplate.pm │ └── TestApp.pm ├── 00_compile.t └── 01_live.t ├── MANIFEST.SKIP ├── .shipit ├── MANIFEST ├── Makefile.PL ├── Changes └── lib └── Catalyst ├── Helper └── View │ └── Jemplate.pm └── View └── Jemplate.pm /t/lib/TestApp/root/foo.tt: -------------------------------------------------------------------------------- 1 | [% foo %] 2 | -------------------------------------------------------------------------------- /t/lib/TestApp/root/bar.tt: -------------------------------------------------------------------------------- 1 | [% bar %] 2 | 3 | -------------------------------------------------------------------------------- /t/00_compile.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use Test::More tests => 1; 3 | 4 | BEGIN { use_ok 'Catalyst::View::Jemplate' } 5 | -------------------------------------------------------------------------------- /t/lib/TestApp/View/Jemplate.pm: -------------------------------------------------------------------------------- 1 | package TestApp::View::Jemplate; 2 | use base qw( Catalyst::View::Jemplate ); 3 | 4 | 1; 5 | -------------------------------------------------------------------------------- /MANIFEST.SKIP: -------------------------------------------------------------------------------- 1 | \bRCS\b 2 | \bCVS\b 3 | ^MANIFEST\. 4 | ^Makefile$ 5 | ~$ 6 | \.old$ 7 | ^blib/ 8 | ^pm_to_blib 9 | ^MakeMaker-\d 10 | \.gz$ 11 | \.cvsignore 12 | .shipit 13 | -------------------------------------------------------------------------------- /.shipit: -------------------------------------------------------------------------------- 1 | steps = FindVersion, ChangeVersion, CheckChangeLog, DistTest, Commit, Tag, MakeDist, UploadCPAN 2 | 3 | # if directory, where the normal "make dist" puts its file. 4 | #MakeDist.destination = ~/shipit-dist 5 | #svn.tagpattern = ShipIt-%v 6 | 7 | #CheckChangeLog.files = ChangeLog 8 | -------------------------------------------------------------------------------- /MANIFEST: -------------------------------------------------------------------------------- 1 | Changes 2 | lib/Catalyst/Helper/View/Jemplate.pm 3 | lib/Catalyst/View/Jemplate.pm 4 | Makefile.PL 5 | MANIFEST This list of files 6 | t/00_compile.t 7 | t/01_live.t 8 | t/lib/TestApp.pm 9 | t/lib/TestApp/root/bar.tt 10 | t/lib/TestApp/root/foo.tt 11 | t/lib/TestApp/View/Jemplate.pm 12 | -------------------------------------------------------------------------------- /Makefile.PL: -------------------------------------------------------------------------------- 1 | use ExtUtils::MakeMaker; 2 | WriteMakefile( 3 | 'NAME' => 'Catalyst::View::Jemplate', 4 | 'VERSION_FROM' => 'lib/Catalyst/View/Jemplate.pm', # finds $VERSION 5 | 'PREREQ_PM' => { 6 | Test::More => 0.32, 7 | Jemplate => 0.19, 8 | Catalyst => 5.50, 9 | File::Find::Rule => 0, 10 | }, 11 | ); 12 | -------------------------------------------------------------------------------- /Changes: -------------------------------------------------------------------------------- 1 | Revision history for Perl extension Catalyst::View::Jemplate 2 | 3 | 0.06 Fri May 4 15:16:09 PDT 2007 4 | - Document update to remove TODO for caching 5 | (Thanks to nothingmuch) 6 | 7 | 0.05 Tue May 1 00:11:30 PDT 2007 8 | - Fixed cache to work with new Catalyst::Plugin::Cache modules 9 | (Thanks to Takeda Akihito) 10 | 11 | 0.04 Fri Feb 23 09:59:06 PST 2007 12 | - Added 'runtime' functionality to serve Jemplate.js (Fujiwara Shuichiro) 13 | 14 | 0.03 Fri Dec 1 02:16:38 PST 2006 15 | - Added caching and the ability to specify which file to jemplatize (Daisuke Maki) 16 | - Added Helper Catalyst::Helper::View::Jemplate (Daisuke Maki) 17 | 18 | 0.02 Fri Apr 28 03:39:16 JST 2006 19 | - Updated to Jemplate new API 20 | (Thanks to Fujiwara Shuichiro) 21 | 22 | 0.01 Tue Feb 7 10:02:24 2006 23 | - original version 24 | -------------------------------------------------------------------------------- /t/lib/TestApp.pm: -------------------------------------------------------------------------------- 1 | package TestApp; 2 | 3 | use strict; 4 | use warnings; 5 | 6 | use Catalyst; 7 | 8 | our $VERSION = '0.01'; 9 | __PACKAGE__->config({ 10 | name => 'TestApp', 11 | 'View::Jemplate' => { 12 | jemplate_dir => TestApp->path_to('root'), 13 | }, 14 | }); 15 | 16 | __PACKAGE__->setup; 17 | 18 | sub jemplate : Global { 19 | my ( $self, $c ) = @_; 20 | $c->forward('View::Jemplate'); 21 | } 22 | 23 | sub finalize_error { 24 | my $c = shift; 25 | $c->res->header('X-Error' => $c->error->[0]); 26 | $c->NEXT::finalize_error; 27 | } 28 | 29 | sub selected : Global { 30 | my ( $self, $c ) = @_; 31 | 32 | $c->stash->{jemplate} = { 33 | files => 'bar.tt' 34 | }; 35 | $c->forward('View::Jemplate'); 36 | } 37 | 38 | sub runtime : Path('Jemplate.js') { 39 | my ( $self, $c ) = @_; 40 | 41 | $c->stash->{jemplate} = { 42 | runtime => 1, 43 | files => [], 44 | }; 45 | $c->forward('View::Jemplate'); 46 | } 47 | 48 | 1; 49 | -------------------------------------------------------------------------------- /lib/Catalyst/Helper/View/Jemplate.pm: -------------------------------------------------------------------------------- 1 | package Catalyst::Helper::View::Jemplate; 2 | 3 | use strict; 4 | 5 | =head1 NAME 6 | 7 | Catalyst::Helper::View::Jemplate - Helper for Jemplate Views 8 | 9 | =head1 SYNOPSIS 10 | 11 | script/create.pl view Jemplate Jemplate 12 | 13 | =head1 DESCRIPTION 14 | 15 | Helper for Jemplate Views. 16 | 17 | =head2 METHODS 18 | 19 | =head3 mk_compclass 20 | 21 | =cut 22 | 23 | sub mk_compclass { 24 | my ( $self, $helper ) = @_; 25 | my $file = $helper->{file}; 26 | $helper->render_file( 'compclass', $file ); 27 | } 28 | 29 | =head1 SEE ALSO 30 | 31 | L 32 | 33 | =head1 AUTHOR 34 | 35 | Tatsuhiko Miyagawa, C 36 | Daisuke Maki, C 37 | 38 | =head1 LICENSE 39 | 40 | This library is free software . You can redistribute it and/or modify 41 | it under the same terms as perl itself. 42 | 43 | =cut 44 | 45 | 1; 46 | 47 | __DATA__ 48 | 49 | __compclass__ 50 | package [% class %]; 51 | 52 | use strict; 53 | use base 'Catalyst::View::Jemplate'; 54 | 55 | =head1 NAME 56 | 57 | [% class %] - Jemplate View for [% app %] 58 | 59 | =head1 DESCRIPTION 60 | 61 | Jemplate View for [% app %]. 62 | 63 | =head1 AUTHOR 64 | 65 | =head1 SEE ALSO 66 | 67 | L<[% app %]> 68 | 69 | [% author %] 70 | 71 | =head1 LICENSE 72 | 73 | This library is free software, you can redistribute it and/or modify 74 | it under the same terms as Perl itself. 75 | 76 | =cut 77 | 78 | 1; -------------------------------------------------------------------------------- /t/01_live.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | 4 | use FindBin; 5 | use lib "$FindBin::Bin/lib"; 6 | 7 | use Test::More tests => 18; 8 | use Catalyst::Test 'TestApp'; 9 | 10 | BEGIN { 11 | no warnings 'redefine'; 12 | 13 | *Catalyst::Test::local_request = sub { 14 | my ( $class, $request ) = @_; 15 | 16 | require HTTP::Request::AsCGI; 17 | my $cgi = HTTP::Request::AsCGI->new( $request, %ENV )->setup; 18 | 19 | $class->handle_request; 20 | 21 | return $cgi->restore->response; 22 | }; 23 | } 24 | 25 | my $entrypoint = "http://localhost/jemplate"; 26 | 27 | { 28 | my $request = HTTP::Request->new( GET => $entrypoint ); 29 | 30 | ok( my $response = request($request), 'Request' ); 31 | ok( $response->is_success, 'Response Successful 2xx' ); 32 | is( $response->code, 200, 'Response Code' ); 33 | 34 | is_deeply( [ $response->content_type ], [ 'text/javascript', 'charset=utf-8' ] ); 35 | 36 | like $response->content, qr!//line 1 "foo\.tt"!; 37 | like $response->content, qr!//line 1 "bar\.tt"!; 38 | } 39 | 40 | { 41 | my $request = HTTP::Request->new( GET => "http://localhost/selected" ); 42 | 43 | ok( my $response = request($request), 'Request' ); 44 | ok( $response->is_success, 'Response Successful 2xx' ); 45 | is( $response->code, 200, 'Response Code' ); 46 | 47 | is_deeply( [ $response->content_type ], [ 'text/javascript', 'charset=utf-8' ] ); 48 | 49 | unlike $response->content, qr!//line 1 "foo\.tt"!; 50 | like $response->content, qr!//line 1 "bar\.tt"!; 51 | } 52 | 53 | { 54 | my $request = HTTP::Request->new( GET => "http://localhost/Jemplate.js" ); 55 | 56 | ok( my $response = request($request), 'Request' ); 57 | ok( $response->is_success, 'Response Successful 2xx' ); 58 | is( $response->code, 200, 'Response Code' ); 59 | 60 | is_deeply( [ $response->content_type ], [ 'text/javascript', 'charset=utf-8' ] ); 61 | 62 | unlike $response->content, qr!//line 1 "foo\.tt"!; 63 | like $response->content, qr!// Main Jemplate class!; 64 | } 65 | -------------------------------------------------------------------------------- /lib/Catalyst/View/Jemplate.pm: -------------------------------------------------------------------------------- 1 | package Catalyst::View::Jemplate; 2 | 3 | use strict; 4 | our $VERSION = '0.06'; 5 | 6 | use base qw( Catalyst::View ); 7 | use File::Find::Rule; 8 | use Jemplate; 9 | use NEXT; 10 | use Path::Class; 11 | 12 | __PACKAGE__->mk_accessors(qw( jemplate_dir jemplate_ext encoding )); 13 | 14 | sub new { 15 | my($class, $c, $arguments) = @_; 16 | my $self = $class->NEXT::new($c); 17 | 18 | $self->jemplate_dir($arguments->{jemplate_dir}); 19 | $self->jemplate_ext($arguments->{jemplate_ext} || '.tt'); 20 | $self->encoding($arguments->{encoding} || 'utf-8'); 21 | 22 | my $dir = $self->jemplate_dir 23 | or Catalyst::Exception->throw("jemplate_dir needed"); 24 | 25 | unless (-e $dir && -d _) { 26 | Catalyst::Exception->throw("$dir: $!"); 27 | } 28 | 29 | $self; 30 | } 31 | 32 | sub process { 33 | my($self, $c) = @_; 34 | 35 | my $data = $c->stash->{jemplate}; 36 | my $cache = $c->can('curry_cache') ? $c->cache("jemplate") 37 | : $c->can('cache') ? $c->cache 38 | : undef; 39 | my $output = ''; 40 | 41 | my $cache_key = $data->{key} || $c->req->match; 42 | if ($cache) { 43 | $output = $cache->get($cache_key); 44 | if ($c->log->is_debug) { 45 | if ($output) { 46 | $c->log->debug("Catalyst::View::Jemplate cache HIT for $cache_key"); 47 | } else { 48 | $c->log->debug("Catalyst::View::Jemplate cache MISS for $cache_key"); 49 | } 50 | } 51 | } 52 | 53 | if (! $output) { 54 | # We aren't cached, or we don't have a cache configured for us 55 | my @files; 56 | 57 | if ($data && $data->{files}) { 58 | # The user can specify exactly which files we include in this 59 | # particular dispatch 60 | @files = 61 | map { file($self->jemplate_dir, $_) } 62 | ref($data->{files}) ? @{ $data->{files} } : ($data->{files}) 63 | ; 64 | } else { 65 | # XXX - not a good idea, but leave it as final alternative 66 | @files = File::Find::Rule->file 67 | ->name( '*' . $self->jemplate_ext ) 68 | ->in( $self->jemplate_dir ); 69 | } 70 | 71 | if ($c->log->is_debug) { 72 | $c->log->debug("Creating Jemplate file from @files"); 73 | } 74 | 75 | # add runtime 76 | if ($data && $data->{runtime}) { 77 | $output = Jemplate->runtime_source_code(); 78 | } 79 | 80 | # xxx error handling? 81 | $output .= Jemplate->compile_template_files(@files); 82 | if ($cache) { 83 | $cache->set($cache_key, $output); 84 | } 85 | } 86 | 87 | my $encoding = $self->encoding || 'utf-8'; 88 | if (($c->req->user_agent || '') =~ /Opera/) { 89 | $c->res->content_type("application/x-javascript; charset=$encoding"); 90 | } else { 91 | $c->res->content_type("text/javascript; charset=$encoding"); 92 | } 93 | 94 | $c->res->output($output || ''); 95 | } 96 | 97 | 1; 98 | __END__ 99 | 100 | =head1 NAME 101 | 102 | Catalyst::View::Jemplate - Jemplate files server 103 | 104 | =head1 SYNOPSIS 105 | 106 | package MyApp::View::Jemplate; 107 | use base qw( Catalyst::View::Jemplate ); 108 | 109 | package MyApp; 110 | 111 | MyApp->config( 112 | 'View::Jemplate' => { 113 | jemplate_dir => MyApp->path_to('root', 'jemplate'), 114 | jemplate_ext => '.tt', 115 | }, 116 | ); 117 | 118 | sub jemplate : Global { 119 | my($self, $c) = @_; 120 | $c->forward('View::Jemplate'); 121 | } 122 | 123 | # To specify which files you want to include 124 | sub select : Global { 125 | my($self, $c) = @_; 126 | $c->stash->{jemplate} = { 127 | files => [ 'foo.tt', 'bar.tt' ] 128 | } 129 | } 130 | 131 | # To serve Jemplate rutime 132 | sub runtime : Path('Jemplate.js') { 133 | my($self, $c) = @_; 134 | $c->stash->{jemplate} = { 135 | runtime => 1, 136 | files => [], # runtime only 137 | } 138 | } 139 | 140 | # To use caching 141 | use Catalyst qw( 142 | ... 143 | Cache 144 | ); 145 | 146 | MyApp->config( 147 | cache => { 148 | backends => { 149 | jemplate => { 150 | # Your cache backend of choice 151 | store => "FastMmap", 152 | } 153 | } 154 | } 155 | ); 156 | 157 | =head1 DESCRIPTION 158 | 159 | Catalyst::View::Jemplate is a Catalyst View plugin to automatically 160 | compile TT files into JavaScript, using ingy's Jemplate. 161 | 162 | Instead of creating the compiled javascript files by-hand, you can 163 | include the file via Catalyst app like: 164 | 165 | 166 | 167 | 168 | When L is enabled, this plugin make uses of 169 | it to cache the compiled output and serve files. 170 | 171 | =head1 TODO 172 | 173 | =over 4 174 | 175 | =item * 176 | 177 | Right now all the template files under C is compiled 178 | into a single JavaScript file and served. Probably we need a path 179 | option to limit the directory. 180 | 181 | =cut 182 | 183 | =head1 AUTHOR 184 | 185 | Tatsuhiko Miyagawa Emiyagawa@bulknews.netE 186 | 187 | This library is free software; you can redistribute it and/or modify 188 | it under the same terms as Perl itself. 189 | 190 | =head1 SEE ALSO 191 | 192 | L<> 193 | 194 | =cut 195 | --------------------------------------------------------------------------------