line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Template::Liquid::Filters; |
2
|
|
|
|
|
|
|
our $VERSION = '1.0.23'; |
3
|
25
|
|
|
25
|
|
183
|
use strict; |
|
25
|
|
|
|
|
65
|
|
|
25
|
|
|
|
|
742
|
|
4
|
25
|
|
|
25
|
|
157
|
use warnings; |
|
25
|
|
|
|
|
53
|
|
|
25
|
|
|
|
|
107955
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
sub import { |
7
|
25
|
|
|
25
|
|
133
|
Template::Liquid::register_filter( |
8
|
|
|
|
|
|
|
qw[ |
9
|
|
|
|
|
|
|
abs append at_least at_most |
10
|
|
|
|
|
|
|
capitalize ceil compact concat |
11
|
|
|
|
|
|
|
date default divided_by downcase |
12
|
|
|
|
|
|
|
escape escape_once |
13
|
|
|
|
|
|
|
first floor |
14
|
|
|
|
|
|
|
join |
15
|
|
|
|
|
|
|
last lstrip |
16
|
|
|
|
|
|
|
map minus modulo |
17
|
|
|
|
|
|
|
newline_to_br |
18
|
|
|
|
|
|
|
plus prepend |
19
|
|
|
|
|
|
|
remove remove_first replace replace_first reverse round rstrip |
20
|
|
|
|
|
|
|
size slice sort sort_natural split strip strip_html strip_newlines |
21
|
|
|
|
|
|
|
times truncate truncatewords |
22
|
|
|
|
|
|
|
uniq upcase url_decode url_encode |
23
|
|
|
|
|
|
|
where |
24
|
|
|
|
|
|
|
money stock_price |
25
|
|
|
|
|
|
|
] |
26
|
|
|
|
|
|
|
); |
27
|
|
|
|
|
|
|
} |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=pod |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
=encoding UTF-8 |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
=begin stopwords |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
Lütke jadedPixel truthy html newlines endcapture vs |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
=end stopwords |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=head1 NAME |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
Template::Liquid::Filters - Default Filters Based on Liquid's Standard Set |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
=head1 Synopsis |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
Filters are simple methods that modify the output of numbers, strings, |
46
|
|
|
|
|
|
|
variables and objects. They are placed within an output tag C<{{ }}> and are |
47
|
|
|
|
|
|
|
denoted by a pipe character C<|>. |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# product.title = "Awesome Shoes" |
50
|
|
|
|
|
|
|
{{ product.title | upcase }} |
51
|
|
|
|
|
|
|
# Output: AWESOME SHOES |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
In the example above, C<product> is the object, C<title> is its attribute, and |
54
|
|
|
|
|
|
|
C<upcase> is the filter being applied. |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
Some filters require a parameter to be passed. |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
{{ product.title | remove: "Awesome" }} |
59
|
|
|
|
|
|
|
# Output: Shoes |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
Multiple filters can be used on one output. They are applied from left to |
62
|
|
|
|
|
|
|
right. |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
{{ product.title | upcase | remove: "AWESOME" }} |
65
|
|
|
|
|
|
|
# SHOES |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=head1 Standard Filters |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
These are the current default filters. They have been written to behave exactly |
71
|
|
|
|
|
|
|
like their Ruby Liquid counterparts accept where Perl makes improvement |
72
|
|
|
|
|
|
|
irresistible. |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=head2 C<abs> |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
Returns the absolute value of a number. |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
{{ 4 | abs }} => 4 |
79
|
|
|
|
|
|
|
{{ -4 | abs }} => 4 |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=cut |
82
|
|
|
|
|
|
|
|
83
|
2
|
|
|
2
|
1
|
6
|
sub abs { CORE::abs($_[0]) } |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
=head2 C<append> |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
Append a string. |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
{{ 'foo' | append:'bar' }} => 'foobar' |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=cut |
92
|
|
|
|
|
|
|
|
93
|
1
|
50
|
|
1
|
1
|
4
|
sub append { my ($x, $y) = @_; return $x . (defined $y ? $y : ''); } |
|
1
|
|
|
|
|
5
|
|
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=head2 C<at_least> |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
Limits a number to a minimum value. |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
{{ 4 | at_least: 5 }} => 5 |
100
|
|
|
|
|
|
|
{{ 4 | at_least: 3 }} => 4 |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=cut |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
sub at_least { |
105
|
2
|
|
|
2
|
1
|
10
|
my ($value, $min) = @_; |
106
|
2
|
100
|
|
|
|
10
|
$min > $value ? $min : $value; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
=head2 C<at_most> |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
Limits a number to a maximum value. |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
{{ 4 | at_most: 5 }} => 4 |
114
|
|
|
|
|
|
|
{{ 4 | at_most: 3 }} => 3 |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
=cut |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub at_most { |
119
|
2
|
|
|
2
|
1
|
5
|
my ($value, $max) = @_; |
120
|
2
|
100
|
|
|
|
8
|
$max < $value ? $max : $value; |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
=head2 C<capitalize> |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
Capitalize words in the input sentence. This filter first applies Perl's C<lc> |
126
|
|
|
|
|
|
|
function and then the C<ucfirst> function. |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
{{ 'this is ONLY a test.' | capitalize }} => This is only a test. |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
=cut |
131
|
|
|
|
|
|
|
|
132
|
3
|
|
|
3
|
1
|
7
|
sub capitalize { my ($x) = @_; return ucfirst lc $x; } |
|
3
|
|
|
|
|
12
|
|
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=head2 C<ceil> |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
Rounds an integer up to the nearest integer. |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
{{ 4.6 | ceil }} => 5 |
139
|
|
|
|
|
|
|
{{ 4.3 | ceil }} => 5 |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=cut |
142
|
|
|
|
|
|
|
|
143
|
4
|
100
|
|
4
|
1
|
13
|
sub ceil { my ($value) = @_; int($value) + ($value > int($value) ? 1 : 0) } |
|
4
|
|
|
|
|
31
|
|
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
=head2 C<compact> |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
Removes any undefined values from an array. |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
For this example, assume C<site.pages> is an array of content pages for a |
150
|
|
|
|
|
|
|
website, and some of these pages have an attribute called category that |
151
|
|
|
|
|
|
|
specifies their content category. If we map those categories to an array, some |
152
|
|
|
|
|
|
|
of the array items might be undefined if any pages do not have a category |
153
|
|
|
|
|
|
|
attribute. |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
{% assign all_categories = site.pages | map: "category" %} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
{% for item in all_categories %} |
158
|
|
|
|
|
|
|
- {{ item }} |
159
|
|
|
|
|
|
|
{% endfor %} |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
The output of this template would look like this: |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
- business |
164
|
|
|
|
|
|
|
- celebrities |
165
|
|
|
|
|
|
|
- |
166
|
|
|
|
|
|
|
- lifestyle |
167
|
|
|
|
|
|
|
- sports |
168
|
|
|
|
|
|
|
- |
169
|
|
|
|
|
|
|
- technology |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
By using compact when we create our C<site_categories> array, we can remove all |
172
|
|
|
|
|
|
|
the nil values in the array. |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
{% assign all_categories = site.pages | map: "category" | compact %} |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
{% for item in all_categories %} |
177
|
|
|
|
|
|
|
- {{ item }} |
178
|
|
|
|
|
|
|
{% endfor %} |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
The output of this template would look like this: |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
- business |
183
|
|
|
|
|
|
|
- celebrities |
184
|
|
|
|
|
|
|
- lifestyle |
185
|
|
|
|
|
|
|
- sports |
186
|
|
|
|
|
|
|
- technology |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
=cut |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
sub compact { |
191
|
1
|
|
|
1
|
1
|
4
|
my ($list) = @_; |
192
|
1
|
|
|
|
|
3
|
[grep { defined $_ } @$list]; |
|
7
|
|
|
|
|
14
|
|
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=head2 C<concat> |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
Concatenates (joins together) multiple arrays. The resulting array contains all |
198
|
|
|
|
|
|
|
the items from the input arrays. |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
{% assign fruits = "apples, oranges, peaches" | split: ", " %} |
202
|
|
|
|
|
|
|
{% assign vegetables = "carrots, turnips, potatoes" | split: ", " %} |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
{% assign everything = fruits | concat: vegetables %} |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
{% for item in everything %} |
207
|
|
|
|
|
|
|
- {{ item }} |
208
|
|
|
|
|
|
|
{% endfor %} |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
...becomes... |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
- apples |
213
|
|
|
|
|
|
|
- oranges |
214
|
|
|
|
|
|
|
- peaches |
215
|
|
|
|
|
|
|
- carrots |
216
|
|
|
|
|
|
|
- turnips |
217
|
|
|
|
|
|
|
- potatoes |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
You can string together two or more array elements with the C<concat> filter: |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
{% assign furniture = "chairs, tables, shelves" | split: ", " %} |
222
|
|
|
|
|
|
|
{% assign vegetables = "carrots, turnips, potatoes" | split: ", " %} |
223
|
|
|
|
|
|
|
{% assign fruits = "apples, oranges, peaches" | split: ", " %} |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
{% assign everything = fruits | concat: vegetables | concat: furniture %} |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
{% for item in everything %} |
228
|
|
|
|
|
|
|
- {{ item }} |
229
|
|
|
|
|
|
|
{% endfor %} |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
...becomes... |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
- apples |
234
|
|
|
|
|
|
|
- oranges |
235
|
|
|
|
|
|
|
- peaches |
236
|
|
|
|
|
|
|
- carrots |
237
|
|
|
|
|
|
|
- turnips |
238
|
|
|
|
|
|
|
- potatoes |
239
|
|
|
|
|
|
|
- chairs |
240
|
|
|
|
|
|
|
- tables |
241
|
|
|
|
|
|
|
- shelves |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
=cut |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
sub concat { |
246
|
3
|
|
|
3
|
1
|
7
|
my ($values, $more) = @_; |
247
|
3
|
|
|
|
|
10
|
[map {@$_} grep {defined} $values, $more]; |
|
6
|
|
|
|
|
19
|
|
|
6
|
|
|
|
|
14
|
|
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=head2 C<date> |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
Converts a timestamp into another date format. The format for this syntax is |
253
|
|
|
|
|
|
|
the same as C<strftime>. |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
{{ article.published_at | date: "%a, %b %d, %y" }} => Fri, Jul 17, 15 |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
{{ article.published_at | date: "%Y" }} => 2015 |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
C<date> works on strings if they contain well-formatted dates: |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
{{ "March 14, 2016" | date: "%b %d, %y" }} => Mar 14, 16 |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
Natural language dates are parsed by C<DateTime::Format::Natural>. |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
To get the current time, pass the special word <"now"> (or C<"today">) to date: |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
This page was last updated at {{ "now" | date: "%Y-%m-%d %H:%M" }}. |
269
|
|
|
|
|
|
|
=> This page was last updated at 2019-09-19 17:48. |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
Note that the value will be the current time of when the page was last |
272
|
|
|
|
|
|
|
generated from the template, not when the page is presented to a user if |
273
|
|
|
|
|
|
|
caching or static site generation is involved. |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
=cut |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
sub date { |
278
|
7
|
|
|
7
|
1
|
12
|
CORE::state $DateTimeFormatNatural; |
279
|
7
|
|
|
|
|
29
|
my ($x, $y) = @_; |
280
|
7
|
100
|
100
|
|
|
33
|
$x = time() if lc $x eq 'now' || lc $x eq 'today'; |
281
|
7
|
100
|
100
|
|
|
109
|
if (ref $x ne 'DateTime' && $x =~ m[\D]) { # Any non-digit |
282
|
1
|
50
|
|
|
|
7
|
if (!defined $DateTimeFormatNatural) { |
283
|
1
|
|
|
|
|
637
|
require DateTime::Format::Natural; |
284
|
1
|
|
|
|
|
46967
|
$DateTimeFormatNatural = DateTime::Format::Natural->new(); |
285
|
|
|
|
|
|
|
} |
286
|
1
|
|
|
|
|
39681
|
$x = $DateTimeFormatNatural->parse_datetime($x); |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
# |
289
|
7
|
50
|
|
|
|
6623
|
$y = defined $y ? $y : '%c'; |
290
|
7
|
100
|
66
|
|
|
40
|
return $x->strftime($y) if ref $x && $x->can('strftime'); |
291
|
5
|
50
|
|
|
|
24
|
return if $x !~ m[^(\d*\.)?\d+?$]o; |
292
|
5
|
|
|
|
|
32
|
require POSIX; |
293
|
5
|
|
|
|
|
262
|
return POSIX::strftime($y, gmtime($x)); |
294
|
|
|
|
|
|
|
} |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
=head2 C<default> |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
Allows you to specify a fallback in case a value doesn't exist. default will |
299
|
|
|
|
|
|
|
show its value if the left side is nil, false, or empty. |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
In this example, C<product_price> is not defined, so the default value is used. |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
{{ product_price | default: 2.99 }} => 2.99 |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
In this example, C<product_price> is defined, so the default value is not used. |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
{% assign product_price = 4.99 %} |
308
|
|
|
|
|
|
|
{{ product_price | default: 2.99 }} => 4.99 |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
In this example, C<product_price> is empty, so the default value is used. |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
{% assign product_price = "" %} |
313
|
|
|
|
|
|
|
{{ product_price | default: 2.99 }} => 2.99 |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
=cut |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
sub default { |
318
|
7
|
|
|
7
|
1
|
19
|
my ($x, $y) = @_; |
319
|
7
|
100
|
|
|
|
29
|
return length $x ? $x : $y if !ref $x; |
|
|
50
|
|
|
|
|
|
320
|
0
|
0
|
|
|
|
0
|
return defined $x ? $x : $y; |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
=head2 C<divided_by> |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
Divides a number by another number. |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
The result is rounded down to the nearest integer (that is, the floor) if the |
328
|
|
|
|
|
|
|
divisor is an integer. |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
{{ 16 | divided_by: 4 }} => 4 |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
{{ 5 | divided_by: 3 }} = 1 |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
=head3 Controlling rounding |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
C<divided_by> produces a result of the same type as the divisor -- that is, if |
338
|
|
|
|
|
|
|
you divide by an integer, the result will be an integer. If you divide by a |
339
|
|
|
|
|
|
|
float (a number with a decimal in it), the result will be a float. |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
For example, here the divisor is an integer: |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
{{ 20 | divided_by: 7 }} => 2 |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
Here it is a float: |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
{{ 20 | divided_by: 7.0 }} => 2.85714285714286 |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
Note that floats will not match thanks to how perl and ruby handle floating |
350
|
|
|
|
|
|
|
point numbers. |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
=cut |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
sub divided_by { |
355
|
6
|
|
|
6
|
1
|
15
|
my ($x, $y) = @_; |
356
|
6
|
|
|
|
|
21
|
my $r = $x / $y; |
357
|
6
|
|
|
|
|
16
|
my ($_x) = $x =~ m[\.(\d+)$]; |
358
|
6
|
|
|
|
|
16
|
my ($_y) = $y =~ m[\.(\d+)$]; |
359
|
6
|
|
|
|
|
40
|
my ($_r) = $r =~ m[\.(\d+)$]; |
360
|
6
|
|
50
|
|
|
31
|
$_x //= ''; |
361
|
6
|
|
100
|
|
|
20
|
$_y //= ''; |
362
|
6
|
|
100
|
|
|
16
|
$_r //= ''; |
363
|
6
|
|
|
|
|
8
|
my $_lx = length $_x; |
364
|
6
|
|
|
|
|
11
|
my $_ly = length $_y; |
365
|
6
|
|
|
|
|
8
|
my $_lr = length $_r; |
366
|
6
|
100
|
66
|
|
|
52
|
($_lx || $_ly) |
367
|
|
|
|
|
|
|
? (sprintf '%0.' . ([sort $_lr, 1]->[-1]) . 'f', $r) |
368
|
|
|
|
|
|
|
: int $r; |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
=head2 C<downcase> |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
Makes each character in a string lowercase. It has no effect on strings which |
374
|
|
|
|
|
|
|
are already all lowercase. |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
{{ "Parker Moore" | downcase }} => parker moore |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
{{ "apple" | downcase }} => apple |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
=cut |
381
|
|
|
|
|
|
|
|
382
|
3
|
|
|
3
|
1
|
9
|
sub downcase { my ($x) = @_; return lc $x } |
|
3
|
|
|
|
|
8
|
|
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
=head2 C<escape> |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
Escapes a string by replacing characters with escape sequences (so that the |
387
|
|
|
|
|
|
|
string can be used in a URL, for example). It doesn't change strings that don't |
388
|
|
|
|
|
|
|
have anything to escape. |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
{{ "Have you read 'James & the Giant Peach'?" | escape }} |
391
|
|
|
|
|
|
|
=> Have you read 'James & the Giant Peach'? |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
{{ "Tetsuro Takara" | escape }} => Tetsuro Takara |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
=cut |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
sub escape { |
398
|
2
|
|
|
2
|
1
|
5
|
my ($x) = @_; |
399
|
2
|
|
|
|
|
9
|
$x =~ s/([^A-Za-z0-9\-\._~ \?])/ |
400
|
3
|
|
|
|
|
9
|
my $x = ord $1; |
401
|
3
|
50
|
|
|
|
26
|
sprintf('&%s;', |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
402
|
|
|
|
|
|
|
$1 eq '&' ? 'amp' : |
403
|
|
|
|
|
|
|
$1 eq '>' ? 'gt' : |
404
|
|
|
|
|
|
|
$1 eq '<' ? 'lt' : |
405
|
|
|
|
|
|
|
$1 eq '"' ? 'quot' : |
406
|
|
|
|
|
|
|
$1 eq "'" ? '#39' : |
407
|
|
|
|
|
|
|
"#$x") |
408
|
|
|
|
|
|
|
/gei; |
409
|
2
|
|
|
|
|
8
|
$x; |
410
|
|
|
|
|
|
|
} |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
=head2 C<escape_once> |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
Escapes a string without changing existing escaped entities. It doesn't change |
415
|
|
|
|
|
|
|
strings that don't have anything to escape. |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
{{ "1 < 2 & 3" | escape_once }} => 1 < 2 & 3 |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
{{ "1 < 2 & 3" | escape_once }} => 1 < 2 & 3 |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
=cut |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
sub escape_once { |
424
|
2
|
|
|
2
|
1
|
6
|
my ($x) = @_; |
425
|
2
|
|
|
|
|
15
|
$x =~ s/("|>|<|'|&(?!([a-z]+|(#\d+));))/ |
426
|
2
|
0
|
|
|
|
21
|
sprintf('&%s;', |
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
427
|
|
|
|
|
|
|
$1 eq '&' ? 'amp' : |
428
|
|
|
|
|
|
|
$1 eq '>' ? 'gt' : |
429
|
|
|
|
|
|
|
$1 eq '<' ? 'lt' : |
430
|
|
|
|
|
|
|
$1 eq '"' ? 'quot' : |
431
|
|
|
|
|
|
|
$1 eq "'" ? '#39' : |
432
|
|
|
|
|
|
|
"#$x;") |
433
|
|
|
|
|
|
|
/gei; |
434
|
2
|
|
|
|
|
7
|
$x; |
435
|
|
|
|
|
|
|
} |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
=head2 C<first> |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
Returns the first item of an array. |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
{{ "Ground control to Major Tom." | split: " " | first }} => Ground |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
{% assign my_array = "zebra, octopus, giraffe, tiger" | split: ", " %} |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
{{ my_array.first }} |
447
|
|
|
|
|
|
|
=> zebra |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
You can use C<first> with dot notation when you need to use the filter inside a |
450
|
|
|
|
|
|
|
tag: |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
{% if my_array.first == "zebra" %} |
453
|
|
|
|
|
|
|
Here comes a zebra! |
454
|
|
|
|
|
|
|
{% endif %} |
455
|
|
|
|
|
|
|
=> Here comes a zebra! |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
=cut |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
sub first { |
460
|
4
|
|
|
4
|
1
|
9
|
my ($x) = @_; |
461
|
4
|
100
|
|
|
|
18
|
return ref $x eq 'ARRAY' ? @{$x}[0] : substr($x, 0, 1); |
|
3
|
|
|
|
|
11
|
|
462
|
|
|
|
|
|
|
} |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
=head2 C<floor> |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
Rounds an integer down to the nearest integer. |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
{{ 1.2 | floor }} => 1 |
469
|
|
|
|
|
|
|
{{ 2.0 | floor }} => 2 |
470
|
|
|
|
|
|
|
{{ 183.357 | floor }} => 183 |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
Here the input value is a string: |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
{{ "3.5" | floor }} => 3 |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
=cut |
477
|
|
|
|
|
|
|
|
478
|
4
|
|
|
4
|
1
|
18
|
sub floor { int $_[0] } |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
=head2 C<join> |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
Combines the items in an array into a single string using the argument as a |
483
|
|
|
|
|
|
|
separator. |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
{% assign beatles = "John, Paul, George, Ringo" | split: ", " %} |
486
|
|
|
|
|
|
|
{{ beatles | join: " and " }} => John and Paul and George and Ringo |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
=cut |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
sub join { |
491
|
9
|
|
|
9
|
1
|
25
|
my ($x, $y) = @_; |
492
|
9
|
50
|
|
|
|
30
|
return CORE::join($y, @{$x}) if ref $x eq 'ARRAY'; |
|
9
|
|
|
|
|
41
|
|
493
|
0
|
0
|
|
|
|
0
|
return CORE::join($y, keys %{$x}) if ref $x eq 'HASH'; |
|
0
|
|
|
|
|
0
|
|
494
|
0
|
|
|
|
|
0
|
return $x; |
495
|
|
|
|
|
|
|
} |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
=head2 C<last> |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
Returns the last item of an array. |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
{{ "Ground control to Major Tom." | split: " " | last }} => Tom. |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
{% assign my_array = "zebra, octopus, giraffe, tiger" | split: ", " %} |
504
|
|
|
|
|
|
|
{{ my_array.last }} => tiger |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
You can use C<last> with dot notation when you need to use the filter inside a |
507
|
|
|
|
|
|
|
tag: |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
{% assign my_array = "zebra, octopus, giraffe, tiger" | split: ", " %} |
510
|
|
|
|
|
|
|
{% if my_array.last == "tiger" %} |
511
|
|
|
|
|
|
|
There goes a tiger! |
512
|
|
|
|
|
|
|
{% endif %} |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
=cut |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
sub last { |
517
|
4
|
|
|
4
|
1
|
12
|
my ($x, $y) = @_; |
518
|
4
|
|
|
|
|
11
|
my $ref = ref $x; |
519
|
4
|
100
|
|
|
|
16
|
return substr $x, -1 if !$ref; |
520
|
3
|
50
|
|
|
|
9
|
return @{$x}[-1] if $ref eq 'ARRAY'; |
|
3
|
|
|
|
|
11
|
|
521
|
|
|
|
|
|
|
} |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
=head2 C<lstrip> |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
Removes all whitespace (tabs, spaces, and newlines) from the left side of a |
526
|
|
|
|
|
|
|
string. It does not affect spaces between words. |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
{{ " So much room for activities! " | lstrip }} |
529
|
|
|
|
|
|
|
=> So much room for activities! |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
=cut |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
sub lstrip { |
534
|
1
|
|
|
1
|
1
|
4
|
my ($x) = @_; |
535
|
1
|
|
|
|
|
5
|
$x =~ s[^\s*][]; |
536
|
1
|
|
|
|
|
4
|
$x; |
537
|
|
|
|
|
|
|
} |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
=head2 C<map> |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
Creates an array of values by extracting the values of a named property from |
542
|
|
|
|
|
|
|
another object. |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
In this example, assume the object C<site.pages> contains all the metadata for |
545
|
|
|
|
|
|
|
a website. Using assign with the map filter creates a variable that contains |
546
|
|
|
|
|
|
|
only the values of the category properties of everything in the site.pages |
547
|
|
|
|
|
|
|
object. |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
{% assign all_categories = site.pages | map: "category" %} |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
{% for item in all_categories %} |
552
|
|
|
|
|
|
|
- {{ item }} |
553
|
|
|
|
|
|
|
{% endfor %} |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
The output of this template would look like this: |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
- business |
558
|
|
|
|
|
|
|
- celebrities |
559
|
|
|
|
|
|
|
- lifestyle |
560
|
|
|
|
|
|
|
- sports |
561
|
|
|
|
|
|
|
- technology |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
=cut |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
sub map { |
566
|
4
|
|
|
4
|
1
|
11
|
my ($list, $key) = @_; |
567
|
4
|
|
|
|
|
8
|
[map { $_->{$key} } @$list]; |
|
23
|
|
|
|
|
48
|
|
568
|
|
|
|
|
|
|
} |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
=head2 C<minus> |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
Subtracts a number from another number. |
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
{{ 4 | minus: 2 }} => 2 |
575
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
{{ 16 | minus: 4 }} => 12 |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
{{ 183.357 | minus: 12 }} => 171.357 |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
=cut |
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
sub minus { |
583
|
11
|
|
|
11
|
1
|
27
|
my ($x, $y) = @_; |
584
|
11
|
|
50
|
|
|
26
|
$x ||= 0; |
585
|
11
|
100
|
66
|
|
|
103
|
return $x =~ m[^[\+-]?(\d*\.)?\d+?$]o && |
586
|
|
|
|
|
|
|
$y =~ m[^[\+-]?(\d*\.)?\d+?$]o ? $x - $y : (); |
587
|
|
|
|
|
|
|
} |
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
=head2 C<modulo> |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
Returns the remainder of a division operation. |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
{{ 3 | modulo: 2 }} => 1 |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
{{ 24 | modulo: 7 }} => 3 |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
{{ 183.357 | modulo: 12 }} => 3.357 |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
=cut |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
sub modulo { |
602
|
3
|
|
|
3
|
1
|
9
|
my ($x, $y) = @_; |
603
|
3
|
|
|
|
|
20
|
require POSIX; |
604
|
3
|
|
|
|
|
30
|
POSIX::fmod($x, $y); |
605
|
|
|
|
|
|
|
} |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
=head2 C<newline_to_br> |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
Replaces each newline (C<\n>) with html break (C<< <br />\n >>). |
610
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
{% capture string_with_newlines %} |
612
|
|
|
|
|
|
|
Hello |
613
|
|
|
|
|
|
|
there |
614
|
|
|
|
|
|
|
{% endcapture %} |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
{{ string_with_newlines | newline_to_br }} |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
...becomes... |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
<br /> |
621
|
|
|
|
|
|
|
Hello<br /> |
622
|
|
|
|
|
|
|
there<br /> |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
=cut |
625
|
|
|
|
|
|
|
|
626
|
2
|
|
|
2
|
1
|
6
|
sub newline_to_br { my ($x, $y) = @_; $x =~ s[\n][<br />\n]go; return $x; } |
|
2
|
|
|
|
|
9
|
|
|
2
|
|
|
|
|
7
|
|
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
=head2 C<plus> |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
Adds a number to another number. |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
{{ 154 | plus:1183 }} => 1337 |
633
|
|
|
|
|
|
|
{{ 4 | plus: 2 }} => 6 |
634
|
|
|
|
|
|
|
{{ 16 | plus: 4 }} => 20 |
635
|
|
|
|
|
|
|
{{ 183.357 | plus: 12 }} => 195.357 |
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
{{ 'What' | plus:'Uhu' }} => WhatUhu |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
=head3 MATHFAIL! |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
Please note that integer behavior differs with Perl vs. Ruby so... |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
{{ '1' | plus: '1' }} |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
...becomes C<11> in Ruby but C<2> in Perl. |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
=cut |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
sub plus { |
650
|
7
|
|
|
7
|
1
|
17
|
my ($x, $y) = @_; |
651
|
7
|
|
50
|
|
|
18
|
$x ||= 0; |
652
|
7
|
100
|
66
|
|
|
65
|
return $x =~ m[^[\+-]?(\d*\.)?\d+?$]o && |
653
|
|
|
|
|
|
|
$y =~ m[^[\+-]?(\d*\.)?\d+?$]o ? $x + $y : $x . $y; |
654
|
|
|
|
|
|
|
} |
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
=head2 C<prepend> |
657
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
Adds the specified string to the beginning of another string. |
659
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
{{ 'bar' | prepend:'foo' }} => 'foobar' |
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
{{ "apples, oranges, and bananas" | prepend: "Some fruit: " }} |
663
|
|
|
|
|
|
|
=> Some fruit: apples, oranges, and bananas |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
{% assign url = "example.com" %} |
666
|
|
|
|
|
|
|
{{ "/index.html" | prepend: url }} => example.com/index.html |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
=cut |
669
|
|
|
|
|
|
|
|
670
|
7
|
100
|
|
7
|
1
|
18
|
sub prepend { my ($x, $y) = @_; return (defined $y ? $y : '') . $x; } |
|
7
|
|
|
|
|
28
|
|
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
=head2 C<remove> |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
Removes every occurrence of the specified substring from a string. |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
{{ 'foobarfoobar' | remove:'foo' }} => 'barbar' |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
{{ "I strained to see the train through the rain" | remove: "rain" }} |
679
|
|
|
|
|
|
|
=> I sted to see the t through the |
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
=cut |
682
|
|
|
|
|
|
|
|
683
|
3
|
|
|
3
|
1
|
12
|
sub remove { my ($x, $y) = @_; $y = quotemeta($y); $x =~ s{$y}{}g; return $x } |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
45
|
|
|
3
|
|
|
|
|
11
|
|
684
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
=head2 C<remove_first> |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
Remove the first occurrence of a string. |
688
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
{{ 'barbar' | remove_first:'bar' }} => bar |
690
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
{{ "I strained to see the train through the rain" | remove_first: "rain" }} |
692
|
|
|
|
|
|
|
=> I sted to see the train through the rain |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
=cut |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
sub remove_first { |
697
|
3
|
|
|
3
|
1
|
10
|
my ($x, $y) = @_; |
698
|
3
|
|
|
|
|
9
|
$y = quotemeta($y); |
699
|
3
|
|
|
|
|
42
|
$x =~ s{$y}{}; |
700
|
3
|
|
|
|
|
11
|
return $x; |
701
|
|
|
|
|
|
|
} |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
=head2 C<replace> |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
Replaces every occurrence of the first argument in a string with the second |
706
|
|
|
|
|
|
|
argument. |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
The replacement value is optional and defaults to an empty string (C<''>). |
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
{{ 'foofoo' | replace:'foo','bar' }} => barbar |
711
|
|
|
|
|
|
|
{% assign this = 'that' %} |
712
|
|
|
|
|
|
|
{{ 'Replace that with this' | replace:this,'this' }} => Replace this with this |
713
|
|
|
|
|
|
|
{{ 'I have a listhp.' | replace:'th' }} => I have a lisp. |
714
|
|
|
|
|
|
|
{{ "Take my protein pills and put my helmet on" | replace: "my", "your" }} |
715
|
|
|
|
|
|
|
=> Take your protein pills and put your helmet on |
716
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
=cut |
718
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
sub replace { |
720
|
5
|
|
|
5
|
1
|
20
|
my ($x, $y, $z) = @_; |
721
|
5
|
100
|
|
|
|
16
|
$z = defined $z ? $z : ''; |
722
|
5
|
|
|
|
|
11
|
$y = quotemeta($y); |
723
|
5
|
50
|
|
|
|
92
|
$x =~ s{$y}{$z}g if $y; |
724
|
5
|
|
|
|
|
19
|
return $x; |
725
|
|
|
|
|
|
|
} |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
=head2 C<replace_first> |
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
Replaces only the first occurrence of the first argument in a string with the |
730
|
|
|
|
|
|
|
second argument. |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
The replacement value is optional and defaults to an empty string (C<''>). |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
{{ 'barbar' | replace_first:'bar','foo' }} => 'foobar' |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
{{ "Take my protein pills and put my helmet on" | replace_first: "my", "your" }} |
737
|
|
|
|
|
|
|
=> Take your protein pills and put my helmet on |
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
=cut |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
sub replace_first { |
742
|
3
|
|
|
3
|
1
|
12
|
my ($x, $y, $z) = @_; |
743
|
3
|
50
|
|
|
|
9
|
$z = defined $z ? $z : ''; |
744
|
3
|
|
|
|
|
7
|
$y = quotemeta($y); |
745
|
3
|
|
|
|
|
48
|
$x =~ s{$y}{$z}; |
746
|
3
|
|
|
|
|
12
|
return $x; |
747
|
|
|
|
|
|
|
} |
748
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
=head2 C<reverse> |
750
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
Reverses the order of the items in an array. C<reverse> cannot reverse a |
752
|
|
|
|
|
|
|
string. |
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
{% assign my_array = "apples, oranges, peaches, plums" | split: ", " %} |
755
|
|
|
|
|
|
|
{{ my_array | reverse | join: ", " }} => plums, peaches, oranges, apples |
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
Although C<reverse> cannot be used directly on a string, you can split a string |
758
|
|
|
|
|
|
|
into an array, reverse the array, and rejoin it by chaining together filters: |
759
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
{{ "Ground control to Major Tom." | split: "" | reverse | join: "" }} |
761
|
|
|
|
|
|
|
=> .moT rojaM ot lortnoc dnuorG |
762
|
|
|
|
|
|
|
|
763
|
|
|
|
|
|
|
=cut |
764
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
sub reverse { |
766
|
2
|
|
|
2
|
1
|
5
|
my ($args) = @_; |
767
|
2
|
|
|
|
|
10
|
[reverse @$args]; |
768
|
|
|
|
|
|
|
} |
769
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
=head2 C<round> |
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
Rounds a number to the nearest integer or, if a number is passed as an |
773
|
|
|
|
|
|
|
argument, to that number of decimal places. |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
{{ 4.6 | round }} => 5 |
776
|
|
|
|
|
|
|
{{ 4.3 | round }} => 4 |
777
|
|
|
|
|
|
|
{{ 1.2 | round }} => 1 |
778
|
|
|
|
|
|
|
{{ 2.7 | round }} => 3 |
779
|
|
|
|
|
|
|
{{ 4.5612 | round: 2 }} => 4.56 |
780
|
|
|
|
|
|
|
{{ 183.357 | round: 2 }} => 183.36 |
781
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
=cut |
783
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
sub round { |
785
|
6
|
|
|
6
|
1
|
14
|
my ($x, $y) = @_; |
786
|
6
|
50
|
|
|
|
30
|
return if $x !~ m[^(\d*\.)?\d+?$]o; |
787
|
6
|
|
100
|
|
|
63
|
return sprintf '%.' . int($y || 0) . 'f', $x; |
788
|
|
|
|
|
|
|
} |
789
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
=head2 C<rstrip> |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
Removes all whitespace (tabs, spaces, and newlines) from the right side of a |
793
|
|
|
|
|
|
|
string. It does not affect spaces between words. |
794
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
{{ " So much room for activities! " | rstrip }} |
796
|
|
|
|
|
|
|
=> So much room for activities! |
797
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
=cut |
799
|
|
|
|
|
|
|
|
800
|
|
|
|
|
|
|
sub rstrip { |
801
|
1
|
|
|
1
|
1
|
4
|
my ($x) = @_; |
802
|
1
|
|
|
|
|
18
|
$x =~ s[\s*$][]; |
803
|
1
|
|
|
|
|
5
|
$x; |
804
|
|
|
|
|
|
|
} |
805
|
|
|
|
|
|
|
|
806
|
|
|
|
|
|
|
=head2 C<size> |
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
Returns the number of characters in a string, the number of items in an array, |
809
|
|
|
|
|
|
|
or the number of keys in a hash reference. Undefined values return C<0>. |
810
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
# Where array is [1..6] and hash is { child => 'blarg'} |
812
|
|
|
|
|
|
|
{{ array | size }} => 6 |
813
|
|
|
|
|
|
|
{{ 'Testing' | size }} => 7 |
814
|
|
|
|
|
|
|
{{ hash | size }} => 1 |
815
|
|
|
|
|
|
|
{{ undefined | size }} => 0 |
816
|
|
|
|
|
|
|
{{ "Ground control to Major Tom." | size }} => 28 |
817
|
|
|
|
|
|
|
|
818
|
|
|
|
|
|
|
{% assign my_array = "apples, oranges, peaches, plums" | split: ", " %} |
819
|
|
|
|
|
|
|
{{ my_array.size }} => 4 |
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
You can use C<size> with dot notation when you need to use the filter inside a |
822
|
|
|
|
|
|
|
tag: |
823
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
{% if site.pages.size > 10 %} |
825
|
|
|
|
|
|
|
This is a big website! |
826
|
|
|
|
|
|
|
{% endif %} |
827
|
|
|
|
|
|
|
|
828
|
|
|
|
|
|
|
=cut |
829
|
|
|
|
|
|
|
|
830
|
|
|
|
|
|
|
sub size { |
831
|
5
|
|
|
5
|
1
|
13
|
my ($x, $y) = @_; |
832
|
5
|
100
|
|
|
|
14
|
return 0 if !defined $x; |
833
|
4
|
100
|
|
|
|
12
|
return scalar @{$x} if ref $x eq 'ARRAY'; |
|
1
|
|
|
|
|
4
|
|
834
|
3
|
100
|
|
|
|
9
|
return scalar keys %{$x} if ref $x eq 'HASH'; |
|
1
|
|
|
|
|
5
|
|
835
|
2
|
|
|
|
|
5
|
return length $x; |
836
|
|
|
|
|
|
|
} |
837
|
|
|
|
|
|
|
|
838
|
|
|
|
|
|
|
=head2 C<slice> |
839
|
|
|
|
|
|
|
|
840
|
|
|
|
|
|
|
Returns a substring of 1 character beginning at the index specified by the |
841
|
|
|
|
|
|
|
first argument. An optional second argument specifies the length of the |
842
|
|
|
|
|
|
|
substring to be returned. |
843
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
String indices are numbered starting from 0. |
845
|
|
|
|
|
|
|
|
846
|
|
|
|
|
|
|
{{ "Liquid" | slice: 0 }} => L |
847
|
|
|
|
|
|
|
{{ "Liquid" | slice: 2 }} => q |
848
|
|
|
|
|
|
|
{{ "Liquid" | slice: 2, 5 }} => quid |
849
|
|
|
|
|
|
|
|
850
|
|
|
|
|
|
|
If the first argument is a negative number, the indices are counted from the |
851
|
|
|
|
|
|
|
end of the string: |
852
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
{{ "Liquid" | slice: -3, 2 }} => ui |
854
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
=cut |
856
|
|
|
|
|
|
|
|
857
|
|
|
|
|
|
|
sub slice { |
858
|
4
|
|
|
4
|
1
|
13
|
my ($x, $pos, $len) = @_; |
859
|
4
|
100
|
|
|
|
22
|
$len = 1 unless defined $len; |
860
|
4
|
|
|
|
|
17
|
substr $x, $pos, $len; |
861
|
|
|
|
|
|
|
} |
862
|
|
|
|
|
|
|
|
863
|
|
|
|
|
|
|
=head2 C<sort> |
864
|
|
|
|
|
|
|
|
865
|
|
|
|
|
|
|
Sorts items in an array in case-sensitive order. |
866
|
|
|
|
|
|
|
|
867
|
|
|
|
|
|
|
{% assign my_array = "zebra, octopus, giraffe, Sally Snake" | split: ", " %} |
868
|
|
|
|
|
|
|
{{ my_array | sort | join: ", " }} => Sally Snake, giraffe, octopus, zebra |
869
|
|
|
|
|
|
|
|
870
|
|
|
|
|
|
|
An optional argument specifies which property of the array's items to use for |
871
|
|
|
|
|
|
|
sorting. |
872
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
{% assign products_by_price = collection.products | sort: "price" %} |
874
|
|
|
|
|
|
|
{% for product in products_by_price %} |
875
|
|
|
|
|
|
|
<h4>{{ product.title }}</h4> |
876
|
|
|
|
|
|
|
{% endfor %} |
877
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
=cut |
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
sub sort { |
881
|
2
|
|
|
2
|
1
|
6
|
my ($x, $y) = @_; |
882
|
15
|
100
|
66
|
|
|
62
|
return [sort { ($a =~ m[\D] || $b =~ m[\D]) ? $a cmp $b : $a <=> $b } |
883
|
2
|
50
|
|
|
|
125
|
@{$x}] |
|
2
|
|
|
|
|
12
|
|
884
|
|
|
|
|
|
|
if ref $x eq 'ARRAY'; |
885
|
|
|
|
|
|
|
return |
886
|
0
|
0
|
0
|
|
|
0
|
sort { ($a =~ m[\D] || $b =~ m[\D]) ? $a cmp $b : $a <=> $b } |
887
|
0
|
0
|
|
|
|
0
|
keys %{$x} |
|
0
|
|
|
|
|
0
|
|
888
|
|
|
|
|
|
|
if ref $x eq 'HASH'; |
889
|
0
|
|
|
|
|
0
|
return $x; |
890
|
|
|
|
|
|
|
} |
891
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
=head2 C<sort_natural> |
893
|
|
|
|
|
|
|
|
894
|
|
|
|
|
|
|
Sorts items in an array in case-sensitive order. |
895
|
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
{% assign my_array = "zebra, octopus, giraffe, Sally Snake" | split: ", " %} |
897
|
|
|
|
|
|
|
{{ my_array | sort_natural | join: ", " }} => giraffe, octopus, Sally Snake, zebra |
898
|
|
|
|
|
|
|
|
899
|
|
|
|
|
|
|
An optional argument specifies which property of the array's items to use for |
900
|
|
|
|
|
|
|
sorting. |
901
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
{% assign products_by_company = collection.products | sort_natural: "company" %} |
903
|
|
|
|
|
|
|
{% for product in products_by_company %} |
904
|
|
|
|
|
|
|
<h4>{{ product.title }}</h4> |
905
|
|
|
|
|
|
|
{% endfor %} |
906
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
=cut |
908
|
|
|
|
|
|
|
|
909
|
|
|
|
|
|
|
sub sort_natural { |
910
|
1
|
|
|
1
|
1
|
3
|
my ($x, $y) = @_; |
911
|
|
|
|
|
|
|
return [ |
912
|
|
|
|
|
|
|
sort { |
913
|
|
|
|
|
|
|
($a->{$y} =~ m[\D] || $b->{$y} =~ m[\D]) |
914
|
|
|
|
|
|
|
? $a->{$y} cmp $b->{$y} |
915
|
0
|
0
|
0
|
|
|
0
|
: $a->{$y} <=> $b->{$y} |
916
|
1
|
50
|
33
|
|
|
7
|
} @{$x} |
|
0
|
|
|
|
|
0
|
|
917
|
|
|
|
|
|
|
] |
918
|
|
|
|
|
|
|
if ref $x eq 'HASH' && defined $y; |
919
|
|
|
|
|
|
|
return [ |
920
|
5
|
50
|
33
|
|
|
34
|
sort { ($a =~ m[\D] || $b =~ m[\D]) ? lc $a cmp lc $b : $a <=> $b } |
921
|
1
|
50
|
|
|
|
4
|
@{$x} |
|
1
|
|
|
|
|
99
|
|
922
|
|
|
|
|
|
|
] |
923
|
|
|
|
|
|
|
if ref $x eq 'ARRAY'; |
924
|
|
|
|
|
|
|
return |
925
|
0
|
0
|
0
|
|
|
0
|
sort { ($a =~ m[\D] || $b =~ m[\D]) ? lc $a cmp lc $b : $a <=> $b } |
926
|
0
|
0
|
|
|
|
0
|
keys %{$x} |
|
0
|
|
|
|
|
0
|
|
927
|
|
|
|
|
|
|
if ref $x eq 'HASH'; |
928
|
0
|
|
|
|
|
0
|
return $x; |
929
|
|
|
|
|
|
|
} |
930
|
|
|
|
|
|
|
|
931
|
|
|
|
|
|
|
=head2 C<split> |
932
|
|
|
|
|
|
|
|
933
|
|
|
|
|
|
|
Divides a string into an array using the argument as a separator. C<split> is |
934
|
|
|
|
|
|
|
commonly used to convert comma-separated items from a string to an array. |
935
|
|
|
|
|
|
|
|
936
|
|
|
|
|
|
|
{% assign beatles = "John, Paul, George, Ringo" | split: ", " %} |
937
|
|
|
|
|
|
|
{% for member in beatles %} |
938
|
|
|
|
|
|
|
{{ member }} |
939
|
|
|
|
|
|
|
{% endfor %} |
940
|
|
|
|
|
|
|
|
941
|
|
|
|
|
|
|
...becomes... |
942
|
|
|
|
|
|
|
|
943
|
|
|
|
|
|
|
John |
944
|
|
|
|
|
|
|
Paul |
945
|
|
|
|
|
|
|
George |
946
|
|
|
|
|
|
|
Ringo |
947
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
=cut |
949
|
|
|
|
|
|
|
|
950
|
|
|
|
|
|
|
sub split { |
951
|
21
|
|
|
21
|
1
|
52
|
my ($x, $y) = @_; |
952
|
21
|
50
|
|
|
|
56
|
return [] if !defined $x; |
953
|
21
|
|
|
|
|
339
|
[split $y, $x]; |
954
|
|
|
|
|
|
|
} |
955
|
|
|
|
|
|
|
|
956
|
|
|
|
|
|
|
=head2 C<strip> |
957
|
|
|
|
|
|
|
|
958
|
|
|
|
|
|
|
Removes all whitespace (tabs, spaces, and newlines) from both the left and |
959
|
|
|
|
|
|
|
right sides of a string. It does not affect spaces between words. |
960
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
|{{ " So much room for activities! " | strip }}| |
962
|
|
|
|
|
|
|
=> |So much room for activities!| |
963
|
|
|
|
|
|
|
|
964
|
|
|
|
|
|
|
=cut |
965
|
|
|
|
|
|
|
|
966
|
|
|
|
|
|
|
sub strip { |
967
|
1
|
|
|
1
|
1
|
3
|
my ($x) = @_; |
968
|
1
|
|
|
|
|
10
|
$x =~ s[^\s+|\s+$][]g; |
969
|
1
|
|
|
|
|
4
|
$x; |
970
|
|
|
|
|
|
|
} |
971
|
|
|
|
|
|
|
|
972
|
|
|
|
|
|
|
=head2 C<strip_html> |
973
|
|
|
|
|
|
|
|
974
|
|
|
|
|
|
|
Removes any HTML tags from a string. |
975
|
|
|
|
|
|
|
|
976
|
|
|
|
|
|
|
{{ '<div>Hello, <em id="whom">world!</em></div>' | strip_html }} => Hello, world! |
977
|
|
|
|
|
|
|
'{{ '<IMG SRC = "foo.gif" ALT = "A > B">' | strip_html }}' => ' B">' |
978
|
|
|
|
|
|
|
'{{ '<!-- <A comment> -->' | strip_html }}' => ' -->' |
979
|
|
|
|
|
|
|
{{ "Have <em>you</em> read <strong>Ulysses</strong>?" | strip_html }} => Have you read Ulysses? |
980
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
Note that this filter uses C<s[<.*?>][]g> in emulation of the Ruby Liquid |
982
|
|
|
|
|
|
|
library's strip_html function. ...so don't email me if you (correctly) think |
983
|
|
|
|
|
|
|
this is a brain dead way of stripping html. |
984
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
=cut |
986
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
sub strip_html { |
988
|
3
|
|
|
3
|
1
|
7
|
my ($x, $y) = @_; |
989
|
3
|
|
|
|
|
21
|
$x =~ s[<.*?>][]go; |
990
|
3
|
|
|
|
|
7
|
$x =~ s[<!--.*?-->][]go; |
991
|
3
|
|
|
|
|
5
|
$x =~ s[<script.*?<\/script>][]go; |
992
|
3
|
|
|
|
|
9
|
return $x; |
993
|
|
|
|
|
|
|
} |
994
|
|
|
|
|
|
|
|
995
|
|
|
|
|
|
|
=head2 C<strip_newlines> |
996
|
|
|
|
|
|
|
|
997
|
|
|
|
|
|
|
Removes any newline characters (line breaks) from a string. |
998
|
|
|
|
|
|
|
|
999
|
|
|
|
|
|
|
{% capture string_with_newlines %} Hello there {% endcapture %} |
1000
|
|
|
|
|
|
|
|
1001
|
|
|
|
|
|
|
{{ string_with_newlines | strip_newlines }} => Hellothere |
1002
|
|
|
|
|
|
|
|
1003
|
|
|
|
|
|
|
=cut |
1004
|
|
|
|
|
|
|
|
1005
|
2
|
|
|
2
|
1
|
5
|
sub strip_newlines { my ($x, $y) = @_; $x =~ s[\n][]go; return $x; } |
|
2
|
|
|
|
|
12
|
|
|
2
|
|
|
|
|
5
|
|
1006
|
|
|
|
|
|
|
|
1007
|
|
|
|
|
|
|
=head2 C<times> |
1008
|
|
|
|
|
|
|
|
1009
|
|
|
|
|
|
|
Simple multiplication or string repetition. |
1010
|
|
|
|
|
|
|
|
1011
|
|
|
|
|
|
|
{{ 'foo' | times: 4 }} => foofoofoofoo |
1012
|
|
|
|
|
|
|
{{ 5 | times: 4 }} => 20 |
1013
|
|
|
|
|
|
|
{{ 3 | times: 2 }} => 6 |
1014
|
|
|
|
|
|
|
{{ 24 | times: 7 }} => 168 |
1015
|
|
|
|
|
|
|
{{ 183.357 | times: 12 }} => 2200.284 |
1016
|
|
|
|
|
|
|
|
1017
|
|
|
|
|
|
|
=cut |
1018
|
|
|
|
|
|
|
|
1019
|
|
|
|
|
|
|
sub times { |
1020
|
6
|
|
|
6
|
1
|
17
|
my ($x, $y) = @_; |
1021
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
#warn sprintf '%s | %s', $x, $y; |
1023
|
6
|
50
|
|
|
|
16
|
return unless $y; |
1024
|
6
|
|
|
|
|
11
|
my $r; |
1025
|
6
|
50
|
|
|
|
26
|
$r = $x if $y !~ m[^[\+-]?(\d*\.)?\d+?$]o; |
1026
|
6
|
100
|
|
|
|
26
|
return $x x $y if $x !~ m[^[\+-]?(\d*\.)?\d+?$]o; |
1027
|
5
|
50
|
|
|
|
18
|
$r = $x * $y unless defined $r; |
1028
|
5
|
|
|
|
|
16
|
my ($_x) = $x =~ m[\.(\d+)$]; |
1029
|
5
|
|
|
|
|
14
|
my ($_y) = $y =~ m[\.(\d+)$]; |
1030
|
5
|
|
|
|
|
26
|
my ($_r) = $r =~ m[\.(\d+)$]; |
1031
|
5
|
|
100
|
|
|
24
|
$_x //= ''; |
1032
|
5
|
|
100
|
|
|
21
|
$_y //= ''; |
1033
|
5
|
|
100
|
|
|
17
|
$_r //= ''; |
1034
|
5
|
|
|
|
|
8
|
my $_lx = length $_x; |
1035
|
5
|
|
|
|
|
10
|
my $_ly = length $_y; |
1036
|
5
|
|
|
|
|
6
|
my $_lr = length $_r; |
1037
|
5
|
100
|
66
|
|
|
55
|
( ($_lx || $_ly || $_lr) |
1038
|
|
|
|
|
|
|
? (sprintf '%0.' . ([sort $_lx, $_ly, $_lr]->[-1]) . 'f', $r) |
1039
|
|
|
|
|
|
|
: $r); |
1040
|
|
|
|
|
|
|
} |
1041
|
|
|
|
|
|
|
|
1042
|
|
|
|
|
|
|
=head2 C<truncate> |
1043
|
|
|
|
|
|
|
|
1044
|
|
|
|
|
|
|
Shortens a string down to the number of characters passed as an argument. If |
1045
|
|
|
|
|
|
|
the specified number of characters is less than the length of the string, an |
1046
|
|
|
|
|
|
|
ellipsis (...) is appended to the string and is included in the character |
1047
|
|
|
|
|
|
|
count. |
1048
|
|
|
|
|
|
|
|
1049
|
|
|
|
|
|
|
{{ "Ground control to Major Tom." | truncate: 20 }} => Ground control to... |
1050
|
|
|
|
|
|
|
{{ 'Running the halls!!!' | truncate:19 }} => Running the hall.. |
1051
|
|
|
|
|
|
|
{% assign blarg = 'STOP!' %} |
1052
|
|
|
|
|
|
|
{{ 'Any Colour You Like' | truncate:10,blarg }} => Any CSTOP! |
1053
|
|
|
|
|
|
|
{{ 'Why are you running away?' | truncate:4,'?' }} => Why? |
1054
|
|
|
|
|
|
|
{{ 'Ha' | truncate:4 }} => Ha |
1055
|
|
|
|
|
|
|
{{ 'Ha' | truncate:1,'Laugh' }} => Laugh |
1056
|
|
|
|
|
|
|
{{ 'Ha' | truncate:1,'...' }} => ... |
1057
|
|
|
|
|
|
|
|
1058
|
|
|
|
|
|
|
...and... |
1059
|
|
|
|
|
|
|
|
1060
|
|
|
|
|
|
|
{{ 'This is a long line of text to test the default values for truncate' | truncate }} |
1061
|
|
|
|
|
|
|
|
1062
|
|
|
|
|
|
|
...becomes... |
1063
|
|
|
|
|
|
|
|
1064
|
|
|
|
|
|
|
This is a long line of text to test the default... |
1065
|
|
|
|
|
|
|
|
1066
|
|
|
|
|
|
|
=head3 Custom ellipsis |
1067
|
|
|
|
|
|
|
|
1068
|
|
|
|
|
|
|
C<truncate> takes an optional second argument that specifies the sequence of |
1069
|
|
|
|
|
|
|
characters to be appended to the truncated string. By default this is an |
1070
|
|
|
|
|
|
|
ellipsis (...), but you can specify a different sequence. |
1071
|
|
|
|
|
|
|
|
1072
|
|
|
|
|
|
|
The length of the second argument counts against the number of characters |
1073
|
|
|
|
|
|
|
specified by the first argument. For example, if you want to truncate a string |
1074
|
|
|
|
|
|
|
to exactly 10 characters, and use a 3-character ellipsis, use B<13> for the |
1075
|
|
|
|
|
|
|
first argument of truncate, since the ellipsis counts as 3 characters. |
1076
|
|
|
|
|
|
|
|
1077
|
|
|
|
|
|
|
{{ "Ground control to Major Tom." | truncate: 25, ", and so on" }} |
1078
|
|
|
|
|
|
|
=> Ground control, and so on |
1079
|
|
|
|
|
|
|
|
1080
|
|
|
|
|
|
|
=head3 No ellipsis |
1081
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
You can truncate to the exact number of characters specified by the first |
1083
|
|
|
|
|
|
|
argument and avoid showing trailing characters by passing a blank string as the |
1084
|
|
|
|
|
|
|
second argument: |
1085
|
|
|
|
|
|
|
|
1086
|
|
|
|
|
|
|
{{ "Ground control to Major Tom." | truncate: 20, "" }} |
1087
|
|
|
|
|
|
|
=> Ground control to Ma |
1088
|
|
|
|
|
|
|
|
1089
|
|
|
|
|
|
|
=cut |
1090
|
|
|
|
|
|
|
|
1091
|
|
|
|
|
|
|
sub truncate { |
1092
|
5
|
|
|
5
|
1
|
15
|
my ($data, $length, $truncate_string) = @_; |
1093
|
5
|
50
|
|
|
|
12
|
$length = defined $length ? $length : 50; |
1094
|
5
|
100
|
|
|
|
13
|
$truncate_string = defined $truncate_string ? $truncate_string : '...'; |
1095
|
5
|
50
|
|
|
|
12
|
return if !$data; |
1096
|
5
|
|
|
|
|
15
|
my $l = $length - length($truncate_string); |
1097
|
5
|
50
|
|
|
|
10
|
$l = 0 if $l < 0; |
1098
|
|
|
|
|
|
|
return |
1099
|
5
|
50
|
|
|
|
23
|
length($data) > $length |
1100
|
|
|
|
|
|
|
? substr($data, 0, $l) . $truncate_string |
1101
|
|
|
|
|
|
|
: $data; |
1102
|
|
|
|
|
|
|
} |
1103
|
|
|
|
|
|
|
|
1104
|
|
|
|
|
|
|
=head2 C<truncatewords> |
1105
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
Shortens a string down to the number of words passed as an argument. If the |
1107
|
|
|
|
|
|
|
specified number of words is less than the number of words in the string, an |
1108
|
|
|
|
|
|
|
ellipsis (...) is appended to the string. |
1109
|
|
|
|
|
|
|
|
1110
|
|
|
|
|
|
|
{{ "Ground control to Major Tom." | truncatewords: 3 }} => Ground control to... |
1111
|
|
|
|
|
|
|
|
1112
|
|
|
|
|
|
|
=head3 Custom ellipsis |
1113
|
|
|
|
|
|
|
|
1114
|
|
|
|
|
|
|
C<truncatewords> takes an optional second argument that specifies the sequence |
1115
|
|
|
|
|
|
|
of characters to be appended to the truncated string. By default this is an |
1116
|
|
|
|
|
|
|
ellipsis (...), but you can specify a different sequence. |
1117
|
|
|
|
|
|
|
|
1118
|
|
|
|
|
|
|
{{ "Ground control to Major Tom." | truncatewords: 3, "--" }} => Ground control to-- |
1119
|
|
|
|
|
|
|
|
1120
|
|
|
|
|
|
|
=head3 No ellipsis |
1121
|
|
|
|
|
|
|
|
1122
|
|
|
|
|
|
|
You can avoid showing trailing characters by passing a blank string as the |
1123
|
|
|
|
|
|
|
second argument: |
1124
|
|
|
|
|
|
|
|
1125
|
|
|
|
|
|
|
{{ "Ground control to Major Tom." | truncatewords: 3, "" }} => Ground control to |
1126
|
|
|
|
|
|
|
|
1127
|
|
|
|
|
|
|
=cut |
1128
|
|
|
|
|
|
|
|
1129
|
|
|
|
|
|
|
sub truncatewords { |
1130
|
5
|
|
|
5
|
1
|
13
|
my ($data, $words, $truncate_string) = @_; |
1131
|
5
|
100
|
|
|
|
15
|
$words = defined $words ? $words : 15; |
1132
|
5
|
100
|
|
|
|
11
|
$truncate_string = defined $truncate_string ? $truncate_string : '...'; |
1133
|
5
|
50
|
|
|
|
11
|
return if !$data; |
1134
|
5
|
|
|
|
|
20
|
my @wordlist = split ' ', $data; |
1135
|
5
|
|
|
|
|
12
|
my $l = $words - 1; |
1136
|
5
|
50
|
|
|
|
12
|
$l = 0 if $l < 0; |
1137
|
5
|
50
|
|
|
|
37
|
return $#wordlist > $l |
1138
|
|
|
|
|
|
|
? CORE::join(' ', @wordlist[0 .. $l]) . $truncate_string |
1139
|
|
|
|
|
|
|
: $data; |
1140
|
|
|
|
|
|
|
} |
1141
|
|
|
|
|
|
|
|
1142
|
|
|
|
|
|
|
=head2 C<uniq> |
1143
|
|
|
|
|
|
|
|
1144
|
|
|
|
|
|
|
Removes any duplicate elements in an array. |
1145
|
|
|
|
|
|
|
|
1146
|
|
|
|
|
|
|
{% assign my_array = "ants, bugs, bees, bugs, ants" | split: ", " %} |
1147
|
|
|
|
|
|
|
{{ my_array | uniq | join: ", " }} => ants, bugs, bees |
1148
|
|
|
|
|
|
|
|
1149
|
|
|
|
|
|
|
=cut |
1150
|
|
|
|
|
|
|
|
1151
|
|
|
|
|
|
|
sub uniq { |
1152
|
1
|
|
|
1
|
1
|
3
|
my ($array) = @_; |
1153
|
1
|
|
|
|
|
3
|
my @retval; |
1154
|
1
|
|
|
|
|
2
|
for my $element (@$array) { |
1155
|
5
|
100
|
|
|
|
12
|
push @retval, $element unless grep { $_ eq $element } @retval; |
|
9
|
|
|
|
|
21
|
|
1156
|
|
|
|
|
|
|
} |
1157
|
1
|
|
|
|
|
3
|
\@retval; |
1158
|
|
|
|
|
|
|
} |
1159
|
|
|
|
|
|
|
|
1160
|
|
|
|
|
|
|
=head2 C<upcase> |
1161
|
|
|
|
|
|
|
|
1162
|
|
|
|
|
|
|
Makes each character in a string uppercase. It has no effect on strings which |
1163
|
|
|
|
|
|
|
are already all uppercase. |
1164
|
|
|
|
|
|
|
|
1165
|
|
|
|
|
|
|
{{ "Parker Moore" | upcase }} => PARKER MOORE |
1166
|
|
|
|
|
|
|
|
1167
|
|
|
|
|
|
|
{{ "APPLE" | upcase }} => APPLE |
1168
|
|
|
|
|
|
|
|
1169
|
|
|
|
|
|
|
=cut |
1170
|
|
|
|
|
|
|
|
1171
|
4
|
|
|
4
|
1
|
10
|
sub upcase { my ($x) = @_; return uc $x } |
|
4
|
|
|
|
|
15
|
|
1172
|
|
|
|
|
|
|
|
1173
|
|
|
|
|
|
|
=head2 C<url_decode> |
1174
|
|
|
|
|
|
|
|
1175
|
|
|
|
|
|
|
Decodes a string that has been encoded as a URL or by C<url_encode>. |
1176
|
|
|
|
|
|
|
|
1177
|
|
|
|
|
|
|
{{ "%27Stop%21%27+said+Fred" | url_decode }} => 'Stop!' said Fred |
1178
|
|
|
|
|
|
|
|
1179
|
|
|
|
|
|
|
=cut |
1180
|
|
|
|
|
|
|
|
1181
|
|
|
|
|
|
|
sub url_decode { |
1182
|
1
|
|
|
1
|
1
|
4
|
my ($x) = @_; |
1183
|
1
|
|
|
|
|
5
|
$x =~ s[\+][ ]g; |
1184
|
1
|
|
|
|
|
6
|
$x =~ s[%(\d+)][chr hex $1]gex; |
|
3
|
|
|
|
|
15
|
|
1185
|
1
|
|
|
|
|
3
|
$x; |
1186
|
|
|
|
|
|
|
} |
1187
|
|
|
|
|
|
|
|
1188
|
|
|
|
|
|
|
=head2 C<url_encode> |
1189
|
|
|
|
|
|
|
|
1190
|
|
|
|
|
|
|
Converts any URL-unsafe characters in a string into percent-encoded characters. |
1191
|
|
|
|
|
|
|
|
1192
|
|
|
|
|
|
|
{{ "john@liquid.com" | url_encode }} => john%40liquid.com |
1193
|
|
|
|
|
|
|
|
1194
|
|
|
|
|
|
|
{{ "Tetsuro Takara" | url_encode }} => Tetsuro+Takara |
1195
|
|
|
|
|
|
|
|
1196
|
|
|
|
|
|
|
{{ "'Stop!'" said Fred" | url_encode }} => %27Stop%21%27+said+Fred |
1197
|
|
|
|
|
|
|
|
1198
|
|
|
|
|
|
|
=cut |
1199
|
|
|
|
|
|
|
|
1200
|
|
|
|
|
|
|
sub url_encode { |
1201
|
3
|
|
|
3
|
1
|
6
|
my $s = shift; |
1202
|
3
|
|
|
|
|
11
|
$s =~ s/ /+/g; |
1203
|
3
|
|
|
|
|
14
|
$s =~ s/([^A-Za-z0-9\+-\.])/sprintf("%%%02X", ord($1))/seg; |
|
4
|
|
|
|
|
23
|
|
1204
|
3
|
|
|
|
|
9
|
return $s; |
1205
|
|
|
|
|
|
|
} |
1206
|
|
|
|
|
|
|
|
1207
|
|
|
|
|
|
|
=head2 C<where> |
1208
|
|
|
|
|
|
|
|
1209
|
|
|
|
|
|
|
Creates an array including only the objects with a given property value, or any |
1210
|
|
|
|
|
|
|
truthy value by default. |
1211
|
|
|
|
|
|
|
|
1212
|
|
|
|
|
|
|
In this example, assume you have a list of products and you want to show your |
1213
|
|
|
|
|
|
|
kitchen products separately. Using C<where>, you can create an array containing |
1214
|
|
|
|
|
|
|
only the products that have a C<"type"> of C<"kitchen">. |
1215
|
|
|
|
|
|
|
|
1216
|
|
|
|
|
|
|
All products: |
1217
|
|
|
|
|
|
|
{% for product in products %} |
1218
|
|
|
|
|
|
|
- {{ product.title }} |
1219
|
|
|
|
|
|
|
{% endfor %} |
1220
|
|
|
|
|
|
|
|
1221
|
|
|
|
|
|
|
{% assign kitchen_products = products | where: "type", "kitchen" %} |
1222
|
|
|
|
|
|
|
|
1223
|
|
|
|
|
|
|
Kitchen products: |
1224
|
|
|
|
|
|
|
{% for product in kitchen_products %} |
1225
|
|
|
|
|
|
|
- {{ product.title }} |
1226
|
|
|
|
|
|
|
{% endfor %} |
1227
|
|
|
|
|
|
|
|
1228
|
|
|
|
|
|
|
...rendered with this data... |
1229
|
|
|
|
|
|
|
|
1230
|
|
|
|
|
|
|
products => [ |
1231
|
|
|
|
|
|
|
{ title => 'Vacuum', type => 'carpet', }, |
1232
|
|
|
|
|
|
|
{ title => 'Spatula', type => 'kitchen' }, |
1233
|
|
|
|
|
|
|
{ title => 'Television', type => 'den' }, |
1234
|
|
|
|
|
|
|
{ title => 'Garlic press', type => 'kitchen' }, |
1235
|
|
|
|
|
|
|
] |
1236
|
|
|
|
|
|
|
|
1237
|
|
|
|
|
|
|
...becomes... |
1238
|
|
|
|
|
|
|
|
1239
|
|
|
|
|
|
|
All products: |
1240
|
|
|
|
|
|
|
- Vacuum |
1241
|
|
|
|
|
|
|
- Spatula |
1242
|
|
|
|
|
|
|
- Television |
1243
|
|
|
|
|
|
|
- Garlic press |
1244
|
|
|
|
|
|
|
|
1245
|
|
|
|
|
|
|
Kitchen products: |
1246
|
|
|
|
|
|
|
- Spatula |
1247
|
|
|
|
|
|
|
- Garlic press |
1248
|
|
|
|
|
|
|
|
1249
|
|
|
|
|
|
|
Say instead you have a list of products and you only want to show those that |
1250
|
|
|
|
|
|
|
are available to buy. You can where with a property name but no target value to |
1251
|
|
|
|
|
|
|
include all products with a truthy "available" value. |
1252
|
|
|
|
|
|
|
|
1253
|
|
|
|
|
|
|
All products: |
1254
|
|
|
|
|
|
|
{% for product in products %} |
1255
|
|
|
|
|
|
|
- {{ product.title }} |
1256
|
|
|
|
|
|
|
{% endfor %} |
1257
|
|
|
|
|
|
|
|
1258
|
|
|
|
|
|
|
{% assign available_products = products | where: "available" %} |
1259
|
|
|
|
|
|
|
|
1260
|
|
|
|
|
|
|
Available products: |
1261
|
|
|
|
|
|
|
{% for product in available_products %} |
1262
|
|
|
|
|
|
|
- {{ product.title }} |
1263
|
|
|
|
|
|
|
{% endfor %} |
1264
|
|
|
|
|
|
|
|
1265
|
|
|
|
|
|
|
...rendered with this data... |
1266
|
|
|
|
|
|
|
|
1267
|
|
|
|
|
|
|
products => [ |
1268
|
|
|
|
|
|
|
{ title => 'Coffee mug', available => 1}, |
1269
|
|
|
|
|
|
|
{ title => 'Limited edition sneakers', available => 0}, |
1270
|
|
|
|
|
|
|
{ title => 'Boring sneakers', available => 1} |
1271
|
|
|
|
|
|
|
] |
1272
|
|
|
|
|
|
|
|
1273
|
|
|
|
|
|
|
...becomes... |
1274
|
|
|
|
|
|
|
|
1275
|
|
|
|
|
|
|
All products: |
1276
|
|
|
|
|
|
|
- Coffee mug |
1277
|
|
|
|
|
|
|
- Limited edition sneakers |
1278
|
|
|
|
|
|
|
- Boring sneakers |
1279
|
|
|
|
|
|
|
|
1280
|
|
|
|
|
|
|
Available products: |
1281
|
|
|
|
|
|
|
- Coffee mug |
1282
|
|
|
|
|
|
|
- Boring sneakers |
1283
|
|
|
|
|
|
|
|
1284
|
|
|
|
|
|
|
The C<where> filter can also be used to find a single object in an array when |
1285
|
|
|
|
|
|
|
combined with the C<first> filter. For example, say you want to show off the |
1286
|
|
|
|
|
|
|
shirt in your new fall collection. |
1287
|
|
|
|
|
|
|
|
1288
|
|
|
|
|
|
|
{% assign new_shirt = products | where: "type", "shirt" | first %} |
1289
|
|
|
|
|
|
|
|
1290
|
|
|
|
|
|
|
Featured product: {{ new_shirt.title }} |
1291
|
|
|
|
|
|
|
|
1292
|
|
|
|
|
|
|
...rendered with the following data... |
1293
|
|
|
|
|
|
|
|
1294
|
|
|
|
|
|
|
products => [ |
1295
|
|
|
|
|
|
|
{ title => 'Limited edition sneakers', type => 'shoes' }, |
1296
|
|
|
|
|
|
|
{ title => 'Hawaiian print sweater vest', type => 'shirt' }, |
1297
|
|
|
|
|
|
|
{ title => 'Tuxedo print tshirt', type => 'shirt' }, |
1298
|
|
|
|
|
|
|
{ title => 'Jorts', type => 'shorts' } |
1299
|
|
|
|
|
|
|
] |
1300
|
|
|
|
|
|
|
|
1301
|
|
|
|
|
|
|
...becomes... |
1302
|
|
|
|
|
|
|
|
1303
|
|
|
|
|
|
|
Featured product: Hawaiian print sweater vest |
1304
|
|
|
|
|
|
|
|
1305
|
|
|
|
|
|
|
=cut |
1306
|
|
|
|
|
|
|
|
1307
|
|
|
|
|
|
|
sub where { |
1308
|
3
|
|
|
3
|
1
|
8
|
my ($list, $key, $value) = @_; |
1309
|
3
|
100
|
|
|
|
7
|
[grep { defined $value ? $_->{$key} eq $value : !!$_->{$key} } @$list]; |
|
11
|
|
|
|
|
35
|
|
1310
|
|
|
|
|
|
|
} |
1311
|
|
|
|
|
|
|
|
1312
|
|
|
|
|
|
|
=head2 C<money> |
1313
|
|
|
|
|
|
|
|
1314
|
|
|
|
|
|
|
Formats floats and integers as if they were money. |
1315
|
|
|
|
|
|
|
|
1316
|
|
|
|
|
|
|
{{ 4.6 | money }} => $4.60 |
1317
|
|
|
|
|
|
|
{{ -4.3 | money }} => -$4.30 |
1318
|
|
|
|
|
|
|
{{ 4.5612 | money }} => $4.56 |
1319
|
|
|
|
|
|
|
|
1320
|
|
|
|
|
|
|
You may pass a currency symbol to override the default dollar sign (C<$>). |
1321
|
|
|
|
|
|
|
|
1322
|
|
|
|
|
|
|
{{ 4.6 | money:'€' }} => €4.60 |
1323
|
|
|
|
|
|
|
|
1324
|
|
|
|
|
|
|
=cut |
1325
|
|
|
|
|
|
|
|
1326
|
|
|
|
|
|
|
sub money { |
1327
|
4
|
|
|
4
|
1
|
11
|
my ($x, $y) = @_; |
1328
|
4
|
50
|
|
|
|
18
|
return if $x !~ m[^[\+-]?(\d*\.)?\d+?$]o; |
1329
|
4
|
100
|
|
|
|
45
|
return (($x < 0 ? '-' : '') . (defined $y ? $y : '$') . sprintf '%.2f', |
|
|
100
|
|
|
|
|
|
1330
|
|
|
|
|
|
|
CORE::abs($x)); |
1331
|
|
|
|
|
|
|
} |
1332
|
|
|
|
|
|
|
|
1333
|
|
|
|
|
|
|
=head2 C<stock_price> |
1334
|
|
|
|
|
|
|
|
1335
|
|
|
|
|
|
|
Formats floats and integers as if they were stock prices. |
1336
|
|
|
|
|
|
|
|
1337
|
|
|
|
|
|
|
{{ 4.6 | stock_price }} => $4.60 |
1338
|
|
|
|
|
|
|
{{ 0.30 | stock_price }} => $0.3000 |
1339
|
|
|
|
|
|
|
{{ 4.5612 | stock_price }} => $4.56 |
1340
|
|
|
|
|
|
|
|
1341
|
|
|
|
|
|
|
You may pass a currency symbol to override the default dollar sign (C<$>). |
1342
|
|
|
|
|
|
|
|
1343
|
|
|
|
|
|
|
{{ 4.6 | stock_price:'€' }} => €4.60 |
1344
|
|
|
|
|
|
|
|
1345
|
|
|
|
|
|
|
=cut |
1346
|
|
|
|
|
|
|
|
1347
|
|
|
|
|
|
|
sub stock_price { |
1348
|
4
|
|
|
4
|
1
|
13
|
my ($x, $y) = @_; |
1349
|
4
|
50
|
|
|
|
25
|
return if $x !~ m[^[\+-]?(\d*\.)?\d+?$]o; |
1350
|
4
|
50
|
|
|
|
52
|
return (($x < 0 ? '-' : '') . |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1351
|
|
|
|
|
|
|
(defined $y ? $y : '$') . |
1352
|
|
|
|
|
|
|
sprintf '%.' . |
1353
|
|
|
|
|
|
|
(int(CORE::abs($x)) > 0 ? 2 : 4) . 'f', |
1354
|
|
|
|
|
|
|
CORE::abs($x) |
1355
|
|
|
|
|
|
|
); |
1356
|
|
|
|
|
|
|
} |
1357
|
|
|
|
|
|
|
|
1358
|
|
|
|
|
|
|
=head1 Author |
1359
|
|
|
|
|
|
|
|
1360
|
|
|
|
|
|
|
Sanko Robinson <sanko@cpan.org> - http://sankorobinson.com/ |
1361
|
|
|
|
|
|
|
|
1362
|
|
|
|
|
|
|
CPAN ID: SANKO |
1363
|
|
|
|
|
|
|
|
1364
|
|
|
|
|
|
|
=head1 License and Legal |
1365
|
|
|
|
|
|
|
|
1366
|
|
|
|
|
|
|
Copyright (C) 2009-2023 by Sanko Robinson E<lt>sanko@cpan.orgE<gt> |
1367
|
|
|
|
|
|
|
|
1368
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it under |
1369
|
|
|
|
|
|
|
the terms of L<The Artistic License |
1370
|
|
|
|
|
|
|
2.0|http://www.perlfoundation.org/artistic_license_2_0>. See the F<LICENSE> |
1371
|
|
|
|
|
|
|
file included with this distribution or L<notes on the Artistic License |
1372
|
|
|
|
|
|
|
2.0|http://www.perlfoundation.org/artistic_2_0_notes> for clarification. |
1373
|
|
|
|
|
|
|
|
1374
|
|
|
|
|
|
|
When separated from the distribution, all original POD documentation is covered |
1375
|
|
|
|
|
|
|
by the L<Creative Commons Attribution-Share Alike 3.0 |
1376
|
|
|
|
|
|
|
License|http://creativecommons.org/licenses/by-sa/3.0/us/legalcode>. See the |
1377
|
|
|
|
|
|
|
L<clarification of the |
1378
|
|
|
|
|
|
|
CCA-SA3.0|http://creativecommons.org/licenses/by-sa/3.0/us/>. |
1379
|
|
|
|
|
|
|
|
1380
|
|
|
|
|
|
|
=for stopwords website |
1381
|
|
|
|
|
|
|
|
1382
|
|
|
|
|
|
|
=cut |