Compare commits

...
Author SHA1 Message Date
Michael Go 4f35b0bc66 update liquid-c 2024-02-12 16:49:52 -04:00
Michael Go a5e5fab82a update variable's context before invoking its to_liquid 2024-02-12 16:48:20 -04:00
Ian Ker-SeymerandGitHub 02ecaab9d1 Merge pull request #1783 from Shopify/contains-encoding
Fallback to binary comparison when `contains` RHS is  UTF8 encoded
2024-01-31 11:14:01 -05:00
Ian Ker-Seymer 1b2b62964e Allow for binary comparison of incompatible strings 2024-01-30 19:03:05 -05:00
Michael GoandGitHub 9b38a15282 Merge pull request #1776 from Shopify/refactor/invalid-encoding-error
add new TemplateEncodingError
2024-01-12 12:38:34 -04:00
Michael GoandGitHub cf76c0bbec Merge pull request #1775 from Shopify/allow-nil-template-source
allow non-string template source
2024-01-12 10:48:30 -04:00
Michael Go 6a0fe3f7e3 convert template source to string to ensure encoding validity 2024-01-10 16:50:31 -04:00
Michael Go 730ad3684a allow nil template source 2024-01-10 16:32:08 -04:00
8 changed files with 62 additions and 6 deletions
+1 -1
View File
@@ -23,6 +23,6 @@ group :test do
gem 'rubocop-performance', require: false
platform :mri, :truffleruby do
gem 'liquid-c', github: 'Shopify/liquid-c', ref: 'master'
gem 'liquid-c', github: 'Shopify/liquid-c', ref: 'main'
end
end
+3
View File
@@ -24,6 +24,9 @@ module Liquid
else
false
end
rescue Encoding::CompatibilityError
# "✅".b.include?("✅") raises Encoding::CompatibilityError despite being materially equal
left.b.include?(right.b)
end,
}
+6 -2
View File
@@ -197,10 +197,14 @@ module Liquid
try_variable_find_in_environments(key, raise_on_not_found: raise_on_not_found)
end
variable = variable.to_liquid
# update variable's context before invoking #to_liquid
variable.context = self if variable.respond_to?(:context=)
variable
liquid_variable = variable.to_liquid
liquid_variable.context = self if variable != liquid_variable && liquid_variable.respond_to?(:context=)
liquid_variable
end
def lookup_and_evaluate(obj, key, raise_on_not_found: true)
+1
View File
@@ -107,6 +107,7 @@ module Liquid
# Returns self for easy chaining
def parse(source, options = {})
parse_context = configure_options(options)
source = source.to_s.to_str
unless source.valid_encoding?
raise TemplateEncodingError, parse_context.locale.t("errors.syntax.invalid_template_encoding")
+1 -1
View File
@@ -5,7 +5,7 @@ module Liquid
attr_reader :line_number, :for_liquid_tag
def initialize(source, line_numbers = false, line_number: nil, for_liquid_tag: false)
@source = source.to_s.to_str
@source = source
@line_number = line_number || (line_numbers ? 1 : nil)
@for_liquid_tag = for_liquid_tag
@offset = 0
+37
View File
@@ -36,6 +36,24 @@ class Category
end
end
class ProductsDrop < Liquid::Drop
def initialize(products)
@products = products
end
def size
@products.size
end
def to_liquid
if @context["forloop"]
@products.first(@context["forloop"].length)
else
@products
end
end
end
class CategoryDrop < Liquid::Drop
attr_accessor :category, :context
@@ -635,6 +653,25 @@ class ContextTest < Minitest::Test
assert_equal(:my_value, c.registers[:my_register])
end
def test_variable_to_liquid_returns_contextual_drop
context = {
"products" => ProductsDrop.new(["A", "B", "C", "D", "E"]),
}
template = Liquid::Template.parse(<<~LIQUID)
{%- for i in (1..3) -%}
for_loop_products_count: {{ products | size }}
{% endfor %}
unscoped_products_count: {{ products | size }}
LIQUID
result = template.render(context)
assert_includes(result, "for_loop_products_count: 3")
assert_includes(result, "unscoped_products_count: 5")
end
private
def assert_no_object_allocations
+6
View File
@@ -349,4 +349,10 @@ class TemplateTest < Minitest::Test
assert_equal('Liquid error: Invalid template encoding', e.message)
end
def test_allows_non_string_values_as_source
assert_equal('', Template.parse(nil).render)
assert_equal('1', Template.parse(1).render)
assert_equal('true', Template.parse(true).render)
end
end
+7 -2
View File
@@ -55,6 +55,11 @@ class ConditionUnitTest < Minitest::Test
assert_evaluates_false('bob', 'contains', '---')
end
def test_contains_binary_encoding_compatibility_with_utf8
assert_evaluates_true('🙈'.b, 'contains', '🙈')
assert_evaluates_true('🙈', 'contains', '🙈'.b)
end
def test_invalid_comparation_operator
assert_evaluates_argument_error(1, '~~', 0)
end
@@ -166,14 +171,14 @@ class ConditionUnitTest < Minitest::Test
def assert_evaluates_true(left, op, right)
assert(
Condition.new(left, op, right).evaluate(@context),
"Evaluated false: #{left} #{op} #{right}",
"Evaluated false: #{left.inspect} #{op} #{right.inspect}",
)
end
def assert_evaluates_false(left, op, right)
assert(
!Condition.new(left, op, right).evaluate(@context),
"Evaluated true: #{left} #{op} #{right}",
"Evaluated true: #{left.inspect} #{op} #{right.inspect}",
)
end