File Coverage

blib/lib/Template/Liquid/Condition.pm
Criterion Covered Total %
statement 95 114 83.3
branch 67 96 69.7
condition 20 45 44.4
subroutine 14 16 87.5
pod 5 9 55.5
total 201 280 71.7


line stmt bran cond sub pod time code
1             our $VERSION = '1.0.21';
2             require Template::Liquid::Error;
3             use base 'Template::Liquid::Block';
4 24     24   132 use strict;
  24         41  
  24         1393  
5 24     24   115 use warnings;
  24         44  
  24         485  
6 24     24   119  
  24         41  
  24         1116  
7             # Makes life easy
8             use overload 'bool' => \&is_true, fallback => 1;
9 24     24   23559  
  24         19585  
  24         163  
10             my ($class, $args) = @_;
11             raise Template::Liquid::Error {type => 'Context',
12 265     265 0 489 template => $args->{template},
13             message => 'Missing template argument',
14             fatal => 1
15             }
16             if !defined $args->{'template'};
17             raise Template::Liquid::Error {type => 'Context',
18 265 50       533 template => $args->{template},
19             message => 'Missing parent argument',
20             fatal => 1
21             }
22             if !defined $args->{'parent'};
23             my ($lval, $condition, $rval)
24 265 50       448 = ((defined $args->{'attrs'} ? $args->{'attrs'} : '')
25             =~ m[("[^"]+"|'[^']+'|(?:[\S]+))]go);
26 265 50       1358 if (defined $lval) {
27             if (!defined $rval && !defined $condition) {
28 265 50       581 return
29 265 100 66     975 bless {lvalue => $lval,
    50          
30             condition => undef,
31             rvalue => undef,
32             template => $args->{'template'},
33             parent => $args->{'parent'}
34             }, $class;
35 127         872 }
36             elsif ($condition =~ m[^(?:eq|==|ne|!=|lt|<|gt|>|contains|&&|\|\|)$]o)
37             { $condition = 'eq' if $condition eq '==';
38             $condition = 'ne' if $condition eq '!=';
39 138 100       269 $condition = 'gt' if $condition eq '>';
40 138 100       236 $condition = 'lt' if $condition eq '<';
41 138 100       232 $condition = '_and' if $condition eq '&&';
42 138 100       214 $condition = '_and' if $condition eq 'and';
43 138 50       203 $condition = '_or' if $condition eq '||';
44 138 50       218 $condition = '_or' if $condition eq 'or';
45 138 50       208 return
46 138 50       229 bless {lvalue => $lval,
47             condition => $condition,
48             rvalue => $rval,
49             template => $args->{'template'},
50             parent => $args->{'parent'}
51             }, $class;
52 138         918 }
53             else {
54             ...;
55             }
56 0         0 raise Template::Liquid::Error {
57             template => $args->{template},
58             type => 'Context',
59             message => 'Unknown operator "' . $condition . '" in ' .
60 0 0       0 $lval . ' ' . $condition . ' ' . (defined $rval ? $rval : '')
61             };
62             }
63             return
64             Template::Liquid::Error->new(
65             template => $args->{template},
66             type => 'Context',
67             message => 'Bad conditional statement: ' . $args->{'attrs'}
68             );
69 0         0 }
70              
71             my ($s) = @_;
72 24     24 1 46 my $l = $s->{template}{context}->get($s->{'lvalue'}) || $s->{'lvalue'};
73             my $r = $s->{template}{context}->get($s->{'rvalue'}) || $s->{'rvalue'};
74              
75 263     263 1 385 # Might need to render these again
76 263   66     560 my $_l = $s->{template}{context}->get($l);
77 263   66     598 my $_r = $s->{template}{context}->get($r);
78             $l = $_l if defined $_l;
79             $r = $_r if defined $_r;
80 263         585 return _equal($l, $r);
81 263         556 }
82 263 100       472  
83 263 100       450 my ($l, $r) = @_;
84 263         416 my $ref_l = ref $l;
85             return !1 if $ref_l ne ref $r;
86             if (!$ref_l) {
87             return
88 283     283   431 !!(grep {defined} $l, $r)
89 283         348 ? (grep {m[\D]o} $l, $r)
90 283 100       496 ? $l eq $r
91 281 100       442 : $l == $r
    100          
    50          
92             : !1;
93 538         1029 }
94 269 100       394 elsif ($ref_l eq 'ARRAY') {
  538 50       2035  
95             return !1 unless scalar @$l == scalar @$r;
96             for my $index (0 .. $#{$l}) {
97             return !1 if !_equal($l->[$index], $r->[$index]);
98             }
99             return !!1;
100 6 100       25 }
101 4         7 elsif ($ref_l eq 'HASH') {
  4         14  
102 16 100       42 my %temp = %$r;
103             for my $key (keys %$l) {
104 2         14 return 0
105             unless exists $temp{$key} and
106             defined($l->{$key}) eq defined($temp{$key}) and
107 6         20 (defined $temp{$key} ? _equal($temp{$key}, $l->{$key}) : !!1);
108 6         15 delete $temp{$key};
109             }
110             return !keys(%temp);
111             }
112 6 50 66     43 }
    100 100        
113 2         7  
114             my ($s) = @_;
115 2         13 my ($l, $r)
116             = map { $s->{template}{context}->get($_) || $_ }
117             ($$s{'lvalue'}, $$s{'rvalue'});
118              
119             # Might need to render these again
120 45     45 1 68 my $_l = $s->{template}{context}->get($l);
121             my $_r = $s->{template}{context}->get($r);
122 90 100       226 $l = $_l if defined $_l;
123 45         75 $r = $_r if defined $_r;
124             return
125             !!(grep {defined} $l, $r)
126 45         111 ? (grep {m[\D]o} $l, $r)
127 45         108 ? $l gt $r
128 45 100       94 : $l > $r
129 45 50       84 : 0;
130             }
131 90         178  
132 45 100       66 my ($s) = @_;
  90 50       374  
133             my $l = $s->{template}{context}->get($s->{'lvalue'});
134             my $r = $s->{template}{context}->get($s->{'rvalue'});
135              
136             # Might need to render these again
137 12     12 1 23 my $_l = $s->{template}{context}->get($l);
138             my $_r = $s->{template}{context}->get($r);
139             $l = $_l if defined $_l;
140 12     12 1 21 $r = $_r if defined $_r;
141 12         30 $r = quotemeta $r;
142 12         31 return if defined $r && !defined $l;
143             return defined($l->{$r}) ? 1 : !1 if ref $l eq 'HASH';
144             return (grep { $_ eq $r } @$l) ? 1 : !1 if ref $l eq 'ARRAY';
145 12         28 return $l =~ qr[${r}] ? 1 : !1;
146 12         29 }
147 12 50       29  
148 12 50       21 my ($s) = @_;
149 12         22 my $l = $s->{template}{context}->get($s->{'lvalue'}) || $s->{'lvalue'};
150 12 50 33     35 my $r = $s->{template}{context}->get($s->{'rvalue'}) || $s->{'rvalue'};
151 12 100       44  
    100          
152 8 100       18 # Might need to render these again
  12 100       38  
153 4 100       79 my $_l = $s->{template}{context}->get($l);
154             my $_r = $s->{template}{context}->get($r);
155             $l = $_l if defined $_l;
156             $r = $_r if defined $_r;
157 0     0   0 return !!($l && $r);
158 0   0     0 }
159 0   0     0  
160             my ($s) = @_;
161             my $l = $s->{template}{context}->get($s->{'lvalue'}) || $s->{'lvalue'};
162 0         0 my $r = $s->{template}{context}->get($s->{'rvalue'}) || $s->{'rvalue'};
163 0         0  
164 0 0       0 # Might need to render these again
165 0 0       0 my $_l = $s->{template}{context}->get($l);
166 0   0     0 my $_r = $s->{template}{context}->get($r);
167             $l = $_l if defined $_l;
168             $r = $_r if defined $_r;
169             return !!($l || $r);
170 0     0   0 }
171 0   0     0 { # Compound inequalities support
172 0   0     0  
173             my ($s) = @_;
174             my $l = $s->{'lvalue'};
175 0         0 my $r = $s->{'rvalue'};
176 0         0 return !!($l && $r);
177 0 0       0 }
178 0 0       0  
179 0   0     0 my ($s) = @_;
180             my $l = $s->{'lvalue'};
181             my $r = $s->{'rvalue'};
182             return !!($l || $r);
183             }
184 15     15 0 29 }
185 15         29  
186 15         21 my ($s) = @_;
187 15   100     28 if (!defined $s->{'condition'} && !defined $s->{'rvalue'}) {
188              
189             # Might need to render these again
190             my $l = $s->{template}{context}->get($s->{'lvalue'});
191 43     43 0 76 my $_l = $s->{template}{context}->get($l);
192 43         66 $l = $_l if defined $_l;
193 43         54 return !!($l) ? 1 : 0;
194 43   100     99 }
195             my $condition = $s->can($s->{'condition'});
196             raise Template::Liquid::Error {
197             template => $s->{template},
198             type => 'Context',
199 406     406 0 618 message => 'Bad condition ' . $s->{'condition'},
200 406 50 66     901 fatal => 1
201             }
202             if !$condition;
203 28         77  
204 28         77 #return !1 if !$condition;
205 28 100       67 return $s->$condition();
206 28 100       157 }
207             1;
208 378         866  
209             =pod
210              
211             =begin stopwords
212 378 50       684  
213             stringwise greps
214              
215             =end stopwords
216              
217             =head1 NAME
218 378         581  
219             Template::Liquid::Condition - Basic Relational, Equality, and Content Operators
220              
221             =head1 Description
222              
223             These operators evaluate to true/false values. This is used internally but
224             since you're here... might as well skim it. Nothing new to most people.
225              
226             =head1 Relational Operators
227              
228             If you're familiar with basic math, you already understand these.
229              
230             Any of the following operators can be combined with logical C<and> and C<or>:
231              
232             5 > 2 and 'okay' contains 'ok' # true
233             4 > 6 or 4 < 6 # true ...silly, but true
234             # where x = [1 .. 10]
235             x contains 3 and x contains 0 # false
236              
237             Binary C<and> performs a short-circuit logical AND operation. That is, if the
238             left operand is false, the right operand is not even evaluated. Likewise,
239             binary C<or> performs a short-circuit logical OR operation. That is, if the
240             left operand is true, the right operand is not even evaluated.
241              
242             =head2 C<< > >>
243              
244             Binary operator which returns true if the left argument is numerically less
245             than the right argument.
246              
247             Given...
248              
249             3 > 4 # false
250             4 > 3 # true
251             # where x == 10 and y == 12
252             x > y # false
253             y > x # true
254             x > 3 # true
255             x > x # false
256              
257             =head2 C<< < >>
258              
259             Binary operator which returns true if the left argument is numerically greater
260             than the right argument.
261              
262             Given...
263              
264             3 < 4 # true
265             4 < 3 # false
266             # where x == 10 and y == 12
267             x < y # true
268             y < x # false
269             x < 30 # true
270             x < x # false
271              
272             =head2 C<==>
273              
274             Binary operator which returns true if the left argument is numerically equal to
275             the right argument.
276              
277             # where x == 10 and y == 12
278             x == y # false
279             x == 10 # true
280             y == y # true
281              
282             =head2 C<!=>
283              
284             Binary operator which returns true if the left argument is numerically not
285             equal to the right argument.
286              
287             # where x == 10 and y == 12
288             x != y # true
289             5 != 5 # false
290              
291             =head2 C<eq>
292              
293             Binary operator which returns true if the left argument is stringwise equal to
294             the right argument.
295              
296             'test' eq 'test' # true
297             'test' eq 'reset' # false
298             # where x = 'cool beans'
299             x eq 'awesome' # false
300             x eq 'Cool beans' # false
301             x eq 'cool beans' # true
302             x eq x # true
303              
304             =head2 C<ne>
305              
306             Binary operator which returns true if the left argument is stringwise not equal
307             to the right argument.
308              
309             'test' ne 'test' # false
310             'test' ne 'reset' # true
311             # where x = 'cool beans'
312             x ne 'awesome' # true
313             x ne 'Cool beans' # true
314             x ne 'cool beans' # false
315             x ne x # false
316              
317             =head2 C<lt>
318              
319             Binary operator which returns true if the left argument is stringwise less than
320             the right argument.
321              
322             'a' lt 'c' # true
323             'A' lt 'a' # true
324             # where x = 'q'
325             x lt 'r' # true
326             x lt 'm' # false
327             x lt x # false
328              
329             =head2 C<gt>
330              
331             Binary operator which returns true if the left argument is stringwise greater
332             than the right argument.
333              
334             'a' gt 'c' # false
335             'A' gt 'a' # false
336             # where x = 'q'
337             x gt 'r' # false
338             x gt 'm' # true
339             x gt x # true
340              
341             =head1 Other Operators
342              
343             These are nice things to have around...
344              
345             =head2 C<contains>
346              
347             The C<contains> operator is context sensitive.
348              
349             =head3 Strings
350              
351             If the variable on the left is a string, this operator searches the string for
352             a pattern match, and (as if in scalar context) returns true if it succeeds,
353             false if it fails.
354              
355             Note that this is a simple C<$x =~ qr[${y}]> match. Case matters.
356              
357             Given...
358              
359             # where x = 'The Angels have the police box!'
360             x contains 'police' # true
361             x contains 'Police' # false
362             x contains 'police box?' # false
363             x contains 'police box!' # true
364             x contains x # true
365              
366             =head3 Lists
367              
368             If the variable is a list, the operator greps the list to find the attribute.
369             If found, a true value is returned. Otherwise, the return value is false.
370              
371             Given...
372              
373             # where x = ['one', 'two', 'three']
374             x contains 'five' # false
375             x contains 'six' # false
376             x contains 'one' # true
377              
378             =head3 Hashes
379              
380             If the variable is a hash reference, the operator returns true if the specified
381             element in the hash has ever been initialized, even if the corresponding value
382             is undefined.
383              
384             Given...
385              
386             # where x = { okay => 'okay', blah => undef }
387             x contains 'okay' # false
388             x contains 'alright' # false
389             x contains 'blah' # true
390              
391             =head1 Known Bugs
392              
393             None right now. Give it time.
394              
395             =head1 Author
396              
397             Sanko Robinson <sanko@cpan.org> - http://sankorobinson.com/
398              
399             =head1 License and Legal
400              
401             Copyright (C) 2009-2022 by Sanko Robinson E<lt>sanko@cpan.orgE<gt>
402              
403             This program is free software; you can redistribute it and/or modify it under
404             the terms of The Artistic License 2.0. See the F<LICENSE> file included with
405             this distribution or http://www.perlfoundation.org/artistic_license_2_0. For
406             clarification, see http://www.perlfoundation.org/artistic_2_0_notes.
407              
408             When separated from the distribution, all original POD documentation is covered
409             by the Creative Commons Attribution-Share Alike 3.0 License. See
410             http://creativecommons.org/licenses/by-sa/3.0/us/legalcode. For clarification,
411             see http://creativecommons.org/licenses/by-sa/3.0/us/.
412              
413             =cut