File Coverage

lib/Async/Template.pm
Criterion Covered Total %
statement 78 106 73.5
branch 9 26 34.6
condition 8 31 25.8
subroutine 16 24 66.6
pod 0 6 0.0
total 111 193 57.5


line stmt bran cond sub pod time code
1             package Async::Template;
2              
3             #! @file
4             #! @author: Serguei Okladnikov
5             #! @date 28.09.2012
6              
7 4     4   142315 use 5.010001;
  4         37  
8 4     4   25 use strict;
  4         7  
  4         106  
9 4     4   21 use warnings;
  4         6  
  4         221  
10              
11             our $VERSION = '0.14';
12              
13 4     4   1812 use Async::Template::Parser;
  4         11  
  4         144  
14 4     4   4556 use Async::Template::Grammar;
  4         6673  
  4         681  
15 4     4   2122 use Async::Template::Context;
  4         12  
  4         128  
16 4     4   1874 use Async::Template::Directive;
  4         69  
  4         151  
17              
18 4     4   1143 use Template;
  4         25685  
  4         126  
19 4     4   25 use Template::Provider;
  4         8  
  4         3956  
20             $Template::Provider::DOCUMENT = 'Async::Template::Document';
21              
22              
23              
24             sub new {
25 3     3 0 160 my $self = bless {}, shift;
26              
27 3         12 $Template::Config::CONTEXT = 'Async::Template::Context';
28 3         8 $Template::Config::FACTORY = 'Async::Template::Directive';
29 3         6 $Template::Config::DOCUMENT = 'Async::Template::Document';
30 3         5 $Template::Config::PROVIDER = 'Async::Template::Provider';
31              
32             # WARN! TODO: incompatible with original template
33             # impossible to solve upgrade, Template does not
34             # recompile unchaged modules, incomptible ...
35             # $output and \$output need to test mem usage
36             # about 2 commented string of code below
37             # not good idea try to solve in process:
38             # my $oldoutput = $Template::Directive::OUTPUT;
39             # $Template::Directive::OUTPUT = $oldoutput;
40             # so
41 3         9 $Template::Directive::OUTPUT = '${$out} .= ';
42              
43 3         5 my $config = $_[0];
44            
45 3         19 $self->{DONE} = $config->{DONE};
46 3 50 33     42 if( $config->{BLOCKER} && ! $config->{DONE} ) {
    50 33        
47 0         0 die 'DONE config options for ' . __PACKAGE__ .
48             '->new() must be specified if BLOCKER specified';
49             } elsif( ! $config->{BLOCKER} && ! $config->{DONE} ) {
50 3         3395 require 'AnyEvent.pm';
51 3         17562 $self->{_ourblocker} = 1;
52             $self->{BLOCKER} = sub {
53 32     32   133 $self->{_blockcv}->recv;
54 3         20 };
55             $self->{DONE} = sub {
56 32     32   79 my $output = shift;
57 32         85 $self->{_output} = $output;
58 32         175 $self->{_blockcv}->send;
59 3         15 };
60             }
61 3         9 $self->{config} = $config;
62             $self->{tt} = Template->new({
63 3         13 %{ $self->{config} },
64             PARSER => Async::Template::Parser->new(
65 3         8 %{$config},
66 3         29 GRAMMAR => Async::Template::Grammar->new( %{$config } ),
67 3         9 FACTORY => Async::Template::Directive->new( %{$config} ),
  3         42  
68             ),
69             });
70 3         54025 $self
71             }
72              
73             sub process {
74 32     32 0 8805 my ($self, $template, $vars, $outstream, @opts) = @_;
75 32 50 33     169 my $options = (@opts == 1) && ref($opts[0]) eq 'HASH'
76             ? shift(@opts) : { @opts };
77 32 50       109 if( $self->{_ourblocker} ) {
78 32         237 require 'AnyEvent.pm';
79 32         843 $self->{_blockcv} = AnyEvent->condvar;
80             }
81 32 50 33     15822 ( defined $outstream && 'SCALAR' ne ref $outstream ) &&
82             die 'only string ref possible as outstream';
83 32         164 my $context = $self->{tt}->context();
84 32         315 $context->event_clear;
85 32         58 my $outstr = '';
86 32 50 33     186 my $output = defined $outstream && 'SCALAR' eq ref $outstream ?
87             $outstream : \$outstr;
88 32         72 $context->{_event_output} = $output;
89 32   33     153 my $cb = $options->{DONE} || $self->{DONE};
90             my $event = sub {
91 32     32   104 my $context = shift;
92 32         56 $cb->( ${$context->event_output()} );
  32         76  
93 32         190 };
94 32         183 $context->event_push( {
95             event => $event,
96             output => $output,
97             resvar => undef,
98             } );
99             # eval{
100             #return $self->{tt}->process( $template, $vars, $outstream );
101 32         94 $self->{tt}->context()->process( $template, $vars );
102             # };
103 32 50       3876 return $self->{tt}->error($@)
104             if $@;
105             $self->{BLOCKER}->()
106 32 50       169 if( $self->{BLOCKER} );
107 32   33     1701 $outstream ||= $self->{tt}->{OUTPUT};
108 32         211 return 1;
109             }
110              
111             sub context {
112             $_[0]->{tt}->context()
113 0     0 0 0 }
114              
115             sub output {
116 0     0 0 0 $_[0]->context->event_output()
117             }
118              
119             sub error {
120 0     0 0 0 my $self = shift;
121 0         0 $self->{tt}->error( @_ )
122             }
123              
124             # This tt impl give not good perforance
125             # will be removed or rewrited with
126             sub tt {
127 0     0 0 0 my $cb = pop;
128 0         0 my $src = pop;
129 0 0 0     0 my $vars = ( 1==@_ && 'HASH' eq ref $_[0] ) ? $_[0] : {@_};
130 0         0 my ($out,$err,$res);
131 0         0 my $msg = 'two param or two elements array only for RESULT() or ERROR()';
132              
133             my $saveres = sub {
134 0 0   0   0 if( 2 == @_ ) {
    0          
135 0         0 ( $err, $res ) = ($_[0], $_[1]);
136             } elsif( 1 == @_ ) {
137 0 0       0 ( $err, $res ) = 'ARRAY' eq ref $_[0] ?
138             ($_[0][0], $_[0][1]) : ($msg, $_[0]);
139             } else {
140 0         0 ( $err, $res ) = ($msg, \@_);
141             };
142 0         0 };
143              
144 0   0 0   0 $vars->{ERROR} ||= sub { $saveres->(@_); $err };
  0         0  
  0         0  
145 0   0 0   0 $vars->{RESULT} ||= sub { $saveres->(@_); $res };
  0         0  
  0         0  
146              
147             my $tt = Async::Template->new( { DONE => sub {
148 0     0   0 $cb->($err,$res,$out);
149 0         0 } } );
150 0         0 $src =~ s/(.*)/[%$1%]/s;
151 0         0 $tt->process( \$src, $vars, \$out );
152             }
153              
154             sub import {
155 4     4   44 my $package = shift;
156 4         18 my $caller = caller;
157 4     4   33 no strict 'refs';
  4         8  
  4         426  
158 4 50 33     115 if( $_[0] && $_[0] eq 'tt' ) {
159 0           *{$caller.'::tt'} = \&{$package.'::tt'};
  0            
  0            
160             }
161             }
162              
163             1;
164              
165             __END__