File Coverage

blib/lib/Template/Stash/AutoEscaping.pm
Criterion Covered Total %
statement 95 106 89.6
branch 27 44 61.3
condition 16 24 66.6
subroutine 16 17 94.1
pod 6 6 100.0
total 160 197 81.2


line stmt bran cond sub pod time code
1             package Template::Stash::AutoEscaping;
2              
3 4     4   390749 use strict;
  4         12  
  4         155  
4 4     4   22 use warnings;
  4         9  
  4         132  
5              
6 4     4   100 use 5.012;
  4         26  
  4         223  
7              
8             our $VERSION = '0.0303';
9              
10 4     4   3753 use Template::Config;
  4         37131  
  4         164  
11 4     4   5952 use parent ($Template::Config::STASH, 'Class::Data::Inheritable');
  4         1252  
  4         23  
12              
13 4     4   220509 use Data::Dumper;
  4         7311  
  4         276  
14 4     4   3955 use UNIVERSAL::require;
  4         7657  
  4         42  
15 4     4   2761 use Template::Stash::AutoEscaping::RawString;
  4         12  
  4         38  
16 4     4   102 use Template::Exception;
  4         7  
  4         31  
17              
18             __PACKAGE__->mk_classdata('class_for_type');
19             __PACKAGE__->class_for_type({
20             HTML => __PACKAGE__ . '::Escaped::HTML',
21             YourCode => __PACKAGE__ . '::Escaped::YourCode',
22             });
23              
24             our $DEBUG = 0;
25             our $escape_count = 0;
26              
27             our $ESCAPE_ARGS = 0;
28              
29             sub new {
30 3     3 1 63 my $class = shift;
31 3         125 my $self = $class->SUPER::new(@_);
32 3   50     124 $self->{method_for_raw} ||= 'raw';
33 3   100     29 $self->{method_for_escape} ||= 'escape';
34 3   50     25 $self->{_raw_string_class} ||= __PACKAGE__ . '::' . 'RawString';
35 3   50     23 $self->{ignore_escape} ||= [];
36 3   100     19 $self->{die_on_unescaped} ||= 0;
37              
38 3 50       13 if (ref $self->{escape_method} eq "CODE") {
39 0         0 $self->{escape_type} = "YourCode";
40 0         0 my $escape_class = $class->class_for($self->{escape_type});
41 0 0       0 if (!$escape_class->can("escape")) {
42 0 0       0 $escape_class->require or die $@;
43             }
44 0         0 $escape_class->escape_method($self->{escape_method});
45             } else {
46 3   50     13 $self->{escape_type} ||= 'HTML';
47 3         14 my $escape_class = $class->class_for($self->{escape_type});
48 3 50       89 if (!$escape_class->can("escape")) {
49 0 0       0 $escape_class->require or die $@;
50             }
51             }
52              
53 3         14 foreach my $ops ($Template::Stash::SCALAR_OPS, $Template::Stash::LIST_OPS)
54             {
55             $ops->{$self->{method_for_raw}} = sub {
56 7     7   26 my $scalar = shift;
57 7         62 return $self->{_raw_string_class}->new($scalar);
58 6         38 };
59              
60             $ops->{$self->{method_for_escape}} = sub {
61 1     1   2 my $scalar = shift;
62 1         6 return $self->{_raw_string_class}->new(
63             $self->escape($scalar),
64             );
65 6         46 };
66              
67             };
68 3         11 return $self;
69             }
70              
71             sub get_raw_args {
72 20     20 1 46 my ( $args, $escaped_class ) = @_;
73 20         32 my $changed = 0;
74 20         27 my @raw_args;
75 20         31 for my $v (@{ $args }) {
  20         48  
76 77         83 my $new_v;
77 77 100       215 if ( ref $v eq $escaped_class ) {
    100          
78 2         3 $changed = 1;
79 2         111 $new_v = $v->[0];
80             } elsif (ref $v eq 'ARRAY') {
81 3         11 $new_v = get_raw_args($v, $escaped_class);
82 3 100       9 if ($new_v) {
83 1         3 $changed = 1;
84             } else {
85 2         3 $new_v = $v;
86             }
87             } else {
88 72         90 $new_v = $v;
89             }
90 77         151 push @raw_args, $new_v;
91             }
92              
93 20 100       86 return unless $changed;
94 3         11 return \@raw_args;
95             }
96              
97             sub get {
98 49     49 1 288417 my ( $self, @args ) = @_;
99             # get value
100 49 50       153 warn Dumper +{ args => \@args } if $DEBUG;
101              
102             # note: hack for [% hash.${key} %] [% hash.item(key) %]
103             # key expected raw string.
104 49 100 66     322 if (!$ESCAPE_ARGS && ref $args[0] eq "ARRAY" && (scalar @{$args[0]} > 2)){
  17   66     71  
105 17         70 my $escaped_class = $self->class_for($self->{escape_type});
106 17         217 my $changed = get_raw_args($args[0], $escaped_class);
107             # retry by non-escaped args
108 17 100       56 if ($changed) {
109 2         3 $args[0] = $changed;
110 2         11 return $self->get(@args);
111             }
112             }
113              
114 47         797 my ($var) = $self->SUPER::get(@args);
115 47 100       356 if (ref $args[0] eq "ARRAY") {
116 15         31 my $key = $args[0]->[0];
117 15 50       51 warn $key if $DEBUG;
118 15 50       21 if (grep { $key eq $_ } @{ $self->{ignore_escape} }) {
  0         0  
  15         62  
119 0 0       0 warn "ignore escape $key" if $DEBUG;
120 0         0 return $var;
121             }
122             }
123              
124 47         96 my $ref = ref $var;
125             # string
126 47 100 100     220 if ((!$ref) and (length($var) > 0)) {
127 13 100       51 if ($self->{die_on_unescaped}) {
128 1         9 die Template::Exception->new(
129             Dumper([ $args[0] ]), "Unescaped and not marked as raw"
130             );
131             }
132             else {
133 12 50       34 $escape_count++ if $DEBUG;
134 12         46 return $self->escape($var);
135             }
136             }
137             # via .raw vmethod
138 34 100       106 if ($ref eq $self->{_raw_string_class}) {
139 8         163 return "$var";
140             }
141 26         276 return $var;
142             # my $escape_class = $self->class_for($self->{escape_type});
143             # warn $ref->isa($escape_class);
144             # if (!$ref->isa($escape_class)) {
145             # $escape_count++ if $DEBUG;
146             # return $self->escape($var);
147             # }
148             # return $var;
149             }
150              
151             sub class_for {
152 38     38 1 3661 my $class = shift;
153 38 50       123 if (@_ == 1) {
    0          
154 38   33     160 return $class->class_for_type->{$_[0]} || __PACKAGE__ . '::Escaped::' . $_[0];
155             } elsif (@_ == 2) {
156 0         0 return $class->class_for_type->{$_[0]} = $_[1];
157             }
158             }
159              
160             sub escape {
161 13     13 1 27 my $self = shift;
162 13         20 my $text = shift;
163 13         40 my $class = $self->class_for($self->{escape_type});
164 13         147 my $stringify_callback = $self->{before_stringify};
165 13         111 $class->new($text, 0, undef, $stringify_callback);
166             }
167              
168             sub escape_count {
169 0     0 1   $escape_count;
170             }
171              
172             1;
173              
174              
175             __END__