Skip to content

Commit 5244e6d

Browse files
committed
Make whitespace filters Unicode-aware
Previously we were only leveraging Ruby's `String#strip` to handle the logic in these filters but that only covers ASCII whitespace. When rendering Liquid templates into HTML it would be confusing for these filters to not strip *all* whitespace. Additionally, it's helpful when trying to compare two values in, say, a Liquid conditional.
1 parent 1954a26 commit 5244e6d

2 files changed

Lines changed: 50 additions & 4 deletions

File tree

lib/liquid/standardfilters.rb

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,17 @@ module StandardFilters
3636
%r{<style.*?</style>}m,
3737
)
3838
STRIP_HTML_TAGS = /<.*?>/m
39+
# Use POSIX whitespace matching so filters handle whitespace beyond Ruby String#strip's ASCII set.
40+
WHITESPACE_LEFT = /\A[[:space:]]+/
41+
WHITESPACE_RIGHT = /[[:space:]]+\z/
42+
WHITESPACE_EDGES = Regexp.union(WHITESPACE_LEFT, WHITESPACE_RIGHT)
43+
WHITESPACE_RUNS = /[[:space:]]+/
44+
private_constant(
45+
:WHITESPACE_EDGES,
46+
:WHITESPACE_LEFT,
47+
:WHITESPACE_RIGHT,
48+
:WHITESPACE_RUNS,
49+
)
3950

4051
class << self
4152
def try_coerce_encoding(input, encoding:)
@@ -312,7 +323,7 @@ def split(input, pattern)
312323
def squish(input)
313324
return if input.nil?
314325

315-
Utils.to_s(input).strip.gsub(/\s+/, ' ')
326+
Utils.to_s(input).gsub(WHITESPACE_RUNS, ' ').strip
316327
end
317328

318329
# @liquid_public_docs
@@ -324,7 +335,7 @@ def squish(input)
324335
# @liquid_return [string]
325336
def strip(input)
326337
input = Utils.to_s(input)
327-
input.strip
338+
input.gsub(WHITESPACE_EDGES, ' ').strip
328339
end
329340

330341
# @liquid_public_docs
@@ -336,7 +347,7 @@ def strip(input)
336347
# @liquid_return [string]
337348
def lstrip(input)
338349
input = Utils.to_s(input)
339-
input.lstrip
350+
input.gsub(WHITESPACE_LEFT, ' ').lstrip
340351
end
341352

342353
# @liquid_public_docs
@@ -348,7 +359,7 @@ def lstrip(input)
348359
# @liquid_return [string]
349360
def rstrip(input)
350361
input = Utils.to_s(input)
351-
input.rstrip
362+
input.gsub(WHITESPACE_RIGHT, ' ').rstrip
352363
end
353364

354365
# @liquid_public_docs

test/integration/standard_filter_test.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,15 @@ def test_squish_filter
169169
\t boo " | squish }})).render)
170170
assert_equal("", Liquid::Template.parse('{{ nil | squish }}').render)
171171
assert_equal("", Liquid::Template.parse('{{ " " | squish }}').render)
172+
173+
unicode_spaces = "\u00A0\u202F\u2009\u2007"
174+
175+
assert_template_result(
176+
"foo bar boo",
177+
"{{ source | squish }}",
178+
{ 'source' => "#{unicode_spaces}foo\u202F\u2009bar\t\n\u2007boo#{unicode_spaces}" },
179+
)
180+
assert_template_result("\u200Bfoo\u200B", "{{ source | squish }}", { 'source' => "\u200Bfoo\u200B" })
172181
end
173182

174183
def test_escape
@@ -703,16 +712,42 @@ def test_pipes_in_string_arguments
703712
def test_strip
704713
assert_template_result('ab c', "{{ source | strip }}", { 'source' => " ab c " })
705714
assert_template_result('ab c', "{{ source | strip }}", { 'source' => " \tab c \n \t" })
715+
716+
unicode_spaces = "\u00A0\u202F\u2009\u2007"
717+
718+
assert_template_result(
719+
'ab c',
720+
"{{ source | strip }}",
721+
{ 'source' => "#{unicode_spaces}ab c#{unicode_spaces}" },
722+
)
723+
assert_template_result("a\u00A0b\u202Fc", "{{ source | strip }}", { 'source' => "a\u00A0b\u202Fc" })
724+
assert_template_result("\u200Bfoo\u200B", "{{ source | strip }}", { 'source' => "\u200Bfoo\u200B" })
706725
end
707726

708727
def test_lstrip
709728
assert_template_result('ab c ', "{{ source | lstrip }}", { 'source' => " ab c " })
710729
assert_template_result("ab c \n \t", "{{ source | lstrip }}", { 'source' => " \tab c \n \t" })
730+
731+
unicode_spaces = "\u00A0\u202F\u2009\u2007"
732+
733+
assert_template_result(
734+
"ab c#{unicode_spaces}",
735+
"{{ source | lstrip }}",
736+
{ 'source' => "#{unicode_spaces}ab c#{unicode_spaces}" },
737+
)
711738
end
712739

713740
def test_rstrip
714741
assert_template_result(" ab c", "{{ source | rstrip }}", { 'source' => " ab c " })
715742
assert_template_result(" \tab c", "{{ source | rstrip }}", { 'source' => " \tab c \n \t" })
743+
744+
unicode_spaces = "\u00A0\u202F\u2009\u2007"
745+
746+
assert_template_result(
747+
"#{unicode_spaces}ab c",
748+
"{{ source | rstrip }}",
749+
{ 'source' => "#{unicode_spaces}ab c#{unicode_spaces}" },
750+
)
716751
end
717752

718753
def test_strip_newlines

0 commit comments

Comments
 (0)