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.22';
2             require Template::Liquid::Error;
3             use base 'Template::Liquid::Block';
4 24     24   137 use strict;
  24         42  
  24         1461  
5 24     24   119 use warnings;
  24         44  
  24         465  
6 24     24   119  
  24         42  
  24         1152  
7             # Makes life easy
8             use overload 'bool' => \&is_true, fallback => 1;
9 24     24   24783  
  24         19832  
  24         178  
10             my ($class, $args) = @_;
11             raise Template::Liquid::Error {type => 'Context',
12 265     265 0 484 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       532 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       451 = ((defined $args->{'attrs'} ? $args->{'attrs'} : '')
25             =~ m[("[^"]+"|'[^']+'|(?:[\S]+))]go);
26 265 50       1384 if (defined $lval) {
27             if (!defined $rval && !defined $condition) {
28 265 50       577 return
29 265 100 66     997 bless {lvalue => $lval,
    50          
30             condition => undef,
31             rvalue => undef,
32             template => $args->{'template'},
33             parent => $args->{'parent'}
34             }, $class;
35 127         862 }
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       318 $condition = 'gt' if $condition eq '>';
40 138 100       237 $condition = 'lt' if $condition eq '<';
41 138 100       267 $condition = '_and' if $condition eq '&&';
42 138 100       218 $condition = '_and' if $condition eq 'and';
43 138 50       241 $condition = '_or' if $condition eq '||';
44 138 50       223 $condition = '_or' if $condition eq 'or';
45 138 50       213 return
46 138 50       216 bless {lvalue => $lval,
47             condition => $condition,
48             rvalue => $rval,
49             template => $args->{'template'},
50             parent => $args->{'parent'}
51             }, $class;
52 138         949 }
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 54 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 373 # Might need to render these again
76 263   66     602 my $_l = $s->{template}{context}->get($l);
77 263   66     610 my $_r = $s->{template}{context}->get($r);
78             $l = $_l if defined $_l;
79             $r = $_r if defined $_r;
80 263         591 return _equal($l, $r);
81 263         570 }
82 263 100       488  
83 263 100       439 my ($l, $r) = @_;
84 263         414 my $ref_l = ref $l;
85             return !1 if $ref_l ne ref $r;
86             if (!$ref_l) {
87             return
88 283     283   437 !!(grep {defined} $l, $r)
89 283         361 ? (grep {m[\D]o} $l, $r)
90 283 100       492 ? $l eq $r
91 281 100       451 : $l == $r
    100          
    50          
92             : !1;
93 538         1062 }
94 269 100       390 elsif ($ref_l eq 'ARRAY') {
  538 50       2033  
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       28 }
101 4         8 elsif ($ref_l eq 'HASH') {
  4         15  
102 16 100       44 my %temp = %$r;
103             for my $key (keys %$l) {
104 2         11 return 0
105             unless exists $temp{$key} and
106             defined($l->{$key}) eq defined($temp{$key}) and
107 6         21 (defined $temp{$key} ? _equal($temp{$key}, $l->{$key}) : !!1);
108 6         18 delete $temp{$key};
109             }
110             return !keys(%temp);
111             }
112 6 50 66     47 }
    100 100        
113 2         6  
114             my ($s) = @_;
115 2         15 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 70 my $_l = $s->{template}{context}->get($l);
121             my $_r = $s->{template}{context}->get($r);
122 90 100       210 $l = $_l if defined $_l;
123 45         78 $r = $_r if defined $_r;
124             return
125             !!(grep {defined} $l, $r)
126 45         127 ? (grep {m[\D]o} $l, $r)
127 45         112 ? $l gt $r
128 45 100       105 : $l > $r
129 45 50       84 : 0;
130             }
131 90         185  
132 45 100       77 my ($s) = @_;
  90 50       370  
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 33 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 25 $r = $_r if defined $_r;
141 12         57 $r = quotemeta $r;
142 12         35 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         37 return $l =~ qr[${r}] ? 1 : !1;
146 12         46 }
147 12 50       41  
148 12 50       26 my ($s) = @_;
149 12         23 my $l = $s->{template}{context}->get($s->{'lvalue'}) || $s->{'lvalue'};
150 12 50 33     46 my $r = $s->{template}{context}->get($s->{'rvalue'}) || $s->{'rvalue'};
151 12 100       47  
    100          
152 8 100       22 # Might need to render these again
  12 100       42  
153 4 100       108 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 25 }
185 15         27  
186 15         26 my ($s) = @_;
187 15   100     29 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 98 my $_l = $s->{template}{context}->get($l);
192 43         63 $l = $_l if defined $_l;
193 43         57 return !!($l) ? 1 : 0;
194 43   100     95 }
195             my $condition = $s->can($s->{'condition'});
196             raise Template::Liquid::Error {
197             template => $s->{template},
198             type => 'Context',
199 406     406 0 626 message => 'Bad condition ' . $s->{'condition'},
200 406 50 66     883 fatal => 1
201             }
202             if !$condition;
203 28         77  
204 28         70 #return !1 if !$condition;
205 28 100       69 return $s->$condition();
206 28 100       156 }
207             1;
208 378         862  
209             =pod
210              
211             =begin stopwords
212 378 50       660  
213             stringwise greps
214              
215             =end stopwords
216              
217             =head1 NAME
218 378         611  
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