From 59950bff8739d34d1b005822924bd91fb29a8b3f Mon Sep 17 00:00:00 2001
From: Eric Chan
Date: Wed, 13 Sep 2017 01:37:40 -0400
Subject: [PATCH 01/74] Fix sort_natural on sorting with non-string values
---
lib/liquid/standardfilters.rb | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb
index 7c18c0d..9ebb763 100644
--- a/lib/liquid/standardfilters.rb
+++ b/lib/liquid/standardfilters.rb
@@ -143,11 +143,19 @@ module Liquid
ary = InputIterator.new(input)
if property.nil?
- ary.sort { |a, b| a.casecmp(b) }
+ ary.sort { |a, b| a.to_s.casecmp(b.to_s) }
elsif ary.empty? # The next two cases assume a non-empty array.
[]
elsif ary.first.respond_to?(:[]) && !ary.first[property].nil?
- ary.sort { |a, b| a[property].casecmp(b[property]) }
+ ary.sort do |a, b|
+ a = a[property]
+ b = b[property]
+ if a && b
+ a[property].to_s.casecmp(b[property].to_s)
+ else
+ a ? -1 : 1
+ end
+ end
end
end
From cfe1844de920970ceb91db600e987b18bb2c8462 Mon Sep 17 00:00:00 2001
From: Eric Chan
Date: Wed, 13 Sep 2017 22:17:59 -0400
Subject: [PATCH 02/74] Added test coverage for sort_natural
---
lib/liquid/standardfilters.rb | 2 +-
test/integration/standard_filter_test.rb | 41 ++++++++++++++++++++++++
2 files changed, 42 insertions(+), 1 deletion(-)
diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb
index 9ebb763..f14ba1d 100644
--- a/lib/liquid/standardfilters.rb
+++ b/lib/liquid/standardfilters.rb
@@ -151,7 +151,7 @@ module Liquid
a = a[property]
b = b[property]
if a && b
- a[property].to_s.casecmp(b[property].to_s)
+ a.to_s.casecmp(b.to_s)
else
a ? -1 : 1
end
diff --git a/test/integration/standard_filter_test.rb b/test/integration/standard_filter_test.rb
index 9de2106..c53aae1 100644
--- a/test/integration/standard_filter_test.rb
+++ b/test/integration/standard_filter_test.rb
@@ -208,6 +208,47 @@ class StandardFiltersTest < Minitest::Test
assert_equal expectation, @filters.sort(input, "price")
end
+ def test_sort_natural_when_property_is_sometimes_missing_puts_nils_last
+ input = [
+ { "price" => "4", "handle" => "alpha" },
+ { "handle" => "beta" },
+ { "price" => "1", "handle" => "gamma" },
+ { "handle" => "delta" },
+ { "price" => 2, "handle" => "epsilon" }
+ ]
+ expectation = [
+ { "price" => "1", "handle" => "gamma" },
+ { "price" => 2, "handle" => "epsilon" },
+ { "price" => "4", "handle" => "alpha" },
+ { "handle" => "delta" },
+ { "handle" => "beta" }
+ ]
+ assert_equal expectation, @filters.sort_natural(input, "price")
+ end
+
+ def test_sort_natural_case_check
+ input = [
+ { "key" => "X" },
+ { "key" => "Y" },
+ { "key" => "Z" },
+ { "fake" => "t" },
+ { "key" => "a" },
+ { "key" => "b" },
+ { "key" => "c" }
+ ]
+ expectation = [
+ { "key" => "a" },
+ { "key" => "b" },
+ { "key" => "c" },
+ { "key" => "X" },
+ { "key" => "Y" },
+ { "key" => "Z" },
+ { "fake" => "t" }
+ ]
+ assert_equal expectation, @filters.sort_natural(input, "key")
+ assert_equal ["a", "b", "c", "X", "Y", "Z"], @filters.sort_natural(["X", "Y", "Z", "a", "b", "c"])
+ end
+
def test_sort_empty_array
assert_equal [], @filters.sort([], "a")
end
From deb10ebc7a8b1979b7c5daec83f2e69d9b68591d Mon Sep 17 00:00:00 2001
From: Eric Chan
Date: Thu, 14 Sep 2017 02:00:43 -0400
Subject: [PATCH 03/74] Sorting support for data with undefined values
---
lib/liquid/standardfilters.rb | 28 +++++++++++++++++-------
test/integration/standard_filter_test.rb | 15 +++++++++++++
2 files changed, 35 insertions(+), 8 deletions(-)
diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb
index f14ba1d..34b4a49 100644
--- a/lib/liquid/standardfilters.rb
+++ b/lib/liquid/standardfilters.rb
@@ -121,17 +121,23 @@ module Liquid
def sort(input, property = nil)
ary = InputIterator.new(input)
if property.nil?
- ary.sort
+ ary.sort do |a, b|
+ if !a.nil? && !b.nil?
+ a <=> b
+ else
+ a.nil? ? 1 : -1
+ end
+ end
elsif ary.empty? # The next two cases assume a non-empty array.
[]
- elsif ary.first.respond_to?(:[]) && !ary.first[property].nil?
+ elsif ary.all? { |el| el.respond_to?(:[]) }
ary.sort do |a, b|
a = a[property]
b = b[property]
- if a && b
+ if !a.nil? && !b.nil?
a <=> b
else
- a ? -1 : 1
+ a.nil? ? 1 : -1
end
end
end
@@ -143,17 +149,23 @@ module Liquid
ary = InputIterator.new(input)
if property.nil?
- ary.sort { |a, b| a.to_s.casecmp(b.to_s) }
+ ary.sort do |a, b|
+ if !a.nil? && !b.nil?
+ a.to_s.casecmp(b.to_s)
+ else
+ a.nil? ? 1 : -1
+ end
+ end
elsif ary.empty? # The next two cases assume a non-empty array.
[]
- elsif ary.first.respond_to?(:[]) && !ary.first[property].nil?
+ elsif ary.all? { |el| el.respond_to?(:[]) }
ary.sort do |a, b|
a = a[property]
b = b[property]
- if a && b
+ if !a.nil? && !b.nil?
a.to_s.casecmp(b.to_s)
else
- a ? -1 : 1
+ a.nil? ? 1 : -1
end
end
end
diff --git a/test/integration/standard_filter_test.rb b/test/integration/standard_filter_test.rb
index c53aae1..6c91f16 100644
--- a/test/integration/standard_filter_test.rb
+++ b/test/integration/standard_filter_test.rb
@@ -190,6 +190,11 @@ class StandardFiltersTest < Minitest::Test
assert_equal [{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }], @filters.sort([{ "a" => 4 }, { "a" => 3 }, { "a" => 1 }, { "a" => 2 }], "a")
end
+ def test_sort_with_nils
+ assert_equal [1, 2, 3, 4, nil], @filters.sort([nil, 4, 3, 2, 1])
+ assert_equal [{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }, {}], @filters.sort([{ "a" => 4 }, { "a" => 3 }, {}, { "a" => 1 }, { "a" => 2 }], "a")
+ end
+
def test_sort_when_property_is_sometimes_missing_puts_nils_last
input = [
{ "price" => 4, "handle" => "alpha" },
@@ -208,6 +213,16 @@ class StandardFiltersTest < Minitest::Test
assert_equal expectation, @filters.sort(input, "price")
end
+ def test_sort_natural
+ assert_equal ["a", "B", "c", "D"], @filters.sort_natural(["c", "D", "a", "B"])
+ assert_equal [{ "a" => "a" }, { "a" => "B" }, { "a" => "c" }, { "a" => "D" }], @filters.sort_natural([{ "a" => "D" }, { "a" => "c" }, { "a" => "a" }, { "a" => "B" }], "a")
+ end
+
+ def test_sort_natural_with_nils
+ assert_equal ["a", "B", "c", "D", nil], @filters.sort_natural([nil, "c", "D", "a", "B"])
+ assert_equal [{ "a" => "a" }, { "a" => "B" }, { "a" => "c" }, { "a" => "D" }, {}], @filters.sort_natural([{ "a" => "D" }, { "a" => "c" }, {}, { "a" => "a" }, { "a" => "B" }], "a")
+ end
+
def test_sort_natural_when_property_is_sometimes_missing_puts_nils_last
input = [
{ "price" => "4", "handle" => "alpha" },
From 479d8fb4a40db6947670fd6b1386cb3e2d612883 Mon Sep 17 00:00:00 2001
From: printercu
Date: Thu, 27 Sep 2018 17:13:35 +0300
Subject: [PATCH 04/74] Single regexp for strip_html
---
lib/liquid/standardfilters.rb | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb
index c5dbcb8..3d939ae 100644
--- a/lib/liquid/standardfilters.rb
+++ b/lib/liquid/standardfilters.rb
@@ -11,6 +11,12 @@ module Liquid
"'".freeze => '''.freeze
}
HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/
+ STRIP_HTML = Regexp.union(
+ //m,
+ //m,
+ //m,
+ /<.*?>/m,
+ )
# Return the size of an array or of an string
def size(input)
@@ -102,8 +108,7 @@ module Liquid
end
def strip_html(input)
- empty = ''.freeze
- input.to_s.gsub(//m, empty).gsub(//m, empty).gsub(//m, empty).gsub(/<.*?>/m, empty)
+ input.to_s.gsub(STRIP_HTML, ''.freeze)
end
# Remove all newlines from the string
From 89c1ba2b0e3f55b3cb1b1b5759c5db58e87effa6 Mon Sep 17 00:00:00 2001
From: printercu
Date: Thu, 27 Sep 2018 17:24:01 +0300
Subject: [PATCH 05/74] Fix rubocop warning
---
lib/liquid/standardfilters.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb
index 3d939ae..d7e2dbb 100644
--- a/lib/liquid/standardfilters.rb
+++ b/lib/liquid/standardfilters.rb
@@ -15,7 +15,7 @@ module Liquid
//m,
//m,
//m,
- /<.*?>/m,
+ /<.*?>/m
)
# Return the size of an array or of an string
From 4661700a979d419521c3a5264071cc48d24cb918 Mon Sep 17 00:00:00 2001
From: Florian Weingarten
Date: Tue, 9 Oct 2018 11:13:19 +0200
Subject: [PATCH 06/74] bump to v4.0.1
---
lib/liquid/version.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/liquid/version.rb b/lib/liquid/version.rb
index af15e07..64abb7e 100644
--- a/lib/liquid/version.rb
+++ b/lib/liquid/version.rb
@@ -1,4 +1,4 @@
# encoding: utf-8
module Liquid
- VERSION = "4.0.0"
+ VERSION = "4.0.1"
end
From 842986a9721de11e71387732be51951285225977 Mon Sep 17 00:00:00 2001
From: Samuel
Date: Thu, 13 Sep 2018 16:37:38 -0400
Subject: [PATCH 07/74] Add `where` filter to standard filters
Users of Liquid will often wish to filter an array to only those items that match a certain criteria. For example, showing "pinned" messages at the top of a list.
Example usage:
`{{ comments | where: "pinned" | first }}`
or
`{{ products | where: "category", "kitchen" }}`
* Add where filter to standard filters
* Add tests for new where functionality
---
lib/liquid/standardfilters.rb | 32 +++++++++++
test/integration/standard_filter_test.rb | 72 ++++++++++++++++++++++++
2 files changed, 104 insertions(+)
diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb
index c5dbcb8..29c2cad 100644
--- a/lib/liquid/standardfilters.rb
+++ b/lib/liquid/standardfilters.rb
@@ -151,6 +151,20 @@ module Liquid
end
end
+ # Filter the elements of an array to those with a certain property value.
+ # By default the target is any truthy value.
+ def where(input, property, target_value = nil)
+ ary = InputIterator.new(input)
+
+ if ary.empty?
+ []
+ elsif ary.first.respond_to?(:[]) && target_value.nil?
+ ary.where_present(property)
+ elsif ary.first.respond_to?(:[])
+ ary.where(property, target_value)
+ end
+ end
+
# Remove duplicate elements from an array
# provide optional property with which to determine uniqueness
def uniq(input, property = nil)
@@ -429,6 +443,24 @@ module Liquid
yield(e.respond_to?(:to_liquid) ? e.to_liquid : e)
end
end
+
+ def where(property, target_value)
+ select do |item|
+ item[property] == target_value
+ end
+ rescue TypeError
+ # Cannot index with the given property type (eg. indexing integers with strings
+ # which are only allowed to be indexed by other integers).
+ raise ArgumentError.new("cannot select the property `#{property}`")
+ end
+
+ def where_present(property)
+ select { |item| item[property] }
+ rescue TypeError
+ # Cannot index with the given property type (eg. indexing integers with strings
+ # which are only allowed to be indexed by other integers).
+ raise ArgumentError.new("cannot select the property `#{property}`")
+ end
end
end
diff --git a/test/integration/standard_filter_test.rb b/test/integration/standard_filter_test.rb
index d39472e..75e6e8d 100644
--- a/test/integration/standard_filter_test.rb
+++ b/test/integration/standard_filter_test.rb
@@ -558,6 +558,78 @@ class StandardFiltersTest < Minitest::Test
assert_template_result('abc', "{{ 'abc' | date: '%D' }}")
end
+ def test_where
+ input = [
+ { "handle" => "alpha", "ok" => true },
+ { "handle" => "beta", "ok" => false },
+ { "handle" => "gamma", "ok" => false },
+ { "handle" => "delta", "ok" => true }
+ ]
+
+ expectation = [
+ { "handle" => "alpha", "ok" => true },
+ { "handle" => "delta", "ok" => true }
+ ]
+
+ assert_equal expectation, @filters.where(input, "ok", true)
+ assert_equal expectation, @filters.where(input, "ok")
+ end
+
+ def test_where_no_key_set
+ input = [
+ { "handle" => "alpha", "ok" => true },
+ { "handle" => "beta" },
+ { "handle" => "gamma" },
+ { "handle" => "delta", "ok" => true }
+ ]
+
+ expectation = [
+ { "handle" => "alpha", "ok" => true },
+ { "handle" => "delta", "ok" => true }
+ ]
+
+ assert_equal expectation, @filters.where(input, "ok", true)
+ assert_equal expectation, @filters.where(input, "ok")
+ end
+
+ def test_where_non_array_map_input
+ assert_equal [{ "a" => "ok" }], @filters.where({ "a" => "ok" }, "a", "ok")
+ assert_equal [], @filters.where({ "a" => "not ok" }, "a", "ok")
+ end
+
+ def test_where_indexable_but_non_map_value
+ assert_raises(Liquid::ArgumentError) { @filters.where(1, "ok", true) }
+ assert_raises(Liquid::ArgumentError) { @filters.where(1, "ok") }
+ end
+
+ def test_where_non_boolean_value
+ input = [
+ { "message" => "Bonjour!", "language" => "French" },
+ { "message" => "Hello!", "language" => "English" },
+ { "message" => "Hallo!", "language" => "German" }
+ ]
+
+ assert_equal [{ "message" => "Bonjour!", "language" => "French" }], @filters.where(input, "language", "French")
+ assert_equal [{ "message" => "Hallo!", "language" => "German" }], @filters.where(input, "language", "German")
+ assert_equal [{ "message" => "Hello!", "language" => "English" }], @filters.where(input, "language", "English")
+ end
+
+ def test_where_array_of_only_unindexable_values
+ assert_nil @filters.where([nil], "ok", true)
+ assert_nil @filters.where([nil], "ok")
+ end
+
+ def test_where_no_target_value
+ input = [
+ { "foo" => false },
+ { "foo" => true },
+ { "foo" => "for sure" },
+ { "bar" => true }
+ ]
+
+ assert_equal [{ "foo" => true }, { "foo" => "for sure" }], @filters.where(input, "foo")
+ end
+
private
def with_timezone(tz)
From d789ec4175176127ca50e0e39e77540c5d7222d6 Mon Sep 17 00:00:00 2001
From: Stephen Paul Weber
Date: Mon, 10 Sep 2018 13:36:27 -0400
Subject: [PATCH 08/74] Liquid::Traversal
This enables traversal over whole document tree.
---
lib/liquid/condition.rb | 4 +-
lib/liquid/tags/assign.rb | 2 +
lib/liquid/tags/case.rb | 2 +
lib/liquid/tags/cycle.rb | 2 +
lib/liquid/tags/for.rb | 3 +-
lib/liquid/tags/if.rb | 10 +-
lib/liquid/tags/include.rb | 2 +
lib/liquid/tags/table_row.rb | 2 +
lib/liquid/traversal.rb | 118 +++++++++++++++
test/integration/traversal_test.rb | 234 +++++++++++++++++++++++++++++
10 files changed, 371 insertions(+), 8 deletions(-)
create mode 100644 lib/liquid/traversal.rb
create mode 100644 test/integration/traversal_test.rb
diff --git a/lib/liquid/condition.rb b/lib/liquid/condition.rb
index 3e79849..72bd2ee 100644
--- a/lib/liquid/condition.rb
+++ b/lib/liquid/condition.rb
@@ -29,7 +29,7 @@ module Liquid
@@operators
end
- attr_reader :attachment
+ attr_reader :attachment, :child_condition
attr_accessor :left, :operator, :right
def initialize(left = nil, operator = nil, right = nil)
@@ -83,7 +83,7 @@ module Liquid
protected
- attr_reader :child_relation, :child_condition
+ attr_reader :child_relation
private
diff --git a/lib/liquid/tags/assign.rb b/lib/liquid/tags/assign.rb
index f6cd5fa..ee6fa76 100644
--- a/lib/liquid/tags/assign.rb
+++ b/lib/liquid/tags/assign.rb
@@ -10,6 +10,8 @@ module Liquid
class Assign < Tag
Syntax = /(#{VariableSignature}+)\s*=\s*(.*)\s*/om
+ attr_reader :to, :from
+
def initialize(tag_name, markup, options)
super
if markup =~ Syntax
diff --git a/lib/liquid/tags/case.rb b/lib/liquid/tags/case.rb
index 453b4d6..f55aa61 100644
--- a/lib/liquid/tags/case.rb
+++ b/lib/liquid/tags/case.rb
@@ -3,6 +3,8 @@ module Liquid
Syntax = /(#{QuotedFragment})/o
WhenSyntax = /(#{QuotedFragment})(?:(?:\s+or\s+|\s*\,\s*)(#{QuotedFragment}.*))?/om
+ attr_reader :blocks, :left
+
def initialize(tag_name, markup, options)
super
@blocks = []
diff --git a/lib/liquid/tags/cycle.rb b/lib/liquid/tags/cycle.rb
index ad116a6..6cf77a2 100644
--- a/lib/liquid/tags/cycle.rb
+++ b/lib/liquid/tags/cycle.rb
@@ -15,6 +15,8 @@ module Liquid
SimpleSyntax = /\A#{QuotedFragment}+/o
NamedSyntax = /\A(#{QuotedFragment})\s*\:\s*(.*)/om
+ attr_reader :variables
+
def initialize(tag_name, markup, options)
super
case markup
diff --git a/lib/liquid/tags/for.rb b/lib/liquid/tags/for.rb
index 6c95624..c529aae 100644
--- a/lib/liquid/tags/for.rb
+++ b/lib/liquid/tags/for.rb
@@ -46,8 +46,7 @@ module Liquid
class For < Block
Syntax = /\A(#{VariableSegment}+)\s+in\s+(#{QuotedFragment}+)\s*(reversed)?/o
- attr_reader :collection_name
- attr_reader :variable_name
+ attr_reader :collection_name, :variable_name, :limit, :from
def initialize(tag_name, markup, options)
super
diff --git a/lib/liquid/tags/if.rb b/lib/liquid/tags/if.rb
index 904369d..2a91741 100644
--- a/lib/liquid/tags/if.rb
+++ b/lib/liquid/tags/if.rb
@@ -14,21 +14,23 @@ module Liquid
ExpressionsAndOperators = /(?:\b(?:\s?and\s?|\s?or\s?)\b|(?:\s*(?!\b(?:\s?and\s?|\s?or\s?)\b)(?:#{QuotedFragment}|\S+)\s*)+)/o
BOOLEAN_OPERATORS = %w(and or)
+ attr_reader :blocks
+
def initialize(tag_name, markup, options)
super
@blocks = []
push_block('if'.freeze, markup)
end
+ def nodelist
+ @blocks.map(&:attachment)
+ end
+
def parse(tokens)
while parse_body(@blocks.last.attachment, tokens)
end
end
- def nodelist
- @blocks.map(&:attachment)
- end
-
def unknown_tag(tag, markup, tokens)
if ['elsif'.freeze, 'else'.freeze].include?(tag)
push_block(tag, markup)
diff --git a/lib/liquid/tags/include.rb b/lib/liquid/tags/include.rb
index a800703..a334d83 100644
--- a/lib/liquid/tags/include.rb
+++ b/lib/liquid/tags/include.rb
@@ -16,6 +16,8 @@ module Liquid
class Include < Tag
Syntax = /(#{QuotedFragment}+)(\s+(?:with|for)\s+(#{QuotedFragment}+))?/o
+ attr_reader :template_name_expr, :variable_name_expr, :attributes
+
def initialize(tag_name, markup, options)
super
diff --git a/lib/liquid/tags/table_row.rb b/lib/liquid/tags/table_row.rb
index cfdef33..99d12ec 100644
--- a/lib/liquid/tags/table_row.rb
+++ b/lib/liquid/tags/table_row.rb
@@ -2,6 +2,8 @@ module Liquid
class TableRow < Block
Syntax = /(\w+)\s+in\s+(#{QuotedFragment}+)/o
+ attr_reader :variable_name, :collection_name, :attributes
+
def initialize(tag_name, markup, options)
super
if markup =~ Syntax
diff --git a/lib/liquid/traversal.rb b/lib/liquid/traversal.rb
new file mode 100644
index 0000000..339fc2c
--- /dev/null
+++ b/lib/liquid/traversal.rb
@@ -0,0 +1,118 @@
+# frozen_string_literal: true
+
+module Liquid
+ class Traversal
+ def self.for(node, callbacks = Hash.new(proc {}))
+ kase = CASES.find { |(klass, _)| node.is_a?(klass) }&.last
+ (kase || self).new(node, callbacks)
+ end
+
+ def initialize(node, callbacks)
+ @node = node
+ @callbacks = callbacks
+ end
+
+ def callback_for(*classes, &block)
+ callback = block
+ callback = ->(node, _) { block.call(node) } if block.arity.abs == 1
+ callback = ->(_, _) { block.call } if block.arity.zero?
+ classes.each { |klass| @callbacks[klass] = callback }
+ self
+ end
+
+ def traverse(context = nil)
+ children.map do |node|
+ item, new_context = @callbacks[node.class].call(node, context)
+ [
+ item,
+ Traversal.for(node, @callbacks).traverse(new_context || context)
+ ]
+ end
+ end
+
+ protected
+
+ def children
+ @node.respond_to?(:nodelist) ? Array(@node.nodelist) : []
+ end
+
+ class Assign < Traversal
+ def children
+ [@node.from]
+ end
+ end
+
+ class Case < Traversal
+ def children
+ [@node.left] + @node.blocks
+ end
+ end
+
+ class Condition < Traversal
+ def children
+ [
+ @node.left, @node.right,
+ @node.child_condition, @node.attachment
+ ].compact
+ end
+ end
+
+ class Cycle < Traversal
+ def children
+ Array(@node.variables)
+ end
+ end
+
+ class For < Traversal
+ def children
+ (super + [@node.limit, @node.from, @node.collection_name]).compact
+ end
+ end
+
+ class If < Traversal
+ def children
+ @node.blocks
+ end
+ end
+
+ class Include < Traversal
+ def children
+ [
+ @node.template_name_expr,
+ @node.variable_name_expr
+ ] + @node.attributes.values
+ end
+ end
+
+ class TableRow < Traversal
+ def children
+ super + @node.attributes.values + [@node.collection_name]
+ end
+ end
+
+ class Variable < Traversal
+ def children
+ [@node.name] + @node.filters.flatten
+ end
+ end
+
+ class VariableLookup < Traversal
+ def children
+ @node.lookups
+ end
+ end
+
+ CASES = {
+ Liquid::Assign => Assign,
+ Liquid::Case => Case,
+ Liquid::Condition => Condition,
+ Liquid::Cycle => Cycle,
+ Liquid::For => For,
+ Liquid::If => If,
+ Liquid::Include => Include,
+ Liquid::TableRow => TableRow,
+ Liquid::Variable => Variable,
+ Liquid::VariableLookup => VariableLookup
+ }.freeze
+ end
+end
diff --git a/test/integration/traversal_test.rb b/test/integration/traversal_test.rb
new file mode 100644
index 0000000..6254cb9
--- /dev/null
+++ b/test/integration/traversal_test.rb
@@ -0,0 +1,234 @@
+# frozen_string_literal: true
+
+require 'test_helper'
+require 'liquid/traversal'
+
+class TraversalTest < Minitest::Test
+ include Liquid
+
+ def test_variable
+ assert_equal(
+ ["test"],
+ traversal(%({{ test }}))
+ )
+ end
+
+ def test_varible_with_filter
+ assert_equal(
+ ["test", "infilter"],
+ traversal(%({{ test | split: infilter }}))
+ )
+ end
+
+ def test_dynamic_variable
+ assert_equal(
+ ["test", "inlookup"],
+ traversal(%({{ test[inlookup] }}))
+ )
+ end
+
+ def test_if_condition
+ assert_equal(
+ ["test"],
+ traversal(%({% if test %}{% endif %}))
+ )
+ end
+
+ def test_complex_if_condition
+ assert_equal(
+ ["test"],
+ traversal(%({% if 1 == 1 and 2 == test %}{% endif %}))
+ )
+ end
+
+ def test_if_body
+ assert_equal(
+ ["test"],
+ traversal(%({% if 1 == 1 %}{{ test }}{% endif %}))
+ )
+ end
+
+ def test_unless_condition
+ assert_equal(
+ ["test"],
+ traversal(%({% unless test %}{% endunless %}))
+ )
+ end
+
+ def test_complex_unless_condition
+ assert_equal(
+ ["test"],
+ traversal(%({% unless 1 == 1 and 2 == test %}{% endunless %}))
+ )
+ end
+
+ def test_unless_body
+ assert_equal(
+ ["test"],
+ traversal(%({% unless 1 == 1 %}{{ test }}{% endunless %}))
+ )
+ end
+
+ def test_elsif_condition
+ assert_equal(
+ ["test"],
+ traversal(%({% if 1 == 1 %}{% elsif test %}{% endif %}))
+ )
+ end
+
+ def test_complex_elsif_condition
+ assert_equal(
+ ["test"],
+ traversal(%({% if 1 == 1 %}{% elsif 1 == 1 and 2 == test %}{% endif %}))
+ )
+ end
+
+ def test_elsif_body
+ assert_equal(
+ ["test"],
+ traversal(%({% if 1 == 1 %}{% elsif 2 == 2 %}{{ test }}{% endif %}))
+ )
+ end
+
+ def test_else_body
+ assert_equal(
+ ["test"],
+ traversal(%({% if 1 == 1 %}{% else %}{{ test }}{% endif %}))
+ )
+ end
+
+ def test_case_left
+ assert_equal(
+ ["test"],
+ traversal(%({% case test %}{% endcase %}))
+ )
+ end
+
+ def test_case_condition
+ assert_equal(
+ ["test"],
+ traversal(%({% case 1 %}{% when test %}{% endcase %}))
+ )
+ end
+
+ def test_case_when_body
+ assert_equal(
+ ["test"],
+ traversal(%({% case 1 %}{% when 2 %}{{ test }}{% endcase %}))
+ )
+ end
+
+ def test_case_else_body
+ assert_equal(
+ ["test"],
+ traversal(%({% case 1 %}{% else %}{{ test }}{% endcase %}))
+ )
+ end
+
+ def test_for_in
+ assert_equal(
+ ["test"],
+ traversal(%({% for x in test %}{% endfor %}))
+ )
+ end
+
+ def test_for_limit
+ assert_equal(
+ ["test"],
+ traversal(%({% for x in (1..5) limit: test %}{% endfor %}))
+ )
+ end
+
+ def test_for_offset
+ assert_equal(
+ ["test"],
+ traversal(%({% for x in (1..5) offset: test %}{% endfor %}))
+ )
+ end
+
+ def test_for_body
+ assert_equal(
+ ["test"],
+ traversal(%({% for x in (1..5) %}{{ test }}{% endfor %}))
+ )
+ end
+
+ def test_tablerow_in
+ assert_equal(
+ ["test"],
+ traversal(%({% tablerow x in test %}{% endtablerow %}))
+ )
+ end
+
+ def test_tablerow_limit
+ assert_equal(
+ ["test"],
+ traversal(%({% tablerow x in (1..5) limit: test %}{% endtablerow %}))
+ )
+ end
+
+ def test_tablerow_offset
+ assert_equal(
+ ["test"],
+ traversal(%({% tablerow x in (1..5) offset: test %}{% endtablerow %}))
+ )
+ end
+
+ def test_tablerow_body
+ assert_equal(
+ ["test"],
+ traversal(%({% tablerow x in (1..5) %}{{ test }}{% endtablerow %}))
+ )
+ end
+
+ def test_cycle
+ assert_equal(
+ ["test"],
+ traversal(%({% cycle test %}))
+ )
+ end
+
+ def test_assign
+ assert_equal(
+ ["test"],
+ traversal(%({% assign x = test %}))
+ )
+ end
+
+ def test_capture
+ assert_equal(
+ ["test"],
+ traversal(%({% capture x %}{{ test }}{% endcapture %}))
+ )
+ end
+
+ def test_include
+ assert_equal(
+ ["test"],
+ traversal(%({% include test %}))
+ )
+ end
+
+ def test_include_with
+ assert_equal(
+ ["test"],
+ traversal(%({% include "hai" with test %}))
+ )
+ end
+
+ def test_include_for
+ assert_equal(
+ ["test"],
+ traversal(%({% include "hai" for test %}))
+ )
+ end
+
+ private
+
+ def traversal(template)
+ ParseTreeVisitor
+ .for(Template.parse(template).root)
+ .add_callback_for(VariableLookup, &:name)
+ .visit.flatten.compact
+ end
+end
From c11fc656cf67365fefac7d1f71a7c172cefd6a5e Mon Sep 17 00:00:00 2001
From: Stephen Paul Weber
Date: Wed, 10 Oct 2018 09:49:14 -0400
Subject: [PATCH 09/74] Colocate Traversal classes with classes they traverse
This puts all knowledge of the traversal in the same file, and removes
the need for a CASES registry.
---
lib/liquid.rb | 1 +
lib/liquid/condition.rb | 9 ++++
lib/liquid/tags/assign.rb | 6 +++
lib/liquid/tags/case.rb | 6 +++
lib/liquid/tags/cycle.rb | 6 +++
lib/liquid/tags/for.rb | 6 +++
lib/liquid/tags/if.rb | 6 +++
lib/liquid/tags/include.rb | 9 ++++
lib/liquid/tags/table_row.rb | 6 +++
lib/liquid/traversal.rb | 86 ++----------------------------
lib/liquid/variable.rb | 6 +++
lib/liquid/variable_lookup.rb | 6 +++
test/integration/traversal_test.rb | 1 -
13 files changed, 72 insertions(+), 82 deletions(-)
diff --git a/lib/liquid.rb b/lib/liquid.rb
index 7d9da26..eef582f 100644
--- a/lib/liquid.rb
+++ b/lib/liquid.rb
@@ -45,6 +45,7 @@ module Liquid
end
require "liquid/version"
+require 'liquid/traversal'
require 'liquid/lexer'
require 'liquid/parser'
require 'liquid/i18n'
diff --git a/lib/liquid/condition.rb b/lib/liquid/condition.rb
index 72bd2ee..aca9420 100644
--- a/lib/liquid/condition.rb
+++ b/lib/liquid/condition.rb
@@ -128,6 +128,15 @@ module Liquid
end
end
end
+
+ class Traversal < Liquid::Traversal
+ def children
+ [
+ @node.left, @node.right,
+ @node.child_condition, @node.attachment
+ ].compact
+ end
+ end
end
class ElseCondition < Condition
diff --git a/lib/liquid/tags/assign.rb b/lib/liquid/tags/assign.rb
index ee6fa76..53c9eb2 100644
--- a/lib/liquid/tags/assign.rb
+++ b/lib/liquid/tags/assign.rb
@@ -47,6 +47,12 @@ module Liquid
1
end
end
+
+ class Traversal < Liquid::Traversal
+ def children
+ [@node.from]
+ end
+ end
end
Template.register_tag('assign'.freeze, Assign)
diff --git a/lib/liquid/tags/case.rb b/lib/liquid/tags/case.rb
index f55aa61..433d404 100644
--- a/lib/liquid/tags/case.rb
+++ b/lib/liquid/tags/case.rb
@@ -82,6 +82,12 @@ module Liquid
block.attach(BlockBody.new)
@blocks << block
end
+
+ class Traversal < Liquid::Traversal
+ def children
+ [@node.left] + @node.blocks
+ end
+ end
end
Template.register_tag('case'.freeze, Case)
diff --git a/lib/liquid/tags/cycle.rb b/lib/liquid/tags/cycle.rb
index 6cf77a2..aaac686 100644
--- a/lib/liquid/tags/cycle.rb
+++ b/lib/liquid/tags/cycle.rb
@@ -53,6 +53,12 @@ module Liquid
$1 ? Expression.parse($1) : nil
end.compact
end
+
+ class Traversal < Liquid::Traversal
+ def children
+ Array(@node.variables)
+ end
+ end
end
Template.register_tag('cycle', Cycle)
diff --git a/lib/liquid/tags/for.rb b/lib/liquid/tags/for.rb
index c529aae..68c1f92 100644
--- a/lib/liquid/tags/for.rb
+++ b/lib/liquid/tags/for.rb
@@ -191,6 +191,12 @@ module Liquid
def render_else(context)
@else_block ? @else_block.render(context) : ''.freeze
end
+
+ class Traversal < Liquid::Traversal
+ def children
+ (super + [@node.limit, @node.from, @node.collection_name]).compact
+ end
+ end
end
Template.register_tag('for'.freeze, For)
diff --git a/lib/liquid/tags/if.rb b/lib/liquid/tags/if.rb
index 2a91741..54560c2 100644
--- a/lib/liquid/tags/if.rb
+++ b/lib/liquid/tags/if.rb
@@ -110,6 +110,12 @@ module Liquid
Condition.new(a)
end
end
+
+ class Traversal < Liquid::Traversal
+ def children
+ @node.blocks
+ end
+ end
end
Template.register_tag('if'.freeze, If)
diff --git a/lib/liquid/tags/include.rb b/lib/liquid/tags/include.rb
index a334d83..23cc591 100644
--- a/lib/liquid/tags/include.rb
+++ b/lib/liquid/tags/include.rb
@@ -109,6 +109,15 @@ module Liquid
file_system.read_template_file(context.evaluate(@template_name_expr))
end
+
+ class Traversal < Liquid::Traversal
+ def children
+ [
+ @node.template_name_expr,
+ @node.variable_name_expr
+ ] + @node.attributes.values
+ end
+ end
end
Template.register_tag('include'.freeze, Include)
diff --git a/lib/liquid/tags/table_row.rb b/lib/liquid/tags/table_row.rb
index 99d12ec..3994553 100644
--- a/lib/liquid/tags/table_row.rb
+++ b/lib/liquid/tags/table_row.rb
@@ -50,6 +50,12 @@ module Liquid
result << "\n"
result
end
+
+ class Traversal < Liquid::Traversal
+ def children
+ super + @node.attributes.values + [@node.collection_name]
+ end
+ end
end
Template.register_tag('tablerow'.freeze, TableRow)
diff --git a/lib/liquid/traversal.rb b/lib/liquid/traversal.rb
index 339fc2c..0cebd96 100644
--- a/lib/liquid/traversal.rb
+++ b/lib/liquid/traversal.rb
@@ -3,8 +3,11 @@
module Liquid
class Traversal
def self.for(node, callbacks = Hash.new(proc {}))
- kase = CASES.find { |(klass, _)| node.is_a?(klass) }&.last
- (kase || self).new(node, callbacks)
+ if defined?(node.class::Traversal)
+ node.class::Traversal
+ else
+ self
+ end.new(node, callbacks)
end
def initialize(node, callbacks)
@@ -35,84 +38,5 @@ module Liquid
def children
@node.respond_to?(:nodelist) ? Array(@node.nodelist) : []
end
-
- class Assign < Traversal
- def children
- [@node.from]
- end
- end
-
- class Case < Traversal
- def children
- [@node.left] + @node.blocks
- end
- end
-
- class Condition < Traversal
- def children
- [
- @node.left, @node.right,
- @node.child_condition, @node.attachment
- ].compact
- end
- end
-
- class Cycle < Traversal
- def children
- Array(@node.variables)
- end
- end
-
- class For < Traversal
- def children
- (super + [@node.limit, @node.from, @node.collection_name]).compact
- end
- end
-
- class If < Traversal
- def children
- @node.blocks
- end
- end
-
- class Include < Traversal
- def children
- [
- @node.template_name_expr,
- @node.variable_name_expr
- ] + @node.attributes.values
- end
- end
-
- class TableRow < Traversal
- def children
- super + @node.attributes.values + [@node.collection_name]
- end
- end
-
- class Variable < Traversal
- def children
- [@node.name] + @node.filters.flatten
- end
- end
-
- class VariableLookup < Traversal
- def children
- @node.lookups
- end
- end
-
- CASES = {
- Liquid::Assign => Assign,
- Liquid::Case => Case,
- Liquid::Condition => Condition,
- Liquid::Cycle => Cycle,
- Liquid::For => For,
- Liquid::If => If,
- Liquid::Include => Include,
- Liquid::TableRow => TableRow,
- Liquid::Variable => Variable,
- Liquid::VariableLookup => VariableLookup
- }.freeze
end
end
diff --git a/lib/liquid/variable.rb b/lib/liquid/variable.rb
index 5f88eb3..1258b2d 100644
--- a/lib/liquid/variable.rb
+++ b/lib/liquid/variable.rb
@@ -138,5 +138,11 @@ module Liquid
raise error
end
end
+
+ class Traversal < Liquid::Traversal
+ def children
+ [@node.name] + @node.filters.flatten
+ end
+ end
end
end
diff --git a/lib/liquid/variable_lookup.rb b/lib/liquid/variable_lookup.rb
index 3ed4e4a..f1b7834 100644
--- a/lib/liquid/variable_lookup.rb
+++ b/lib/liquid/variable_lookup.rb
@@ -78,5 +78,11 @@ module Liquid
def state
[@name, @lookups, @command_flags]
end
+
+ class Traversal < Liquid::Traversal
+ def children
+ @node.lookups
+ end
+ end
end
end
diff --git a/test/integration/traversal_test.rb b/test/integration/traversal_test.rb
index 6254cb9..7bcfac8 100644
--- a/test/integration/traversal_test.rb
+++ b/test/integration/traversal_test.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'test_helper'
-require 'liquid/traversal'
class TraversalTest < Minitest::Test
include Liquid
From ff727016ef946bccceadf4c98384f45889081ef2 Mon Sep 17 00:00:00 2001
From: Stephen Paul Weber
Date: Wed, 10 Oct 2018 09:51:37 -0400
Subject: [PATCH 10/74] s/callback_for/add_callback_for
---
lib/liquid/traversal.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/liquid/traversal.rb b/lib/liquid/traversal.rb
index 0cebd96..d9d6fa8 100644
--- a/lib/liquid/traversal.rb
+++ b/lib/liquid/traversal.rb
@@ -15,7 +15,7 @@ module Liquid
@callbacks = callbacks
end
- def callback_for(*classes, &block)
+ def add_callback_for(*classes, &block)
callback = block
callback = ->(node, _) { block.call(node) } if block.arity.abs == 1
callback = ->(_, _) { block.call } if block.arity.zero?
From 7d13d882583bae1794a40be048a03662f35d5dde Mon Sep 17 00:00:00 2001
From: Stephen Paul Weber
Date: Thu, 11 Oct 2018 10:45:31 -0400
Subject: [PATCH 11/74] s/Traversal/ParseTreeVisitor
---
lib/liquid.rb | 2 +-
lib/liquid/condition.rb | 2 +-
lib/liquid/{traversal.rb => parse_tree_visitor.rb} | 10 +++++-----
lib/liquid/tags/assign.rb | 2 +-
lib/liquid/tags/case.rb | 2 +-
lib/liquid/tags/cycle.rb | 2 +-
lib/liquid/tags/for.rb | 2 +-
lib/liquid/tags/if.rb | 2 +-
lib/liquid/tags/include.rb | 2 +-
lib/liquid/tags/table_row.rb | 2 +-
lib/liquid/variable.rb | 2 +-
lib/liquid/variable_lookup.rb | 2 +-
.../{traversal_test.rb => parse_tree_visitor_test.rb} | 2 +-
13 files changed, 17 insertions(+), 17 deletions(-)
rename lib/liquid/{traversal.rb => parse_tree_visitor.rb} (78%)
rename test/integration/{traversal_test.rb => parse_tree_visitor_test.rb} (98%)
diff --git a/lib/liquid.rb b/lib/liquid.rb
index eef582f..770d2f9 100644
--- a/lib/liquid.rb
+++ b/lib/liquid.rb
@@ -45,7 +45,7 @@ module Liquid
end
require "liquid/version"
-require 'liquid/traversal'
+require 'liquid/parse_tree_visitor'
require 'liquid/lexer'
require 'liquid/parser'
require 'liquid/i18n'
diff --git a/lib/liquid/condition.rb b/lib/liquid/condition.rb
index aca9420..3b51682 100644
--- a/lib/liquid/condition.rb
+++ b/lib/liquid/condition.rb
@@ -129,7 +129,7 @@ module Liquid
end
end
- class Traversal < Liquid::Traversal
+ class ParseTreeVisitor < Liquid::ParseTreeVisitor
def children
[
@node.left, @node.right,
diff --git a/lib/liquid/traversal.rb b/lib/liquid/parse_tree_visitor.rb
similarity index 78%
rename from lib/liquid/traversal.rb
rename to lib/liquid/parse_tree_visitor.rb
index d9d6fa8..62f6c7b 100644
--- a/lib/liquid/traversal.rb
+++ b/lib/liquid/parse_tree_visitor.rb
@@ -1,10 +1,10 @@
# frozen_string_literal: true
module Liquid
- class Traversal
+ class ParseTreeVisitor
def self.for(node, callbacks = Hash.new(proc {}))
- if defined?(node.class::Traversal)
- node.class::Traversal
+ if defined?(node.class::ParseTreeVisitor)
+ node.class::ParseTreeVisitor
else
self
end.new(node, callbacks)
@@ -23,12 +23,12 @@ module Liquid
self
end
- def traverse(context = nil)
+ def visit(context = nil)
children.map do |node|
item, new_context = @callbacks[node.class].call(node, context)
[
item,
- Traversal.for(node, @callbacks).traverse(new_context || context)
+ ParseTreeVisitor.for(node, @callbacks).visit(new_context || context)
]
end
end
diff --git a/lib/liquid/tags/assign.rb b/lib/liquid/tags/assign.rb
index 53c9eb2..c8d0574 100644
--- a/lib/liquid/tags/assign.rb
+++ b/lib/liquid/tags/assign.rb
@@ -48,7 +48,7 @@ module Liquid
end
end
- class Traversal < Liquid::Traversal
+ class ParseTreeVisitor < Liquid::ParseTreeVisitor
def children
[@node.from]
end
diff --git a/lib/liquid/tags/case.rb b/lib/liquid/tags/case.rb
index 433d404..5036b27 100644
--- a/lib/liquid/tags/case.rb
+++ b/lib/liquid/tags/case.rb
@@ -83,7 +83,7 @@ module Liquid
@blocks << block
end
- class Traversal < Liquid::Traversal
+ class ParseTreeVisitor < Liquid::ParseTreeVisitor
def children
[@node.left] + @node.blocks
end
diff --git a/lib/liquid/tags/cycle.rb b/lib/liquid/tags/cycle.rb
index aaac686..17aa860 100644
--- a/lib/liquid/tags/cycle.rb
+++ b/lib/liquid/tags/cycle.rb
@@ -54,7 +54,7 @@ module Liquid
end.compact
end
- class Traversal < Liquid::Traversal
+ class ParseTreeVisitor < Liquid::ParseTreeVisitor
def children
Array(@node.variables)
end
diff --git a/lib/liquid/tags/for.rb b/lib/liquid/tags/for.rb
index 68c1f92..b69aa78 100644
--- a/lib/liquid/tags/for.rb
+++ b/lib/liquid/tags/for.rb
@@ -192,7 +192,7 @@ module Liquid
@else_block ? @else_block.render(context) : ''.freeze
end
- class Traversal < Liquid::Traversal
+ class ParseTreeVisitor < Liquid::ParseTreeVisitor
def children
(super + [@node.limit, @node.from, @node.collection_name]).compact
end
diff --git a/lib/liquid/tags/if.rb b/lib/liquid/tags/if.rb
index 54560c2..1451c25 100644
--- a/lib/liquid/tags/if.rb
+++ b/lib/liquid/tags/if.rb
@@ -111,7 +111,7 @@ module Liquid
end
end
- class Traversal < Liquid::Traversal
+ class ParseTreeVisitor < Liquid::ParseTreeVisitor
def children
@node.blocks
end
diff --git a/lib/liquid/tags/include.rb b/lib/liquid/tags/include.rb
index 23cc591..c9f2a28 100644
--- a/lib/liquid/tags/include.rb
+++ b/lib/liquid/tags/include.rb
@@ -110,7 +110,7 @@ module Liquid
file_system.read_template_file(context.evaluate(@template_name_expr))
end
- class Traversal < Liquid::Traversal
+ class ParseTreeVisitor < Liquid::ParseTreeVisitor
def children
[
@node.template_name_expr,
diff --git a/lib/liquid/tags/table_row.rb b/lib/liquid/tags/table_row.rb
index 3994553..7f391cf 100644
--- a/lib/liquid/tags/table_row.rb
+++ b/lib/liquid/tags/table_row.rb
@@ -51,7 +51,7 @@ module Liquid
result
end
- class Traversal < Liquid::Traversal
+ class ParseTreeVisitor < Liquid::ParseTreeVisitor
def children
super + @node.attributes.values + [@node.collection_name]
end
diff --git a/lib/liquid/variable.rb b/lib/liquid/variable.rb
index 1258b2d..c31bffe 100644
--- a/lib/liquid/variable.rb
+++ b/lib/liquid/variable.rb
@@ -139,7 +139,7 @@ module Liquid
end
end
- class Traversal < Liquid::Traversal
+ class ParseTreeVisitor < Liquid::ParseTreeVisitor
def children
[@node.name] + @node.filters.flatten
end
diff --git a/lib/liquid/variable_lookup.rb b/lib/liquid/variable_lookup.rb
index f1b7834..8f7ad46 100644
--- a/lib/liquid/variable_lookup.rb
+++ b/lib/liquid/variable_lookup.rb
@@ -79,7 +79,7 @@ module Liquid
[@name, @lookups, @command_flags]
end
- class Traversal < Liquid::Traversal
+ class ParseTreeVisitor < Liquid::ParseTreeVisitor
def children
@node.lookups
end
diff --git a/test/integration/traversal_test.rb b/test/integration/parse_tree_visitor_test.rb
similarity index 98%
rename from test/integration/traversal_test.rb
rename to test/integration/parse_tree_visitor_test.rb
index 7bcfac8..4ffef08 100644
--- a/test/integration/traversal_test.rb
+++ b/test/integration/parse_tree_visitor_test.rb
@@ -2,7 +2,7 @@
require 'test_helper'
-class TraversalTest < Minitest::Test
+class ParseTreeVisitorTest < Minitest::Test
include Liquid
def test_variable
From 8217a8d86cbc4f5d0ea1c3f6e02dc271cbe3e73f Mon Sep 17 00:00:00 2001
From: Stephen Paul Weber
Date: Mon, 15 Oct 2018 10:22:09 -0400
Subject: [PATCH 12/74] Add test for the full array structure
---
test/integration/parse_tree_visitor_test.rb | 78 ++++++++++++---------
1 file changed, 46 insertions(+), 32 deletions(-)
diff --git a/test/integration/parse_tree_visitor_test.rb b/test/integration/parse_tree_visitor_test.rb
index 4ffef08..6ad6a2d 100644
--- a/test/integration/parse_tree_visitor_test.rb
+++ b/test/integration/parse_tree_visitor_test.rb
@@ -8,217 +8,228 @@ class ParseTreeVisitorTest < Minitest::Test
def test_variable
assert_equal(
["test"],
- traversal(%({{ test }}))
+ visit(%({{ test }}))
)
end
def test_varible_with_filter
assert_equal(
["test", "infilter"],
- traversal(%({{ test | split: infilter }}))
+ visit(%({{ test | split: infilter }}))
)
end
def test_dynamic_variable
assert_equal(
["test", "inlookup"],
- traversal(%({{ test[inlookup] }}))
+ visit(%({{ test[inlookup] }}))
)
end
def test_if_condition
assert_equal(
["test"],
- traversal(%({% if test %}{% endif %}))
+ visit(%({% if test %}{% endif %}))
)
end
def test_complex_if_condition
assert_equal(
["test"],
- traversal(%({% if 1 == 1 and 2 == test %}{% endif %}))
+ visit(%({% if 1 == 1 and 2 == test %}{% endif %}))
)
end
def test_if_body
assert_equal(
["test"],
- traversal(%({% if 1 == 1 %}{{ test }}{% endif %}))
+ visit(%({% if 1 == 1 %}{{ test }}{% endif %}))
)
end
def test_unless_condition
assert_equal(
["test"],
- traversal(%({% unless test %}{% endunless %}))
+ visit(%({% unless test %}{% endunless %}))
)
end
def test_complex_unless_condition
assert_equal(
["test"],
- traversal(%({% unless 1 == 1 and 2 == test %}{% endunless %}))
+ visit(%({% unless 1 == 1 and 2 == test %}{% endunless %}))
)
end
def test_unless_body
assert_equal(
["test"],
- traversal(%({% unless 1 == 1 %}{{ test }}{% endunless %}))
+ visit(%({% unless 1 == 1 %}{{ test }}{% endunless %}))
)
end
def test_elsif_condition
assert_equal(
["test"],
- traversal(%({% if 1 == 1 %}{% elsif test %}{% endif %}))
+ visit(%({% if 1 == 1 %}{% elsif test %}{% endif %}))
)
end
def test_complex_elsif_condition
assert_equal(
["test"],
- traversal(%({% if 1 == 1 %}{% elsif 1 == 1 and 2 == test %}{% endif %}))
+ visit(%({% if 1 == 1 %}{% elsif 1 == 1 and 2 == test %}{% endif %}))
)
end
def test_elsif_body
assert_equal(
["test"],
- traversal(%({% if 1 == 1 %}{% elsif 2 == 2 %}{{ test }}{% endif %}))
+ visit(%({% if 1 == 1 %}{% elsif 2 == 2 %}{{ test }}{% endif %}))
)
end
def test_else_body
assert_equal(
["test"],
- traversal(%({% if 1 == 1 %}{% else %}{{ test }}{% endif %}))
+ visit(%({% if 1 == 1 %}{% else %}{{ test }}{% endif %}))
)
end
def test_case_left
assert_equal(
["test"],
- traversal(%({% case test %}{% endcase %}))
+ visit(%({% case test %}{% endcase %}))
)
end
def test_case_condition
assert_equal(
["test"],
- traversal(%({% case 1 %}{% when test %}{% endcase %}))
+ visit(%({% case 1 %}{% when test %}{% endcase %}))
)
end
def test_case_when_body
assert_equal(
["test"],
- traversal(%({% case 1 %}{% when 2 %}{{ test }}{% endcase %}))
+ visit(%({% case 1 %}{% when 2 %}{{ test }}{% endcase %}))
)
end
def test_case_else_body
assert_equal(
["test"],
- traversal(%({% case 1 %}{% else %}{{ test }}{% endcase %}))
+ visit(%({% case 1 %}{% else %}{{ test }}{% endcase %}))
)
end
def test_for_in
assert_equal(
["test"],
- traversal(%({% for x in test %}{% endfor %}))
+ visit(%({% for x in test %}{% endfor %}))
)
end
def test_for_limit
assert_equal(
["test"],
- traversal(%({% for x in (1..5) limit: test %}{% endfor %}))
+ visit(%({% for x in (1..5) limit: test %}{% endfor %}))
)
end
def test_for_offset
assert_equal(
["test"],
- traversal(%({% for x in (1..5) offset: test %}{% endfor %}))
+ visit(%({% for x in (1..5) offset: test %}{% endfor %}))
)
end
def test_for_body
assert_equal(
["test"],
- traversal(%({% for x in (1..5) %}{{ test }}{% endfor %}))
+ visit(%({% for x in (1..5) %}{{ test }}{% endfor %}))
)
end
def test_tablerow_in
assert_equal(
["test"],
- traversal(%({% tablerow x in test %}{% endtablerow %}))
+ visit(%({% tablerow x in test %}{% endtablerow %}))
)
end
def test_tablerow_limit
assert_equal(
["test"],
- traversal(%({% tablerow x in (1..5) limit: test %}{% endtablerow %}))
+ visit(%({% tablerow x in (1..5) limit: test %}{% endtablerow %}))
)
end
def test_tablerow_offset
assert_equal(
["test"],
- traversal(%({% tablerow x in (1..5) offset: test %}{% endtablerow %}))
+ visit(%({% tablerow x in (1..5) offset: test %}{% endtablerow %}))
)
end
def test_tablerow_body
assert_equal(
["test"],
- traversal(%({% tablerow x in (1..5) %}{{ test }}{% endtablerow %}))
+ visit(%({% tablerow x in (1..5) %}{{ test }}{% endtablerow %}))
)
end
def test_cycle
assert_equal(
["test"],
- traversal(%({% cycle test %}))
+ visit(%({% cycle test %}))
)
end
def test_assign
assert_equal(
["test"],
- traversal(%({% assign x = test %}))
+ visit(%({% assign x = test %}))
)
end
def test_capture
assert_equal(
["test"],
- traversal(%({% capture x %}{{ test }}{% endcapture %}))
+ visit(%({% capture x %}{{ test }}{% endcapture %}))
)
end
def test_include
assert_equal(
["test"],
- traversal(%({% include test %}))
+ visit(%({% include test %}))
)
end
def test_include_with
assert_equal(
["test"],
- traversal(%({% include "hai" with test %}))
+ visit(%({% include "hai" with test %}))
)
end
def test_include_for
assert_equal(
["test"],
- traversal(%({% include "hai" for test %}))
+ visit(%({% include "hai" for test %}))
+ )
+ end
+
+ def test_preserve_tree_structure
+ assert_equal(
+ [[nil, [
+ [nil, [[nil, [["other", []]]]]],
+ ["test", []],
+ ["xs", []]
+ ]]],
+ traversal(%({% for x in xs offset: test %}{{ other }}{% endfor %})).visit
)
end
@@ -228,6 +239,9 @@ class ParseTreeVisitorTest < Minitest::Test
ParseTreeVisitor
.for(Template.parse(template).root)
.add_callback_for(VariableLookup, &:name)
- .visit.flatten.compact
+ end
+
+ def visit(template)
+ traversal(template).visit.flatten.compact
end
end
From 52ee303a3656e798f8a5a47a97a80640c9eb15ba Mon Sep 17 00:00:00 2001
From: Stephen Paul Weber
Date: Thu, 18 Oct 2018 09:41:53 -0400
Subject: [PATCH 13/74] s/block.call/yield
---
lib/liquid/parse_tree_visitor.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/liquid/parse_tree_visitor.rb b/lib/liquid/parse_tree_visitor.rb
index 62f6c7b..74f5563 100644
--- a/lib/liquid/parse_tree_visitor.rb
+++ b/lib/liquid/parse_tree_visitor.rb
@@ -17,8 +17,8 @@ module Liquid
def add_callback_for(*classes, &block)
callback = block
- callback = ->(node, _) { block.call(node) } if block.arity.abs == 1
- callback = ->(_, _) { block.call } if block.arity.zero?
+ callback = ->(node, _) { yield node } if block.arity.abs == 1
+ callback = ->(_, _) { yield } if block.arity.zero?
classes.each { |klass| @callbacks[klass] = callback }
self
end
From 7c613e87cb1d2bc7247a60d9b438398d6af611a1 Mon Sep 17 00:00:00 2001
From: Tim Layton
Date: Thu, 18 Oct 2018 23:10:56 -0700
Subject: [PATCH 14/74] Enable CLA bot
---
.github/probots.yml | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 .github/probots.yml
diff --git a/.github/probots.yml b/.github/probots.yml
new file mode 100644
index 0000000..1491d27
--- /dev/null
+++ b/.github/probots.yml
@@ -0,0 +1,2 @@
+enabled:
+ - cla
From 407c8abf301acd2ee8c4e4d0d35942dbc2ee04da Mon Sep 17 00:00:00 2001
From: David Cornu
Date: Fri, 19 Oct 2018 14:52:16 -0400
Subject: [PATCH 15/74] Use TrailingCommaInLiteral
TrailingCommaInArrayLiteral and TrailingCommaInHashLiteral were introduced in v0.53.0 and we're running v0.49.0.
https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md#0530-2018-03-05
---
.rubocop.yml | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/.rubocop.yml b/.rubocop.yml
index 4e18078..a622ef1 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -71,10 +71,7 @@ Style/Documentation:
Style/ClassAndModuleChildren:
Enabled: false
-Style/TrailingCommaInArrayLiteral:
- Enabled: false
-
-Style/TrailingCommaInHashLiteral:
+Style/TrailingCommaInLiteral:
Enabled: false
Layout/IndentHash:
@@ -125,6 +122,6 @@ Style/TrivialAccessors:
Style/WordArray:
Enabled: false
-Naming/MethodName:
+Style/MethodName:
Exclude:
- 'example/server/liquid_servlet.rb'
From ca9e75db5329b864982218f70b9f3bab9a8ddc05 Mon Sep 17 00:00:00 2001
From: David Cornu
Date: Fri, 19 Oct 2018 14:57:33 -0400
Subject: [PATCH 16/74] Reduce perceived complexity for #sort and #sort_natural
---
lib/liquid/standardfilters.rb | 53 +++++++++++++++++------------------
1 file changed, 25 insertions(+), 28 deletions(-)
diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb
index b675ba2..ee14f5c 100644
--- a/lib/liquid/standardfilters.rb
+++ b/lib/liquid/standardfilters.rb
@@ -120,25 +120,16 @@ module Liquid
# provide optional property with which to sort an array of hashes or drops
def sort(input, property = nil)
ary = InputIterator.new(input)
+
+ return [] if ary.empty?
+
if property.nil?
ary.sort do |a, b|
- if !a.nil? && !b.nil?
- a <=> b
- else
- a.nil? ? 1 : -1
- end
+ nil_safe_compare(a, b)
end
- elsif ary.empty? # The next two cases assume a non-empty array.
- []
elsif ary.all? { |el| el.respond_to?(:[]) }
ary.sort do |a, b|
- a = a[property]
- b = b[property]
- if !a.nil? && !b.nil?
- a <=> b
- else
- a.nil? ? 1 : -1
- end
+ nil_safe_compare(a[property], b[property])
end
end
end
@@ -148,25 +139,15 @@ module Liquid
def sort_natural(input, property = nil)
ary = InputIterator.new(input)
+ return [] if ary.empty?
+
if property.nil?
ary.sort do |a, b|
- if !a.nil? && !b.nil?
- a.to_s.casecmp(b.to_s)
- else
- a.nil? ? 1 : -1
- end
+ nil_safe_casecmp(a, b)
end
- elsif ary.empty? # The next two cases assume a non-empty array.
- []
elsif ary.all? { |el| el.respond_to?(:[]) }
ary.sort do |a, b|
- a = a[property]
- b = b[property]
- if !a.nil? && !b.nil?
- a.to_s.casecmp(b.to_s)
- else
- a.nil? ? 1 : -1
- end
+ nil_safe_casecmp(a[property], b[property])
end
end
end
@@ -418,6 +399,22 @@ module Liquid
result.is_a?(BigDecimal) ? result.to_f : result
end
+ def nil_safe_compare(a, b)
+ if !a.nil? && !b.nil?
+ a <=> b
+ else
+ a.nil? ? 1 : -1
+ end
+ end
+
+ def nil_safe_casecmp(a, b)
+ if !a.nil? && !b.nil?
+ a.to_s.casecmp(b.to_s)
+ else
+ a.nil? ? 1 : -1
+ end
+ end
+
class InputIterator
include Enumerable
From 2a2376bfd97f8a813934f832c1945af4ae60f46a Mon Sep 17 00:00:00 2001
From: David Cornu
Date: Fri, 19 Oct 2018 15:06:36 -0400
Subject: [PATCH 17/74] Run :test before :rubocop in the default Rake task
---
Rakefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Rakefile b/Rakefile
index e3633f5..3dba4cf 100755
--- a/Rakefile
+++ b/Rakefile
@@ -3,7 +3,7 @@ require 'rake/testtask'
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
require "liquid/version"
-task default: [:rubocop, :test]
+task default: [:test, :rubocop]
desc 'run test suite with default parser'
Rake::TestTask.new(:base_test) do |t|
From b41fc10d8e22ae4182b90ce3a069c88da14db16c Mon Sep 17 00:00:00 2001
From: Eric Chan
Date: Mon, 3 Dec 2018 23:27:14 -0500
Subject: [PATCH 18/74] Updated changelog for v4.0.1
---
History.md | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/History.md b/History.md
index 2dc8f3d..620f7a1 100644
--- a/History.md
+++ b/History.md
@@ -1,5 +1,42 @@
# Liquid Change Log
+## 4.0.1 / 2018-10-09
+
+### Changed
+* Add benchmark group in Gemfile (#855) [Jerry Liu]
+* Allow benchmarks to benchmark render by itself (#851) [Jerry Liu]
+* Avoid calling `line_number` on String node when rescuing a render error. (#860) [Dylan Thacker-Smith]
+* Avoid duck typing to detect whether to call render on a node. [Dylan Thacker-Smith]
+* Clarify spelling of `reversed` on `for` block tag (#843) [Mark Crossfield]
+* Replace recursion with loop to avoid potential stack overflow from malicious input (#891, #892) [Dylan Thacker-Smith]
+* Limit block tag nesting to 100 (#894) [Dylan Thacker-Smith]
+* Replace `assert_equal nil` with `assert_nil` (#895) [Dylan Thacker-Smith]
+* Remove Spy Gem (#896) [Dylan Thacker-Smith]
+* Add `collection_name` and `variable_name` reader to `For` block (#909)
+* Symbols render as strings (#920) [Justin Li]
+* Remove default value from Hash objects (#932) [Maxime Bedard]
+* Remove one level of nesting (#944) [Dylan Thacker-Smith]
+* Update Rubocop version (#952) [Justin Li]
+* Add `at_least` and `at_most` filters (#954, #958) [Nithin Bekal]
+* Add a regression test for a liquid-c trim mode bug (#972) [Dylan Thacker-Smith]
+* Use https rather than git protocol to fetch liquid-c [Dylan Thacker-Smith]
+* Add tests against Ruby 2.4 (#963) and 2.5 (#981)
+* Replace RegExp literals with constants (#988) [Ashwin Maroli]
+* Replace unnecessary `#each_with_index` with `#each` (#992) [Ashwin Maroli]
+* Improve the unexpected end delimiter message for block tags. (#1003) [Dylan Thacker-Smith]
+* Refactor and optimize rendering (#1005) [Christopher Aue]
+* Add installation instruction (#1006) [Ben Gift]
+* Remove Circle CI (#1010)
+* Rename deprecated `BigDecimal.new` to `BigDecimal` (#1024) [Koichi ITO]
+* Rename deprecated Rubocop name (#1027) [Justin Li]
+
+### Fixed
+* Handle `join` filter on non String joiners (#857) [Richard Monette]
+* Fix duplicate inclusion condition logic error of `Liquid::Strainer.add_filter` method (#861)
+* Fix `escape`, `url_encode`, `url_decode` not handling non-string values (#898) [Thierry Joyal]
+* Fix raise when variable is defined but nil when using `strict_variables` [Pascal Betz]
+* Fix `sort` and `sort_natural` to handle arrays with nils (#930) [Eric Chan]
+
## 4.0.0 / 2016-12-14 / branch "4-0-stable"
### Changed
From cec27ea326f3bdf09622363bf5df75f41e71f8bc Mon Sep 17 00:00:00 2001
From: Garland Zhang
Date: Fri, 15 Feb 2019 15:55:43 -0500
Subject: [PATCH 19/74] Extract raise error line and some filters with
begin/rescue blocks
---
lib/liquid/standardfilters.rb | 60 +++++++++++---------
test/integration/standard_filter_test.rb | 71 ++++++++++++++++++++++++
2 files changed, 105 insertions(+), 26 deletions(-)
diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb
index ee14f5c..6047258 100644
--- a/lib/liquid/standardfilters.rb
+++ b/lib/liquid/standardfilters.rb
@@ -128,8 +128,10 @@ module Liquid
nil_safe_compare(a, b)
end
elsif ary.all? { |el| el.respond_to?(:[]) }
- ary.sort do |a, b|
- nil_safe_compare(a[property], b[property])
+ begin
+ ary.sort { |a, b| nil_safe_compare(a[property], b[property]) }
+ rescue TypeError
+ raise_property_error(property)
end
end
end
@@ -146,8 +148,10 @@ module Liquid
nil_safe_casecmp(a, b)
end
elsif ary.all? { |el| el.respond_to?(:[]) }
- ary.sort do |a, b|
- nil_safe_casecmp(a[property], b[property])
+ begin
+ ary.sort { |a, b| nil_safe_casecmp(a[property], b[property]) }
+ rescue TypeError
+ raise_property_error(property)
end
end
end
@@ -160,9 +164,17 @@ module Liquid
if ary.empty?
[]
elsif ary.first.respond_to?(:[]) && target_value.nil?
- ary.where_present(property)
+ begin
+ ary.select { |item| item[property] }
+ rescue TypeError
+ raise_property_error(property)
+ end
elsif ary.first.respond_to?(:[])
- ary.where(property, target_value)
+ begin
+ ary.select { |item| item[property] == target_value }
+ rescue TypeError
+ raise_property_error(property)
+ end
end
end
@@ -176,7 +188,11 @@ module Liquid
elsif ary.empty? # The next two cases assume a non-empty array.
[]
elsif ary.first.respond_to?(:[])
- ary.uniq{ |a| a[property] }
+ begin
+ ary.uniq { |a| a[property] }
+ rescue TypeError
+ raise_property_error(property)
+ end
end
end
@@ -198,6 +214,8 @@ module Liquid
r.is_a?(Proc) ? r.call : r
end
end
+ rescue TypeError
+ raise_property_error(property)
end
# Remove nils within an array
@@ -210,7 +228,11 @@ module Liquid
elsif ary.empty? # The next two cases assume a non-empty array.
[]
elsif ary.first.respond_to?(:[])
- ary.reject{ |a| a[property].nil? }
+ begin
+ ary.reject { |a| a[property].nil? }
+ rescue TypeError
+ raise_property_error(property)
+ end
end
end
@@ -394,6 +416,10 @@ module Liquid
private
+ def raise_property_error(property)
+ raise Liquid::ArgumentError.new("cannot select the property '#{property}'")
+ end
+
def apply_operation(input, operand, operation)
result = Utils.to_number(input).send(operation, Utils.to_number(operand))
result.is_a?(BigDecimal) ? result.to_f : result
@@ -460,24 +486,6 @@ module Liquid
yield(e.respond_to?(:to_liquid) ? e.to_liquid : e)
end
end
-
- def where(property, target_value)
- select do |item|
- item[property] == target_value
- end
- rescue TypeError
- # Cannot index with the given property type (eg. indexing integers with strings
- # which are only allowed to be indexed by other integers).
- raise ArgumentError.new("cannot select the property `#{property}`")
- end
-
- def where_present(property)
- select { |item| item[property] }
- rescue TypeError
- # Cannot index with the given property type (eg. indexing integers with strings
- # which are only allowed to be indexed by other integers).
- raise ArgumentError.new("cannot select the property `#{property}`")
- end
end
end
diff --git a/test/integration/standard_filter_test.rb b/test/integration/standard_filter_test.rb
index c32f4bc..2709a6c 100644
--- a/test/integration/standard_filter_test.rb
+++ b/test/integration/standard_filter_test.rb
@@ -268,10 +268,34 @@ class StandardFiltersTest < Minitest::Test
assert_equal [], @filters.sort([], "a")
end
+ def test_sort_invalid_property
+ foo = [
+ [1],
+ [2],
+ [3]
+ ]
+
+ assert_raises Liquid::ArgumentError do
+ @filters.sort(foo, "bar")
+ end
+ end
+
def test_sort_natural_empty_array
assert_equal [], @filters.sort_natural([], "a")
end
+ def test_sort_natural_invalid_property
+ foo = [
+ [1],
+ [2],
+ [3]
+ ]
+
+ assert_raises Liquid::ArgumentError do
+ @filters.sort_natural(foo, "bar")
+ end
+ end
+
def test_legacy_sort_hash
assert_equal [{ a: 1, b: 2 }], @filters.sort({ a: 1, b: 2 })
end
@@ -295,10 +319,34 @@ class StandardFiltersTest < Minitest::Test
assert_equal [], @filters.uniq([], "a")
end
+ def test_uniq_invalid_property
+ foo = [
+ [1],
+ [2],
+ [3]
+ ]
+
+ assert_raises Liquid::ArgumentError do
+ @filters.uniq(foo, "bar")
+ end
+ end
+
def test_compact_empty_array
assert_equal [], @filters.compact([], "a")
end
+ def test_compact_invalid_property
+ foo = [
+ [1],
+ [2],
+ [3]
+ ]
+
+ assert_raises Liquid::ArgumentError do
+ @filters.compact(foo, "bar")
+ end
+ end
+
def test_reverse
assert_equal [4, 3, 2, 1], @filters.reverse([1, 2, 3, 4])
end
@@ -364,6 +412,29 @@ class StandardFiltersTest < Minitest::Test
assert_template_result "123", '{{ foo | map: "foo" }}', "foo" => TestEnumerable.new
end
+ def test_map_returns_empty_on_2d_input_array
+ foo = [
+ [1],
+ [2],
+ [3]
+ ]
+
+ assert_raises Liquid::ArgumentError do
+ @filters.map(foo, "bar")
+ end
+ end
+
+ def test_map_returns_empty_with_no_property
+ foo = [
+ [1],
+ [2],
+ [3]
+ ]
+ assert_raises Liquid::ArgumentError do
+ @filters.map(foo, nil)
+ end
+ end
+
def test_sort_works_on_enumerables
assert_template_result "213", '{{ foo | sort: "bar" | map: "foo" }}', "foo" => TestEnumerable.new
end
From f59f6dea83234b71a7be994078ee8e9dddf60dc3 Mon Sep 17 00:00:00 2001
From: Ashwin Maroli
Date: Fri, 22 Feb 2019 23:02:56 +0530
Subject: [PATCH 20/74] Fix simple RuboCop offenses and update TODO file
(#1062)
* Fix Layout/EmptyLineAfterMagicComment offense
* Fix Layout/ExtraSpacing offense
* Fix Layout/ClosingParenthesisIndentation offenses
* Fix Style/MutableConstant offense
* Fix Style/UnneededInterpolation offenses
* Fix Style/RedundantParentheses offenses
* Update TODO config for RuboCop
* Add executable bit to test/test_helper.rb
ref: https://travis-ci.org/Shopify/liquid/jobs/488169512#L578
---
.rubocop_todo.yml | 66 +++---------------------
lib/liquid/expression.rb | 2 +-
lib/liquid/i18n.rb | 2 +-
lib/liquid/lexer.rb | 2 +-
lib/liquid/standardfilters.rb | 2 +-
lib/liquid/tags/if.rb | 2 +-
lib/liquid/variable_lookup.rb | 2 +-
lib/liquid/version.rb | 3 +-
test/integration/error_handling_test.rb | 6 +--
test/integration/parsing_quirks_test.rb | 2 +-
test/integration/standard_filter_test.rb | 6 +--
test/test_helper.rb | 0
test/unit/condition_unit_test.rb | 4 +-
13 files changed, 23 insertions(+), 76 deletions(-)
mode change 100644 => 100755 test/test_helper.rb
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 8860c19..bd80b38 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -1,30 +1,11 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
-# on 2017-11-22 11:35:55 -0500 using RuboCop version 0.49.1.
+# on 2019-02-03 21:12:39 +0530 using RuboCop version 0.49.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
-# Offense count: 3
-# Cop supports --auto-correct.
-Layout/ClosingParenthesisIndentation:
- Exclude:
- - 'test/integration/error_handling_test.rb'
-
-# Offense count: 1
-# Cop supports --auto-correct.
-Layout/EmptyLineAfterMagicComment:
- Exclude:
- - 'lib/liquid/version.rb'
-
-# Offense count: 1
-# Cop supports --auto-correct.
-# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
-Layout/ExtraSpacing:
- Exclude:
- - 'test/integration/parsing_quirks_test.rb'
-
# Offense count: 5
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
@@ -51,31 +32,26 @@ Lint/InheritException:
Exclude:
- 'lib/liquid/interrupts.rb'
-# Offense count: 1
-Lint/ScriptPermission:
- Exclude:
- - 'test/test_helper.rb'
-
-# Offense count: 52
+# Offense count: 51
Metrics/AbcSize:
Max: 56
-# Offense count: 13
+# Offense count: 11
Metrics/CyclomaticComplexity:
Max: 12
-# Offense count: 620
+# Offense count: 639
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
# URISchemes: http, https
Metrics/LineLength:
Max: 294
-# Offense count: 102
+# Offense count: 108
# Configuration parameters: CountComments.
Metrics/MethodLength:
Max: 37
-# Offense count: 9
+# Offense count: 7
Metrics/PerceivedComplexity:
Max: 11
@@ -143,23 +119,6 @@ Style/GuardClause:
- 'lib/liquid/variable.rb'
- 'test/unit/tokenizer_unit_test.rb'
-# Offense count: 4
-# Configuration parameters: SupportedStyles.
-# SupportedStyles: snake_case, camelCase
-Style/MethodName:
- EnforcedStyle: snake_case
-
-# Offense count: 6
-# Cop supports --auto-correct.
-Style/MutableConstant:
- Exclude:
- - 'lib/liquid/expression.rb'
- - 'lib/liquid/lexer.rb'
- - 'lib/liquid/standardfilters.rb'
- - 'lib/liquid/tags/if.rb'
- - 'lib/liquid/variable_lookup.rb'
- - 'lib/liquid/version.rb'
-
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
@@ -190,12 +149,6 @@ Style/PercentLiteralDelimiters:
- 'test/integration/assign_test.rb'
- 'test/integration/standard_filter_test.rb'
-# Offense count: 2
-# Cop supports --auto-correct.
-Style/RedundantParentheses:
- Exclude:
- - 'test/unit/condition_unit_test.rb'
-
# Offense count: 1
# Cop supports --auto-correct.
Style/RedundantSelf:
@@ -227,13 +180,6 @@ Style/TernaryParentheses:
- 'lib/liquid/context.rb'
- 'lib/liquid/utils.rb'
-# Offense count: 4
-# Cop supports --auto-correct.
-Style/UnneededInterpolation:
- Exclude:
- - 'lib/liquid/i18n.rb'
- - 'test/integration/standard_filter_test.rb'
-
# Offense count: 2
# Cop supports --auto-correct.
Style/UnneededPercentQ:
diff --git a/lib/liquid/expression.rb b/lib/liquid/expression.rb
index 1d01cdd..98be6db 100644
--- a/lib/liquid/expression.rb
+++ b/lib/liquid/expression.rb
@@ -19,7 +19,7 @@ module Liquid
'false'.freeze => false,
'blank'.freeze => MethodLiteral.new(:blank?, '').freeze,
'empty'.freeze => MethodLiteral.new(:empty?, '').freeze
- }
+ }.freeze
SINGLE_QUOTED_STRING = /\A'(.*)'\z/m
DOUBLE_QUOTED_STRING = /\A"(.*)"\z/m
diff --git a/lib/liquid/i18n.rb b/lib/liquid/i18n.rb
index e998d58..2671507 100644
--- a/lib/liquid/i18n.rb
+++ b/lib/liquid/i18n.rb
@@ -26,7 +26,7 @@ module Liquid
def interpolate(name, vars)
name.gsub(/%\{(\w+)\}/) do
# raise TranslationError, "Undefined key #{$1} for interpolation in translation #{name}" unless vars[$1.to_sym]
- "#{vars[$1.to_sym]}"
+ (vars[$1.to_sym]).to_s
end
end
diff --git a/lib/liquid/lexer.rb b/lib/liquid/lexer.rb
index e9114df..f290744 100644
--- a/lib/liquid/lexer.rb
+++ b/lib/liquid/lexer.rb
@@ -12,7 +12,7 @@ module Liquid
')'.freeze => :close_round,
'?'.freeze => :question,
'-'.freeze => :dash
- }
+ }.freeze
IDENTIFIER = /[a-zA-Z_][\w-]*\??/
SINGLE_STRING_LITERAL = /'[^\']*'/
DOUBLE_STRING_LITERAL = /"[^\"]*"/
diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb
index 6047258..e63d388 100644
--- a/lib/liquid/standardfilters.rb
+++ b/lib/liquid/standardfilters.rb
@@ -9,7 +9,7 @@ module Liquid
'<'.freeze => '<'.freeze,
'"'.freeze => '"'.freeze,
"'".freeze => '''.freeze
- }
+ }.freeze
HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/
# Return the size of an array or of an string
diff --git a/lib/liquid/tags/if.rb b/lib/liquid/tags/if.rb
index 1451c25..02da42b 100644
--- a/lib/liquid/tags/if.rb
+++ b/lib/liquid/tags/if.rb
@@ -12,7 +12,7 @@ module Liquid
class If < Block
Syntax = /(#{QuotedFragment})\s*([=!<>a-z_]+)?\s*(#{QuotedFragment})?/o
ExpressionsAndOperators = /(?:\b(?:\s?and\s?|\s?or\s?)\b|(?:\s*(?!\b(?:\s?and\s?|\s?or\s?)\b)(?:#{QuotedFragment}|\S+)\s*)+)/o
- BOOLEAN_OPERATORS = %w(and or)
+ BOOLEAN_OPERATORS = %w(and or).freeze
attr_reader :blocks
diff --git a/lib/liquid/variable_lookup.rb b/lib/liquid/variable_lookup.rb
index 8f7ad46..62f4877 100644
--- a/lib/liquid/variable_lookup.rb
+++ b/lib/liquid/variable_lookup.rb
@@ -1,7 +1,7 @@
module Liquid
class VariableLookup
SQUARE_BRACKETED = /\A\[(.*)\]\z/m
- COMMAND_METHODS = ['size'.freeze, 'first'.freeze, 'last'.freeze]
+ COMMAND_METHODS = ['size'.freeze, 'first'.freeze, 'last'.freeze].freeze
attr_reader :name, :lookups
diff --git a/lib/liquid/version.rb b/lib/liquid/version.rb
index 64abb7e..388a0c0 100644
--- a/lib/liquid/version.rb
+++ b/lib/liquid/version.rb
@@ -1,4 +1,5 @@
# encoding: utf-8
+
module Liquid
- VERSION = "4.0.1"
+ VERSION = "4.0.1".freeze
end
diff --git a/test/integration/error_handling_test.rb b/test/integration/error_handling_test.rb
index ba81861..b2d186c 100644
--- a/test/integration/error_handling_test.rb
+++ b/test/integration/error_handling_test.rb
@@ -123,7 +123,7 @@ class ErrorHandlingTest < Minitest::Test
',
error_mode: :warn,
line_numbers: true
- )
+ )
assert_equal ['Liquid syntax error (line 4): Unexpected character = in "1 =! 2"'],
template.warnings.map(&:message)
@@ -140,7 +140,7 @@ class ErrorHandlingTest < Minitest::Test
',
error_mode: :strict,
line_numbers: true
- )
+ )
end
assert_equal 'Liquid syntax error (line 4): Unexpected character = in "1 =! 2"', err.message
@@ -158,7 +158,7 @@ class ErrorHandlingTest < Minitest::Test
bla
',
line_numbers: true
- )
+ )
end
assert_equal "Liquid syntax error (line 5): Unknown tag 'foo'", err.message
diff --git a/test/integration/parsing_quirks_test.rb b/test/integration/parsing_quirks_test.rb
index 23742dc..29cb6d6 100644
--- a/test/integration/parsing_quirks_test.rb
+++ b/test/integration/parsing_quirks_test.rb
@@ -99,7 +99,7 @@ class ParsingQuirksTest < Minitest::Test
# After the messed up quotes a filter without parameters (reverse) should work
# but one with parameters (remove) shouldn't be detected.
assert_template_result('here', "{{ 'hi there' | split:\"t\"\" | reverse | first}}")
- assert_template_result('hi ', "{{ 'hi there' | split:\"t\"\" | remove:\"i\" | first}}")
+ assert_template_result('hi ', "{{ 'hi there' | split:\"t\"\" | remove:\"i\" | first}}")
end
end
diff --git a/test/integration/standard_filter_test.rb b/test/integration/standard_filter_test.rb
index 2709a6c..0aa8bbf 100644
--- a/test/integration/standard_filter_test.rb
+++ b/test/integration/standard_filter_test.rb
@@ -465,9 +465,9 @@ class StandardFiltersTest < Minitest::Test
assert_equal '07/05/2006', @filters.date("2006-07-05 10:00:00", "%m/%d/%Y")
assert_equal "07/16/2004", @filters.date("Fri Jul 16 01:00:00 2004", "%m/%d/%Y")
- assert_equal "#{Date.today.year}", @filters.date('now', '%Y')
- assert_equal "#{Date.today.year}", @filters.date('today', '%Y')
- assert_equal "#{Date.today.year}", @filters.date('Today', '%Y')
+ assert_equal Date.today.year.to_s, @filters.date('now', '%Y')
+ assert_equal Date.today.year.to_s, @filters.date('today', '%Y')
+ assert_equal Date.today.year.to_s, @filters.date('Today', '%Y')
assert_nil @filters.date(nil, "%B")
diff --git a/test/test_helper.rb b/test/test_helper.rb
old mode 100644
new mode 100755
diff --git a/test/unit/condition_unit_test.rb b/test/unit/condition_unit_test.rb
index 5afa2b7..b3b90e8 100644
--- a/test/unit/condition_unit_test.rb
+++ b/test/unit/condition_unit_test.rb
@@ -24,9 +24,9 @@ class ConditionUnitTest < Minitest::Test
assert_evaluates_true 1, '<=', 1
# negative numbers
assert_evaluates_true 1, '>', -1
- assert_evaluates_true (-1), '<', 1
+ assert_evaluates_true -1, '<', 1
assert_evaluates_true 1.0, '>', -1.0
- assert_evaluates_true (-1.0), '<', 1.0
+ assert_evaluates_true -1.0, '<', 1.0
end
def test_default_operators_evalute_false
From ed73794f82b6a7fc529c7bd85761c225e7bc5a09 Mon Sep 17 00:00:00 2001
From: Justin Li
Date: Fri, 22 Feb 2019 12:53:54 -0500
Subject: [PATCH 21/74] Preserve existing strip_html behaviour for weird inputs
---
lib/liquid/standardfilters.rb | 11 +++++++----
test/integration/standard_filter_test.rb | 3 +++
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb
index d7e2dbb..af9b30b 100644
--- a/lib/liquid/standardfilters.rb
+++ b/lib/liquid/standardfilters.rb
@@ -11,12 +11,12 @@ module Liquid
"'".freeze => '''.freeze
}
HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/
- STRIP_HTML = Regexp.union(
+ STRIP_HTML_BLOCKS = Regexp.union(
//m,
//m,
- //m,
- /<.*?>/m
+ //m
)
+ STRIP_HTML_TAGS = /<.*?>/m
# Return the size of an array or of an string
def size(input)
@@ -108,7 +108,10 @@ module Liquid
end
def strip_html(input)
- input.to_s.gsub(STRIP_HTML, ''.freeze)
+ empty = ''.freeze
+ result = input.to_s.gsub(STRIP_HTML_BLOCKS, empty)
+ result.gsub!(STRIP_HTML_TAGS, empty)
+ result
end
# Remove all newlines from the string
diff --git a/test/integration/standard_filter_test.rb b/test/integration/standard_filter_test.rb
index d39472e..d7a575e 100644
--- a/test/integration/standard_filter_test.rb
+++ b/test/integration/standard_filter_test.rb
@@ -177,6 +177,9 @@ class StandardFiltersTest < Minitest::Test
assert_equal 'test', @filters.strip_html("test
")
assert_equal 'test', @filters.strip_html("test")
assert_equal '', @filters.strip_html(nil)
+
+ # Quirk of the existing implementation
+ assert_equal 'foo;', @filters.strip_html("<<")
end
def test_join
From e2d9907df280ee4099757bd57d240de44690d695 Mon Sep 17 00:00:00 2001
From: Clayton Smith
Date: Thu, 7 Mar 2019 14:01:10 -0500
Subject: [PATCH 22/74] Validate the character encoding in url_decode.
---
lib/liquid/standardfilters.rb | 7 ++++++-
test/integration/standard_filter_test.rb | 4 ++++
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb
index 68ff2c5..0bddfa9 100644
--- a/lib/liquid/standardfilters.rb
+++ b/lib/liquid/standardfilters.rb
@@ -52,7 +52,12 @@ module Liquid
end
def url_decode(input)
- CGI.unescape(input.to_s) unless input.nil?
+ return if input.nil?
+
+ result = CGI.unescape(input.to_s)
+ raise Liquid::ArgumentError, "invalid byte sequence in #{result.encoding}" unless result.valid_encoding?
+
+ result
end
def slice(input, offset, length = nil)
diff --git a/test/integration/standard_filter_test.rb b/test/integration/standard_filter_test.rb
index 98818eb..6090951 100644
--- a/test/integration/standard_filter_test.rb
+++ b/test/integration/standard_filter_test.rb
@@ -158,6 +158,10 @@ class StandardFiltersTest < Minitest::Test
assert_equal '1', @filters.url_decode(1)
assert_equal '2001-02-03', @filters.url_decode(Date.new(2001, 2, 3))
assert_nil @filters.url_decode(nil)
+ exception = assert_raises Liquid::ArgumentError do
+ @filters.url_decode('%ff')
+ end
+ assert_equal 'Liquid error: invalid byte sequence in UTF-8', exception.message
end
def test_truncatewords
From 8013df8ca2e25b72260d945f0d6bfb1484a7d04c Mon Sep 17 00:00:00 2001
From: Justin Li
Date: Fri, 8 Mar 2019 15:43:46 -0500
Subject: [PATCH 23/74] v4.0.2
---
History.md | 11 +++++++++++
lib/liquid/version.rb | 2 +-
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/History.md b/History.md
index 620f7a1..91f6257 100644
--- a/History.md
+++ b/History.md
@@ -1,5 +1,16 @@
# Liquid Change Log
+## 4.0.2 / 2019-03-08
+
+### Changed
+* Add `where` filter (#1026) [Samuel Doiron]
+* Add `ParseTreeVisitor` to iterate the Liquid AST (#1025) [Stephen Paul Weber]
+* Improve `strip_html` performance (#1032) [printercu]
+
+### Fixed
+* Add error checking for invalid combinations of inputs to sort, sort_natural, where, uniq, map, compact filters (#1059) [Garland Zhang]
+* Validate the character encoding in url_decode (#1070) [Clayton Smith]
+
## 4.0.1 / 2018-10-09
### Changed
diff --git a/lib/liquid/version.rb b/lib/liquid/version.rb
index 388a0c0..07bd0f1 100644
--- a/lib/liquid/version.rb
+++ b/lib/liquid/version.rb
@@ -1,5 +1,5 @@
# encoding: utf-8
module Liquid
- VERSION = "4.0.1".freeze
+ VERSION = "4.0.2".freeze
end
From 39fecd06db1424ea8b7e222141b3f5686feb6270 Mon Sep 17 00:00:00 2001
From: Justin Li
Date: Tue, 12 Mar 2019 12:18:22 -0400
Subject: [PATCH 24/74] Fix interrupts through includes
---
lib/liquid/block_body.rb | 1 +
test/integration/tags/include_tag_test.rb | 8 ++++++++
2 files changed, 9 insertions(+)
diff --git a/lib/liquid/block_body.rb b/lib/liquid/block_body.rb
index 266d8ed..ba29415 100644
--- a/lib/liquid/block_body.rb
+++ b/lib/liquid/block_body.rb
@@ -89,6 +89,7 @@ module Liquid
break
else # Other non-Block tags
render_node_to_output(node, output, context)
+ break if context.interrupt? # might have happened through an include
end
idx += 1
end
diff --git a/test/integration/tags/include_tag_test.rb b/test/integration/tags/include_tag_test.rb
index 1d854b0..9c188d5 100644
--- a/test/integration/tags/include_tag_test.rb
+++ b/test/integration/tags/include_tag_test.rb
@@ -30,6 +30,9 @@ class TestFileSystem
when 'assignments'
"{% assign foo = 'bar' %}"
+ when 'break'
+ "{% break %}"
+
else
template_path
end
@@ -242,4 +245,9 @@ class IncludeTagTest < Minitest::Test
assert_equal [], template.errors
end
+
+ def test_break_through_include
+ assert_template_result "1", "{% for i in (1..3) %}{{ i }}{% break %}{{ i }}{% endfor %}"
+ assert_template_result "1", "{% for i in (1..3) %}{{ i }}{% include 'break' %}{{ i }}{% endfor %}"
+ end
end # IncludeTagTest
From f2f467bdbc248e7bf26b4f5e552cfbce6052f811 Mon Sep 17 00:00:00 2001
From: Justin Li
Date: Tue, 12 Mar 2019 12:43:48 -0400
Subject: [PATCH 25/74] v4.0.3
---
History.md | 5 +++++
lib/liquid/version.rb | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/History.md b/History.md
index 91f6257..9a82faa 100644
--- a/History.md
+++ b/History.md
@@ -1,5 +1,10 @@
# Liquid Change Log
+## 4.0.3 / 2019-03-12
+
+### Fixed
+* Fix break and continue tags inside included templates in loops (#1072) [Justin Li]
+
## 4.0.2 / 2019-03-08
### Changed
diff --git a/lib/liquid/version.rb b/lib/liquid/version.rb
index 07bd0f1..da01c47 100644
--- a/lib/liquid/version.rb
+++ b/lib/liquid/version.rb
@@ -1,5 +1,5 @@
# encoding: utf-8
module Liquid
- VERSION = "4.0.2".freeze
+ VERSION = "4.0.3".freeze
end
From 06c4789dc58b6719620ab1a344cee17618526591 Mon Sep 17 00:00:00 2001
From: Richard Monette
Date: Mon, 18 Mar 2019 14:51:26 -0400
Subject: [PATCH 26/74] update Rubocop for trailing comma styles
---
.rubocop.yml | 17 ++++---
.rubocop_todo.yml | 116 ++++++++++++++++++++++++++++++++++++----------
Gemfile | 2 +-
3 files changed, 103 insertions(+), 32 deletions(-)
diff --git a/.rubocop.yml b/.rubocop.yml
index a622ef1..6a306a1 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -1,4 +1,6 @@
-inherit_from: ./.rubocop_todo.yml
+inherit_from:
+ - .rubocop_todo.yml
+ - ./.rubocop_todo.yml
AllCops:
Exclude:
@@ -29,7 +31,7 @@ Lint/ParenthesesAsGroupedExpression:
Lint/UnusedBlockArgument:
Enabled: false
-Lint/EndAlignment:
+Layout/EndAlignment:
EnforcedStyleAlignWith: variable
Lint/UnusedMethodArgument:
@@ -59,7 +61,7 @@ Style/BracesAroundHashParameters:
Style/NumericLiterals:
Enabled: false
-Layout/SpaceInsideBrackets:
+Layout/SpaceInsideArrayLiteralBrackets:
Enabled: false
Layout/SpaceBeforeBlockBraces:
@@ -71,7 +73,10 @@ Style/Documentation:
Style/ClassAndModuleChildren:
Enabled: false
-Style/TrailingCommaInLiteral:
+Style/TrailingCommaInArrayLiteral:
+ Enabled: false
+
+Style/TrailingCommaInHashLiteral:
Enabled: false
Layout/IndentHash:
@@ -104,7 +109,7 @@ Style/SymbolLiteral:
Performance/Count:
Enabled: false
-Style/ConstantName:
+Naming/ConstantName:
Enabled: false
Layout/CaseIndentation:
@@ -122,6 +127,6 @@ Style/TrivialAccessors:
Style/WordArray:
Enabled: false
-Style/MethodName:
+Naming/MethodName:
Exclude:
- 'example/server/liquid_servlet.rb'
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index bd80b38..6868a7a 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -1,14 +1,22 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
-# on 2019-02-03 21:12:39 +0530 using RuboCop version 0.49.1.
+# on 2019-03-19 11:04:37 -0400 using RuboCop version 0.53.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
+# Offense count: 1
+# Cop supports --auto-correct.
+# Configuration parameters: Include, TreatCommentsAsGroupSeparators.
+# Include: **/*.gemspec
+Gemspec/OrderedDependencies:
+ Exclude:
+ - 'liquid.gemspec'
+
# Offense count: 5
# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, SupportedStyles.
+# Configuration parameters: EnforcedStyle.
# SupportedStyles: auto_detection, squiggly, active_support, powerpack, unindent
Layout/IndentHeredoc:
Exclude:
@@ -17,7 +25,7 @@ Layout/IndentHeredoc:
# Offense count: 6
# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, SupportedStyles.
+# Configuration parameters: EnforcedStyle.
# SupportedStyles: symmetrical, new_line, same_line
Layout/MultilineMethodCallBraceLayout:
Exclude:
@@ -26,38 +34,65 @@ Layout/MultilineMethodCallBraceLayout:
# Offense count: 2
# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, SupportedStyles.
+# Configuration parameters: EnforcedStyle.
# SupportedStyles: runtime_error, standard_error
Lint/InheritException:
Exclude:
- 'lib/liquid/interrupts.rb'
-# Offense count: 51
+# Offense count: 1
+# Configuration parameters: CheckForMethodsWithNoSideEffects.
+Lint/Void:
+ Exclude:
+ - 'lib/liquid/parse_context.rb'
+
+# Offense count: 54
Metrics/AbcSize:
Max: 56
-# Offense count: 11
+# Offense count: 12
Metrics/CyclomaticComplexity:
Max: 12
-# Offense count: 639
-# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
-# URISchemes: http, https
-Metrics/LineLength:
- Max: 294
-
-# Offense count: 108
+# Offense count: 112
# Configuration parameters: CountComments.
Metrics/MethodLength:
Max: 37
-# Offense count: 7
+# Offense count: 8
Metrics/PerceivedComplexity:
Max: 11
+# Offense count: 52
+# Configuration parameters: Blacklist.
+# Blacklist: END, (?-mix:EO[A-Z]{1})
+Naming/HeredocDelimiterNaming:
+ Exclude:
+ - 'test/integration/assign_test.rb'
+ - 'test/integration/capture_test.rb'
+ - 'test/integration/trim_mode_test.rb'
+
+# Offense count: 23
+# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
+# AllowedNames: io, id
+Naming/UncommunicativeMethodParamName:
+ Exclude:
+ - 'example/server/example_servlet.rb'
+ - 'lib/liquid/condition.rb'
+ - 'lib/liquid/context.rb'
+ - 'lib/liquid/standardfilters.rb'
+ - 'lib/liquid/tags/if.rb'
+ - 'lib/liquid/utils.rb'
+ - 'lib/liquid/variable.rb'
+ - 'test/integration/filter_test.rb'
+ - 'test/integration/standard_filter_test.rb'
+ - 'test/integration/tags/for_tag_test.rb'
+ - 'test/integration/template_test.rb'
+ - 'test/unit/condition_unit_test.rb'
+
# Offense count: 10
# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, SupportedStyles.
+# Configuration parameters: EnforcedStyle.
# SupportedStyles: prefer_alias, prefer_alias_method
Style/Alias:
Exclude:
@@ -69,14 +104,23 @@ Style/Alias:
- 'lib/liquid/tags/include.rb'
- 'lib/liquid/variable.rb'
+# Offense count: 22
+Style/CommentedKeyword:
+ Enabled: false
+
# Offense count: 1
# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, SupportedStyles, SingleLineConditionsOnly, IncludeTernaryExpressions.
+# Configuration parameters: EnforcedStyle, SingleLineConditionsOnly, IncludeTernaryExpressions.
# SupportedStyles: assign_to_condition, assign_inside_condition
Style/ConditionalAssignment:
Exclude:
- 'lib/liquid/errors.rb'
+# Offense count: 1
+Style/DateTime:
+ Exclude:
+ - 'test/unit/context_unit_test.rb'
+
# Offense count: 2
# Cop supports --auto-correct.
Style/EmptyCaseCondition:
@@ -86,7 +130,7 @@ Style/EmptyCaseCondition:
# Offense count: 5
# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, SupportedStyles.
+# Configuration parameters: EnforcedStyle.
# SupportedStyles: compact, expanded
Style/EmptyMethod:
Exclude:
@@ -96,11 +140,28 @@ Style/EmptyMethod:
- 'test/integration/tags/include_tag_test.rb'
- 'test/unit/context_unit_test.rb'
+# Offense count: 3
+# Cop supports --auto-correct.
+Style/Encoding:
+ Exclude:
+ - 'lib/liquid/version.rb'
+ - 'liquid.gemspec'
+ - 'test/integration/standard_filter_test.rb'
+
# Offense count: 2
-# Configuration parameters: SupportedStyles.
-# SupportedStyles: annotated, template
+# Cop supports --auto-correct.
+Style/ExpandPathArguments:
+ Exclude:
+ - 'Rakefile'
+ - 'liquid.gemspec'
+
+# Offense count: 7
+# Configuration parameters: EnforcedStyle.
+# SupportedStyles: annotated, template, unannotated
Style/FormatStringToken:
- EnforcedStyle: template
+ Exclude:
+ - 'test/integration/filter_test.rb'
+ - 'test/integration/hash_ordering_test.rb'
# Offense count: 14
# Configuration parameters: MinBodyLength.
@@ -121,7 +182,7 @@ Style/GuardClause:
# Offense count: 1
# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
+# Configuration parameters: EnforcedStyle, MinBodyLength.
# SupportedStyles: skip_modifier_ifs, always
Style/Next:
Exclude:
@@ -129,7 +190,7 @@ Style/Next:
# Offense count: 4
# Cop supports --auto-correct.
-# Configuration parameters: AutoCorrect, EnforcedStyle, SupportedStyles.
+# Configuration parameters: AutoCorrect, EnforcedStyle.
# SupportedStyles: predicate, comparison
Style/NumericPredicate:
Exclude:
@@ -166,14 +227,14 @@ Style/Semicolon:
# Offense count: 7
# Cop supports --auto-correct.
-# Configuration parameters: MinSize, SupportedStyles.
+# Configuration parameters: MinSize.
# SupportedStyles: percent, brackets
Style/SymbolArray:
EnforcedStyle: brackets
# Offense count: 2
# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, SupportedStyles, AllowSafeAssignment.
+# Configuration parameters: EnforcedStyle, AllowSafeAssignment.
# SupportedStyles: require_parentheses, require_no_parentheses, require_parentheses_when_complex
Style/TernaryParentheses:
Exclude:
@@ -188,7 +249,12 @@ Style/UnneededPercentQ:
# Offense count: 1
# Cop supports --auto-correct.
-# Configuration parameters: MaxLineLength.
Style/WhileUntilModifier:
Exclude:
- 'lib/liquid/tags/case.rb'
+
+# Offense count: 640
+# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
+# URISchemes: http, https
+Metrics/LineLength:
+ Max: 294
diff --git a/Gemfile b/Gemfile
index bdeefac..6e3136d 100644
--- a/Gemfile
+++ b/Gemfile
@@ -12,7 +12,7 @@ group :benchmark, :test do
end
group :test do
- gem 'rubocop', '~> 0.49.0'
+ gem 'rubocop', '~> 0.53.0'
platform :mri do
gem 'liquid-c', github: 'Shopify/liquid-c', ref: '9168659de45d6d576fce30c735f857e597fa26f6'
From 274f07880604576c745e431a3e41d6fe97bede43 Mon Sep 17 00:00:00 2001
From: Richard Monette
Date: Tue, 12 Mar 2019 17:28:16 -0400
Subject: [PATCH 27/74] defer hash allocation in parse_filter_expressions
add exploration of GC object allocation
remove performance test
can actually remove one more if branch
use named locals to improve readability
---
lib/liquid/variable.rb | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lib/liquid/variable.rb b/lib/liquid/variable.rb
index c31bffe..717b1a2 100644
--- a/lib/liquid/variable.rb
+++ b/lib/liquid/variable.rb
@@ -95,16 +95,17 @@ module Liquid
def parse_filter_expressions(filter_name, unparsed_args)
filter_args = []
- keyword_args = {}
+ keyword_args = nil
unparsed_args.each do |a|
if matches = a.match(JustTagAttributes)
+ keyword_args ||= {}
keyword_args[matches[1]] = Expression.parse(matches[2])
else
filter_args << Expression.parse(a)
end
end
result = [filter_name, filter_args]
- result << keyword_args unless keyword_args.empty?
+ result << keyword_args if keyword_args
result
end
From 8d1cd4145335d9ee0c7cc0b99da0143c8334bba2 Mon Sep 17 00:00:00 2001
From: Justin Li
Date: Fri, 15 Mar 2019 14:49:31 -0400
Subject: [PATCH 28/74] Add {% liquid %}, {% echo %}, and {% local %} tags
---
Gemfile | 2 +-
lib/liquid/block_body.rb | 60 +++++++++++++--
lib/liquid/locales/en.yml | 1 +
lib/liquid/tag.rb | 4 +-
lib/liquid/tags/assign.rb | 6 +-
lib/liquid/tags/echo.rb | 24 ++++++
lib/liquid/tags/local.rb | 30 ++++++++
lib/liquid/tokenizer.rb | 18 +++--
test/integration/tags/echo_test.rb | 11 +++
test/integration/tags/liquid_tag_test.rb | 98 ++++++++++++++++++++++++
test/integration/tags/local_test.rb | 15 ++++
test/test_helper.rb | 6 +-
12 files changed, 257 insertions(+), 18 deletions(-)
create mode 100644 lib/liquid/tags/echo.rb
create mode 100644 lib/liquid/tags/local.rb
create mode 100644 test/integration/tags/echo_test.rb
create mode 100644 test/integration/tags/liquid_tag_test.rb
create mode 100644 test/integration/tags/local_test.rb
diff --git a/Gemfile b/Gemfile
index bdeefac..60f1a7a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -15,6 +15,6 @@ group :test do
gem 'rubocop', '~> 0.49.0'
platform :mri do
- gem 'liquid-c', github: 'Shopify/liquid-c', ref: '9168659de45d6d576fce30c735f857e597fa26f6'
+ gem 'liquid-c', github: 'Shopify/liquid-c', ref: 'liquid-tag'
end
end
diff --git a/lib/liquid/block_body.rb b/lib/liquid/block_body.rb
index 266d8ed..5f86545 100644
--- a/lib/liquid/block_body.rb
+++ b/lib/liquid/block_body.rb
@@ -1,6 +1,7 @@
module Liquid
class BlockBody
- FullToken = /\A#{TagStart}#{WhitespaceControl}?\s*(\w+)\s*(.*?)#{WhitespaceControl}?#{TagEnd}\z/om
+ LiquidTagToken = /\A\s*(\w+)\s*(.*?)\z/o
+ FullToken = /\A#{TagStart}#{WhitespaceControl}?(\s*)(\w+)(\s*)(.*?)#{WhitespaceControl}?#{TagEnd}\z/om
ContentOfVariable = /\A#{VariableStart}#{WhitespaceControl}?(.*?)#{WhitespaceControl}?#{VariableEnd}\z/om
WhitespaceOrNothing = /\A\s*\z/
TAGSTART = "{%".freeze
@@ -13,8 +14,46 @@ module Liquid
@blank = true
end
- def parse(tokenizer, parse_context)
+ def parse(tokenizer, parse_context, &block)
parse_context.line_number = tokenizer.line_number
+
+ if tokenizer.for_liquid_tag
+ parse_for_liquid_tag(tokenizer, parse_context, &block)
+ else
+ parse_for_document(tokenizer, parse_context, &block)
+ end
+ end
+
+ private def parse_for_liquid_tag(tokenizer, parse_context)
+ while token = tokenizer.shift
+ case
+ when token.empty?
+ # pass
+ else
+ unless token =~ LiquidTagToken
+ next if token =~ WhitespaceOrNothing
+ # line isn't empty but didn't match tag syntax, yield and let the
+ # caller raise a syntax error
+ return yield token, token
+ end
+ tag_name = $1
+ markup = $2
+ unless tag = registered_tags[tag_name]
+ # end parsing if we reach an unknown tag and let the caller decide
+ # determine how to proceed
+ return yield tag_name, markup
+ end
+ new_tag = tag.parse(tag_name, markup, tokenizer, parse_context)
+ @blank &&= new_tag.blank?
+ @nodelist << new_tag
+ end
+ parse_context.line_number = tokenizer.line_number
+ end
+
+ yield nil, nil
+ end
+
+ private def parse_for_document(tokenizer, parse_context, &block)
while token = tokenizer.shift
next if token.empty?
case
@@ -23,9 +62,20 @@ module Liquid
unless token =~ FullToken
raise_missing_tag_terminator(token, parse_context)
end
- tag_name = $1
- markup = $2
- # fetch the tag from registered blocks
+ tag_name = $2
+ markup = $4
+
+ if parse_context.line_number
+ # newlines inside the tag should increase the line number,
+ # particularly important for multiline {% liquid %} tags
+ parse_context.line_number += $1.count("\n".freeze) + $3.count("\n".freeze)
+ end
+
+ if tag_name == 'liquid'.freeze
+ liquid_tag_tokenizer = Tokenizer.new(markup, line_number: parse_context.line_number, for_liquid_tag: true)
+ next parse(liquid_tag_tokenizer, parse_context, &block)
+ end
+
unless tag = registered_tags[tag_name]
# end parsing if we reach an unknown tag and let the caller decide
# determine how to proceed
diff --git a/lib/liquid/locales/en.yml b/lib/liquid/locales/en.yml
index 48b3b1d..56c068f 100644
--- a/lib/liquid/locales/en.yml
+++ b/lib/liquid/locales/en.yml
@@ -3,6 +3,7 @@
syntax:
tag_unexpected_args: "Syntax Error in '%{tag}' - Valid syntax: %{tag}"
assign: "Syntax Error in 'assign' - Valid syntax: assign [var] = [source]"
+ local: "Syntax Error in 'local' - Valid syntax: local [var] = [source]"
capture: "Syntax Error in 'capture' - Valid syntax: capture [var]"
case: "Syntax Error in 'case' - Valid syntax: case [condition]"
case_invalid_when: "Syntax Error in tag 'case' - Valid when condition: {% when [condition] [or condition2...] %}"
diff --git a/lib/liquid/tag.rb b/lib/liquid/tag.rb
index 06970c1..ac99ecd 100644
--- a/lib/liquid/tag.rb
+++ b/lib/liquid/tag.rb
@@ -5,8 +5,8 @@ module Liquid
include ParserSwitching
class << self
- def parse(tag_name, markup, tokenizer, options)
- tag = new(tag_name, markup, options)
+ def parse(tag_name, markup, tokenizer, parse_context)
+ tag = new(tag_name, markup, parse_context)
tag.parse(tokenizer)
tag
end
diff --git a/lib/liquid/tags/assign.rb b/lib/liquid/tags/assign.rb
index c8d0574..55753d8 100644
--- a/lib/liquid/tags/assign.rb
+++ b/lib/liquid/tags/assign.rb
@@ -10,6 +10,10 @@ module Liquid
class Assign < Tag
Syntax = /(#{VariableSignature}+)\s*=\s*(.*)\s*/om
+ def self.syntax_error_translation_key
+ "errors.syntax.assign".freeze
+ end
+
attr_reader :to, :from
def initialize(tag_name, markup, options)
@@ -18,7 +22,7 @@ module Liquid
@to = $1
@from = Variable.new($2, options)
else
- raise SyntaxError.new options[:locale].t("errors.syntax.assign".freeze)
+ raise SyntaxError.new(options[:locale].t(self.class.syntax_error_translation_key))
end
end
diff --git a/lib/liquid/tags/echo.rb b/lib/liquid/tags/echo.rb
new file mode 100644
index 0000000..acb9ab4
--- /dev/null
+++ b/lib/liquid/tags/echo.rb
@@ -0,0 +1,24 @@
+module Liquid
+ # Echo outputs an expression
+ #
+ # {% echo monkey %}
+ # {% echo user.name %}
+ #
+ # This is identical to variable output syntax, like {{ foo }}, but works
+ # inside {% liquid %} tags. The full syntax is supported, including filters:
+ #
+ # {% echo user | link %}
+ #
+ class Echo < Tag
+ def initialize(tag_name, markup, parse_context)
+ super
+ @variable = Variable.new(markup, parse_context)
+ end
+
+ def render(context)
+ @variable.render(context)
+ end
+ end
+
+ Template.register_tag('echo'.freeze, Echo)
+end
diff --git a/lib/liquid/tags/local.rb b/lib/liquid/tags/local.rb
new file mode 100644
index 0000000..572920e
--- /dev/null
+++ b/lib/liquid/tags/local.rb
@@ -0,0 +1,30 @@
+require_relative 'assign'
+
+module Liquid
+ # Local sets a variable in the current scope.
+ #
+ # {% local foo = 'monkey' %}
+ #
+ # You can then use the variable later in the scope.
+ #
+ # {% if true %}
+ # {% local foo = 'monkey' %}
+ # {{ foo }} outputs monkey
+ # {% endif %}
+ # {{ foo }} outputs nothing
+ #
+ class Local < Assign
+ def self.syntax_error_translation_key
+ "errors.syntax.local".freeze
+ end
+
+ def render(context)
+ val = @from.render(context)
+ context[@to] = val
+ context.resource_limits.assign_score += assign_score_of(val)
+ ''.freeze
+ end
+ end
+
+ Template.register_tag('local'.freeze, Local)
+end
diff --git a/lib/liquid/tokenizer.rb b/lib/liquid/tokenizer.rb
index d03657e..d3fd676 100644
--- a/lib/liquid/tokenizer.rb
+++ b/lib/liquid/tokenizer.rb
@@ -1,25 +1,31 @@
module Liquid
class Tokenizer
- attr_reader :line_number
+ attr_reader :line_number, :for_liquid_tag
- def initialize(source, line_numbers = false)
+ def initialize(source, line_numbers = false, line_number: nil, for_liquid_tag: false)
@source = source
- @line_number = line_numbers ? 1 : nil
+ @line_number = line_number || (line_numbers ? 1 : nil)
+ @for_liquid_tag = for_liquid_tag
@tokens = tokenize
end
def shift
- token = @tokens.shift
- @line_number += token.count("\n") if @line_number && token
+ token = @tokens.shift or return
+
+ if @line_number
+ @line_number += @for_liquid_tag ? 1 : token.count("\n")
+ end
+
token
end
private
def tokenize
- @source = @source.source if @source.respond_to?(:source)
return [] if @source.to_s.empty?
+ return @source.split("\n") if @for_liquid_tag
+
tokens = @source.split(TemplateParser)
# removes the rogue empty element at the beginning of the array
diff --git a/test/integration/tags/echo_test.rb b/test/integration/tags/echo_test.rb
new file mode 100644
index 0000000..ed5b821
--- /dev/null
+++ b/test/integration/tags/echo_test.rb
@@ -0,0 +1,11 @@
+require 'test_helper'
+
+class EchoTest < Minitest::Test
+ include Liquid
+
+ def test_echo_outputs_its_input
+ assert_template_result('BAR', <<~LIQUID, { 'variable-name' => 'bar' })
+ {%- echo variable-name | upcase -%}
+ LIQUID
+ end
+end
diff --git a/test/integration/tags/liquid_tag_test.rb b/test/integration/tags/liquid_tag_test.rb
new file mode 100644
index 0000000..2cfd13a
--- /dev/null
+++ b/test/integration/tags/liquid_tag_test.rb
@@ -0,0 +1,98 @@
+require 'test_helper'
+
+class LiquidTagTest < Minitest::Test
+ include Liquid
+
+ def test_liquid_tag
+ assert_template_result('1 2 3', <<~LIQUID, 'array' => [1, 2, 3])
+ {%- liquid
+ echo array | join: " "
+ -%}
+ LIQUID
+
+ assert_template_result('1 2 3', <<~LIQUID, 'array' => [1, 2, 3])
+ {%- liquid
+ for value in array
+ echo value
+ unless forloop.last
+ echo " "
+ endunless
+ endfor
+ -%}
+ LIQUID
+
+ assert_template_result('4 8 12', <<~LIQUID, 'array' => [1, 2, 3])
+ {%- liquid
+ for value in array
+ local double_value = value | times: 2
+ echo double_value | times: 2
+ unless forloop.last
+ echo " "
+ endunless
+ endfor
+
+ echo double_value
+ -%}
+ LIQUID
+
+ assert_template_result('abc', <<~LIQUID)
+ {%- liquid echo "a" -%}
+ b
+ {%- liquid echo "c" -%}
+ LIQUID
+ end
+
+ def test_liquid_tag_errors
+ assert_match_syntax_error("syntax error (line 1): Unknown tag 'error'", <<~LIQUID)
+ {%- liquid error no such tag -%}
+ LIQUID
+
+ assert_match_syntax_error("syntax error (line 7): Unknown tag 'error'", <<~LIQUID)
+ {{ test }}
+
+ {%-
+ liquid
+ for value in array
+
+ error no such tag
+ endfor
+ -%}
+ LIQUID
+
+ assert_match_syntax_error("syntax error (line 2): Unknown tag '!!! the guards are vigilant'", <<~LIQUID)
+ {%- liquid
+ !!! the guards are vigilant
+ -%}
+ LIQUID
+
+ assert_match_syntax_error("syntax error (line 4): 'for' tag was never closed", <<~LIQUID)
+ {%- liquid
+ for value in array
+ echo 'forgot to close the for tag'
+ -%}
+ LIQUID
+ end
+
+ def test_cannot_open_blocks_living_past_a_liquid_tag
+ assert_match_syntax_error("syntax error (line 3): 'if' tag was never closed", <<~LIQUID)
+ {%- liquid
+ if true
+ -%}
+ {%- endif -%}
+ LIQUID
+ end
+
+ def test_quirk_can_close_blocks_created_before_a_liquid_tag
+ assert_template_result("42", <<~LIQUID)
+ {%- if true -%}
+ 42
+ {%- liquid endif -%}
+ LIQUID
+ end
+
+ def test_liquid_tag_in_raw
+ assert_template_result("{% liquid echo 'test' %}\n", <<~LIQUID)
+ {% raw %}{% liquid echo 'test' %}{% endraw %}
+ LIQUID
+ end
+end
diff --git a/test/integration/tags/local_test.rb b/test/integration/tags/local_test.rb
new file mode 100644
index 0000000..412ee26
--- /dev/null
+++ b/test/integration/tags/local_test.rb
@@ -0,0 +1,15 @@
+require 'test_helper'
+
+class LocalTest < Minitest::Test
+ include Liquid
+
+ def test_local_is_scope_aware
+ assert_template_result('value', <<~LIQUID)
+ {%- if true -%}
+ {%- local variable-name = 'value' -%}
+ {{- variable-name -}}
+ {%- endif -%}
+ {{- variable-name -}}
+ LIQUID
+ end
+end
diff --git a/test/test_helper.rb b/test/test_helper.rb
index ac5ab53..c55328d 100755
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -37,18 +37,18 @@ module Minitest
include Liquid
def assert_template_result(expected, template, assigns = {}, message = nil)
- assert_equal expected, Template.parse(template).render!(assigns), message
+ assert_equal expected, Template.parse(template, line_numbers: true).render!(assigns), message
end
def assert_template_result_matches(expected, template, assigns = {}, message = nil)
return assert_template_result(expected, template, assigns, message) unless expected.is_a? Regexp
- assert_match expected, Template.parse(template).render!(assigns), message
+ assert_match expected, Template.parse(template, line_numbers: true).render!(assigns), message
end
def assert_match_syntax_error(match, template, assigns = {})
exception = assert_raises(Liquid::SyntaxError) do
- Template.parse(template).render(assigns)
+ Template.parse(template, line_numbers: true).render(assigns)
end
assert_match match, exception.message
end
From 951abb67ee29af54378960815eb7118c90414653 Mon Sep 17 00:00:00 2001
From: Justin Li
Date: Mon, 8 Apr 2019 18:34:39 -0400
Subject: [PATCH 29/74] Remove {% local %} tag
---
lib/liquid/tags/local.rb | 30 ------------------------
test/integration/tags/liquid_tag_test.rb | 5 ++--
test/integration/tags/local_test.rb | 15 ------------
3 files changed, 3 insertions(+), 47 deletions(-)
delete mode 100644 lib/liquid/tags/local.rb
delete mode 100644 test/integration/tags/local_test.rb
diff --git a/lib/liquid/tags/local.rb b/lib/liquid/tags/local.rb
deleted file mode 100644
index 572920e..0000000
--- a/lib/liquid/tags/local.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require_relative 'assign'
-
-module Liquid
- # Local sets a variable in the current scope.
- #
- # {% local foo = 'monkey' %}
- #
- # You can then use the variable later in the scope.
- #
- # {% if true %}
- # {% local foo = 'monkey' %}
- # {{ foo }} outputs monkey
- # {% endif %}
- # {{ foo }} outputs nothing
- #
- class Local < Assign
- def self.syntax_error_translation_key
- "errors.syntax.local".freeze
- end
-
- def render(context)
- val = @from.render(context)
- context[@to] = val
- context.resource_limits.assign_score += assign_score_of(val)
- ''.freeze
- end
- end
-
- Template.register_tag('local'.freeze, Local)
-end
diff --git a/test/integration/tags/liquid_tag_test.rb b/test/integration/tags/liquid_tag_test.rb
index 2cfd13a..56ca712 100644
--- a/test/integration/tags/liquid_tag_test.rb
+++ b/test/integration/tags/liquid_tag_test.rb
@@ -21,16 +21,17 @@ class LiquidTagTest < Minitest::Test
-%}
LIQUID
- assert_template_result('4 8 12', <<~LIQUID, 'array' => [1, 2, 3])
+ assert_template_result('4 8 12 6', <<~LIQUID, 'array' => [1, 2, 3])
{%- liquid
for value in array
- local double_value = value | times: 2
+ assign double_value = value | times: 2
echo double_value | times: 2
unless forloop.last
echo " "
endunless
endfor
+ echo " "
echo double_value
-%}
LIQUID
diff --git a/test/integration/tags/local_test.rb b/test/integration/tags/local_test.rb
deleted file mode 100644
index 412ee26..0000000
--- a/test/integration/tags/local_test.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require 'test_helper'
-
-class LocalTest < Minitest::Test
- include Liquid
-
- def test_local_is_scope_aware
- assert_template_result('value', <<~LIQUID)
- {%- if true -%}
- {%- local variable-name = 'value' -%}
- {{- variable-name -}}
- {%- endif -%}
- {{- variable-name -}}
- LIQUID
- end
-end
From e6ed804ca56d6bcc818e439bee372cd5d8a379c3 Mon Sep 17 00:00:00 2001
From: Justin Li
Date: Mon, 8 Apr 2019 18:43:09 -0400
Subject: [PATCH 30/74] Fix line number tracking after a non-empty blank token
---
lib/liquid/block_body.rb | 6 +++---
test/integration/tags/liquid_tag_test.rb | 5 +++++
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/lib/liquid/block_body.rb b/lib/liquid/block_body.rb
index 5f86545..4861bca 100644
--- a/lib/liquid/block_body.rb
+++ b/lib/liquid/block_body.rb
@@ -27,11 +27,11 @@ module Liquid
private def parse_for_liquid_tag(tokenizer, parse_context)
while token = tokenizer.shift
case
- when token.empty?
- # pass
+ when token.empty? || token =~ WhitespaceOrNothing
+ # pass, but assign line_number below, since it could change even when
+ # the token is empty
else
unless token =~ LiquidTagToken
- next if token =~ WhitespaceOrNothing
# line isn't empty but didn't match tag syntax, yield and let the
# caller raise a syntax error
return yield token, token
diff --git a/test/integration/tags/liquid_tag_test.rb b/test/integration/tags/liquid_tag_test.rb
index 56ca712..d4be128 100644
--- a/test/integration/tags/liquid_tag_test.rb
+++ b/test/integration/tags/liquid_tag_test.rb
@@ -74,6 +74,11 @@ class LiquidTagTest < Minitest::Test
LIQUID
end
+ def test_line_number_is_correct_after_a_blank_token
+ assert_match_syntax_error("syntax error (line 3): Unknown tag 'error'", "{% liquid echo ''\n\n error %}")
+ assert_match_syntax_error("syntax error (line 3): Unknown tag 'error'", "{% liquid echo ''\n \n error %}")
+ end
+
def test_cannot_open_blocks_living_past_a_liquid_tag
assert_match_syntax_error("syntax error (line 3): 'if' tag was never closed", <<~LIQUID)
{%- liquid
From 7dc488a73b8bbe8717f318ed510bacc090abe3be Mon Sep 17 00:00:00 2001
From: Justin Li
Date: Tue, 9 Apr 2019 15:19:47 -0400
Subject: [PATCH 31/74] Simplifications from review
---
lib/liquid/block_body.rb | 8 ++------
lib/liquid/locales/en.yml | 1 -
2 files changed, 2 insertions(+), 7 deletions(-)
diff --git a/lib/liquid/block_body.rb b/lib/liquid/block_body.rb
index 4861bca..cffb15b 100644
--- a/lib/liquid/block_body.rb
+++ b/lib/liquid/block_body.rb
@@ -26,11 +26,7 @@ module Liquid
private def parse_for_liquid_tag(tokenizer, parse_context)
while token = tokenizer.shift
- case
- when token.empty? || token =~ WhitespaceOrNothing
- # pass, but assign line_number below, since it could change even when
- # the token is empty
- else
+ unless token.empty? || token =~ WhitespaceOrNothing
unless token =~ LiquidTagToken
# line isn't empty but didn't match tag syntax, yield and let the
# caller raise a syntax error
@@ -73,7 +69,7 @@ module Liquid
if tag_name == 'liquid'.freeze
liquid_tag_tokenizer = Tokenizer.new(markup, line_number: parse_context.line_number, for_liquid_tag: true)
- next parse(liquid_tag_tokenizer, parse_context, &block)
+ next parse_for_liquid_tag(liquid_tag_tokenizer, parse_context, &block)
end
unless tag = registered_tags[tag_name]
diff --git a/lib/liquid/locales/en.yml b/lib/liquid/locales/en.yml
index 56c068f..48b3b1d 100644
--- a/lib/liquid/locales/en.yml
+++ b/lib/liquid/locales/en.yml
@@ -3,7 +3,6 @@
syntax:
tag_unexpected_args: "Syntax Error in '%{tag}' - Valid syntax: %{tag}"
assign: "Syntax Error in 'assign' - Valid syntax: assign [var] = [source]"
- local: "Syntax Error in 'local' - Valid syntax: local [var] = [source]"
capture: "Syntax Error in 'capture' - Valid syntax: capture [var]"
case: "Syntax Error in 'case' - Valid syntax: case [condition]"
case_invalid_when: "Syntax Error in tag 'case' - Valid when condition: {% when [condition] [or condition2...] %}"
From c89ce9c2ed523f05152dfb0dfc2ecb32afff6b76 Mon Sep 17 00:00:00 2001
From: Florian Weingarten
Date: Wed, 17 Apr 2019 18:48:36 +0100
Subject: [PATCH 32/74] use bytesize, not length
---
lib/liquid/block_body.rb | 2 +-
lib/liquid/tags/assign.rb | 2 +-
lib/liquid/tags/capture.rb | 2 +-
test/integration/template_test.rb | 18 ++++++++++++++++++
4 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/lib/liquid/block_body.rb b/lib/liquid/block_body.rb
index ba29415..d4fab30 100644
--- a/lib/liquid/block_body.rb
+++ b/lib/liquid/block_body.rb
@@ -115,7 +115,7 @@ module Liquid
end
def check_resources(context, node_output)
- context.resource_limits.render_length += node_output.length
+ context.resource_limits.render_length += node_output.bytesize
return unless context.resource_limits.reached?
raise MemoryError.new("Memory limits exceeded".freeze)
end
diff --git a/lib/liquid/tags/assign.rb b/lib/liquid/tags/assign.rb
index c8d0574..3b696dd 100644
--- a/lib/liquid/tags/assign.rb
+++ b/lib/liquid/tags/assign.rb
@@ -37,7 +37,7 @@ module Liquid
def assign_score_of(val)
if val.instance_of?(String)
- val.length
+ val.bytesize
elsif val.instance_of?(Array) || val.instance_of?(Hash)
sum = 1
# Uses #each to avoid extra allocations.
diff --git a/lib/liquid/tags/capture.rb b/lib/liquid/tags/capture.rb
index 8674356..d5b8e29 100644
--- a/lib/liquid/tags/capture.rb
+++ b/lib/liquid/tags/capture.rb
@@ -25,7 +25,7 @@ module Liquid
def render(context)
output = super
context.scopes.last[@to] = output
- context.resource_limits.assign_score += output.length
+ context.resource_limits.assign_score += output.bytesize
''.freeze
end
diff --git a/test/integration/template_test.rb b/test/integration/template_test.rb
index d10e1c5..0dc0ae5 100644
--- a/test/integration/template_test.rb
+++ b/test/integration/template_test.rb
@@ -139,6 +139,16 @@ class TemplateTest < Minitest::Test
refute_nil t.resource_limits.assign_score
end
+ def test_resource_limits_assign_score_counts_bytes_not_characters
+ t = Template.parse("{% assign foo = 'すごい' %}")
+ t.render
+ assert_equal 9, t.resource_limits.assign_score
+
+ t = Template.parse("{% capture foo %}すごい{% endcapture %}")
+ t.render
+ assert_equal 9, t.resource_limits.assign_score
+ end
+
def test_resource_limits_assign_score_nested
t = Template.parse("{% assign foo = 'aaaa' | reverse %}")
@@ -187,6 +197,14 @@ class TemplateTest < Minitest::Test
assert_equal "ababab", t.render
end
+ def test_render_length_uses_number_of_bytes_not_characters
+ t = Template.parse("{% if true %}すごい{% endif %}")
+ t.resource_limits.render_length_limit = 10
+ assert_equal "Liquid error: Memory limits exceeded", t.render
+ t.resource_limits.render_length_limit = 18
+ assert_equal "すごい", t.render
+ end
+
def test_default_resource_limits_unaffected_by_render_with_context
context = Context.new
t = Template.parse("{% for a in (1..100) %} {% assign foo = 1 %} {% endfor %}")
From c67b77709d45d663de62d200c1870d5487d1509b Mon Sep 17 00:00:00 2001
From: Florian Weingarten
Date: Wed, 17 Apr 2019 18:33:59 +0100
Subject: [PATCH 33/74] rake memory_profile:run
---
Gemfile | 7 +++++--
Rakefile | 7 +++++++
performance/memory_profile.rb | 26 ++++++++++++++++++++++++++
3 files changed, 38 insertions(+), 2 deletions(-)
create mode 100644 performance/memory_profile.rb
diff --git a/Gemfile b/Gemfile
index 6e3136d..c7cde24 100644
--- a/Gemfile
+++ b/Gemfile
@@ -5,10 +5,13 @@ end
gemspec
-gem 'stackprof', platforms: :mri
-
group :benchmark, :test do
gem 'benchmark-ips'
+ gem 'memory_profiler'
+
+ install_if -> { RUBY_PLATFORM !~ /mingw|mswin/ } do
+ gem 'stackprof'
+ end
end
group :test do
diff --git a/Rakefile b/Rakefile
index 3dba4cf..9650abb 100755
--- a/Rakefile
+++ b/Rakefile
@@ -85,6 +85,13 @@ namespace :profile do
end
end
+namespace :memory_profile do
+ desc "Run memory profiler"
+ task :run do
+ ruby "./performance/memory_profile.rb"
+ end
+end
+
desc "Run example"
task :example do
ruby "-w -d -Ilib example/server/server.rb"
diff --git a/performance/memory_profile.rb b/performance/memory_profile.rb
new file mode 100644
index 0000000..bfacde8
--- /dev/null
+++ b/performance/memory_profile.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'benchmark/ips'
+require 'memory_profiler'
+require_relative 'theme_runner'
+
+def profile(phase, &block)
+ puts
+ puts "#{phase}:"
+ puts
+
+ report = MemoryProfiler.report(&block)
+
+ report.pretty_print(
+ color_output: true,
+ scale_bytes: true,
+ detailed_report: true
+ )
+end
+
+Liquid::Template.error_mode = ARGV.first.to_sym if ARGV.first
+
+profiler = ThemeRunner.new
+
+profile("Parsing") { profiler.compile }
+profile("Rendering") { profiler.render }
From 2a1ca3152d1e5726e05ac27c0a6b33a61577cbe1 Mon Sep 17 00:00:00 2001
From: Florian Weingarten
Date: Wed, 17 Apr 2019 14:07:10 +0100
Subject: [PATCH 34/74] liquid without the garbage
---
lib/liquid/block.rb | 4 ++--
lib/liquid/block_body.rb | 24 ++++++++++-------------
lib/liquid/profiler/hooks.rb | 12 ++++++------
lib/liquid/tag.rb | 4 ++--
lib/liquid/tags/assign.rb | 6 +++---
lib/liquid/tags/capture.rb | 8 ++++----
lib/liquid/tags/case.rb | 10 +++++-----
lib/liquid/tags/comment.rb | 4 ++--
lib/liquid/tags/cycle.rb | 17 +++++++++++++---
lib/liquid/tags/decrement.rb | 5 +++--
lib/liquid/tags/for.rb | 22 +++++++++++----------
lib/liquid/tags/if.rb | 7 ++++---
lib/liquid/tags/ifchanged.rb | 14 ++++++-------
lib/liquid/tags/include.rb | 10 ++++++----
lib/liquid/tags/increment.rb | 5 +++--
lib/liquid/tags/raw.rb | 5 +++--
lib/liquid/tags/table_row.rb | 15 ++++++++------
lib/liquid/tags/unless.rb | 10 +++++-----
lib/liquid/template.rb | 10 +++++++++-
lib/liquid/variable.rb | 17 ++++++++++++++--
performance/shopify/comment_form.rb | 6 ++++--
performance/shopify/paginate.rb | 2 +-
test/integration/blank_test.rb | 5 +++--
test/integration/tags/include_tag_test.rb | 5 +++--
test/integration/template_test.rb | 18 ++++++++---------
25 files changed, 144 insertions(+), 101 deletions(-)
diff --git a/lib/liquid/block.rb b/lib/liquid/block.rb
index 00c59b2..843b6b7 100644
--- a/lib/liquid/block.rb
+++ b/lib/liquid/block.rb
@@ -13,8 +13,8 @@ module Liquid
end
end
- def render(context)
- @body.render(context)
+ def render(context, output = '')
+ @body.render(context, output)
end
def blank?
diff --git a/lib/liquid/block_body.rb b/lib/liquid/block_body.rb
index d4fab30..f404d20 100644
--- a/lib/liquid/block_body.rb
+++ b/lib/liquid/block_body.rb
@@ -66,8 +66,7 @@ module Liquid
@blank
end
- def render(context)
- output = []
+ def render(context, output = '')
context.resource_limits.render_score += @nodelist.length
idx = 0
@@ -77,9 +76,9 @@ module Liquid
check_resources(context, node)
output << node
when Variable
- render_node_to_output(node, output, context)
+ render_node(context, output, node)
when Block
- render_node_to_output(node, output, context, node.blank?)
+ render_node(context, node.blank? ? '' : output, node)
break if context.interrupt? # might have happened in a for-block
when Continue, Break
# If we get an Interrupt that means the block must stop processing. An
@@ -88,34 +87,31 @@ module Liquid
context.push_interrupt(node.interrupt)
break
else # Other non-Block tags
- render_node_to_output(node, output, context)
+ render_node(context, output, node)
break if context.interrupt? # might have happened through an include
end
idx += 1
end
- output.join
+ output
end
private
- def render_node_to_output(node, output, context, skip_output = false)
- node_output = node.render(context)
- node_output = node_output.is_a?(Array) ? node_output.join : node_output.to_s
- check_resources(context, node_output)
- output << node_output unless skip_output
+ def render_node(context, output, node)
+ node.render(context, output)
+ check_resources(context, output)
rescue MemoryError => e
raise e
rescue UndefinedVariable, UndefinedDropMethod, UndefinedFilter => e
context.handle_error(e, node.line_number)
- output << nil
rescue ::StandardError => e
line_number = node.is_a?(String) ? nil : node.line_number
output << context.handle_error(e, line_number)
end
- def check_resources(context, node_output)
- context.resource_limits.render_length += node_output.bytesize
+ def check_resources(context, output)
+ context.resource_limits.render_length = output.bytesize
return unless context.resource_limits.reached?
raise MemoryError.new("Memory limits exceeded".freeze)
end
diff --git a/lib/liquid/profiler/hooks.rb b/lib/liquid/profiler/hooks.rb
index cb11cd7..112a7d3 100644
--- a/lib/liquid/profiler/hooks.rb
+++ b/lib/liquid/profiler/hooks.rb
@@ -1,19 +1,19 @@
module Liquid
class BlockBody
- def render_node_with_profiling(node, output, context, skip_output = false)
+ def render_node_with_profiling(context, output, node)
Profiler.profile_node_render(node) do
- render_node_without_profiling(node, output, context, skip_output)
+ render_node_without_profiling(context, output, node)
end
end
- alias_method :render_node_without_profiling, :render_node_to_output
- alias_method :render_node_to_output, :render_node_with_profiling
+ alias_method :render_node_without_profiling, :render_node
+ alias_method :render_node, :render_node_with_profiling
end
class Include < Tag
- def render_with_profiling(context)
+ def render_with_profiling(context, output)
Profiler.profile_children(context.evaluate(@template_name_expr).to_s) do
- render_without_profiling(context)
+ render_without_profiling(context, output)
end
end
diff --git a/lib/liquid/tag.rb b/lib/liquid/tag.rb
index 06970c1..d9d4ff7 100644
--- a/lib/liquid/tag.rb
+++ b/lib/liquid/tag.rb
@@ -32,8 +32,8 @@ module Liquid
self.class.name.downcase
end
- def render(_context)
- ''.freeze
+ def render(_context, output = '')
+ output
end
def blank?
diff --git a/lib/liquid/tags/assign.rb b/lib/liquid/tags/assign.rb
index 3b696dd..62a4747 100644
--- a/lib/liquid/tags/assign.rb
+++ b/lib/liquid/tags/assign.rb
@@ -22,11 +22,11 @@ module Liquid
end
end
- def render(context)
- val = @from.render(context)
+ def render(context, output = '')
+ val = @from.render(context, nil)
context.scopes.last[@to] = val
context.resource_limits.assign_score += assign_score_of(val)
- ''.freeze
+ output
end
def blank?
diff --git a/lib/liquid/tags/capture.rb b/lib/liquid/tags/capture.rb
index d5b8e29..b4d418b 100644
--- a/lib/liquid/tags/capture.rb
+++ b/lib/liquid/tags/capture.rb
@@ -22,11 +22,11 @@ module Liquid
end
end
- def render(context)
- output = super
+ def render(context, output = '')
+ super
context.scopes.last[@to] = output
- context.resource_limits.assign_score += output.bytesize
- ''.freeze
+ context.resource_limits.assign_score = output.bytesize
+ output
end
def blank?
diff --git a/lib/liquid/tags/case.rb b/lib/liquid/tags/case.rb
index 5036b27..385c878 100644
--- a/lib/liquid/tags/case.rb
+++ b/lib/liquid/tags/case.rb
@@ -38,21 +38,21 @@ module Liquid
end
end
- def render(context)
+ def render(context, output = '')
context.stack do
execute_else_block = true
- output = ''
@blocks.each do |block|
if block.else?
- return block.attachment.render(context) if execute_else_block
+ block.attachment.render(context, output) if execute_else_block
elsif block.evaluate(context)
execute_else_block = false
- output << block.attachment.render(context)
+ block.attachment.render(context, output)
end
end
- output
end
+
+ output
end
private
diff --git a/lib/liquid/tags/comment.rb b/lib/liquid/tags/comment.rb
index c57c9cd..cb7739f 100644
--- a/lib/liquid/tags/comment.rb
+++ b/lib/liquid/tags/comment.rb
@@ -1,7 +1,7 @@
module Liquid
class Comment < Block
- def render(_context)
- ''.freeze
+ def render(_context, output = '')
+ output
end
def unknown_tag(_tag, _markup, _tokens)
diff --git a/lib/liquid/tags/cycle.rb b/lib/liquid/tags/cycle.rb
index 17aa860..cbcff79 100644
--- a/lib/liquid/tags/cycle.rb
+++ b/lib/liquid/tags/cycle.rb
@@ -31,18 +31,29 @@ module Liquid
end
end
- def render(context)
+ def render(context, output = '')
context.registers[:cycle] ||= {}
context.stack do
key = context.evaluate(@name)
iteration = context.registers[:cycle][key].to_i
- result = context.evaluate(@variables[iteration])
+
+ val = context.evaluate(@variables[iteration])
+
+ if val.is_a?(Array)
+ val = val.join
+ elsif !val.is_a?(String)
+ val = val.to_s
+ end
+
+ output << val
+
iteration += 1
iteration = 0 if iteration >= @variables.size
context.registers[:cycle][key] = iteration
- result
end
+
+ output
end
private
diff --git a/lib/liquid/tags/decrement.rb b/lib/liquid/tags/decrement.rb
index b5cdaaa..9cf3073 100644
--- a/lib/liquid/tags/decrement.rb
+++ b/lib/liquid/tags/decrement.rb
@@ -23,11 +23,12 @@ module Liquid
@variable = markup.strip
end
- def render(context)
+ def render(context, output = '')
value = context.environments.first[@variable] ||= 0
value -= 1
context.environments.first[@variable] = value
- value.to_s
+ output << value.to_s
+ output
end
end
diff --git a/lib/liquid/tags/for.rb b/lib/liquid/tags/for.rb
index b69aa78..01df484 100644
--- a/lib/liquid/tags/for.rb
+++ b/lib/liquid/tags/for.rb
@@ -70,13 +70,13 @@ module Liquid
@else_block = BlockBody.new
end
- def render(context)
+ def render(context, output = '')
segment = collection_segment(context)
if segment.empty?
- render_else(context)
+ render_else(context, output)
else
- render_segment(context, segment)
+ render_segment(context, output, segment)
end
end
@@ -141,12 +141,10 @@ module Liquid
segment
end
- def render_segment(context, segment)
+ def render_segment(context, output, segment)
for_stack = context.registers[:for_stack] ||= []
length = segment.length
- result = ''
-
context.stack do
loop_vars = Liquid::ForloopDrop.new(@name, length, for_stack[-1])
@@ -157,7 +155,7 @@ module Liquid
segment.each do |item|
context[@variable_name] = item
- result << @for_block.render(context)
+ @for_block.render(context, output)
loop_vars.send(:increment!)
# Handle any interrupts if they exist.
@@ -172,7 +170,7 @@ module Liquid
end
end
- result
+ output
end
def set_attribute(key, expr)
@@ -188,8 +186,12 @@ module Liquid
end
end
- def render_else(context)
- @else_block ? @else_block.render(context) : ''.freeze
+ def render_else(context, output)
+ if @else_block
+ @else_block.render(context, output)
+ else
+ output
+ end
end
class ParseTreeVisitor < Liquid::ParseTreeVisitor
diff --git a/lib/liquid/tags/if.rb b/lib/liquid/tags/if.rb
index 02da42b..a1e4eec 100644
--- a/lib/liquid/tags/if.rb
+++ b/lib/liquid/tags/if.rb
@@ -39,15 +39,16 @@ module Liquid
end
end
- def render(context)
+ def render(context, output)
context.stack do
@blocks.each do |block|
if block.evaluate(context)
- return block.attachment.render(context)
+ return block.attachment.render(context, output)
end
end
- ''.freeze
end
+
+ output
end
private
diff --git a/lib/liquid/tags/ifchanged.rb b/lib/liquid/tags/ifchanged.rb
index d70cbe1..2c026f1 100644
--- a/lib/liquid/tags/ifchanged.rb
+++ b/lib/liquid/tags/ifchanged.rb
@@ -1,16 +1,16 @@
module Liquid
class Ifchanged < Block
- def render(context)
+ def render(context, output)
context.stack do
- output = super
+ block_output = super(context, '')
- if output != context.registers[:ifchanged]
- context.registers[:ifchanged] = output
- output
- else
- ''.freeze
+ if block_output != context.registers[:ifchanged]
+ context.registers[:ifchanged] = block_output
+ output << block_output
end
end
+
+ output
end
end
diff --git a/lib/liquid/tags/include.rb b/lib/liquid/tags/include.rb
index c9f2a28..28a7481 100644
--- a/lib/liquid/tags/include.rb
+++ b/lib/liquid/tags/include.rb
@@ -42,7 +42,7 @@ module Liquid
def parse(_tokens)
end
- def render(context)
+ def render(context, output)
template_name = context.evaluate(@template_name_expr)
raise ArgumentError.new(options[:locale].t("errors.argument.include")) unless template_name
@@ -66,19 +66,21 @@ module Liquid
end
if variable.is_a?(Array)
- variable.collect do |var|
+ variable.each do |var|
context[context_variable_name] = var
- partial.render(context)
+ partial.render(context, output: output)
end
else
context[context_variable_name] = variable
- partial.render(context)
+ partial.render(context, output: output)
end
end
ensure
context.template_name = old_template_name
context.partial = old_partial
end
+
+ output
end
private
diff --git a/lib/liquid/tags/increment.rb b/lib/liquid/tags/increment.rb
index baa0cbb..4182c46 100644
--- a/lib/liquid/tags/increment.rb
+++ b/lib/liquid/tags/increment.rb
@@ -20,10 +20,11 @@ module Liquid
@variable = markup.strip
end
- def render(context)
+ def render(context, output = '')
value = context.environments.first[@variable] ||= 0
context.environments.first[@variable] = value + 1
- value.to_s
+ output << value.to_s
+ output
end
end
diff --git a/lib/liquid/tags/raw.rb b/lib/liquid/tags/raw.rb
index 6b461bd..4f6aa15 100644
--- a/lib/liquid/tags/raw.rb
+++ b/lib/liquid/tags/raw.rb
@@ -22,8 +22,9 @@ module Liquid
raise SyntaxError.new(parse_context.locale.t("errors.syntax.tag_never_closed".freeze, block_name: block_name))
end
- def render(_context)
- @body
+ def render(_context, output = '')
+ output << @body
+ output
end
def nodelist
diff --git a/lib/liquid/tags/table_row.rb b/lib/liquid/tags/table_row.rb
index 7f391cf..09b69e9 100644
--- a/lib/liquid/tags/table_row.rb
+++ b/lib/liquid/tags/table_row.rb
@@ -18,7 +18,7 @@ module Liquid
end
end
- def render(context)
+ def render(context, output = '')
collection = context.evaluate(@collection_name) or return ''.freeze
from = @attributes.key?('offset'.freeze) ? context.evaluate(@attributes['offset'.freeze]).to_i : 0
@@ -30,7 +30,7 @@ module Liquid
cols = context.evaluate(@attributes['cols'.freeze]).to_i
- result = "\n"
+ output << "
\n"
context.stack do
tablerowloop = Liquid::TablerowloopDrop.new(length, cols)
context['tablerowloop'.freeze] = tablerowloop
@@ -38,17 +38,20 @@ module Liquid
collection.each do |item|
context[@variable_name] = item
- result << "| " << super << ' | '
+ output << ""
+ super
+ output << ' | '
if tablerowloop.col_last && !tablerowloop.last
- result << "
\n"
+ output << "
\n"
end
tablerowloop.send(:increment!)
end
end
- result << "
\n"
- result
+
+ output << "\n"
+ output
end
class ParseTreeVisitor < Liquid::ParseTreeVisitor
diff --git a/lib/liquid/tags/unless.rb b/lib/liquid/tags/unless.rb
index 1d4280d..8d4c32e 100644
--- a/lib/liquid/tags/unless.rb
+++ b/lib/liquid/tags/unless.rb
@@ -6,23 +6,23 @@ module Liquid
# {% unless x < 0 %} x is greater than zero {% endunless %}
#
class Unless < If
- def render(context)
+ def render(context, output = '')
context.stack do
# First condition is interpreted backwards ( if not )
first_block = @blocks.first
unless first_block.evaluate(context)
- return first_block.attachment.render(context)
+ return first_block.attachment.render(context, output)
end
# After the first condition unless works just like if
@blocks[1..-1].each do |block|
if block.evaluate(context)
- return block.attachment.render(context)
+ return block.attachment.render(context, output)
end
end
-
- ''.freeze
end
+
+ output
end
end
diff --git a/lib/liquid/template.rb b/lib/liquid/template.rb
index 31a67e4..c22f164 100644
--- a/lib/liquid/template.rb
+++ b/lib/liquid/template.rb
@@ -187,9 +187,12 @@ module Liquid
raise ArgumentError, "Expected Hash or Liquid::Context as parameter"
end
+ output = nil
+
case args.last
when Hash
options = args.pop
+ output = options[:output] if options[:output]
registers.merge!(options[:registers]) if options[:registers].is_a?(Hash)
@@ -205,7 +208,8 @@ module Liquid
# render the nodelist.
# for performance reasons we get an array back here. join will make a string out of it.
result = with_profiling(context) do
- @root.render(context)
+ output ||= self.class.output_buffer.clear
+ @root.render(context, output)
end
result.respond_to?(:join) ? result.join : result
rescue Liquid::MemoryError => e
@@ -215,6 +219,10 @@ module Liquid
end
end
+ def self.output_buffer
+ @output_buffer ||= String.new(capacity: 1024)
+ end
+
def render!(*args)
@rethrow_errors = true
render(*args)
diff --git a/lib/liquid/variable.rb b/lib/liquid/variable.rb
index 717b1a2..5e03706 100644
--- a/lib/liquid/variable.rb
+++ b/lib/liquid/variable.rb
@@ -78,7 +78,7 @@ module Liquid
filterargs
end
- def render(context)
+ def render(context, output = '')
obj = @filters.inject(context.evaluate(@name)) do |output, (filter_name, filter_args, filter_kwargs)|
filter_args = evaluate_filter_expressions(context, filter_args, filter_kwargs)
context.invoke(filter_name, output, *filter_args)
@@ -88,7 +88,20 @@ module Liquid
taint_check(context, obj)
- obj
+ if output
+ if obj.is_a?(Array)
+ output << obj.join
+ elsif obj.nil?
+ elsif !obj.is_a?(String)
+ output << obj.to_s
+ else
+ output << obj
+ end
+
+ output
+ else
+ obj
+ end
end
private
diff --git a/performance/shopify/comment_form.rb b/performance/shopify/comment_form.rb
index d661c31..ce33a2c 100644
--- a/performance/shopify/comment_form.rb
+++ b/performance/shopify/comment_form.rb
@@ -12,7 +12,7 @@ class CommentForm < Liquid::Block
end
end
- def render(context)
+ def render(context, output = '')
article = context[@variable_name]
context.stack do
@@ -23,7 +23,9 @@ class CommentForm < Liquid::Block
'email' => context['comment.email'],
'body' => context['comment.body']
}
- wrap_in_form(article, render_all(@nodelist, context))
+
+ output << wrap_in_form(article, render_all(@nodelist, context, output))
+ output
end
end
diff --git a/performance/shopify/paginate.rb b/performance/shopify/paginate.rb
index 38a9a1a..875e58b 100644
--- a/performance/shopify/paginate.rb
+++ b/performance/shopify/paginate.rb
@@ -21,7 +21,7 @@ class Paginate < Liquid::Block
end
end
- def render(context)
+ def render(context, output = '')
@context = context
context.stack do
diff --git a/test/integration/blank_test.rb b/test/integration/blank_test.rb
index e9b56df..cc09781 100644
--- a/test/integration/blank_test.rb
+++ b/test/integration/blank_test.rb
@@ -1,8 +1,9 @@
require 'test_helper'
class FoobarTag < Liquid::Tag
- def render(*args)
- " "
+ def render(context, output = '')
+ output << ' '
+ output
end
Liquid::Template.register_tag('foobar', FoobarTag)
diff --git a/test/integration/tags/include_tag_test.rb b/test/integration/tags/include_tag_test.rb
index 9c188d5..cf83f59 100644
--- a/test/integration/tags/include_tag_test.rb
+++ b/test/integration/tags/include_tag_test.rb
@@ -66,8 +66,9 @@ class CustomInclude < Liquid::Tag
def parse(tokens)
end
- def render(context)
- @template_name[1..-2]
+ def render(context, output = '')
+ output << @template_name[1..-2]
+ output
end
end
diff --git a/test/integration/template_test.rb b/test/integration/template_test.rb
index 0dc0ae5..c8b7770 100644
--- a/test/integration/template_test.rb
+++ b/test/integration/template_test.rb
@@ -177,31 +177,31 @@ class TemplateTest < Minitest::Test
def test_render_length_persists_between_blocks
t = Template.parse("{% if true %}aaaa{% endif %}")
- t.resource_limits.render_length_limit = 7
+ t.resource_limits.render_length_limit = 3
assert_equal "Liquid error: Memory limits exceeded", t.render
- t.resource_limits.render_length_limit = 8
+ t.resource_limits.render_length_limit = 4
assert_equal "aaaa", t.render
t = Template.parse("{% if true %}aaaa{% endif %}{% if true %}bbb{% endif %}")
- t.resource_limits.render_length_limit = 13
+ t.resource_limits.render_length_limit = 6
assert_equal "Liquid error: Memory limits exceeded", t.render
- t.resource_limits.render_length_limit = 14
+ t.resource_limits.render_length_limit = 7
assert_equal "aaaabbb", t.render
t = Template.parse("{% if true %}a{% endif %}{% if true %}b{% endif %}{% if true %}a{% endif %}{% if true %}b{% endif %}{% if true %}a{% endif %}{% if true %}b{% endif %}")
+ t.resource_limits.render_length_limit = 4
+ assert_equal "Liquid error: Memory limits exceeded", t.render
t.resource_limits.render_length_limit = 5
assert_equal "Liquid error: Memory limits exceeded", t.render
- t.resource_limits.render_length_limit = 11
- assert_equal "Liquid error: Memory limits exceeded", t.render
- t.resource_limits.render_length_limit = 12
+ t.resource_limits.render_length_limit = 6
assert_equal "ababab", t.render
end
def test_render_length_uses_number_of_bytes_not_characters
t = Template.parse("{% if true %}すごい{% endif %}")
- t.resource_limits.render_length_limit = 10
+ t.resource_limits.render_length_limit = 8
assert_equal "Liquid error: Memory limits exceeded", t.render
- t.resource_limits.render_length_limit = 18
+ t.resource_limits.render_length_limit = 9
assert_equal "すごい", t.render
end
From 70ed1fc86d22440bfeff657a10ceb8783f8510ee Mon Sep 17 00:00:00 2001
From: David Cornu
Date: Tue, 23 Apr 2019 15:32:59 -0400
Subject: [PATCH 35/74] Make sure the limit and offset values are integers
---
lib/liquid/tags/for.rb | 15 +++++++++++---
test/integration/tags/for_tag_test.rb | 28 +++++++++++++++++++++++++++
2 files changed, 40 insertions(+), 3 deletions(-)
diff --git a/lib/liquid/tags/for.rb b/lib/liquid/tags/for.rb
index b69aa78..f18fb71 100644
--- a/lib/liquid/tags/for.rb
+++ b/lib/liquid/tags/for.rb
@@ -124,14 +124,23 @@ module Liquid
from = if @from == :continue
offsets[@name].to_i
else
- context.evaluate(@from).to_i
+ from_value = context.evaluate(@from)
+ if from_value.nil?
+ 0
+ else
+ Utils.to_integer(from_value)
+ end
end
collection = context.evaluate(@collection_name)
collection = collection.to_a if collection.is_a?(Range)
- limit = context.evaluate(@limit)
- to = limit ? limit.to_i + from : nil
+ limit_value = context.evaluate(@limit)
+ to = if limit_value.nil?
+ nil
+ else
+ Utils.to_integer(limit_value) + from
+ end
segment = Utils.slice_collection(collection, from, to)
segment.reverse! if @reversed
diff --git a/test/integration/tags/for_tag_test.rb b/test/integration/tags/for_tag_test.rb
index cb7a822..9980e25 100644
--- a/test/integration/tags/for_tag_test.rb
+++ b/test/integration/tags/for_tag_test.rb
@@ -103,6 +103,34 @@ HERE
assert_template_result('3456', '{%for i in array limit: 4 offset: 2 %}{{ i }}{%endfor%}', assigns)
end
+ def test_limiting_with_invalid_limit
+ assigns = { 'array' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] }
+ template = <<-MKUP
+ {% for i in array limit: true offset: 1 %}
+ {{ i }}
+ {% endfor %}
+ MKUP
+
+ exception = assert_raises(Liquid::ArgumentError) do
+ Template.parse(template).render!(assigns)
+ end
+ assert_equal("Liquid error: invalid integer", exception.message)
+ end
+
+ def test_limiting_with_invalid_offset
+ assigns = { 'array' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] }
+ template = <<-MKUP
+ {% for i in array limit: 1 offset: true %}
+ {{ i }}
+ {% endfor %}
+ MKUP
+
+ exception = assert_raises(Liquid::ArgumentError) do
+ Template.parse(template).render!(assigns)
+ end
+ assert_equal("Liquid error: invalid integer", exception.message)
+ end
+
def test_dynamic_variable_limiting
assigns = { 'array' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] }
assigns['limit'] = 2
From 453f6348c27652bf47b965bbeaad8958e5fa5e38 Mon Sep 17 00:00:00 2001
From: David Cornu
Date: Tue, 23 Apr 2019 16:55:37 -0400
Subject: [PATCH 36/74] Stop installing the rainbow gem on Travis
---
.travis.yml | 1 -
1 file changed, 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 0e3e476..3a01754 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -23,7 +23,6 @@ matrix:
- rvm: jruby-head
install:
- - gem install rainbow -v 2.2.1
- bundle install
script: bundle exec rake
From 9640e7780537772585fe470912830dbba02f37b1 Mon Sep 17 00:00:00 2001
From: Florian Weingarten
Date: Mon, 22 Apr 2019 17:23:44 -0400
Subject: [PATCH 37/74] render_to_output_buffer
---
.gitignore | 1 +
.rubocop_todo.yml | 12 +++---
lib/liquid/block.rb | 5 ++-
lib/liquid/block_body.rb | 20 ++++++----
lib/liquid/profiler/hooks.rb | 8 ++--
lib/liquid/tag.rb | 10 ++++-
lib/liquid/tags/assign.rb | 4 +-
lib/liquid/tags/capture.rb | 5 ++-
lib/liquid/tags/case.rb | 6 +--
lib/liquid/tags/comment.rb | 2 +-
lib/liquid/tags/cycle.rb | 2 +-
lib/liquid/tags/decrement.rb | 2 +-
lib/liquid/tags/for.rb | 8 ++--
lib/liquid/tags/if.rb | 4 +-
lib/liquid/tags/ifchanged.rb | 5 ++-
lib/liquid/tags/include.rb | 6 +--
lib/liquid/tags/increment.rb | 2 +-
lib/liquid/tags/raw.rb | 2 +-
lib/liquid/tags/table_row.rb | 2 +-
lib/liquid/tags/unless.rb | 6 +--
lib/liquid/template.rb | 14 +++----
lib/liquid/variable.rb | 24 ++++++------
performance/shopify/comment_form.rb | 2 +-
performance/shopify/paginate.rb | 2 +-
test/integration/blank_test.rb | 8 ++--
test/integration/tags/include_tag_test.rb | 2 +-
test/integration/template_test.rb | 18 ++++-----
test/test_helper.rb | 7 ++++
test/unit/block_unit_test.rb | 45 +++++++++++++++++++++--
test/unit/tag_unit_test.rb | 38 +++++++++++++++++++
30 files changed, 184 insertions(+), 88 deletions(-)
diff --git a/.gitignore b/.gitignore
index 7ac01c1..90bf6dc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@ pkg
.ruby-version
Gemfile.lock
.bundle
+.byebug_history
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 6868a7a..4af3202 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
-# on 2019-03-19 11:04:37 -0400 using RuboCop version 0.53.0.
+# on 2019-04-22 19:11:24 -0400 using RuboCop version 0.53.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
@@ -46,18 +46,18 @@ Lint/Void:
Exclude:
- 'lib/liquid/parse_context.rb'
-# Offense count: 54
+# Offense count: 53
Metrics/AbcSize:
Max: 56
# Offense count: 12
Metrics/CyclomaticComplexity:
- Max: 12
+ Max: 13
# Offense count: 112
# Configuration parameters: CountComments.
Metrics/MethodLength:
- Max: 37
+ Max: 38
# Offense count: 8
Metrics/PerceivedComplexity:
@@ -90,7 +90,7 @@ Naming/UncommunicativeMethodParamName:
- 'test/integration/template_test.rb'
- 'test/unit/condition_unit_test.rb'
-# Offense count: 10
+# Offense count: 12
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: prefer_alias, prefer_alias_method
@@ -253,7 +253,7 @@ Style/WhileUntilModifier:
Exclude:
- 'lib/liquid/tags/case.rb'
-# Offense count: 640
+# Offense count: 648
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
# URISchemes: http, https
Metrics/LineLength:
diff --git a/lib/liquid/block.rb b/lib/liquid/block.rb
index 843b6b7..549a3a3 100644
--- a/lib/liquid/block.rb
+++ b/lib/liquid/block.rb
@@ -13,8 +13,9 @@ module Liquid
end
end
- def render(context, output = '')
- @body.render(context, output)
+ # For backwards compatibility
+ def render(context)
+ @body.render(context)
end
def blank?
diff --git a/lib/liquid/block_body.rb b/lib/liquid/block_body.rb
index f404d20..c2478ce 100644
--- a/lib/liquid/block_body.rb
+++ b/lib/liquid/block_body.rb
@@ -66,14 +66,19 @@ module Liquid
@blank
end
- def render(context, output = '')
+ def render(context)
+ render_to_output_buffer(context, '')
+ end
+
+ def render_to_output_buffer(context, output)
context.resource_limits.render_score += @nodelist.length
idx = 0
while node = @nodelist[idx]
+ previous_output_size = output.bytesize
+
case node
when String
- check_resources(context, node)
output << node
when Variable
render_node(context, output, node)
@@ -91,6 +96,8 @@ module Liquid
break if context.interrupt? # might have happened through an include
end
idx += 1
+
+ raise_if_resource_limits_reached(context, output.bytesize - previous_output_size)
end
output
@@ -99,10 +106,7 @@ module Liquid
private
def render_node(context, output, node)
- node.render(context, output)
- check_resources(context, output)
- rescue MemoryError => e
- raise e
+ node.render_to_output_buffer(context, output)
rescue UndefinedVariable, UndefinedDropMethod, UndefinedFilter => e
context.handle_error(e, node.line_number)
rescue ::StandardError => e
@@ -110,8 +114,8 @@ module Liquid
output << context.handle_error(e, line_number)
end
- def check_resources(context, output)
- context.resource_limits.render_length = output.bytesize
+ def raise_if_resource_limits_reached(context, length)
+ context.resource_limits.render_length += length
return unless context.resource_limits.reached?
raise MemoryError.new("Memory limits exceeded".freeze)
end
diff --git a/lib/liquid/profiler/hooks.rb b/lib/liquid/profiler/hooks.rb
index 112a7d3..cda166b 100644
--- a/lib/liquid/profiler/hooks.rb
+++ b/lib/liquid/profiler/hooks.rb
@@ -11,13 +11,13 @@ module Liquid
end
class Include < Tag
- def render_with_profiling(context, output)
+ def render_to_output_buffer_with_profiling(context, output)
Profiler.profile_children(context.evaluate(@template_name_expr).to_s) do
- render_without_profiling(context, output)
+ render_to_output_buffer_without_profiling(context, output)
end
end
- alias_method :render_without_profiling, :render
- alias_method :render, :render_with_profiling
+ alias_method :render_to_output_buffer_without_profiling, :render_to_output_buffer
+ alias_method :render_to_output_buffer, :render_to_output_buffer_with_profiling
end
end
diff --git a/lib/liquid/tag.rb b/lib/liquid/tag.rb
index d9d4ff7..5099ccb 100644
--- a/lib/liquid/tag.rb
+++ b/lib/liquid/tag.rb
@@ -32,7 +32,15 @@ module Liquid
self.class.name.downcase
end
- def render(_context, output = '')
+ def render(_context)
+ ''.freeze
+ end
+
+ # For backwards compatibility with custom tags. In a future release, the semantics
+ # of the `render_to_output_buffer` method will become the default and the `render`
+ # method will be removed.
+ def render_to_output_buffer(context, output)
+ output << render(context)
output
end
diff --git a/lib/liquid/tags/assign.rb b/lib/liquid/tags/assign.rb
index 62a4747..767d874 100644
--- a/lib/liquid/tags/assign.rb
+++ b/lib/liquid/tags/assign.rb
@@ -22,8 +22,8 @@ module Liquid
end
end
- def render(context, output = '')
- val = @from.render(context, nil)
+ def render_to_output_buffer(context, output)
+ val = @from.render(context)
context.scopes.last[@to] = val
context.resource_limits.assign_score += assign_score_of(val)
output
diff --git a/lib/liquid/tags/capture.rb b/lib/liquid/tags/capture.rb
index b4d418b..d717b76 100644
--- a/lib/liquid/tags/capture.rb
+++ b/lib/liquid/tags/capture.rb
@@ -22,10 +22,11 @@ module Liquid
end
end
- def render(context, output = '')
+ def render_to_output_buffer(context, output)
+ previous_output_size = output.bytesize
super
context.scopes.last[@to] = output
- context.resource_limits.assign_score = output.bytesize
+ context.resource_limits.assign_score += (output.bytesize - previous_output_size)
output
end
diff --git a/lib/liquid/tags/case.rb b/lib/liquid/tags/case.rb
index 385c878..92b2ed0 100644
--- a/lib/liquid/tags/case.rb
+++ b/lib/liquid/tags/case.rb
@@ -38,16 +38,16 @@ module Liquid
end
end
- def render(context, output = '')
+ def render_to_output_buffer(context, output)
context.stack do
execute_else_block = true
@blocks.each do |block|
if block.else?
- block.attachment.render(context, output) if execute_else_block
+ block.attachment.render_to_output_buffer(context, output) if execute_else_block
elsif block.evaluate(context)
execute_else_block = false
- block.attachment.render(context, output)
+ block.attachment.render_to_output_buffer(context, output)
end
end
end
diff --git a/lib/liquid/tags/comment.rb b/lib/liquid/tags/comment.rb
index cb7739f..cad3931 100644
--- a/lib/liquid/tags/comment.rb
+++ b/lib/liquid/tags/comment.rb
@@ -1,6 +1,6 @@
module Liquid
class Comment < Block
- def render(_context, output = '')
+ def render_to_output_buffer(_context, output)
output
end
diff --git a/lib/liquid/tags/cycle.rb b/lib/liquid/tags/cycle.rb
index cbcff79..e42244d 100644
--- a/lib/liquid/tags/cycle.rb
+++ b/lib/liquid/tags/cycle.rb
@@ -31,7 +31,7 @@ module Liquid
end
end
- def render(context, output = '')
+ def render_to_output_buffer(context, output)
context.registers[:cycle] ||= {}
context.stack do
diff --git a/lib/liquid/tags/decrement.rb b/lib/liquid/tags/decrement.rb
index 9cf3073..08ddd4d 100644
--- a/lib/liquid/tags/decrement.rb
+++ b/lib/liquid/tags/decrement.rb
@@ -23,7 +23,7 @@ module Liquid
@variable = markup.strip
end
- def render(context, output = '')
+ def render_to_output_buffer(context, output)
value = context.environments.first[@variable] ||= 0
value -= 1
context.environments.first[@variable] = value
diff --git a/lib/liquid/tags/for.rb b/lib/liquid/tags/for.rb
index 01df484..8dceab0 100644
--- a/lib/liquid/tags/for.rb
+++ b/lib/liquid/tags/for.rb
@@ -70,7 +70,7 @@ module Liquid
@else_block = BlockBody.new
end
- def render(context, output = '')
+ def render_to_output_buffer(context, output)
segment = collection_segment(context)
if segment.empty?
@@ -78,6 +78,8 @@ module Liquid
else
render_segment(context, output, segment)
end
+
+ output
end
protected
@@ -155,7 +157,7 @@ module Liquid
segment.each do |item|
context[@variable_name] = item
- @for_block.render(context, output)
+ @for_block.render_to_output_buffer(context, output)
loop_vars.send(:increment!)
# Handle any interrupts if they exist.
@@ -188,7 +190,7 @@ module Liquid
def render_else(context, output)
if @else_block
- @else_block.render(context, output)
+ @else_block.render_to_output_buffer(context, output)
else
output
end
diff --git a/lib/liquid/tags/if.rb b/lib/liquid/tags/if.rb
index a1e4eec..25534a9 100644
--- a/lib/liquid/tags/if.rb
+++ b/lib/liquid/tags/if.rb
@@ -39,11 +39,11 @@ module Liquid
end
end
- def render(context, output)
+ def render_to_output_buffer(context, output)
context.stack do
@blocks.each do |block|
if block.evaluate(context)
- return block.attachment.render(context, output)
+ return block.attachment.render_to_output_buffer(context, output)
end
end
end
diff --git a/lib/liquid/tags/ifchanged.rb b/lib/liquid/tags/ifchanged.rb
index 2c026f1..e3040ce 100644
--- a/lib/liquid/tags/ifchanged.rb
+++ b/lib/liquid/tags/ifchanged.rb
@@ -1,8 +1,9 @@
module Liquid
class Ifchanged < Block
- def render(context, output)
+ def render_to_output_buffer(context, output)
context.stack do
- block_output = super(context, '')
+ block_output = ''
+ super(context, block_output)
if block_output != context.registers[:ifchanged]
context.registers[:ifchanged] = block_output
diff --git a/lib/liquid/tags/include.rb b/lib/liquid/tags/include.rb
index 28a7481..24acf9d 100644
--- a/lib/liquid/tags/include.rb
+++ b/lib/liquid/tags/include.rb
@@ -42,7 +42,7 @@ module Liquid
def parse(_tokens)
end
- def render(context, output)
+ def render_to_output_buffer(context, output)
template_name = context.evaluate(@template_name_expr)
raise ArgumentError.new(options[:locale].t("errors.argument.include")) unless template_name
@@ -68,11 +68,11 @@ module Liquid
if variable.is_a?(Array)
variable.each do |var|
context[context_variable_name] = var
- partial.render(context, output: output)
+ partial.render_to_output_buffer(context, output)
end
else
context[context_variable_name] = variable
- partial.render(context, output: output)
+ partial.render_to_output_buffer(context, output)
end
end
ensure
diff --git a/lib/liquid/tags/increment.rb b/lib/liquid/tags/increment.rb
index 4182c46..5af1242 100644
--- a/lib/liquid/tags/increment.rb
+++ b/lib/liquid/tags/increment.rb
@@ -20,7 +20,7 @@ module Liquid
@variable = markup.strip
end
- def render(context, output = '')
+ def render_to_output_buffer(context, output)
value = context.environments.first[@variable] ||= 0
context.environments.first[@variable] = value + 1
output << value.to_s
diff --git a/lib/liquid/tags/raw.rb b/lib/liquid/tags/raw.rb
index 4f6aa15..4fa75d9 100644
--- a/lib/liquid/tags/raw.rb
+++ b/lib/liquid/tags/raw.rb
@@ -22,7 +22,7 @@ module Liquid
raise SyntaxError.new(parse_context.locale.t("errors.syntax.tag_never_closed".freeze, block_name: block_name))
end
- def render(_context, output = '')
+ def render_to_output_buffer(_context, output)
output << @body
output
end
diff --git a/lib/liquid/tags/table_row.rb b/lib/liquid/tags/table_row.rb
index 09b69e9..9532102 100644
--- a/lib/liquid/tags/table_row.rb
+++ b/lib/liquid/tags/table_row.rb
@@ -18,7 +18,7 @@ module Liquid
end
end
- def render(context, output = '')
+ def render_to_output_buffer(context, output)
collection = context.evaluate(@collection_name) or return ''.freeze
from = @attributes.key?('offset'.freeze) ? context.evaluate(@attributes['offset'.freeze]).to_i : 0
diff --git a/lib/liquid/tags/unless.rb b/lib/liquid/tags/unless.rb
index 8d4c32e..18856c3 100644
--- a/lib/liquid/tags/unless.rb
+++ b/lib/liquid/tags/unless.rb
@@ -6,18 +6,18 @@ module Liquid
# {% unless x < 0 %} x is greater than zero {% endunless %}
#
class Unless < If
- def render(context, output = '')
+ def render_to_output_buffer(context, output)
context.stack do
# First condition is interpreted backwards ( if not )
first_block = @blocks.first
unless first_block.evaluate(context)
- return first_block.attachment.render(context, output)
+ return first_block.attachment.render_to_output_buffer(context, output)
end
# After the first condition unless works just like if
@blocks[1..-1].each do |block|
if block.evaluate(context)
- return block.attachment.render(context, output)
+ return block.attachment.render_to_output_buffer(context, output)
end
end
end
diff --git a/lib/liquid/template.rb b/lib/liquid/template.rb
index c22f164..35db674 100644
--- a/lib/liquid/template.rb
+++ b/lib/liquid/template.rb
@@ -207,11 +207,9 @@ module Liquid
begin
# render the nodelist.
# for performance reasons we get an array back here. join will make a string out of it.
- result = with_profiling(context) do
- output ||= self.class.output_buffer.clear
- @root.render(context, output)
+ with_profiling(context) do
+ @root.render_to_output_buffer(context, output || '')
end
- result.respond_to?(:join) ? result.join : result
rescue Liquid::MemoryError => e
context.handle_error(e)
ensure
@@ -219,15 +217,15 @@ module Liquid
end
end
- def self.output_buffer
- @output_buffer ||= String.new(capacity: 1024)
- end
-
def render!(*args)
@rethrow_errors = true
render(*args)
end
+ def render_to_output_buffer(context, output)
+ render(context, output: output)
+ end
+
private
def tokenize(source)
diff --git a/lib/liquid/variable.rb b/lib/liquid/variable.rb
index 5e03706..cbf9986 100644
--- a/lib/liquid/variable.rb
+++ b/lib/liquid/variable.rb
@@ -78,30 +78,28 @@ module Liquid
filterargs
end
- def render(context, output = '')
+ def render(context)
obj = @filters.inject(context.evaluate(@name)) do |output, (filter_name, filter_args, filter_kwargs)|
filter_args = evaluate_filter_expressions(context, filter_args, filter_kwargs)
context.invoke(filter_name, output, *filter_args)
end
obj = context.apply_global_filter(obj)
-
taint_check(context, obj)
+ obj
+ end
- if output
- if obj.is_a?(Array)
- output << obj.join
- elsif obj.nil?
- elsif !obj.is_a?(String)
- output << obj.to_s
- else
- output << obj
- end
+ def render_to_output_buffer(context, output)
+ obj = render(context)
- output
+ if obj.is_a?(Array)
+ output << obj.join
+ elsif obj.nil?
else
- obj
+ output << obj.to_s
end
+
+ output
end
private
diff --git a/performance/shopify/comment_form.rb b/performance/shopify/comment_form.rb
index ce33a2c..7b5bd53 100644
--- a/performance/shopify/comment_form.rb
+++ b/performance/shopify/comment_form.rb
@@ -12,7 +12,7 @@ class CommentForm < Liquid::Block
end
end
- def render(context, output = '')
+ def render_to_output_buffer(context, output)
article = context[@variable_name]
context.stack do
diff --git a/performance/shopify/paginate.rb b/performance/shopify/paginate.rb
index 875e58b..0abd11f 100644
--- a/performance/shopify/paginate.rb
+++ b/performance/shopify/paginate.rb
@@ -21,7 +21,7 @@ class Paginate < Liquid::Block
end
end
- def render(context, output = '')
+ def render_to_output_buffer(context, output)
@context = context
context.stack do
diff --git a/test/integration/blank_test.rb b/test/integration/blank_test.rb
index cc09781..2b46ad7 100644
--- a/test/integration/blank_test.rb
+++ b/test/integration/blank_test.rb
@@ -1,12 +1,10 @@
require 'test_helper'
class FoobarTag < Liquid::Tag
- def render(context, output = '')
+ def render_to_output_buffer(context, output)
output << ' '
output
end
-
- Liquid::Template.register_tag('foobar', FoobarTag)
end
class BlankTestFileSystem
@@ -32,7 +30,9 @@ class BlankTest < Minitest::Test
end
def test_new_tags_are_not_blank_by_default
- assert_template_result(" " * N, wrap_in_for("{% foobar %}"))
+ with_custom_tag('foobar', FoobarTag) do
+ assert_template_result(" " * N, wrap_in_for("{% foobar %}"))
+ end
end
def test_loops_are_blank
diff --git a/test/integration/tags/include_tag_test.rb b/test/integration/tags/include_tag_test.rb
index cf83f59..14bb8c3 100644
--- a/test/integration/tags/include_tag_test.rb
+++ b/test/integration/tags/include_tag_test.rb
@@ -66,7 +66,7 @@ class CustomInclude < Liquid::Tag
def parse(tokens)
end
- def render(context, output = '')
+ def render_to_output_buffer(context, output)
output << @template_name[1..-2]
output
end
diff --git a/test/integration/template_test.rb b/test/integration/template_test.rb
index c8b7770..0dc0ae5 100644
--- a/test/integration/template_test.rb
+++ b/test/integration/template_test.rb
@@ -177,31 +177,31 @@ class TemplateTest < Minitest::Test
def test_render_length_persists_between_blocks
t = Template.parse("{% if true %}aaaa{% endif %}")
- t.resource_limits.render_length_limit = 3
+ t.resource_limits.render_length_limit = 7
assert_equal "Liquid error: Memory limits exceeded", t.render
- t.resource_limits.render_length_limit = 4
+ t.resource_limits.render_length_limit = 8
assert_equal "aaaa", t.render
t = Template.parse("{% if true %}aaaa{% endif %}{% if true %}bbb{% endif %}")
- t.resource_limits.render_length_limit = 6
+ t.resource_limits.render_length_limit = 13
assert_equal "Liquid error: Memory limits exceeded", t.render
- t.resource_limits.render_length_limit = 7
+ t.resource_limits.render_length_limit = 14
assert_equal "aaaabbb", t.render
t = Template.parse("{% if true %}a{% endif %}{% if true %}b{% endif %}{% if true %}a{% endif %}{% if true %}b{% endif %}{% if true %}a{% endif %}{% if true %}b{% endif %}")
- t.resource_limits.render_length_limit = 4
- assert_equal "Liquid error: Memory limits exceeded", t.render
t.resource_limits.render_length_limit = 5
assert_equal "Liquid error: Memory limits exceeded", t.render
- t.resource_limits.render_length_limit = 6
+ t.resource_limits.render_length_limit = 11
+ assert_equal "Liquid error: Memory limits exceeded", t.render
+ t.resource_limits.render_length_limit = 12
assert_equal "ababab", t.render
end
def test_render_length_uses_number_of_bytes_not_characters
t = Template.parse("{% if true %}すごい{% endif %}")
- t.resource_limits.render_length_limit = 8
+ t.resource_limits.render_length_limit = 10
assert_equal "Liquid error: Memory limits exceeded", t.render
- t.resource_limits.render_length_limit = 9
+ t.resource_limits.render_length_limit = 18
assert_equal "すごい", t.render
end
diff --git a/test/test_helper.rb b/test/test_helper.rb
index ac5ab53..34e7553 100755
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -84,6 +84,13 @@ module Minitest
ensure
Liquid::Template.error_mode = old_mode
end
+
+ def with_custom_tag(tag_name, tag_class)
+ Liquid::Template.register_tag(tag_name, tag_class)
+ yield
+ ensure
+ Liquid::Template.tags.delete(tag_name)
+ end
end
end
diff --git a/test/unit/block_unit_test.rb b/test/unit/block_unit_test.rb
index 6a27a7d..9f7b94f 100644
--- a/test/unit/block_unit_test.rb
+++ b/test/unit/block_unit_test.rb
@@ -44,10 +44,47 @@ class BlockUnitTest < Minitest::Test
end
def test_with_custom_tag
- Liquid::Template.register_tag("testtag", Block)
- assert Liquid::Template.parse("{% testtag %} {% endtesttag %}")
- ensure
- Liquid::Template.tags.delete('testtag')
+ with_custom_tag('testtag', Block) do
+ assert Liquid::Template.parse("{% testtag %} {% endtesttag %}")
+ end
+ end
+
+ def test_custom_block_tags_have_a_default_render_to_output_buffer_method_for_backwards_compatibility
+ klass1 = Class.new(Block) do
+ def render(*)
+ 'hello'
+ end
+ end
+
+ with_custom_tag('blabla', klass1) do
+ template = Liquid::Template.parse("{% blabla %} bla {% endblabla %}")
+
+ assert_equal 'hello', template.render
+
+ buf = ''
+ output = template.render({}, output: buf)
+ assert_equal 'hello', output
+ assert_equal 'hello', buf
+ assert_equal buf.object_id, output.object_id
+ end
+
+ klass2 = Class.new(klass1) do
+ def render(*)
+ 'foo' + super + 'bar'
+ end
+ end
+
+ with_custom_tag('blabla', klass2) do
+ template = Liquid::Template.parse("{% blabla %} foo {% endblabla %}")
+
+ assert_equal 'foohellobar', template.render
+
+ buf = ''
+ output = template.render({}, output: buf)
+ assert_equal 'foohellobar', output
+ assert_equal 'foohellobar', buf
+ assert_equal buf.object_id, output.object_id
+ end
end
private
diff --git a/test/unit/tag_unit_test.rb b/test/unit/tag_unit_test.rb
index c4b901b..a3fb40e 100644
--- a/test/unit/tag_unit_test.rb
+++ b/test/unit/tag_unit_test.rb
@@ -18,4 +18,42 @@ class TagUnitTest < Minitest::Test
tag = Tag.parse("some_tag", "", Tokenizer.new(""), ParseContext.new)
assert_equal 'some_tag', tag.tag_name
end
+
+ def test_custom_tags_have_a_default_render_to_output_buffer_method_for_backwards_compatibility
+ klass1 = Class.new(Tag) do
+ def render(*)
+ 'hello'
+ end
+ end
+
+ with_custom_tag('blabla', klass1) do
+ template = Liquid::Template.parse("{% blabla %}")
+
+ assert_equal 'hello', template.render
+
+ buf = ''
+ output = template.render({}, output: buf)
+ assert_equal 'hello', output
+ assert_equal 'hello', buf
+ assert_equal buf.object_id, output.object_id
+ end
+
+ klass2 = Class.new(klass1) do
+ def render(*)
+ 'foo' + super + 'bar'
+ end
+ end
+
+ with_custom_tag('blabla', klass2) do
+ template = Liquid::Template.parse("{% blabla %}")
+
+ assert_equal 'foohellobar', template.render
+
+ buf = ''
+ output = template.render({}, output: buf)
+ assert_equal 'foohellobar', output
+ assert_equal 'foohellobar', buf
+ assert_equal buf.object_id, output.object_id
+ end
+ end
end
From 1c577c5b62423662b9edf7cf93596942d1819592 Mon Sep 17 00:00:00 2001
From: Ashwin Maroli
Date: Wed, 24 Apr 2019 11:31:20 +0530
Subject: [PATCH 38/74] Don't attempt to install stackprof gem on JRuby
---
Gemfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Gemfile b/Gemfile
index c7cde24..37ffe1d 100644
--- a/Gemfile
+++ b/Gemfile
@@ -9,7 +9,7 @@ group :benchmark, :test do
gem 'benchmark-ips'
gem 'memory_profiler'
- install_if -> { RUBY_PLATFORM !~ /mingw|mswin/ } do
+ install_if -> { RUBY_PLATFORM !~ /mingw|mswin|java/ } do
gem 'stackprof'
end
end
From 4684478e94f92726bbd90b099b3c2f5321d1a7d4 Mon Sep 17 00:00:00 2001
From: Ashwin Maroli
Date: Mon, 29 Apr 2019 23:45:45 +0530
Subject: [PATCH 39/74] Use a private constant to stash token-types
---
lib/liquid/parser.rb | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/lib/liquid/parser.rb b/lib/liquid/parser.rb
index 6954343..152e04c 100644
--- a/lib/liquid/parser.rb
+++ b/lib/liquid/parser.rb
@@ -44,11 +44,14 @@ module Liquid
tok[0] == type
end
+ CONSUME_TOKENS = [:string, :number]
+ private_constant :CONSUME_TOKENS
+
def expression
token = @tokens[@p]
if token[0] == :id
variable_signature
- elsif [:string, :number].include? token[0]
+ elsif CONSUME_TOKENS.include? token[0]
consume
elsif token.first == :open_round
consume
From 9ef6f9b642dfc0769bdb058bacf0e57f882839e6 Mon Sep 17 00:00:00 2001
From: Ashwin Maroli
Date: Mon, 29 Apr 2019 23:50:49 +0530
Subject: [PATCH 40/74] Freeze mutable object assigned to constant
---
lib/liquid/parser.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/liquid/parser.rb b/lib/liquid/parser.rb
index 152e04c..2bc4f95 100644
--- a/lib/liquid/parser.rb
+++ b/lib/liquid/parser.rb
@@ -44,7 +44,7 @@ module Liquid
tok[0] == type
end
- CONSUME_TOKENS = [:string, :number]
+ CONSUME_TOKENS = [:string, :number].freeze
private_constant :CONSUME_TOKENS
def expression
From ab698191b9681228f8a50946fbd79e8779af09f2 Mon Sep 17 00:00:00 2001
From: Ashwin Maroli
Date: Thu, 16 May 2019 19:14:27 +0530
Subject: [PATCH 41/74] Add a CI job to profile memory usage of commit
---
.travis.yml | 7 ++--
Gemfile | 1 +
performance/memory_profile.rb | 64 +++++++++++++++++++++++++++--------
3 files changed, 56 insertions(+), 16 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 3a01754..24e755b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,18 +6,21 @@ rvm:
- 2.3
- 2.4
- 2.5
+ - &latest_ruby 2.6
- ruby-head
- jruby-head
# - rbx-2
-sudo: false
-
addons:
apt:
packages:
- libgmp3-dev
matrix:
+ include:
+ - rvm: *latest_ruby
+ script: bundle exec rake memory_profile:run
+ name: Profiling Memory Usage
allow_failures:
- rvm: ruby-head
- rvm: jruby-head
diff --git a/Gemfile b/Gemfile
index 37ffe1d..ddff94a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -8,6 +8,7 @@ gemspec
group :benchmark, :test do
gem 'benchmark-ips'
gem 'memory_profiler'
+ gem 'terminal-table'
install_if -> { RUBY_PLATFORM !~ /mingw|mswin|java/ } do
gem 'stackprof'
diff --git a/performance/memory_profile.rb b/performance/memory_profile.rb
index bfacde8..9a15375 100644
--- a/performance/memory_profile.rb
+++ b/performance/memory_profile.rb
@@ -2,25 +2,61 @@
require 'benchmark/ips'
require 'memory_profiler'
+require 'terminal-table'
require_relative 'theme_runner'
-def profile(phase, &block)
- puts
- puts "#{phase}:"
- puts
+class Profiler
+ LOG_LABEL = "Profiling: ".rjust(14).freeze
+ REPORTS_DIR = File.expand_path('.memprof', __dir__).freeze
- report = MemoryProfiler.report(&block)
+ def self.run
+ puts
+ yield new
+ end
- report.pretty_print(
- color_output: true,
- scale_bytes: true,
- detailed_report: true
- )
+ def initialize
+ @allocated = []
+ @retained = []
+ @headings = []
+ end
+
+ def profile(phase, &block)
+ print LOG_LABEL
+ print "#{phase}.. ".ljust(10)
+ report = MemoryProfiler.report(&block)
+ puts 'Done.'
+ @headings << phase.capitalize
+ @allocated << "#{report.scale_bytes(report.total_allocated_memsize)} (#{report.total_allocated} objects)"
+ @retained << "#{report.scale_bytes(report.total_retained_memsize)} (#{report.total_retained} objects)"
+
+ return if ENV['CI']
+ require 'fileutils'
+ report_file = File.join(REPORTS_DIR, "#{sanitize(phase)}.txt")
+ FileUtils.mkdir_p(REPORTS_DIR)
+ report.pretty_print(to_file: report_file, scale_bytes: true)
+ end
+
+ def tabulate
+ table = Terminal::Table.new(headings: @headings.unshift('Phase')) do |t|
+ t << @allocated.unshift('Total allocated')
+ t << @retained.unshift('Total retained')
+ end
+
+ puts
+ puts table
+ puts "\nDetailed report(s) saved to #{REPORTS_DIR}/" unless ENV['CI']
+ end
+
+ def sanitize(string)
+ string.downcase.gsub(/[\W]/, '-').squeeze('-')
+ end
end
Liquid::Template.error_mode = ARGV.first.to_sym if ARGV.first
-profiler = ThemeRunner.new
-
-profile("Parsing") { profiler.compile }
-profile("Rendering") { profiler.render }
+runner = ThemeRunner.new
+Profiler.run do |x|
+ x.profile('parse') { runner.compile }
+ x.profile('render') { runner.render }
+ x.tabulate
+end
From 2c424476597b03d65e87cef272d7505e5184aad4 Mon Sep 17 00:00:00 2001
From: Ashwin Maroli
Date: Fri, 17 May 2019 23:30:24 +0530
Subject: [PATCH 42/74] Rename constant to SINGLE_TOKEN_EXPRESSION_TYPES
---
lib/liquid/parser.rb | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/lib/liquid/parser.rb b/lib/liquid/parser.rb
index 2bc4f95..16df6e9 100644
--- a/lib/liquid/parser.rb
+++ b/lib/liquid/parser.rb
@@ -44,14 +44,14 @@ module Liquid
tok[0] == type
end
- CONSUME_TOKENS = [:string, :number].freeze
- private_constant :CONSUME_TOKENS
+ SINGLE_TOKEN_EXPRESSION_TYPES = [:string, :number].freeze
+ private_constant :SINGLE_TOKEN_EXPRESSION_TYPES
def expression
token = @tokens[@p]
if token[0] == :id
variable_signature
- elsif CONSUME_TOKENS.include? token[0]
+ elsif SINGLE_TOKEN_EXPRESSION_TYPES.include? token[0]
consume
elsif token.first == :open_round
consume
From d19967a79dc1263230d0d9a7ea94c277542d34c2 Mon Sep 17 00:00:00 2001
From: Ashwin Maroli
Date: Mon, 22 Jul 2019 17:35:45 +0530
Subject: [PATCH 43/74] Reduce string allocations from truncate filters
---
lib/liquid/standardfilters.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb
index 0bddfa9..afcf479 100644
--- a/lib/liquid/standardfilters.rb
+++ b/lib/liquid/standardfilters.rb
@@ -79,7 +79,7 @@ module Liquid
truncate_string_str = truncate_string.to_s
l = length - truncate_string_str.length
l = 0 if l < 0
- input_str.length > length ? input_str[0...l] + truncate_string_str : input_str
+ input_str.length > length ? input_str[0...l].concat(truncate_string_str) : input_str
end
def truncatewords(input, words = 15, truncate_string = "...".freeze)
@@ -88,7 +88,7 @@ module Liquid
words = Utils.to_integer(words)
l = words - 1
l = 0 if l < 0
- wordlist.length > l ? wordlist[0..l].join(" ".freeze) + truncate_string.to_s : input
+ wordlist.length > l ? wordlist[0..l].join(" ".freeze).concat(truncate_string.to_s) : input
end
# Split input string into an array of substrings separated by given pattern.
From c2c1497ca87db47e300fdfa431320ff7f059aacd Mon Sep 17 00:00:00 2001
From: Ashwin Maroli
Date: Mon, 22 Jul 2019 20:42:37 +0530
Subject: [PATCH 44/74] Reduce allocations while registering Liquid tags
---
lib/liquid/template.rb | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/lib/liquid/template.rb b/lib/liquid/template.rb
index 35db674..9136967 100644
--- a/lib/liquid/template.rb
+++ b/lib/liquid/template.rb
@@ -50,7 +50,9 @@ module Liquid
private
def lookup_class(name)
- name.split("::").reject(&:empty?).reduce(Object) { |scope, const| scope.const_get(const) }
+ names = name.split("::".freeze)
+ names.reject!(&:empty?)
+ names.reduce(Object) { |scope, const| scope.const_get(const) }
end
end
From 00702d8e6308759b9a6748c79714e41e2493f12a Mon Sep 17 00:00:00 2001
From: Ashwin Maroli
Date: Wed, 7 Aug 2019 11:44:53 +0530
Subject: [PATCH 45/74] Use `Object.const_get` directly
---
lib/liquid/template.rb | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/lib/liquid/template.rb b/lib/liquid/template.rb
index 9136967..91e30fb 100644
--- a/lib/liquid/template.rb
+++ b/lib/liquid/template.rb
@@ -50,9 +50,7 @@ module Liquid
private
def lookup_class(name)
- names = name.split("::".freeze)
- names.reject!(&:empty?)
- names.reduce(Object) { |scope, const| scope.const_get(const) }
+ Object.const_get(name)
end
end
From b16b109a80194190f0b6b4e824dd1398e34085f7 Mon Sep 17 00:00:00 2001
From: Mike Angell
Date: Tue, 27 Aug 2019 22:35:17 +1000
Subject: [PATCH 46/74] Bump Minimum version to 2.4 and bump Rubocop
---
.rubocop.yml | 12 ++--
.rubocop_todo.yml | 142 +++++++++++++++++++++++++++++++++++---------
.travis.yml | 18 ++----
Gemfile | 9 +--
Rakefile | 10 ++--
liquid.gemspec | 2 +-
test/test_helper.rb | 2 +-
7 files changed, 137 insertions(+), 58 deletions(-)
diff --git a/.rubocop.yml b/.rubocop.yml
index 6a306a1..671f076 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -2,9 +2,15 @@ inherit_from:
- .rubocop_todo.yml
- ./.rubocop_todo.yml
+require: rubocop-performance
+
+Performance:
+ Enabled: true
+
AllCops:
Exclude:
- 'performance/shopify/*'
+ - 'vendor/bundle/**/*'
- 'pkg/**'
Metrics/BlockNesting:
@@ -79,9 +85,6 @@ Style/TrailingCommaInArrayLiteral:
Style/TrailingCommaInHashLiteral:
Enabled: false
-Layout/IndentHash:
- EnforcedStyle: consistent
-
Style/FormatString:
Enabled: false
@@ -106,9 +109,6 @@ Style/RegexpLiteral:
Style/SymbolLiteral:
Enabled: false
-Performance/Count:
- Enabled: false
-
Naming/ConstantName:
Enabled: false
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 4af3202..19c27e8 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
-# on 2019-04-22 19:11:24 -0400 using RuboCop version 0.53.0.
+# on 2019-08-27 22:42:50 +1000 using RuboCop version 0.74.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
@@ -8,16 +8,67 @@
# Offense count: 1
# Cop supports --auto-correct.
-# Configuration parameters: Include, TreatCommentsAsGroupSeparators.
+# Configuration parameters: TreatCommentsAsGroupSeparators, Include.
# Include: **/*.gemspec
Gemspec/OrderedDependencies:
Exclude:
- 'liquid.gemspec'
+# Offense count: 1
+# Configuration parameters: Include.
+# Include: **/*.gemspec,
+Gemspec/RequiredRubyVersion:
+ Exclude:
+ - 'liquid.gemspec'
+
+# Offense count: 124
+# Cop supports --auto-correct.
+# Configuration parameters: EnforcedStyle, IndentationWidth.
+# SupportedStyles: with_first_argument, with_fixed_indentation
+Layout/AlignArguments:
+ Enabled: false
+
+# Offense count: 7
+# Cop supports --auto-correct.
+# Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle.
+# SupportedHashRocketStyles: key, separator, table
+# SupportedColonStyles: key, separator, table
+# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit
+Layout/AlignHash:
+ Exclude:
+ - 'lib/liquid/condition.rb'
+ - 'lib/liquid/expression.rb'
+ - 'test/unit/context_unit_test.rb'
+
+# Offense count: 6
+# Cop supports --auto-correct.
+Layout/ClosingHeredocIndentation:
+ Exclude:
+ - 'test/integration/tags/for_tag_test.rb'
+
+# Offense count: 25
+# Cop supports --auto-correct.
+Layout/EmptyLineAfterGuardClause:
+ Exclude:
+ - 'lib/liquid/block.rb'
+ - 'lib/liquid/block_body.rb'
+ - 'lib/liquid/context.rb'
+ - 'lib/liquid/drop.rb'
+ - 'lib/liquid/lexer.rb'
+ - 'lib/liquid/parser.rb'
+ - 'lib/liquid/standardfilters.rb'
+ - 'lib/liquid/strainer.rb'
+ - 'lib/liquid/tags/for.rb'
+ - 'lib/liquid/tags/if.rb'
+ - 'lib/liquid/tags/include.rb'
+ - 'lib/liquid/utils.rb'
+ - 'lib/liquid/variable.rb'
+ - 'lib/liquid/variable_lookup.rb'
+
# Offense count: 5
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
-# SupportedStyles: auto_detection, squiggly, active_support, powerpack, unindent
+# SupportedStyles: squiggly, active_support, powerpack, unindent
Layout/IndentHeredoc:
Exclude:
- 'test/integration/tags/for_tag_test.rb'
@@ -32,6 +83,13 @@ Layout/MultilineMethodCallBraceLayout:
- 'test/integration/error_handling_test.rb'
- 'test/unit/strainer_unit_test.rb'
+# Offense count: 1
+# Cop supports --auto-correct.
+# Configuration parameters: AllowForAlignment.
+Layout/SpaceAroundOperators:
+ Exclude:
+ - 'lib/liquid/condition.rb'
+
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
@@ -46,7 +104,7 @@ Lint/Void:
Exclude:
- 'lib/liquid/parse_context.rb'
-# Offense count: 53
+# Offense count: 52
Metrics/AbcSize:
Max: 56
@@ -54,27 +112,25 @@ Metrics/AbcSize:
Metrics/CyclomaticComplexity:
Max: 13
-# Offense count: 112
-# Configuration parameters: CountComments.
+# Offense count: 114
+# Configuration parameters: CountComments, ExcludedMethods.
Metrics/MethodLength:
Max: 38
-# Offense count: 8
+# Offense count: 9
Metrics/PerceivedComplexity:
Max: 11
-# Offense count: 52
-# Configuration parameters: Blacklist.
-# Blacklist: END, (?-mix:EO[A-Z]{1})
-Naming/HeredocDelimiterNaming:
+# Offense count: 1
+# Cop supports --auto-correct.
+# Configuration parameters: PreferredName.
+Naming/RescuedExceptionsVariableName:
Exclude:
- - 'test/integration/assign_test.rb'
- - 'test/integration/capture_test.rb'
- - 'test/integration/trim_mode_test.rb'
+ - 'lib/liquid/context.rb'
-# Offense count: 23
+# Offense count: 20
# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
-# AllowedNames: io, id
+# AllowedNames: io, id, to, by, on, in, at, ip, db
Naming/UncommunicativeMethodParamName:
Exclude:
- 'example/server/example_servlet.rb'
@@ -82,15 +138,22 @@ Naming/UncommunicativeMethodParamName:
- 'lib/liquid/context.rb'
- 'lib/liquid/standardfilters.rb'
- 'lib/liquid/tags/if.rb'
- - 'lib/liquid/utils.rb'
- 'lib/liquid/variable.rb'
- 'test/integration/filter_test.rb'
- 'test/integration/standard_filter_test.rb'
- - 'test/integration/tags/for_tag_test.rb'
- 'test/integration/template_test.rb'
- 'test/unit/condition_unit_test.rb'
-# Offense count: 12
+# Offense count: 3
+# Configuration parameters: EnforcedStyle.
+# SupportedStyles: inline, group
+Style/AccessModifierDeclarations:
+ Exclude:
+ - 'lib/liquid/tag.rb'
+ - 'lib/liquid/tags/include.rb'
+ - 'test/unit/strainer_unit_test.rb'
+
+# Offense count: 10
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: prefer_alias, prefer_alias_method
@@ -117,15 +180,9 @@ Style/ConditionalAssignment:
- 'lib/liquid/errors.rb'
# Offense count: 1
-Style/DateTime:
- Exclude:
- - 'test/unit/context_unit_test.rb'
-
-# Offense count: 2
# Cop supports --auto-correct.
Style/EmptyCaseCondition:
Exclude:
- - 'lib/liquid/block_body.rb'
- 'lib/liquid/lexer.rb'
# Offense count: 5
@@ -163,6 +220,13 @@ Style/FormatStringToken:
- 'test/integration/filter_test.rb'
- 'test/integration/hash_ordering_test.rb'
+# Offense count: 103
+# Cop supports --auto-correct.
+# Configuration parameters: EnforcedStyle.
+# SupportedStyles: always, never
+Style/FrozenStringLiteralComment:
+ Enabled: false
+
# Offense count: 14
# Configuration parameters: MinBodyLength.
Style/GuardClause:
@@ -180,6 +244,13 @@ Style/GuardClause:
- 'lib/liquid/variable.rb'
- 'test/unit/tokenizer_unit_test.rb'
+# Offense count: 52
+# Cop supports --auto-correct.
+# Configuration parameters: EnforcedStyle.
+# SupportedStyles: literals, strict
+Style/MutableConstant:
+ Enabled: false
+
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, MinBodyLength.
@@ -188,9 +259,9 @@ Style/Next:
Exclude:
- 'lib/liquid/tags/for.rb'
-# Offense count: 4
+# Offense count: 13
# Cop supports --auto-correct.
-# Configuration parameters: AutoCorrect, EnforcedStyle.
+# Configuration parameters: AutoCorrect, EnforcedStyle, IgnoredMethods.
# SupportedStyles: predicate, comparison
Style/NumericPredicate:
Exclude:
@@ -199,6 +270,8 @@ Style/NumericPredicate:
- 'lib/liquid/forloop_drop.rb'
- 'lib/liquid/standardfilters.rb'
- 'lib/liquid/tablerowloop_drop.rb'
+ - 'test/integration/standard_filter_test.rb'
+ - 'test/integration/template_test.rb'
# Offense count: 14
# Cop supports --auto-correct.
@@ -216,6 +289,16 @@ Style/RedundantSelf:
Exclude:
- 'lib/liquid/strainer.rb'
+# Offense count: 3
+# Cop supports --auto-correct.
+# Configuration parameters: ConvertCodeThatCanStartToReturnNil, Whitelist.
+# Whitelist: present?, blank?, presence, try, try!
+Style/SafeNavigation:
+ Exclude:
+ - 'lib/liquid/drop.rb'
+ - 'lib/liquid/strainer.rb'
+ - 'lib/liquid/tokenizer.rb'
+
# Offense count: 9
# Cop supports --auto-correct.
# Configuration parameters: AllowAsExpressionSeparator.
@@ -253,8 +336,9 @@ Style/WhileUntilModifier:
Exclude:
- 'lib/liquid/tags/case.rb'
-# Offense count: 648
-# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
+# Offense count: 650
+# Cop supports --auto-correct.
+# Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
# URISchemes: http, https
Metrics/LineLength:
Max: 294
diff --git a/.travis.yml b/.travis.yml
index 3a01754..082cb57 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,29 +1,21 @@
language: ruby
rvm:
- - 2.1
- - 2.2
- - 2.3
- 2.4
- 2.5
+ - 2.6
+ - 2.7
- ruby-head
- jruby-head
-# - rbx-2
-
-sudo: false
-
-addons:
- apt:
- packages:
- - libgmp3-dev
+ - truffleruby
matrix:
allow_failures:
- rvm: ruby-head
- rvm: jruby-head
+ - rvm: truffleruby
-install:
- - bundle install
+cache: bundler
script: bundle exec rake
diff --git a/Gemfile b/Gemfile
index 37ffe1d..370fa03 100644
--- a/Gemfile
+++ b/Gemfile
@@ -9,15 +9,16 @@ group :benchmark, :test do
gem 'benchmark-ips'
gem 'memory_profiler'
- install_if -> { RUBY_PLATFORM !~ /mingw|mswin|java/ } do
+ install_if -> { RUBY_PLATFORM !~ /mingw|mswin|java/ && RUBY_ENGINE != 'truffleruby' } do
gem 'stackprof'
end
end
group :test do
- gem 'rubocop', '~> 0.53.0'
+ gem 'rubocop', '~> 0.74.0', require: false
+ gem 'rubocop-performance', require: false
- platform :mri do
- gem 'liquid-c', github: 'Shopify/liquid-c', ref: '9168659de45d6d576fce30c735f857e597fa26f6'
+ platform :mri, :truffleruby do
+ gem 'liquid-c', github: 'Shopify/liquid-c', ref: '7ba926791ef8411984d0f3e41c6353fd716041c6'
end
end
diff --git a/Rakefile b/Rakefile
index 9650abb..f7186eb 100755
--- a/Rakefile
+++ b/Rakefile
@@ -19,8 +19,10 @@ task :warn_test do
end
task :rubocop do
- require 'rubocop/rake_task'
- RuboCop::RakeTask.new
+ if RUBY_ENGINE == 'ruby'
+ require 'rubocop/rake_task'
+ RuboCop::RakeTask.new
+ end
end
desc 'runs test suite with both strict and lax parsers'
@@ -32,8 +34,8 @@ task :test do
Rake::Task['base_test'].reenable
Rake::Task['base_test'].invoke
- if RUBY_ENGINE == 'ruby'
- ENV['LIQUID-C'] = '1'
+ if RUBY_ENGINE == 'ruby' || RUBY_ENGINE == 'truffleruby'
+ ENV['LIQUID_C'] = '1'
ENV['LIQUID_PARSER_MODE'] = 'lax'
Rake::Task['base_test'].reenable
diff --git a/liquid.gemspec b/liquid.gemspec
index e0e4ddb..89df19a 100644
--- a/liquid.gemspec
+++ b/liquid.gemspec
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
s.license = "MIT"
# s.description = "A secure, non-evaling end user template engine with aesthetic markup."
- s.required_ruby_version = ">= 2.1.0"
+ s.required_ruby_version = ">= 2.4.0"
s.required_rubygems_version = ">= 1.3.7"
s.test_files = Dir.glob("{test}/**/*")
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 34e7553..affa2e4 100755
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -14,7 +14,7 @@ if env_mode = ENV['LIQUID_PARSER_MODE']
end
Liquid::Template.error_mode = mode
-if ENV['LIQUID-C'] == '1'
+if ENV['LIQUID_C'] == '1'
puts "-- LIQUID C"
require 'liquid/c'
end
From 7bae55dd3943907716166cef5bd8f6757e7664e5 Mon Sep 17 00:00:00 2001
From: Mike Angell
Date: Wed, 28 Aug 2019 19:22:40 +1000
Subject: [PATCH 47/74] Bugfix for new Liquid tag
---
lib/liquid/tags/echo.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/liquid/tags/echo.rb b/lib/liquid/tags/echo.rb
index acb9ab4..d3d30e3 100644
--- a/lib/liquid/tags/echo.rb
+++ b/lib/liquid/tags/echo.rb
@@ -16,7 +16,7 @@ module Liquid
end
def render(context)
- @variable.render(context)
+ @variable.render_to_output_buffer(context, '')
end
end
From 8f68cffdf139ac37b40b9ac8e6aaf2ee295310e1 Mon Sep 17 00:00:00 2001
From: Mike Angell
Date: Thu, 29 Aug 2019 00:45:38 +1000
Subject: [PATCH 48/74] Resolve failing rubocop issues
---
.rubocop_todo.yml | 17 +++--
performance/memory_profile.rb | 1 +
test/integration/tags/liquid_tag_test.rb | 96 ++++++++++++------------
3 files changed, 58 insertions(+), 56 deletions(-)
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 19c27e8..992d135 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
-# on 2019-08-27 22:42:50 +1000 using RuboCop version 0.74.0.
+# on 2019-08-29 00:43:36 +1000 using RuboCop version 0.74.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
@@ -46,7 +46,7 @@ Layout/ClosingHeredocIndentation:
Exclude:
- 'test/integration/tags/for_tag_test.rb'
-# Offense count: 25
+# Offense count: 27
# Cop supports --auto-correct.
Layout/EmptyLineAfterGuardClause:
Exclude:
@@ -104,7 +104,7 @@ Lint/Void:
Exclude:
- 'lib/liquid/parse_context.rb'
-# Offense count: 52
+# Offense count: 53
Metrics/AbcSize:
Max: 56
@@ -112,7 +112,7 @@ Metrics/AbcSize:
Metrics/CyclomaticComplexity:
Max: 13
-# Offense count: 114
+# Offense count: 118
# Configuration parameters: CountComments, ExcludedMethods.
Metrics/MethodLength:
Max: 38
@@ -144,11 +144,12 @@ Naming/UncommunicativeMethodParamName:
- 'test/integration/template_test.rb'
- 'test/unit/condition_unit_test.rb'
-# Offense count: 3
+# Offense count: 5
# Configuration parameters: EnforcedStyle.
# SupportedStyles: inline, group
Style/AccessModifierDeclarations:
Exclude:
+ - 'lib/liquid/block_body.rb'
- 'lib/liquid/tag.rb'
- 'lib/liquid/tags/include.rb'
- 'test/unit/strainer_unit_test.rb'
@@ -220,7 +221,7 @@ Style/FormatStringToken:
- 'test/integration/filter_test.rb'
- 'test/integration/hash_ordering_test.rb'
-# Offense count: 103
+# Offense count: 106
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: always, never
@@ -244,7 +245,7 @@ Style/GuardClause:
- 'lib/liquid/variable.rb'
- 'test/unit/tokenizer_unit_test.rb'
-# Offense count: 52
+# Offense count: 53
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: literals, strict
@@ -336,7 +337,7 @@ Style/WhileUntilModifier:
Exclude:
- 'lib/liquid/tags/case.rb'
-# Offense count: 650
+# Offense count: 665
# Cop supports --auto-correct.
# Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
# URISchemes: http, https
diff --git a/performance/memory_profile.rb b/performance/memory_profile.rb
index 9a15375..14b3770 100644
--- a/performance/memory_profile.rb
+++ b/performance/memory_profile.rb
@@ -30,6 +30,7 @@ class Profiler
@retained << "#{report.scale_bytes(report.total_retained_memsize)} (#{report.total_retained} objects)"
return if ENV['CI']
+
require 'fileutils'
report_file = File.join(REPORTS_DIR, "#{sanitize(phase)}.txt")
FileUtils.mkdir_p(REPORTS_DIR)
diff --git a/test/integration/tags/liquid_tag_test.rb b/test/integration/tags/liquid_tag_test.rb
index d4be128..628eb85 100644
--- a/test/integration/tags/liquid_tag_test.rb
+++ b/test/integration/tags/liquid_tag_test.rb
@@ -5,72 +5,72 @@ class LiquidTagTest < Minitest::Test
def test_liquid_tag
assert_template_result('1 2 3', <<~LIQUID, 'array' => [1, 2, 3])
- {%- liquid
- echo array | join: " "
- -%}
+ {%- liquid
+ echo array | join: " "
+ -%}
LIQUID
assert_template_result('1 2 3', <<~LIQUID, 'array' => [1, 2, 3])
- {%- liquid
- for value in array
- echo value
- unless forloop.last
- echo " "
- endunless
- endfor
- -%}
+ {%- liquid
+ for value in array
+ echo value
+ unless forloop.last
+ echo " "
+ endunless
+ endfor
+ -%}
LIQUID
assert_template_result('4 8 12 6', <<~LIQUID, 'array' => [1, 2, 3])
- {%- liquid
- for value in array
- assign double_value = value | times: 2
- echo double_value | times: 2
- unless forloop.last
- echo " "
- endunless
- endfor
+ {%- liquid
+ for value in array
+ assign double_value = value | times: 2
+ echo double_value | times: 2
+ unless forloop.last
+ echo " "
+ endunless
+ endfor
- echo " "
- echo double_value
- -%}
+ echo " "
+ echo double_value
+ -%}
LIQUID
assert_template_result('abc', <<~LIQUID)
- {%- liquid echo "a" -%}
- b
- {%- liquid echo "c" -%}
+ {%- liquid echo "a" -%}
+ b
+ {%- liquid echo "c" -%}
LIQUID
end
def test_liquid_tag_errors
assert_match_syntax_error("syntax error (line 1): Unknown tag 'error'", <<~LIQUID)
- {%- liquid error no such tag -%}
+ {%- liquid error no such tag -%}
LIQUID
assert_match_syntax_error("syntax error (line 7): Unknown tag 'error'", <<~LIQUID)
- {{ test }}
+ {{ test }}
- {%-
- liquid
- for value in array
+ {%-
+ liquid
+ for value in array
- error no such tag
- endfor
- -%}
+ error no such tag
+ endfor
+ -%}
LIQUID
assert_match_syntax_error("syntax error (line 2): Unknown tag '!!! the guards are vigilant'", <<~LIQUID)
- {%- liquid
- !!! the guards are vigilant
- -%}
+ {%- liquid
+ !!! the guards are vigilant
+ -%}
LIQUID
assert_match_syntax_error("syntax error (line 4): 'for' tag was never closed", <<~LIQUID)
- {%- liquid
- for value in array
- echo 'forgot to close the for tag'
- -%}
+ {%- liquid
+ for value in array
+ echo 'forgot to close the for tag'
+ -%}
LIQUID
end
@@ -81,24 +81,24 @@ class LiquidTagTest < Minitest::Test
def test_cannot_open_blocks_living_past_a_liquid_tag
assert_match_syntax_error("syntax error (line 3): 'if' tag was never closed", <<~LIQUID)
- {%- liquid
- if true
- -%}
- {%- endif -%}
+ {%- liquid
+ if true
+ -%}
+ {%- endif -%}
LIQUID
end
def test_quirk_can_close_blocks_created_before_a_liquid_tag
assert_template_result("42", <<~LIQUID)
- {%- if true -%}
- 42
- {%- liquid endif -%}
+ {%- if true -%}
+ 42
+ {%- liquid endif -%}
LIQUID
end
def test_liquid_tag_in_raw
assert_template_result("{% liquid echo 'test' %}\n", <<~LIQUID)
- {% raw %}{% liquid echo 'test' %}{% endraw %}
+ {% raw %}{% liquid echo 'test' %}{% endraw %}
LIQUID
end
end
From b3097f143cfb3bbec4f010c5a0a86e368be70464 Mon Sep 17 00:00:00 2001
From: Ashwin Maroli
Date: Wed, 28 Aug 2019 21:28:49 +0530
Subject: [PATCH 49/74] Build only pushes to certain branches on Travis CI
---
.travis.yml | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index e6fb9aa..b6a7db0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,5 @@
language: ruby
+cache: bundler
rvm:
- 2.4
@@ -9,7 +10,6 @@ rvm:
- jruby-head
- truffleruby
-
matrix:
include:
- rvm: *latest_ruby
@@ -20,9 +20,11 @@ matrix:
- rvm: jruby-head
- rvm: truffleruby
-cache: bundler
-
-script: bundle exec rake
+branches:
+ only:
+ - master
+ - gh-pages
+ - /.*-stable/
notifications:
disable: true
From 2324564743f005a3366ab3cecc3e5c2532433f81 Mon Sep 17 00:00:00 2001
From: Mike Angell
Date: Thu, 29 Aug 2019 08:50:36 +1000
Subject: [PATCH 50/74] Remove lazy load stacks
Remove lazy load stacks and instead only create a new scope when a tag is known to need one
---
lib/liquid/context.rb | 35 ++++++++++++++++++-----------------
lib/liquid/tags/case.rb | 16 +++++++---------
lib/liquid/tags/cycle.rb | 28 +++++++++++++---------------
lib/liquid/tags/if.rb | 8 +++-----
lib/liquid/tags/ifchanged.rb | 12 +++++-------
lib/liquid/tags/unless.rb | 20 +++++++++-----------
6 files changed, 55 insertions(+), 64 deletions(-)
diff --git a/lib/liquid/context.rb b/lib/liquid/context.rb
index 2dcc6af..b341a31 100644
--- a/lib/liquid/context.rb
+++ b/lib/liquid/context.rb
@@ -25,8 +25,6 @@ module Liquid
@resource_limits = resource_limits || ResourceLimits.new(Template.default_resource_limits)
squash_instance_assigns_with_environments
- @this_stack_used = false
-
self.exception_renderer = Template.default_exception_renderer
if rethrow_errors
self.exception_renderer = ->(e) { raise }
@@ -111,19 +109,26 @@ module Liquid
# end
#
# context['var] #=> nil
- def stack(new_scope = nil)
- old_stack_used = @this_stack_used
- if new_scope
- push(new_scope)
- @this_stack_used = true
- else
- @this_stack_used = false
- end
-
+ #
+ # false or {} can be used to control if a new scope is needed
+ #
+ # Example:
+ # new_scope = false
+ # context.stack(new_scope) do
+ # # no scope created
+ # end
+ #
+ # Example:
+ # new_scope = {}
+ # context.stack(new_scope) do
+ # # scope created
+ # end
+ #
+ def stack(new_scope = {})
+ push(new_scope) unless new_scope == false
yield
ensure
- pop if @this_stack_used
- @this_stack_used = old_stack_used
+ pop unless new_scope == false
end
def clear_instance_assigns
@@ -132,10 +137,6 @@ module Liquid
# Only allow String, Numeric, Hash, Array, Proc, Boolean or Liquid::Drop
def []=(key, value)
- unless @this_stack_used
- @this_stack_used = true
- push({})
- end
@scopes[0][key] = value
end
diff --git a/lib/liquid/tags/case.rb b/lib/liquid/tags/case.rb
index 92b2ed0..e167b9d 100644
--- a/lib/liquid/tags/case.rb
+++ b/lib/liquid/tags/case.rb
@@ -39,16 +39,14 @@ module Liquid
end
def render_to_output_buffer(context, output)
- context.stack do
- execute_else_block = true
+ execute_else_block = true
- @blocks.each do |block|
- if block.else?
- block.attachment.render_to_output_buffer(context, output) if execute_else_block
- elsif block.evaluate(context)
- execute_else_block = false
- block.attachment.render_to_output_buffer(context, output)
- end
+ @blocks.each do |block|
+ if block.else?
+ block.attachment.render_to_output_buffer(context, output) if execute_else_block
+ elsif block.evaluate(context)
+ execute_else_block = false
+ block.attachment.render_to_output_buffer(context, output)
end
end
diff --git a/lib/liquid/tags/cycle.rb b/lib/liquid/tags/cycle.rb
index e42244d..8c11d37 100644
--- a/lib/liquid/tags/cycle.rb
+++ b/lib/liquid/tags/cycle.rb
@@ -34,25 +34,23 @@ module Liquid
def render_to_output_buffer(context, output)
context.registers[:cycle] ||= {}
- context.stack do
- key = context.evaluate(@name)
- iteration = context.registers[:cycle][key].to_i
+ key = context.evaluate(@name)
+ iteration = context.registers[:cycle][key].to_i
- val = context.evaluate(@variables[iteration])
+ val = context.evaluate(@variables[iteration])
- if val.is_a?(Array)
- val = val.join
- elsif !val.is_a?(String)
- val = val.to_s
- end
-
- output << val
-
- iteration += 1
- iteration = 0 if iteration >= @variables.size
- context.registers[:cycle][key] = iteration
+ if val.is_a?(Array)
+ val = val.join
+ elsif !val.is_a?(String)
+ val = val.to_s
end
+ output << val
+
+ iteration += 1
+ iteration = 0 if iteration >= @variables.size
+ context.registers[:cycle][key] = iteration
+
output
end
diff --git a/lib/liquid/tags/if.rb b/lib/liquid/tags/if.rb
index 25534a9..709cf7f 100644
--- a/lib/liquid/tags/if.rb
+++ b/lib/liquid/tags/if.rb
@@ -40,11 +40,9 @@ module Liquid
end
def render_to_output_buffer(context, output)
- context.stack do
- @blocks.each do |block|
- if block.evaluate(context)
- return block.attachment.render_to_output_buffer(context, output)
- end
+ @blocks.each do |block|
+ if block.evaluate(context)
+ return block.attachment.render_to_output_buffer(context, output)
end
end
diff --git a/lib/liquid/tags/ifchanged.rb b/lib/liquid/tags/ifchanged.rb
index e3040ce..ddd276c 100644
--- a/lib/liquid/tags/ifchanged.rb
+++ b/lib/liquid/tags/ifchanged.rb
@@ -1,14 +1,12 @@
module Liquid
class Ifchanged < Block
def render_to_output_buffer(context, output)
- context.stack do
- block_output = ''
- super(context, block_output)
+ block_output = ''
+ super(context, block_output)
- if block_output != context.registers[:ifchanged]
- context.registers[:ifchanged] = block_output
- output << block_output
- end
+ if block_output != context.registers[:ifchanged]
+ context.registers[:ifchanged] = block_output
+ output << block_output
end
output
diff --git a/lib/liquid/tags/unless.rb b/lib/liquid/tags/unless.rb
index 18856c3..32aa3a4 100644
--- a/lib/liquid/tags/unless.rb
+++ b/lib/liquid/tags/unless.rb
@@ -7,18 +7,16 @@ module Liquid
#
class Unless < If
def render_to_output_buffer(context, output)
- context.stack do
- # First condition is interpreted backwards ( if not )
- first_block = @blocks.first
- unless first_block.evaluate(context)
- return first_block.attachment.render_to_output_buffer(context, output)
- end
+ # First condition is interpreted backwards ( if not )
+ first_block = @blocks.first
+ unless first_block.evaluate(context)
+ return first_block.attachment.render_to_output_buffer(context, output)
+ end
- # After the first condition unless works just like if
- @blocks[1..-1].each do |block|
- if block.evaluate(context)
- return block.attachment.render_to_output_buffer(context, output)
- end
+ # After the first condition unless works just like if
+ @blocks[1..-1].each do |block|
+ if block.evaluate(context)
+ return block.attachment.render_to_output_buffer(context, output)
end
end
From d67de1c9b28c986d93e861e8d56dc0156876e9bd Mon Sep 17 00:00:00 2001
From: Mike Angell
Date: Thu, 29 Aug 2019 12:21:49 +1000
Subject: [PATCH 51/74] Follow Shopify ruby style
This is the first step in bringing Liquid style inline with Shopify ruby style
---
...ify-github-io-ruby-style-guide-rubocop-yml | 1027 +++++++++++++++++
.rubocop.yml | 122 +-
.rubocop_todo.yml | 434 ++++---
3 files changed, 1280 insertions(+), 303 deletions(-)
create mode 100644 .rubocop-https---shopify-github-io-ruby-style-guide-rubocop-yml
diff --git a/.rubocop-https---shopify-github-io-ruby-style-guide-rubocop-yml b/.rubocop-https---shopify-github-io-ruby-style-guide-rubocop-yml
new file mode 100644
index 0000000..5f5212c
--- /dev/null
+++ b/.rubocop-https---shopify-github-io-ruby-style-guide-rubocop-yml
@@ -0,0 +1,1027 @@
+AllCops:
+ Exclude:
+ - 'db/schema.rb'
+ DisabledByDefault: true
+ StyleGuideBaseURL: https://shopify.github.io/ruby-style-guide/
+
+Lint/AssignmentInCondition:
+ Enabled: true
+
+Layout/AccessModifierIndentation:
+ EnforcedStyle: indent
+ SupportedStyles:
+ - outdent
+ - indent
+ IndentationWidth:
+
+Style/Alias:
+ EnforcedStyle: prefer_alias_method
+ SupportedStyles:
+ - prefer_alias
+ - prefer_alias_method
+
+Layout/AlignHash:
+ EnforcedHashRocketStyle: key
+ EnforcedColonStyle: key
+ EnforcedLastArgumentHashStyle: ignore_implicit
+ SupportedLastArgumentHashStyles:
+ - always_inspect
+ - always_ignore
+ - ignore_implicit
+ - ignore_explicit
+
+Layout/AlignParameters:
+ EnforcedStyle: with_fixed_indentation
+ SupportedStyles:
+ - with_first_parameter
+ - with_fixed_indentation
+ IndentationWidth:
+
+Style/AndOr:
+ EnforcedStyle: always
+ SupportedStyles:
+ - always
+ - conditionals
+
+Style/BarePercentLiterals:
+ EnforcedStyle: bare_percent
+ SupportedStyles:
+ - percent_q
+ - bare_percent
+
+Style/BlockDelimiters:
+ EnforcedStyle: line_count_based
+ SupportedStyles:
+ - line_count_based
+ - semantic
+ - braces_for_chaining
+ ProceduralMethods:
+ - benchmark
+ - bm
+ - bmbm
+ - create
+ - each_with_object
+ - measure
+ - new
+ - realtime
+ - tap
+ - with_object
+ FunctionalMethods:
+ - let
+ - let!
+ - subject
+ - watch
+ IgnoredMethods:
+ - lambda
+ - proc
+ - it
+
+Style/BracesAroundHashParameters:
+ EnforcedStyle: no_braces
+ SupportedStyles:
+ - braces
+ - no_braces
+ - context_dependent
+
+Layout/CaseIndentation:
+ EnforcedStyle: end
+ SupportedStyles:
+ - case
+ - end
+ IndentOneStep: false
+ IndentationWidth:
+
+Style/ClassAndModuleChildren:
+ EnforcedStyle: nested
+ SupportedStyles:
+ - nested
+ - compact
+
+Style/ClassCheck:
+ EnforcedStyle: is_a?
+ SupportedStyles:
+ - is_a?
+ - kind_of?
+
+Style/CommandLiteral:
+ EnforcedStyle: percent_x
+ SupportedStyles:
+ - backticks
+ - percent_x
+ - mixed
+ AllowInnerBackticks: false
+
+Style/CommentAnnotation:
+ Keywords:
+ - TODO
+ - FIXME
+ - OPTIMIZE
+ - HACK
+ - REVIEW
+
+Style/ConditionalAssignment:
+ EnforcedStyle: assign_to_condition
+ SupportedStyles:
+ - assign_to_condition
+ - assign_inside_condition
+ SingleLineConditionsOnly: true
+
+Layout/DotPosition:
+ EnforcedStyle: leading
+ SupportedStyles:
+ - leading
+ - trailing
+
+Style/EmptyElse:
+ EnforcedStyle: both
+ SupportedStyles:
+ - empty
+ - nil
+ - both
+
+Layout/EmptyLineBetweenDefs:
+ AllowAdjacentOneLineDefs: false
+
+Layout/EmptyLinesAroundBlockBody:
+ EnforcedStyle: no_empty_lines
+ SupportedStyles:
+ - empty_lines
+ - no_empty_lines
+
+Layout/EmptyLinesAroundClassBody:
+ EnforcedStyle: no_empty_lines
+ SupportedStyles:
+ - empty_lines
+ - empty_lines_except_namespace
+ - no_empty_lines
+
+Layout/EmptyLinesAroundModuleBody:
+ EnforcedStyle: no_empty_lines
+ SupportedStyles:
+ - empty_lines
+ - empty_lines_except_namespace
+ - no_empty_lines
+
+Layout/ExtraSpacing:
+ AllowForAlignment: true
+ ForceEqualSignAlignment: false
+
+Naming/FileName:
+ Exclude: []
+ ExpectMatchingDefinition: false
+ Regex:
+ IgnoreExecutableScripts: true
+
+Layout/IndentFirstArgument:
+ EnforcedStyle: consistent
+ SupportedStyles:
+ - consistent
+ - special_for_inner_method_call
+ - special_for_inner_method_call_in_parentheses
+ IndentationWidth:
+
+Style/For:
+ EnforcedStyle: each
+ SupportedStyles:
+ - for
+ - each
+
+Style/FormatString:
+ EnforcedStyle: format
+ SupportedStyles:
+ - format
+ - sprintf
+ - percent
+
+Style/FrozenStringLiteralComment:
+ Details: >-
+ Add `# frozen_string_literal: true` to the top of the file. Frozen string
+ literals will become the default in a future Ruby version, and we want to
+ make sure we're ready.
+ EnforcedStyle: always
+ SupportedStyles:
+ - always
+ - never
+
+Style/GlobalVars:
+ AllowedVariables: []
+
+Style/HashSyntax:
+ EnforcedStyle: ruby19
+ SupportedStyles:
+ - ruby19
+ - hash_rockets
+ - no_mixed_keys
+ - ruby19_no_mixed_keys
+ UseHashRocketsWithSymbolValues: false
+ PreferHashRocketsForNonAlnumEndingSymbols: false
+
+Layout/IndentationConsistency:
+ EnforcedStyle: normal
+ SupportedStyles:
+ - normal
+ - rails
+
+Layout/IndentationWidth:
+ Width: 2
+
+Layout/IndentFirstArrayElement:
+ EnforcedStyle: consistent
+ SupportedStyles:
+ - special_inside_parentheses
+ - consistent
+ - align_brackets
+ IndentationWidth:
+
+Layout/IndentAssignment:
+ IndentationWidth:
+
+Layout/IndentFirstHashElement:
+ EnforcedStyle: consistent
+ SupportedStyles:
+ - special_inside_parentheses
+ - consistent
+ - align_braces
+ IndentationWidth:
+
+Style/LambdaCall:
+ EnforcedStyle: call
+ SupportedStyles:
+ - call
+ - braces
+
+Style/Next:
+ EnforcedStyle: skip_modifier_ifs
+ MinBodyLength: 3
+ SupportedStyles:
+ - skip_modifier_ifs
+ - always
+
+Style/NonNilCheck:
+ IncludeSemanticChanges: false
+
+Style/MethodCallWithArgsParentheses:
+ Enabled: true
+ IgnoreMacros: true
+ IgnoredMethods:
+ - require
+ - require_relative
+ - require_dependency
+ - yield
+ - raise
+ - puts
+ Exclude:
+ - Gemfile
+
+Style/MethodDefParentheses:
+ EnforcedStyle: require_parentheses
+ SupportedStyles:
+ - require_parentheses
+ - require_no_parentheses
+ - require_no_parentheses_except_multiline
+
+Naming/MethodName:
+ EnforcedStyle: snake_case
+ SupportedStyles:
+ - snake_case
+ - camelCase
+
+Layout/MultilineArrayBraceLayout:
+ EnforcedStyle: symmetrical
+ SupportedStyles:
+ - symmetrical
+ - new_line
+ - same_line
+
+Layout/MultilineHashBraceLayout:
+ EnforcedStyle: symmetrical
+ SupportedStyles:
+ - symmetrical
+ - new_line
+ - same_line
+
+Layout/MultilineMethodCallBraceLayout:
+ EnforcedStyle: symmetrical
+ SupportedStyles:
+ - symmetrical
+ - new_line
+ - same_line
+
+Layout/MultilineMethodCallIndentation:
+ EnforcedStyle: indented
+ SupportedStyles:
+ - aligned
+ - indented
+ - indented_relative_to_receiver
+ IndentationWidth: 2
+
+Layout/MultilineMethodDefinitionBraceLayout:
+ EnforcedStyle: symmetrical
+ SupportedStyles:
+ - symmetrical
+ - new_line
+ - same_line
+
+Style/NumericLiteralPrefix:
+ EnforcedOctalStyle: zero_only
+ SupportedOctalStyles:
+ - zero_with_o
+ - zero_only
+
+Style/ParenthesesAroundCondition:
+ AllowSafeAssignment: true
+
+Style/PercentQLiterals:
+ EnforcedStyle: lower_case_q
+ SupportedStyles:
+ - lower_case_q
+ - upper_case_q
+
+Naming/PredicateName:
+ NamePrefix:
+ - is_
+ NamePrefixBlacklist:
+ - is_
+ NameWhitelist:
+ - is_a?
+ Exclude:
+ - 'spec/**/*'
+
+Style/PreferredHashMethods:
+ EnforcedStyle: short
+ SupportedStyles:
+ - short
+ - verbose
+
+Style/RaiseArgs:
+ EnforcedStyle: exploded
+ SupportedStyles:
+ - compact
+ - exploded
+
+Style/RedundantReturn:
+ AllowMultipleReturnValues: false
+
+Style/RegexpLiteral:
+ EnforcedStyle: mixed
+ SupportedStyles:
+ - slashes
+ - percent_r
+ - mixed
+ AllowInnerSlashes: false
+
+Style/SafeNavigation:
+ ConvertCodeThatCanStartToReturnNil: false
+ Enabled: true
+
+Lint/SafeNavigationChain:
+ Enabled: true
+
+Style/Semicolon:
+ AllowAsExpressionSeparator: false
+
+Style/SignalException:
+ EnforcedStyle: only_raise
+ SupportedStyles:
+ - only_raise
+ - only_fail
+ - semantic
+
+Style/SingleLineMethods:
+ AllowIfMethodIsEmpty: true
+
+Layout/SpaceBeforeFirstArg:
+ AllowForAlignment: true
+
+Style/SpecialGlobalVars:
+ EnforcedStyle: use_english_names
+ SupportedStyles:
+ - use_perl_names
+ - use_english_names
+
+Style/StabbyLambdaParentheses:
+ EnforcedStyle: require_parentheses
+ SupportedStyles:
+ - require_parentheses
+ - require_no_parentheses
+
+Style/StringLiteralsInInterpolation:
+ EnforcedStyle: single_quotes
+ SupportedStyles:
+ - single_quotes
+ - double_quotes
+
+Layout/SpaceAroundBlockParameters:
+ EnforcedStyleInsidePipes: no_space
+ SupportedStylesInsidePipes:
+ - space
+ - no_space
+
+Layout/SpaceAroundEqualsInParameterDefault:
+ EnforcedStyle: space
+ SupportedStyles:
+ - space
+ - no_space
+
+Layout/SpaceAroundOperators:
+ AllowForAlignment: true
+
+Layout/SpaceBeforeBlockBraces:
+ EnforcedStyle: space
+ EnforcedStyleForEmptyBraces: space
+ SupportedStyles:
+ - space
+ - no_space
+
+Layout/SpaceInsideBlockBraces:
+ EnforcedStyle: space
+ SupportedStyles:
+ - space
+ - no_space
+ EnforcedStyleForEmptyBraces: no_space
+ SpaceBeforeBlockParameters: true
+
+Layout/SpaceInsideHashLiteralBraces:
+ EnforcedStyle: space
+ EnforcedStyleForEmptyBraces: no_space
+ SupportedStyles:
+ - space
+ - no_space
+ - compact
+
+Layout/SpaceInsideStringInterpolation:
+ EnforcedStyle: no_space
+ SupportedStyles:
+ - space
+ - no_space
+
+Style/SymbolProc:
+ IgnoredMethods:
+ - respond_to
+ - define_method
+
+Style/TernaryParentheses:
+ EnforcedStyle: require_no_parentheses
+ SupportedStyles:
+ - require_parentheses
+ - require_no_parentheses
+ AllowSafeAssignment: true
+
+Layout/TrailingBlankLines:
+ EnforcedStyle: final_newline
+ SupportedStyles:
+ - final_newline
+ - final_blank_line
+
+Style/TrivialAccessors:
+ ExactNameMatch: true
+ AllowPredicates: true
+ AllowDSLWriters: false
+ IgnoreClassMethods: false
+ Whitelist:
+ - to_ary
+ - to_a
+ - to_c
+ - to_enum
+ - to_h
+ - to_hash
+ - to_i
+ - to_int
+ - to_io
+ - to_open
+ - to_path
+ - to_proc
+ - to_r
+ - to_regexp
+ - to_str
+ - to_s
+ - to_sym
+
+Naming/VariableName:
+ EnforcedStyle: snake_case
+ SupportedStyles:
+ - snake_case
+ - camelCase
+
+Style/WhileUntilModifier:
+ Enabled: true
+
+Metrics/BlockNesting:
+ Max: 3
+
+Metrics/LineLength:
+ Max: 120
+ AllowHeredoc: true
+ AllowURI: true
+ URISchemes:
+ - http
+ - https
+ IgnoreCopDirectives: false
+ IgnoredPatterns:
+ - '\A\s*(remote_)?test(_\w+)?\s.*(do|->)(\s|\Z)'
+
+Metrics/ParameterLists:
+ Max: 5
+ CountKeywordArgs: false
+
+Layout/BlockAlignment:
+ EnforcedStyleAlignWith: either
+ SupportedStylesAlignWith:
+ - either
+ - start_of_block
+ - start_of_line
+
+Layout/EndAlignment:
+ EnforcedStyleAlignWith: variable
+ SupportedStylesAlignWith:
+ - keyword
+ - variable
+ - start_of_line
+
+Layout/DefEndAlignment:
+ EnforcedStyleAlignWith: start_of_line
+ SupportedStylesAlignWith:
+ - start_of_line
+ - def
+
+Lint/InheritException:
+ EnforcedStyle: runtime_error
+ SupportedStyles:
+ - runtime_error
+ - standard_error
+
+Lint/UnusedBlockArgument:
+ IgnoreEmptyBlocks: true
+ AllowUnusedKeywordArguments: false
+
+Lint/UnusedMethodArgument:
+ AllowUnusedKeywordArguments: false
+ IgnoreEmptyMethods: true
+
+Naming/AccessorMethodName:
+ Enabled: true
+
+Layout/AlignArray:
+ Enabled: true
+
+Style/ArrayJoin:
+ Enabled: true
+
+Naming/AsciiIdentifiers:
+ Enabled: true
+
+Style/Attr:
+ Enabled: true
+
+Style/BeginBlock:
+ Enabled: true
+
+Style/BlockComments:
+ Enabled: true
+
+Layout/BlockEndNewline:
+ Enabled: true
+
+Style/CaseEquality:
+ Enabled: true
+
+Style/CharacterLiteral:
+ Enabled: true
+
+Naming/ClassAndModuleCamelCase:
+ Enabled: true
+
+Style/ClassMethods:
+ Enabled: true
+
+Style/ClassVars:
+ Enabled: true
+
+Layout/ClosingParenthesisIndentation:
+ Enabled: true
+
+Style/ColonMethodCall:
+ Enabled: true
+
+Layout/CommentIndentation:
+ Enabled: true
+
+Naming/ConstantName:
+ Enabled: true
+
+Style/DateTime:
+ Enabled: true
+
+Style/DefWithParentheses:
+ Enabled: true
+
+Style/EachForSimpleLoop:
+ Enabled: true
+
+Style/EachWithObject:
+ Enabled: true
+
+Layout/ElseAlignment:
+ Enabled: true
+
+Style/EmptyCaseCondition:
+ Enabled: true
+
+Layout/EmptyLines:
+ Enabled: true
+
+Layout/EmptyLinesAroundAccessModifier:
+ Enabled: true
+
+Layout/EmptyLinesAroundMethodBody:
+ Enabled: true
+
+Style/EmptyLiteral:
+ Enabled: true
+
+Style/EndBlock:
+ Enabled: true
+
+Layout/EndOfLine:
+ Enabled: true
+
+Style/EvenOdd:
+ Enabled: true
+
+Layout/InitialIndentation:
+ Enabled: true
+
+Lint/FlipFlop:
+ Enabled: true
+
+Style/IfInsideElse:
+ Enabled: true
+
+Style/IfUnlessModifierOfIfUnless:
+ Enabled: true
+
+Style/IfWithSemicolon:
+ Enabled: true
+
+Style/IdenticalConditionalBranches:
+ Enabled: true
+
+Style/InfiniteLoop:
+ Enabled: true
+
+Layout/LeadingCommentSpace:
+ Enabled: true
+
+Style/LineEndConcatenation:
+ Enabled: true
+
+Style/MethodCallWithoutArgsParentheses:
+ Enabled: true
+
+Style/MethodMissingSuper:
+ Enabled: true
+
+Style/MissingRespondToMissing:
+ Enabled: true
+
+Layout/MultilineBlockLayout:
+ Enabled: true
+
+Style/MultilineIfThen:
+ Enabled: true
+
+Style/MultilineMemoization:
+ Enabled: true
+
+Style/MultilineTernaryOperator:
+ Enabled: true
+
+Style/NegatedIf:
+ Enabled: true
+
+Style/NegatedWhile:
+ Enabled: true
+
+Style/NestedModifier:
+ Enabled: true
+
+Style/NestedParenthesizedCalls:
+ Enabled: true
+
+Style/NestedTernaryOperator:
+ Enabled: true
+
+Style/NilComparison:
+ Enabled: true
+
+Style/Not:
+ Enabled: true
+
+Style/OneLineConditional:
+ Enabled: true
+
+Naming/BinaryOperatorParameterName:
+ Enabled: true
+
+Style/OptionalArguments:
+ Enabled: true
+
+Style/ParallelAssignment:
+ Enabled: true
+
+Style/PerlBackrefs:
+ Enabled: true
+
+Style/Proc:
+ Enabled: true
+
+Style/RedundantBegin:
+ Enabled: true
+
+Style/RedundantException:
+ Enabled: true
+
+Style/RedundantFreeze:
+ Enabled: true
+
+Style/RedundantParentheses:
+ Enabled: true
+
+Style/RedundantSelf:
+ Enabled: true
+
+Style/RedundantSortBy:
+ Enabled: true
+
+Layout/RescueEnsureAlignment:
+ Enabled: true
+
+Style/RescueModifier:
+ Enabled: true
+
+Style/Sample:
+ Enabled: true
+
+Style/SelfAssignment:
+ Enabled: true
+
+Layout/SpaceAfterColon:
+ Enabled: true
+
+Layout/SpaceAfterComma:
+ Enabled: true
+
+Layout/SpaceAfterMethodName:
+ Enabled: true
+
+Layout/SpaceAfterNot:
+ Enabled: true
+
+Layout/SpaceAfterSemicolon:
+ Enabled: true
+
+Layout/SpaceBeforeComma:
+ Enabled: true
+
+Layout/SpaceBeforeComment:
+ Enabled: true
+
+Layout/SpaceBeforeSemicolon:
+ Enabled: true
+
+Layout/SpaceAroundKeyword:
+ Enabled: true
+
+Layout/SpaceInsideArrayPercentLiteral:
+ Enabled: true
+
+Layout/SpaceInsidePercentLiteralDelimiters:
+ Enabled: true
+
+Layout/SpaceInsideArrayLiteralBrackets:
+ Enabled: true
+
+Layout/SpaceInsideParens:
+ Enabled: true
+
+Layout/SpaceInsideRangeLiteral:
+ Enabled: true
+
+Style/SymbolLiteral:
+ Enabled: true
+
+Layout/Tab:
+ Enabled: true
+
+Layout/TrailingWhitespace:
+ Enabled: true
+
+Style/UnlessElse:
+ Enabled: true
+
+Style/UnneededCapitalW:
+ Enabled: true
+
+Style/UnneededInterpolation:
+ Enabled: true
+
+Style/UnneededPercentQ:
+ Enabled: true
+
+Style/VariableInterpolation:
+ Enabled: true
+
+Style/WhenThen:
+ Enabled: true
+
+Style/WhileUntilDo:
+ Enabled: true
+
+Style/ZeroLengthPredicate:
+ Enabled: true
+
+Layout/IndentHeredoc:
+ EnforcedStyle: squiggly
+
+Lint/AmbiguousOperator:
+ Enabled: true
+
+Lint/AmbiguousRegexpLiteral:
+ Enabled: true
+
+Lint/CircularArgumentReference:
+ Enabled: true
+
+Layout/ConditionPosition:
+ Enabled: true
+
+Lint/Debugger:
+ Enabled: true
+
+Lint/DeprecatedClassMethods:
+ Enabled: true
+
+Lint/DuplicateMethods:
+ Enabled: true
+
+Lint/DuplicatedKey:
+ Enabled: true
+
+Lint/EachWithObjectArgument:
+ Enabled: true
+
+Lint/ElseLayout:
+ Enabled: true
+
+Lint/EmptyEnsure:
+ Enabled: true
+
+Lint/EmptyInterpolation:
+ Enabled: true
+
+Lint/EndInMethod:
+ Enabled: true
+
+Lint/EnsureReturn:
+ Enabled: true
+
+Lint/FloatOutOfRange:
+ Enabled: true
+
+Lint/FormatParameterMismatch:
+ Enabled: true
+
+Lint/HandleExceptions:
+ Enabled: true
+
+Lint/ImplicitStringConcatenation:
+ Description: Checks for adjacent string literals on the same line, which could
+ better be represented as a single string literal.
+
+Lint/IneffectiveAccessModifier:
+ Description: Checks for attempts to use `private` or `protected` to set the visibility
+ of a class method, which does not work.
+
+Lint/LiteralAsCondition:
+ Enabled: true
+
+Lint/LiteralInInterpolation:
+ Enabled: true
+
+Lint/Loop:
+ Description: Use Kernel#loop with break rather than begin/end/until or begin/end/while
+ for post-loop tests.
+
+Lint/NestedMethodDefinition:
+ Enabled: true
+
+Lint/NextWithoutAccumulator:
+ Description: Do not omit the accumulator when calling `next` in a `reduce`/`inject`
+ block.
+
+Lint/NonLocalExitFromIterator:
+ Enabled: true
+
+Lint/ParenthesesAsGroupedExpression:
+ Enabled: true
+
+Lint/PercentStringArray:
+ Enabled: true
+
+Lint/PercentSymbolArray:
+ Enabled: true
+
+Lint/RandOne:
+ Description: Checks for `rand(1)` calls. Such calls always return `0` and most
+ likely a mistake.
+
+Lint/RequireParentheses:
+ Enabled: true
+
+Lint/RescueException:
+ Enabled: true
+
+Lint/ShadowedException:
+ Enabled: true
+
+Lint/ShadowingOuterLocalVariable:
+ Enabled: true
+
+Lint/StringConversionInInterpolation:
+ Enabled: true
+
+Lint/UnderscorePrefixedVariableName:
+ Enabled: true
+
+Lint/UnifiedInteger:
+ Enabled: true
+
+Lint/UnneededCopDisableDirective:
+ Enabled: true
+
+Lint/UnneededCopEnableDirective:
+ Enabled: true
+
+Lint/UnneededSplatExpansion:
+ Enabled: true
+
+Lint/UnreachableCode:
+ Enabled: true
+
+Lint/UselessAccessModifier:
+ ContextCreatingMethods: []
+
+Lint/UselessAssignment:
+ Enabled: true
+
+Lint/UselessComparison:
+ Enabled: true
+
+Lint/UselessElseWithoutRescue:
+ Enabled: true
+
+Lint/UselessSetterCall:
+ Enabled: true
+
+Lint/Void:
+ Enabled: true
+
+Security/Eval:
+ Enabled: true
+
+Security/JSONLoad:
+ Enabled: true
+
+Security/Open:
+ Enabled: true
+
+Lint/BigDecimalNew:
+ Enabled: true
+
+Style/Strip:
+ Enabled: true
+
+Style/TrailingBodyOnClass:
+ Enabled: true
+
+Style/TrailingBodyOnModule:
+ Enabled: true
+
+Style/TrailingCommaInArrayLiteral:
+ EnforcedStyleForMultiline: comma
+ Enabled: true
+
+Style/TrailingCommaInHashLiteral:
+ EnforcedStyleForMultiline: comma
+ Enabled: true
+
+Layout/SpaceInsideReferenceBrackets:
+ EnforcedStyle: no_space
+ EnforcedStyleForEmptyBrackets: no_space
+ Enabled: true
+
+Style/ModuleFunction:
+ EnforcedStyle: extend_self
+
+Lint/OrderedMagicComments:
+ Enabled: true
diff --git a/.rubocop.yml b/.rubocop.yml
index 671f076..6b9aa9f 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -1,6 +1,6 @@
inherit_from:
+ - https://shopify.github.io/ruby-style-guide/rubocop.yml
- .rubocop_todo.yml
- - ./.rubocop_todo.yml
require: rubocop-performance
@@ -9,124 +9,8 @@ Performance:
AllCops:
Exclude:
- - 'performance/shopify/*'
- 'vendor/bundle/**/*'
- - 'pkg/**'
-
-Metrics/BlockNesting:
- Max: 3
-
-Metrics/ModuleLength:
- Enabled: false
-
-Metrics/ClassLength:
- Enabled: false
-
-Lint/AssignmentInCondition:
- Enabled: false
-
-Lint/AmbiguousOperator:
- Enabled: false
-
-Lint/AmbiguousRegexpLiteral:
- Enabled: false
-
-Lint/ParenthesesAsGroupedExpression:
- Enabled: false
-
-Lint/UnusedBlockArgument:
- Enabled: false
-
-Layout/EndAlignment:
- EnforcedStyleAlignWith: variable
-
-Lint/UnusedMethodArgument:
- Enabled: false
-
-Style/SingleLineBlockParams:
- Enabled: false
-
-Style/DoubleNegation:
- Enabled: false
-
-Style/StringLiteralsInInterpolation:
- Enabled: false
-
-Style/AndOr:
- Enabled: false
-
-Style/SignalException:
- Enabled: false
-
-Style/StringLiterals:
- Enabled: false
-
-Style/BracesAroundHashParameters:
- Enabled: false
-
-Style/NumericLiterals:
- Enabled: false
-
-Layout/SpaceInsideArrayLiteralBrackets:
- Enabled: false
-
-Layout/SpaceBeforeBlockBraces:
- Enabled: false
-
-Style/Documentation:
- Enabled: false
-
-Style/ClassAndModuleChildren:
- Enabled: false
-
-Style/TrailingCommaInArrayLiteral:
- Enabled: false
-
-Style/TrailingCommaInHashLiteral:
- Enabled: false
-
-Style/FormatString:
- Enabled: false
-
-Layout/AlignParameters:
- EnforcedStyle: with_fixed_indentation
-
-Layout/MultilineOperationIndentation:
- EnforcedStyle: indented
-
-Style/IfUnlessModifier:
- Enabled: false
-
-Style/RaiseArgs:
- Enabled: false
-
-Style/PreferredHashMethods:
- Enabled: false
-
-Style/RegexpLiteral:
- Enabled: false
-
-Style/SymbolLiteral:
- Enabled: false
-
-Naming/ConstantName:
- Enabled: false
-
-Layout/CaseIndentation:
- Enabled: false
-
-Style/ClassVars:
- Enabled: false
-
-Style/PerlBackrefs:
- Enabled: false
-
-Style/TrivialAccessors:
- AllowPredicates: true
-
-Style/WordArray:
- Enabled: false
-
+
Naming/MethodName:
Exclude:
- - 'example/server/liquid_servlet.rb'
+ - 'example/server/liquid_servlet.rb'
\ No newline at end of file
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 992d135..22330ae 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -1,34 +1,12 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
-# on 2019-08-29 00:43:36 +1000 using RuboCop version 0.74.0.
+# on 2019-08-29 12:16:25 +1000 using RuboCop version 0.74.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
-# Offense count: 1
-# Cop supports --auto-correct.
-# Configuration parameters: TreatCommentsAsGroupSeparators, Include.
-# Include: **/*.gemspec
-Gemspec/OrderedDependencies:
- Exclude:
- - 'liquid.gemspec'
-
-# Offense count: 1
-# Configuration parameters: Include.
-# Include: **/*.gemspec,
-Gemspec/RequiredRubyVersion:
- Exclude:
- - 'liquid.gemspec'
-
-# Offense count: 124
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, IndentationWidth.
-# SupportedStyles: with_first_argument, with_fixed_indentation
-Layout/AlignArguments:
- Enabled: false
-
-# Offense count: 7
+# Offense count: 13
# Cop supports --auto-correct.
# Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle.
# SupportedHashRocketStyles: key, separator, table
@@ -38,32 +16,17 @@ Layout/AlignHash:
Exclude:
- 'lib/liquid/condition.rb'
- 'lib/liquid/expression.rb'
+ - 'performance/shopify/comment_form.rb'
+ - 'performance/shopify/database.rb'
+ - 'performance/shopify/paginate.rb'
- 'test/unit/context_unit_test.rb'
-# Offense count: 6
+# Offense count: 3
# Cop supports --auto-correct.
-Layout/ClosingHeredocIndentation:
+# Configuration parameters: AllowForAlignment, AllowBeforeTrailingComments, ForceEqualSignAlignment.
+Layout/ExtraSpacing:
Exclude:
- - 'test/integration/tags/for_tag_test.rb'
-
-# Offense count: 27
-# Cop supports --auto-correct.
-Layout/EmptyLineAfterGuardClause:
- Exclude:
- - 'lib/liquid/block.rb'
- - 'lib/liquid/block_body.rb'
- - 'lib/liquid/context.rb'
- - 'lib/liquid/drop.rb'
- - 'lib/liquid/lexer.rb'
- - 'lib/liquid/parser.rb'
- - 'lib/liquid/standardfilters.rb'
- - 'lib/liquid/strainer.rb'
- - 'lib/liquid/tags/for.rb'
- - 'lib/liquid/tags/if.rb'
- - 'lib/liquid/tags/include.rb'
- - 'lib/liquid/utils.rb'
- - 'lib/liquid/variable.rb'
- - 'lib/liquid/variable_lookup.rb'
+ - 'performance/shopify/paginate.rb'
# Offense count: 5
# Cop supports --auto-correct.
@@ -83,12 +46,61 @@ Layout/MultilineMethodCallBraceLayout:
- 'test/integration/error_handling_test.rb'
- 'test/unit/strainer_unit_test.rb'
-# Offense count: 1
+# Offense count: 4
# Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment.
Layout/SpaceAroundOperators:
Exclude:
- 'lib/liquid/condition.rb'
+ - 'performance/shopify/paginate.rb'
+
+# Offense count: 9
+# Cop supports --auto-correct.
+# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces.
+# SupportedStyles: space, no_space
+# SupportedStylesForEmptyBraces: space, no_space
+Layout/SpaceBeforeBlockBraces:
+ Exclude:
+ - 'example/server/server.rb'
+ - 'lib/liquid/variable.rb'
+ - 'test/integration/drop_test.rb'
+ - 'test/integration/standard_filter_test.rb'
+ - 'test/integration/tags/if_else_tag_test.rb'
+
+# Offense count: 19
+# Cop supports --auto-correct.
+# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBrackets.
+# SupportedStyles: space, no_space, compact
+# SupportedStylesForEmptyBrackets: space, no_space
+Layout/SpaceInsideArrayLiteralBrackets:
+ Exclude:
+ - 'test/integration/drop_test.rb'
+ - 'test/integration/standard_filter_test.rb'
+ - 'test/integration/tags/for_tag_test.rb'
+ - 'test/integration/tags/include_tag_test.rb'
+ - 'test/integration/tags/standard_tag_test.rb'
+ - 'test/unit/context_unit_test.rb'
+
+# Offense count: 2
+Lint/AmbiguousOperator:
+ Exclude:
+ - 'test/unit/condition_unit_test.rb'
+
+# Offense count: 16
+# Configuration parameters: AllowSafeAssignment.
+Lint/AssignmentInCondition:
+ Exclude:
+ - 'lib/liquid/block_body.rb'
+ - 'lib/liquid/lexer.rb'
+ - 'lib/liquid/standardfilters.rb'
+ - 'lib/liquid/tags/for.rb'
+ - 'lib/liquid/tags/if.rb'
+ - 'lib/liquid/tags/include.rb'
+ - 'lib/liquid/tags/raw.rb'
+ - 'lib/liquid/variable.rb'
+ - 'performance/profile.rb'
+ - 'test/test_helper.rb'
+ - 'test/unit/tokenizer_unit_test.rb'
# Offense count: 2
# Cop supports --auto-correct.
@@ -98,87 +110,133 @@ Lint/InheritException:
Exclude:
- 'lib/liquid/interrupts.rb'
+# Offense count: 10
+# Cop supports --auto-correct.
+# Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments.
+Lint/UnusedBlockArgument:
+ Exclude:
+ - 'lib/liquid/condition.rb'
+ - 'lib/liquid/context.rb'
+ - 'lib/liquid/document.rb'
+ - 'lib/liquid/parse_context.rb'
+ - 'lib/liquid/template.rb'
+ - 'performance/shopify/json_filter.rb'
+ - 'test/integration/filter_test.rb'
+ - 'test/integration/render_profiling_test.rb'
+ - 'test/integration/variable_test.rb'
+ - 'test/unit/condition_unit_test.rb'
+
+# Offense count: 12
+# Cop supports --auto-correct.
+# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods.
+Lint/UnusedMethodArgument:
+ Exclude:
+ - 'example/server/liquid_servlet.rb'
+ - 'test/integration/blank_test.rb'
+ - 'test/integration/error_handling_test.rb'
+ - 'test/integration/filter_test.rb'
+ - 'test/integration/output_test.rb'
+ - 'test/integration/standard_filter_test.rb'
+ - 'test/integration/tags/include_tag_test.rb'
+ - 'test/unit/strainer_unit_test.rb'
+
+# Offense count: 2
+Lint/UselessAssignment:
+ Exclude:
+ - 'performance/shopify/database.rb'
+
# Offense count: 1
# Configuration parameters: CheckForMethodsWithNoSideEffects.
Lint/Void:
Exclude:
- 'lib/liquid/parse_context.rb'
-# Offense count: 53
-Metrics/AbcSize:
- Max: 56
-
-# Offense count: 12
-Metrics/CyclomaticComplexity:
- Max: 13
-
-# Offense count: 118
-# Configuration parameters: CountComments, ExcludedMethods.
-Metrics/MethodLength:
- Max: 38
-
-# Offense count: 9
-Metrics/PerceivedComplexity:
- Max: 11
-
-# Offense count: 1
+# Offense count: 95
# Cop supports --auto-correct.
-# Configuration parameters: PreferredName.
-Naming/RescuedExceptionsVariableName:
- Exclude:
- - 'lib/liquid/context.rb'
+# Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
+# URISchemes: http, https
+Metrics/LineLength:
+ Max: 294
-# Offense count: 20
-# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
-# AllowedNames: io, id, to, by, on, in, at, ip, db
-Naming/UncommunicativeMethodParamName:
+# Offense count: 44
+Naming/ConstantName:
Exclude:
- - 'example/server/example_servlet.rb'
- - 'lib/liquid/condition.rb'
- - 'lib/liquid/context.rb'
- - 'lib/liquid/standardfilters.rb'
+ - 'lib/liquid.rb'
+ - 'lib/liquid/block_body.rb'
+ - 'lib/liquid/tags/assign.rb'
+ - 'lib/liquid/tags/capture.rb'
+ - 'lib/liquid/tags/case.rb'
+ - 'lib/liquid/tags/cycle.rb'
+ - 'lib/liquid/tags/for.rb'
- 'lib/liquid/tags/if.rb'
+ - 'lib/liquid/tags/include.rb'
+ - 'lib/liquid/tags/raw.rb'
+ - 'lib/liquid/tags/table_row.rb'
- 'lib/liquid/variable.rb'
+ - 'performance/shopify/comment_form.rb'
+ - 'performance/shopify/paginate.rb'
+ - 'test/integration/tags/include_tag_test.rb'
+
+# Offense count: 2
+# Configuration parameters: .
+# SupportedStyles: snake_case, camelCase
+Naming/MethodName:
+ EnforcedStyle: snake_case
+
+# Offense count: 3
+# Cop supports --auto-correct.
+# Configuration parameters: EnforcedStyle.
+# SupportedStyles: always, conditionals
+Style/AndOr:
+ Exclude:
+ - 'lib/liquid/i18n.rb'
+ - 'lib/liquid/tags/table_row.rb'
+ - 'lib/liquid/tokenizer.rb'
+
+# Offense count: 40
+# Cop supports --auto-correct.
+# Configuration parameters: EnforcedStyle.
+# SupportedStyles: braces, no_braces, context_dependent
+Style/BracesAroundHashParameters:
+ Exclude:
+ - 'test/integration/error_handling_test.rb'
- 'test/integration/filter_test.rb'
+ - 'test/integration/render_profiling_test.rb'
- 'test/integration/standard_filter_test.rb'
+ - 'test/integration/tags/echo_test.rb'
+ - 'test/integration/tags/increment_tag_test.rb'
+ - 'test/integration/tags/standard_tag_test.rb'
- 'test/integration/template_test.rb'
- 'test/unit/condition_unit_test.rb'
+ - 'test/unit/context_unit_test.rb'
# Offense count: 5
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: inline, group
-Style/AccessModifierDeclarations:
+Style/ClassVars:
Exclude:
- - 'lib/liquid/block_body.rb'
- - 'lib/liquid/tag.rb'
- - 'lib/liquid/tags/include.rb'
- - 'test/unit/strainer_unit_test.rb'
+ - 'lib/liquid/condition.rb'
+ - 'lib/liquid/strainer.rb'
+ - 'lib/liquid/template.rb'
-# Offense count: 10
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: prefer_alias, prefer_alias_method
-Style/Alias:
- Exclude:
- - 'lib/liquid/drop.rb'
- - 'lib/liquid/i18n.rb'
- - 'lib/liquid/profiler/hooks.rb'
- - 'lib/liquid/standardfilters.rb'
- - 'lib/liquid/tag.rb'
- - 'lib/liquid/tags/include.rb'
- - 'lib/liquid/variable.rb'
-
-# Offense count: 22
-Style/CommentedKeyword:
- Enabled: false
-
-# Offense count: 1
+# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SingleLineConditionsOnly, IncludeTernaryExpressions.
# SupportedStyles: assign_to_condition, assign_inside_condition
Style/ConditionalAssignment:
Exclude:
- 'lib/liquid/errors.rb'
+ - 'performance/shopify/shop_filter.rb'
+
+# Offense count: 1
+# Configuration parameters: AllowCoercion.
+Style/DateTime:
+ Exclude:
+ - 'test/unit/context_unit_test.rb'
+
+# Offense count: 2
+# Cop supports --auto-correct.
+Style/EachWithObject:
+ Exclude:
+ - 'performance/shopify/database.rb'
# Offense count: 1
# Cop supports --auto-correct.
@@ -186,71 +244,50 @@ Style/EmptyCaseCondition:
Exclude:
- 'lib/liquid/lexer.rb'
-# Offense count: 5
+# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
-# SupportedStyles: compact, expanded
-Style/EmptyMethod:
+# SupportedStyles: each, for
+Style/For:
Exclude:
- - 'lib/liquid/tag.rb'
- - 'lib/liquid/tags/comment.rb'
- - 'lib/liquid/tags/include.rb'
- - 'test/integration/tags/include_tag_test.rb'
- - 'test/unit/context_unit_test.rb'
+ - 'performance/shopify/shop_filter.rb'
-# Offense count: 3
+# Offense count: 9
# Cop supports --auto-correct.
-Style/Encoding:
- Exclude:
- - 'lib/liquid/version.rb'
- - 'liquid.gemspec'
- - 'test/integration/standard_filter_test.rb'
-
-# Offense count: 2
-# Cop supports --auto-correct.
-Style/ExpandPathArguments:
- Exclude:
- - 'Rakefile'
- - 'liquid.gemspec'
-
-# Offense count: 7
# Configuration parameters: EnforcedStyle.
-# SupportedStyles: annotated, template, unannotated
-Style/FormatStringToken:
+# SupportedStyles: format, sprintf, percent
+Style/FormatString:
Exclude:
+ - 'example/server/example_servlet.rb'
+ - 'performance/shopify/money_filter.rb'
+ - 'performance/shopify/weight_filter.rb'
- 'test/integration/filter_test.rb'
- 'test/integration/hash_ordering_test.rb'
-# Offense count: 106
+# Offense count: 115
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: always, never
Style/FrozenStringLiteralComment:
Enabled: false
-# Offense count: 14
-# Configuration parameters: MinBodyLength.
-Style/GuardClause:
- Exclude:
- - 'lib/liquid/condition.rb'
- - 'lib/liquid/lexer.rb'
- - 'lib/liquid/strainer.rb'
- - 'lib/liquid/tags/assign.rb'
- - 'lib/liquid/tags/capture.rb'
- - 'lib/liquid/tags/case.rb'
- - 'lib/liquid/tags/for.rb'
- - 'lib/liquid/tags/include.rb'
- - 'lib/liquid/tags/raw.rb'
- - 'lib/liquid/tags/table_row.rb'
- - 'lib/liquid/variable.rb'
- - 'test/unit/tokenizer_unit_test.rb'
-
-# Offense count: 53
+# Offense count: 30
# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: literals, strict
-Style/MutableConstant:
- Enabled: false
+# Configuration parameters: IgnoreMacros, IgnoredMethods, IncludedMacros, AllowParenthesesInMultilineCall, AllowParenthesesInChaining, AllowParenthesesInCamelCaseMethod, EnforcedStyle.
+# SupportedStyles: require_parentheses, omit_parentheses
+Style/MethodCallWithArgsParentheses:
+ Exclude:
+ - 'Gemfile'
+ - 'Rakefile'
+ - 'lib/liquid/block_body.rb'
+ - 'lib/liquid/parser.rb'
+ - 'lib/liquid/tags/for.rb'
+ - 'liquid.gemspec'
+ - 'performance/shopify/database.rb'
+ - 'performance/shopify/liquid.rb'
+ - 'test/test_helper.rb'
+ - 'test/unit/condition_unit_test.rb'
+ - 'test/unit/tags/if_tag_unit_test.rb'
# Offense count: 1
# Cop supports --auto-correct.
@@ -260,29 +297,17 @@ Style/Next:
Exclude:
- 'lib/liquid/tags/for.rb'
-# Offense count: 13
+# Offense count: 52
# Cop supports --auto-correct.
-# Configuration parameters: AutoCorrect, EnforcedStyle, IgnoredMethods.
-# SupportedStyles: predicate, comparison
-Style/NumericPredicate:
- Exclude:
- - 'spec/**/*'
- - 'lib/liquid/context.rb'
- - 'lib/liquid/forloop_drop.rb'
- - 'lib/liquid/standardfilters.rb'
- - 'lib/liquid/tablerowloop_drop.rb'
- - 'test/integration/standard_filter_test.rb'
- - 'test/integration/template_test.rb'
+Style/PerlBackrefs:
+ Enabled: false
-# Offense count: 14
+# Offense count: 33
# Cop supports --auto-correct.
-# Configuration parameters: PreferredDelimiters.
-Style/PercentLiteralDelimiters:
- Exclude:
- - 'lib/liquid/tags/if.rb'
- - 'liquid.gemspec'
- - 'test/integration/assign_test.rb'
- - 'test/integration/standard_filter_test.rb'
+# Configuration parameters: EnforcedStyle.
+# SupportedStyles: compact, exploded
+Style/RaiseArgs:
+ Enabled: false
# Offense count: 1
# Cop supports --auto-correct.
@@ -290,6 +315,17 @@ Style/RedundantSelf:
Exclude:
- 'lib/liquid/strainer.rb'
+# Offense count: 5
+# Cop supports --auto-correct.
+# Configuration parameters: EnforcedStyle, AllowInnerSlashes.
+# SupportedStyles: slashes, percent_r, mixed
+Style/RegexpLiteral:
+ Exclude:
+ - 'lib/liquid/file_system.rb'
+ - 'lib/liquid/standardfilters.rb'
+ - 'performance/shopify/shop_filter.rb'
+ - 'test/unit/condition_unit_test.rb'
+
# Offense count: 3
# Cop supports --auto-correct.
# Configuration parameters: ConvertCodeThatCanStartToReturnNil, Whitelist.
@@ -300,21 +336,31 @@ Style/SafeNavigation:
- 'lib/liquid/strainer.rb'
- 'lib/liquid/tokenizer.rb'
-# Offense count: 9
+# Offense count: 10
# Cop supports --auto-correct.
# Configuration parameters: AllowAsExpressionSeparator.
Style/Semicolon:
Exclude:
+ - 'performance/shopify/database.rb'
- 'test/integration/error_handling_test.rb'
- 'test/integration/template_test.rb'
- 'test/unit/context_unit_test.rb'
-# Offense count: 7
+# Offense count: 1
# Cop supports --auto-correct.
-# Configuration parameters: MinSize.
-# SupportedStyles: percent, brackets
-Style/SymbolArray:
- EnforcedStyle: brackets
+# Configuration parameters: EnforcedStyle.
+# SupportedStyles: use_perl_names, use_english_names
+Style/SpecialGlobalVars:
+ Exclude:
+ - 'performance/shopify/liquid.rb'
+
+# Offense count: 2
+# Cop supports --auto-correct.
+# Configuration parameters: EnforcedStyle.
+# SupportedStyles: single_quotes, double_quotes
+Style/StringLiteralsInInterpolation:
+ Exclude:
+ - 'performance/shopify/tag_filter.rb'
# Offense count: 2
# Cop supports --auto-correct.
@@ -325,6 +371,33 @@ Style/TernaryParentheses:
- 'lib/liquid/context.rb'
- 'lib/liquid/utils.rb'
+# Offense count: 21
+# Cop supports --auto-correct.
+# Configuration parameters: EnforcedStyleForMultiline.
+# SupportedStylesForMultiline: comma, consistent_comma, no_comma
+Style/TrailingCommaInArrayLiteral:
+ Exclude:
+ - 'lib/liquid/parse_tree_visitor.rb'
+ - 'lib/liquid/tags/include.rb'
+ - 'test/integration/parse_tree_visitor_test.rb'
+ - 'test/integration/standard_filter_test.rb'
+
+# Offense count: 9
+# Cop supports --auto-correct.
+# Configuration parameters: EnforcedStyleForMultiline.
+# SupportedStylesForMultiline: comma, consistent_comma, no_comma
+Style/TrailingCommaInHashLiteral:
+ Exclude:
+ - 'lib/liquid/condition.rb'
+ - 'lib/liquid/lexer.rb'
+ - 'lib/liquid/standardfilters.rb'
+ - 'performance/shopify/comment_form.rb'
+ - 'performance/shopify/database.rb'
+ - 'performance/shopify/paginate.rb'
+ - 'performance/theme_runner.rb'
+ - 'test/integration/output_test.rb'
+ - 'test/unit/context_unit_test.rb'
+
# Offense count: 2
# Cop supports --auto-correct.
Style/UnneededPercentQ:
@@ -336,10 +409,3 @@ Style/UnneededPercentQ:
Style/WhileUntilModifier:
Exclude:
- 'lib/liquid/tags/case.rb'
-
-# Offense count: 665
-# Cop supports --auto-correct.
-# Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
-# URISchemes: http, https
-Metrics/LineLength:
- Max: 294
From d338ccb9a631a4f021de91272e3972d586061584 Mon Sep 17 00:00:00 2001
From: Samuel
Date: Mon, 22 Jul 2019 11:38:23 -0400
Subject: [PATCH 52/74] Add isolated subcontexts
An isolated subcontext inherits the environment, filters,
and static registers of its supercontext, but with a fresh
(isolated) scope.
This will pave the way for adding the `render` tag, which renders
templates in such a subcontext.
---
lib/liquid/context.rb | 22 +-
lib/liquid/tags/render.rb | 89 ++++++++
test/integration/tags/render_rag_test.rb | 255 +++++++++++++++++++++++
test/integration/tags/render_tag_test.rb | 230 ++++++++++++++++++++
test/unit/context_unit_test.rb | 58 ++++++
5 files changed, 652 insertions(+), 2 deletions(-)
create mode 100644 lib/liquid/tags/render.rb
create mode 100644 test/integration/tags/render_rag_test.rb
create mode 100644 test/integration/tags/render_tag_test.rb
diff --git a/lib/liquid/context.rb b/lib/liquid/context.rb
index 2dcc6af..a05cdaa 100644
--- a/lib/liquid/context.rb
+++ b/lib/liquid/context.rb
@@ -12,13 +12,18 @@ module Liquid
#
# context['bob'] #=> nil class Context
class Context
- attr_reader :scopes, :errors, :registers, :environments, :resource_limits
+ attr_reader :scopes, :errors, :registers, :environments, :resource_limits, :static_registers
attr_accessor :exception_renderer, :template_name, :partial, :global_filter, :strict_variables, :strict_filters
- def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = nil)
+ def self.build(environments: {}, outer_scope: {}, registers: {}, rethrow_errors: false, resource_limits: nil, static_registers: {})
+ new(environments, outer_scope, registers, rethrow_errors, resource_limits, static_registers)
+ end
+
+ def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = nil, static_registers = {})
@environments = [environments].flatten
@scopes = [(outer_scope || {})]
@registers = registers
+ @static_registers = static_registers.tap(&:freeze)
@errors = []
@partial = false
@strict_variables = false
@@ -126,6 +131,19 @@ module Liquid
@this_stack_used = old_stack_used
end
+ # Creates a new context inheriting resource limits, filters, environment etc.,
+ # but with an isolated scope.
+ def new_isolated_subcontext
+ Context.build(
+ environments: environments,
+ resource_limits: resource_limits,
+ static_registers: static_registers
+ ).tap do |subcontext|
+ subcontext.exception_renderer = exception_renderer
+ subcontext.add_filters(@filters)
+ end
+ end
+
def clear_instance_assigns
@scopes[0] = {}
end
diff --git a/lib/liquid/tags/render.rb b/lib/liquid/tags/render.rb
new file mode 100644
index 0000000..f0f6f10
--- /dev/null
+++ b/lib/liquid/tags/render.rb
@@ -0,0 +1,89 @@
+module Liquid
+ #
+ # TODO: docs
+ #
+ class Render < Tag
+ Syntax = /(#{QuotedFragment}+)/o
+
+ attr_reader :template_name_expr, :attributes
+
+ def initialize(tag_name, markup, options)
+ super
+
+ if markup =~ Syntax
+ template_name = $1
+
+ @template_name_expr = Expression.parse(template_name)
+
+ @attributes = {}
+ markup.scan(TagAttributes) do |key, value|
+ @attributes[key] = Expression.parse(value)
+ end
+
+ else
+ raise SyntaxError.new(options[:locale].t("errors.syntax.include".freeze))
+ end
+ end
+
+ def parse(_tokens)
+ end
+
+ def render_to_output_buffer(context, output)
+ template_name = context.evaluate(@template_name_expr)
+ raise ArgumentError.new(options[:locale].t("errors.argument.include")) unless template_name
+
+ partial = load_cached_partial(template_name, context)
+
+ inner_context = Context.new
+ inner_context.template_name = template_name
+ inner_context.partial = true
+ @attributes.each do |key, value|
+ inner_context[key] = context.evaluate(value)
+ end
+ partial.render_to_output_buffer(inner_context, output)
+
+ # TODO: Put into a new #isolated_stack method in Context?
+ inner_context.errors.each { |e| context.errors << e }
+
+ output
+ end
+
+ private
+
+ alias_method :parse_context, :options
+ private :parse_context
+
+ def load_cached_partial(template_name, context)
+ cached_partials = context.registers[:cached_partials] || {}
+
+ if cached = cached_partials[template_name]
+ return cached
+ end
+ source = read_template_from_file_system(context)
+ begin
+ parse_context.partial = true
+ partial = Liquid::Template.parse(source, parse_context)
+ ensure
+ parse_context.partial = false
+ end
+ cached_partials[template_name] = partial
+ context.registers[:cached_partials] = cached_partials
+ partial
+ end
+
+ def read_template_from_file_system(context)
+ file_system = context.registers[:file_system] || Liquid::Template.file_system
+ file_system.read_template_file(context.evaluate(@template_name_expr))
+ end
+
+ class ParseTreeVisitor < Liquid::ParseTreeVisitor
+ def children
+ [
+ @node.template_name_expr,
+ ] + @node.attributes.values
+ end
+ end
+ end
+
+ Template.register_tag('render'.freeze, Render)
+end
diff --git a/test/integration/tags/render_rag_test.rb b/test/integration/tags/render_rag_test.rb
new file mode 100644
index 0000000..2352bc1
--- /dev/null
+++ b/test/integration/tags/render_rag_test.rb
@@ -0,0 +1,255 @@
+require 'test_helper'
+
+class TestFileSystem
+ def read_template_file(template_path)
+ case template_path
+ when "product"
+ "Product: {{ product.title }} "
+
+ when "locale_variables"
+ "Locale: {{echo1}} {{echo2}}"
+
+ when "variant"
+ "Variant: {{ variant.title }}"
+
+ when "nested_template"
+ "{% include 'header' %} {% include 'body' %} {% include 'footer' %}"
+
+ when "body"
+ "body {% include 'body_detail' %}"
+
+ when "nested_product_template"
+ "Product: {{ nested_product_template.title }} {%include 'details'%} "
+
+ when "recursively_nested_template"
+ "-{% include 'recursively_nested_template' %}"
+
+ when "pick_a_source"
+ "from TestFileSystem"
+
+ when 'assignments'
+ "{% assign foo = 'bar' %}"
+
+ when 'break'
+ "{% break %}"
+
+ else
+ template_path
+ end
+ end
+end
+
+class OtherFileSystem
+ def read_template_file(template_path)
+ 'from OtherFileSystem'
+ end
+end
+
+class CountingFileSystem
+ attr_reader :count
+ def read_template_file(template_path)
+ @count ||= 0
+ @count += 1
+ 'from CountingFileSystem'
+ end
+end
+
+class CustomInclude < Liquid::Tag
+ Syntax = /(#{Liquid::QuotedFragment}+)(\s+(?:with|for)\s+(#{Liquid::QuotedFragment}+))?/o
+
+ def initialize(tag_name, markup, tokens)
+ markup =~ Syntax
+ @template_name = $1
+ super
+ end
+
+ def parse(tokens)
+ end
+
+ def render_to_output_buffer(context, output)
+ output << @template_name[1..-2]
+ output
+ end
+end
+
+class IncludeTagTest < Minitest::Test
+ include Liquid
+
+ def setup
+ Liquid::Template.file_system = TestFileSystem.new
+ end
+
+ def test_include_tag_looks_for_file_system_in_registers_first
+ assert_equal 'from OtherFileSystem',
+ Template.parse("{% include 'pick_a_source' %}").render!({}, registers: { file_system: OtherFileSystem.new })
+ end
+
+ def test_include_tag_with
+ assert_template_result "Product: Draft 151cm ",
+ "{% include 'product' with products[0] %}", "products" => [ { 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' } ]
+ end
+
+ def test_include_tag_with_default_name
+ assert_template_result "Product: Draft 151cm ",
+ "{% include 'product' %}", "product" => { 'title' => 'Draft 151cm' }
+ end
+
+ def test_include_tag_for
+ assert_template_result "Product: Draft 151cm Product: Element 155cm ",
+ "{% include 'product' for products %}", "products" => [ { 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' } ]
+ end
+
+ def test_include_tag_with_local_variables
+ assert_template_result "Locale: test123 ", "{% include 'locale_variables' echo1: 'test123' %}"
+ end
+
+ def test_include_tag_with_multiple_local_variables
+ assert_template_result "Locale: test123 test321",
+ "{% include 'locale_variables' echo1: 'test123', echo2: 'test321' %}"
+ end
+
+ def test_include_tag_with_multiple_local_variables_from_context
+ assert_template_result "Locale: test123 test321",
+ "{% include 'locale_variables' echo1: echo1, echo2: more_echos.echo2 %}",
+ 'echo1' => 'test123', 'more_echos' => { "echo2" => 'test321' }
+ end
+
+ def test_included_templates_assigns_variables
+ assert_template_result "bar", "{% include 'assignments' %}{{ foo }}"
+ end
+
+ def test_nested_include_tag
+ assert_template_result "body body_detail", "{% include 'body' %}"
+
+ assert_template_result "header body body_detail footer", "{% include 'nested_template' %}"
+ end
+
+ def test_nested_include_with_variable
+ assert_template_result "Product: Draft 151cm details ",
+ "{% include 'nested_product_template' with product %}", "product" => { "title" => 'Draft 151cm' }
+
+ assert_template_result "Product: Draft 151cm details Product: Element 155cm details ",
+ "{% include 'nested_product_template' for products %}", "products" => [{ "title" => 'Draft 151cm' }, { "title" => 'Element 155cm' }]
+ end
+
+ def test_recursively_included_template_does_not_produce_endless_loop
+ infinite_file_system = Class.new do
+ def read_template_file(template_path)
+ "-{% include 'loop' %}"
+ end
+ end
+
+ Liquid::Template.file_system = infinite_file_system.new
+
+ assert_raises(Liquid::StackLevelError) do
+ Template.parse("{% include 'loop' %}").render!
+ end
+ end
+
+ def test_dynamically_choosen_template
+ assert_template_result "Test123", "{% include template %}", "template" => 'Test123'
+ assert_template_result "Test321", "{% include template %}", "template" => 'Test321'
+
+ assert_template_result "Product: Draft 151cm ", "{% include template for product %}",
+ "template" => 'product', 'product' => { 'title' => 'Draft 151cm' }
+ end
+
+ def test_include_tag_caches_second_read_of_same_partial
+ file_system = CountingFileSystem.new
+ assert_equal 'from CountingFileSystemfrom CountingFileSystem',
+ Template.parse("{% include 'pick_a_source' %}{% include 'pick_a_source' %}").render!({}, registers: { file_system: file_system })
+ assert_equal 1, file_system.count
+ end
+
+ def test_include_tag_doesnt_cache_partials_across_renders
+ file_system = CountingFileSystem.new
+ assert_equal 'from CountingFileSystem',
+ Template.parse("{% include 'pick_a_source' %}").render!({}, registers: { file_system: file_system })
+ assert_equal 1, file_system.count
+
+ assert_equal 'from CountingFileSystem',
+ Template.parse("{% include 'pick_a_source' %}").render!({}, registers: { file_system: file_system })
+ assert_equal 2, file_system.count
+ end
+
+ def test_include_tag_within_if_statement
+ assert_template_result "foo_if_true", "{% if true %}{% include 'foo_if_true' %}{% endif %}"
+ end
+
+ def test_custom_include_tag
+ original_tag = Liquid::Template.tags['include']
+ Liquid::Template.tags['include'] = CustomInclude
+ begin
+ assert_equal "custom_foo",
+ Template.parse("{% include 'custom_foo' %}").render!
+ ensure
+ Liquid::Template.tags['include'] = original_tag
+ end
+ end
+
+ def test_custom_include_tag_within_if_statement
+ original_tag = Liquid::Template.tags['include']
+ Liquid::Template.tags['include'] = CustomInclude
+ begin
+ assert_equal "custom_foo_if_true",
+ Template.parse("{% if true %}{% include 'custom_foo_if_true' %}{% endif %}").render!
+ ensure
+ Liquid::Template.tags['include'] = original_tag
+ end
+ end
+
+ def test_does_not_add_error_in_strict_mode_for_missing_variable
+ Liquid::Template.file_system = TestFileSystem.new
+
+ a = Liquid::Template.parse(' {% include "nested_template" %}')
+ a.render!
+ assert_empty a.errors
+ end
+
+ def test_passing_options_to_included_templates
+ assert_raises(Liquid::SyntaxError) do
+ Template.parse("{% include template %}", error_mode: :strict).render!("template" => '{{ "X" || downcase }}')
+ end
+ with_error_mode(:lax) do
+ assert_equal 'x', Template.parse("{% include template %}", error_mode: :strict, include_options_blacklist: true).render!("template" => '{{ "X" || downcase }}')
+ end
+ assert_raises(Liquid::SyntaxError) do
+ Template.parse("{% include template %}", error_mode: :strict, include_options_blacklist: [:locale]).render!("template" => '{{ "X" || downcase }}')
+ end
+ with_error_mode(:lax) do
+ assert_equal 'x', Template.parse("{% include template %}", error_mode: :strict, include_options_blacklist: [:error_mode]).render!("template" => '{{ "X" || downcase }}')
+ end
+ end
+
+ def test_render_raise_argument_error_when_template_is_undefined
+ assert_raises(Liquid::ArgumentError) do
+ template = Liquid::Template.parse('{% include undefined_variable %}')
+ template.render!
+ end
+ assert_raises(Liquid::ArgumentError) do
+ template = Liquid::Template.parse('{% include nil %}')
+ template.render!
+ end
+ end
+
+ def test_including_via_variable_value
+ assert_template_result "from TestFileSystem", "{% assign page = 'pick_a_source' %}{% include page %}"
+
+ assert_template_result "Product: Draft 151cm ", "{% assign page = 'product' %}{% include page %}", "product" => { 'title' => 'Draft 151cm' }
+
+ assert_template_result "Product: Draft 151cm ", "{% assign page = 'product' %}{% include page for foo %}", "foo" => { 'title' => 'Draft 151cm' }
+ end
+
+ def test_including_with_strict_variables
+ template = Liquid::Template.parse("{% include 'simple' %}", error_mode: :warn)
+ template.render(nil, strict_variables: true)
+
+ assert_equal [], template.errors
+ end
+
+ def test_break_through_include
+ assert_template_result "1", "{% for i in (1..3) %}{{ i }}{% break %}{{ i }}{% endfor %}"
+ assert_template_result "1", "{% for i in (1..3) %}{{ i }}{% include 'break' %}{{ i }}{% endfor %}"
+ end
+end # IncludeTagTest
+
diff --git a/test/integration/tags/render_tag_test.rb b/test/integration/tags/render_tag_test.rb
new file mode 100644
index 0000000..928dc38
--- /dev/null
+++ b/test/integration/tags/render_tag_test.rb
@@ -0,0 +1,230 @@
+require 'test_helper'
+
+class StubFileSystem
+ def initialize(values)
+ @values = values
+ end
+
+ def read_template_file(template_path)
+ @values.fetch(template_path)
+ end
+end
+
+class RenderTagTest < Minitest::Test
+ include Liquid
+
+ def test_render_with_no_arguments
+ Liquid::Template.file_system = StubFileSystem.new('source' => 'rendered content')
+ assert_template_result 'rendered content', "{% render 'source' %}"
+ end
+
+ def test_render_tag_looks_for_file_system_in_registers_first
+ file_system = StubFileSystem.new('pick_a_source' => 'from register file system')
+ assert_equal 'from register file system',
+ Template.parse("{% render 'pick_a_source' %}").render!({}, registers: { file_system: file_system })
+ end
+
+ def test_render_passes_named_arguments_into_inner_scope
+ Liquid::Template.file_system = StubFileSystem.new('product' => '{{ inner_product.title }}')
+ assert_template_result 'My Product', "{% render 'product', inner_product: outer_product %}",
+ 'outer_product' => { 'title' => 'My Product' }
+ end
+
+ def test_render_accepts_literals_as_arguments
+ Liquid::Template.file_system = StubFileSystem.new('snippet' => '{{ price }}')
+ assert_template_result '123', "{% render 'snippet', price: 123 %}"
+ end
+
+ def test_render_accepts_multiple_named_arguments
+ Liquid::Template.file_system = StubFileSystem.new('snippet' => '{{ one }} {{ two }}')
+ assert_template_result '1 2', "{% render 'snippet', one: 1, two: 2 %}"
+ end
+
+ def test_render_does_inherit_parent_scope_variables
+ Liquid::Template.file_system = StubFileSystem.new('snippet' => '{{ outer_variable }}')
+ assert_template_result '', "{% render 'snippet' %}", 'outer_variable' => 'should not be visible'
+ end
+
+ def test_render_does_not_inherit_variable_with_same_name_as_snippet
+ Liquid::Template.file_system = StubFileSystem.new('snippet' => '{{ snippet }}')
+ assert_template_result '', "{% render 'snippet' %}", 'snippet' => 'should not be visible'
+ end
+
+ def test_render_sets_the_correct_template_name_for_errors
+ Liquid::Template.file_system = StubFileSystem.new('snippet' => '{{ unsafe }}')
+ Liquid::Template.taint_mode = :error
+
+ template = Liquid::Template.parse("{% render 'snippet', unsafe: unsafe %}")
+ template.render('unsafe' => String.new('unsafe').tap(&:taint))
+ refute_empty template.errors
+
+ assert_equal 'snippet', template.errors.first.template_name
+ end
+
+ def test_render_sets_the_correct_template_name_for_warnings
+ Liquid::Template.file_system = StubFileSystem.new('snippet' => '{{ unsafe }}')
+ Liquid::Template.taint_mode = :warn
+
+ template = Liquid::Template.parse("{% render 'snippet', unsafe: unsafe %}")
+ template.render('unsafe' => String.new('unsafe').tap(&:taint))
+ refute_empty template.warnings
+
+ assert_equal 'snippet', template.errors.first.template_name
+ end
+
+ def test_render_does_not_mutate_parent_scope
+ Liquid::Template.file_system = StubFileSystem.new('snippet' => '{% assign inner = 1 %}')
+ assert_template_result '', "{% render 'snippet' %}{{ inner }}"
+ end
+
+ def test_nested_render_tag
+ Liquid::Template.file_system = StubFileSystem.new(
+ 'one' => "one {{ render 'two' }}",
+ 'two' => 'two'
+ )
+ assert_template_result 'one two', "{% include 'one' %}"
+ end
+
+ def test_nested_include_with_variable
+ skip 'To be implemented'
+ assert_template_result "Product: Draft 151cm details ",
+ "{% include 'nested_product_template' with product %}", "product" => { "title" => 'Draft 151cm' }
+
+ assert_template_result "Product: Draft 151cm details Product: Element 155cm details ",
+ "{% include 'nested_product_template' for products %}", "products" => [{ "title" => 'Draft 151cm' }, { "title" => 'Element 155cm' }]
+ end
+
+ def test_recursively_included_template_does_not_produce_endless_loop
+ skip 'To be implemented'
+ infinite_file_system = Class.new do
+ def read_template_file(template_path)
+ "-{% include 'loop' %}"
+ end
+ end
+
+ Liquid::Template.file_system = infinite_file_system.new
+
+ assert_raises(Liquid::StackLevelError) do
+ Template.parse("{% include 'loop' %}").render!
+ end
+ end
+
+ def test_dynamically_choosen_template
+ skip 'To be implemented'
+ assert_template_result "Test123", "{% include template %}", "template" => 'Test123'
+ assert_template_result "Test321", "{% include template %}", "template" => 'Test321'
+
+ assert_template_result "Product: Draft 151cm ", "{% include template for product %}",
+ "template" => 'product', 'product' => { 'title' => 'Draft 151cm' }
+ end
+
+ def test_include_tag_caches_second_read_of_same_partial
+ skip 'To be implemented'
+ file_system = CountingFileSystem.new
+ assert_equal 'from CountingFileSystemfrom CountingFileSystem',
+ Template.parse("{% include 'pick_a_source' %}{% include 'pick_a_source' %}").render!({}, registers: { file_system: file_system })
+ assert_equal 1, file_system.count
+ end
+
+ def test_include_tag_doesnt_cache_partials_across_renders
+ skip 'To be implemented'
+ file_system = CountingFileSystem.new
+ assert_equal 'from CountingFileSystem',
+ Template.parse("{% include 'pick_a_source' %}").render!({}, registers: { file_system: file_system })
+ assert_equal 1, file_system.count
+
+ assert_equal 'from CountingFileSystem',
+ Template.parse("{% include 'pick_a_source' %}").render!({}, registers: { file_system: file_system })
+ assert_equal 2, file_system.count
+ end
+
+ def test_include_tag_within_if_statement
+ skip 'To be implemented'
+ assert_template_result "foo_if_true", "{% if true %}{% include 'foo_if_true' %}{% endif %}"
+ end
+
+ def test_custom_include_tag
+ skip 'To be implemented'
+ original_tag = Liquid::Template.tags['include']
+ Liquid::Template.tags['include'] = CustomInclude
+ begin
+ assert_equal "custom_foo",
+ Template.parse("{% include 'custom_foo' %}").render!
+ ensure
+ Liquid::Template.tags['include'] = original_tag
+ end
+ end
+
+ def test_custom_include_tag_within_if_statement
+ skip 'To be implemented'
+ original_tag = Liquid::Template.tags['include']
+ Liquid::Template.tags['include'] = CustomInclude
+ begin
+ assert_equal "custom_foo_if_true",
+ Template.parse("{% if true %}{% include 'custom_foo_if_true' %}{% endif %}").render!
+ ensure
+ Liquid::Template.tags['include'] = original_tag
+ end
+ end
+
+ def test_does_not_add_error_in_strict_mode_for_missing_variable
+ skip 'To be implemented'
+ Liquid::Template.file_system = TestFileSystem.new
+
+ a = Liquid::Template.parse(' {% include "nested_template" %}')
+ a.render!
+ assert_empty a.errors
+ end
+
+ def test_passing_options_to_included_templates
+ skip 'To be implemented'
+ assert_raises(Liquid::SyntaxError) do
+ Template.parse("{% include template %}", error_mode: :strict).render!("template" => '{{ "X" || downcase }}')
+ end
+ with_error_mode(:lax) do
+ assert_equal 'x', Template.parse("{% include template %}", error_mode: :strict, include_options_blacklist: true).render!("template" => '{{ "X" || downcase }}')
+ end
+ assert_raises(Liquid::SyntaxError) do
+ Template.parse("{% include template %}", error_mode: :strict, include_options_blacklist: [:locale]).render!("template" => '{{ "X" || downcase }}')
+ end
+ with_error_mode(:lax) do
+ assert_equal 'x', Template.parse("{% include template %}", error_mode: :strict, include_options_blacklist: [:error_mode]).render!("template" => '{{ "X" || downcase }}')
+ end
+ end
+
+ def test_render_raise_argument_error_when_template_is_undefined
+ skip 'To be implemented'
+ assert_raises(Liquid::ArgumentError) do
+ template = Liquid::Template.parse('{% include undefined_variable %}')
+ template.render!
+ end
+ assert_raises(Liquid::ArgumentError) do
+ template = Liquid::Template.parse('{% include nil %}')
+ template.render!
+ end
+ end
+
+ def test_including_via_variable_value
+ skip 'To be implemented'
+ assert_template_result "from TestFileSystem", "{% assign page = 'pick_a_source' %}{% include page %}"
+
+ assert_template_result "Product: Draft 151cm ", "{% assign page = 'product' %}{% include page %}", "product" => { 'title' => 'Draft 151cm' }
+
+ assert_template_result "Product: Draft 151cm ", "{% assign page = 'product' %}{% include page for foo %}", "foo" => { 'title' => 'Draft 151cm' }
+ end
+
+ def test_including_with_strict_variables
+ skip 'To be implemented'
+ template = Liquid::Template.parse("{% include 'simple' %}", error_mode: :warn)
+ template.render(nil, strict_variables: true)
+
+ assert_equal [], template.errors
+ end
+
+ def test_break_through_include
+ skip 'To be implemented'
+ assert_template_result "1", "{% for i in (1..3) %}{{ i }}{% break %}{{ i }}{% endfor %}"
+ assert_template_result "1", "{% for i in (1..3) %}{{ i }}{% include 'break' %}{{ i }}{% endfor %}"
+ end
+end # IncludeTagTest
+
diff --git a/test/unit/context_unit_test.rb b/test/unit/context_unit_test.rb
index fab19b8..1545763 100644
--- a/test/unit/context_unit_test.rb
+++ b/test/unit/context_unit_test.rb
@@ -473,6 +473,64 @@ class ContextUnitTest < Minitest::Test
assert_equal 'hi', context.apply_global_filter('hi')
end
+ def test_new_isolated_subcontext_does_not_inherit_variables
+ super_context = Context.new
+ super_context['my_variable'] = 'some value'
+ subcontext = super_context.new_isolated_subcontext
+
+ assert_nil subcontext['my_variable']
+ end
+
+ def test_new_isolated_subcontext_inherits_environment
+ super_context = Context.new('my_environment_value' => 'my value')
+ subcontext = super_context.new_isolated_subcontext
+
+ assert_equal 'my value',subcontext['my_environment_value']
+ end
+
+ def test_new_isolated_subcontext_inherits_resource_limits
+ resource_limits = ResourceLimits.new({})
+ super_context = Context.new({}, {}, {}, false, resource_limits)
+ subcontext = super_context.new_isolated_subcontext
+ assert_equal resource_limits, subcontext.resource_limits
+ end
+
+ def test_new_isolated_subcontext_inherits_exception_renderer
+ super_context = Context.new
+ super_context.exception_renderer = -> (_e) { 'my exception message' }
+ subcontext = super_context.new_isolated_subcontext
+ assert_equal 'my exception message', subcontext.handle_error(Liquid::Error.new)
+ end
+
+ def test_new_isolated_subcontext_does_not_inherit_non_static_registers
+ registers = {
+ my_register: :my_value
+ }
+ super_context = Context.new({}, {}, registers)
+ subcontext = super_context.new_isolated_subcontext
+ assert_nil subcontext.registers[:my_register]
+ end
+
+ def test_new_isolated_subcontext_inherits_static_registers
+ super_context = Context.build(static_registers: { my_register: :my_value })
+ subcontext = super_context.new_isolated_subcontext
+ assert_equal :my_value, subcontext.static_registers[:my_register]
+ end
+
+ def test_new_isolated_subcontext_inherits_filters
+ my_filter = Module.new do
+ def my_filter(*)
+ 'my filter result'
+ end
+ end
+
+ super_context = Context.new
+ super_context.add_filters([my_filter])
+ subcontext = super_context.new_isolated_subcontext
+ template = Template.parse('{{ 123 | my_filter }}')
+ assert_equal 'my filter result', template.render(subcontext)
+ end
+
private
def assert_no_object_allocations
From 9672ed52850913bdafdc66d1f5ab09e4d8ed6a5c Mon Sep 17 00:00:00 2001
From: Samuel
Date: Wed, 31 Jul 2019 11:20:49 -0400
Subject: [PATCH 53/74] Add a new `{% render %}` tag
Example:
```
// the_count.liquid
{{ number }}! Ah ah ah.
// my_template.liquid
{% for number in range (1..3) %}
{% render "the_count", number: number %}
{% endfor %}
Output:
1! Ah ah ah.
2! Ah ah ah.
3! Ah ah ah.
```
The `render` tag is a more strict version of the `include` tag. It is
designed to isolate itself from the parent rendering context both by
creating a new scope (which does not inherit the parent scope) and by
only inheriting "static" registers.
Static registers are those that do not hold mutable state which could
affect rendering. This again helps `render`ed templates remain entirely
separate from their calling context.
Unlike `include`, `render` does not permit specifying the target
template using a variable, only a string literal. For example, this
means that `{% render my_dynamic_template %}` is invalid syntax. This
will make it possible to statically analyze the dependencies between
templates without making Turing angry.
Note that the `static_environment` of a rendered template is inherited, unlike
the scope and regular environment. This environment is immutable from within the
template.
An alternate syntax, which mimics the `{% include ... for %}` tag is
currently in design discussion.
---
lib/liquid.rb | 1 +
lib/liquid/context.rb | 90 +++++---
lib/liquid/locales/en.yml | 1 +
lib/liquid/partial_cache.rb | 18 ++
lib/liquid/tags/include.rb | 33 +--
lib/liquid/tags/increment.rb | 1 +
lib/liquid/tags/render.rb | 63 ++----
test/integration/tags/render_rag_test.rb | 255 -----------------------
test/integration/tags/render_tag_test.rb | 225 +++++++-------------
test/test_helper.rb | 14 ++
test/unit/context_unit_test.rb | 18 +-
test/unit/partial_cache_unit_test.rb | 91 ++++++++
12 files changed, 291 insertions(+), 519 deletions(-)
create mode 100644 lib/liquid/partial_cache.rb
delete mode 100644 test/integration/tags/render_rag_test.rb
create mode 100644 test/unit/partial_cache_unit_test.rb
diff --git a/lib/liquid.rb b/lib/liquid.rb
index 770d2f9..0e198bb 100644
--- a/lib/liquid.rb
+++ b/lib/liquid.rb
@@ -74,6 +74,7 @@ require 'liquid/condition'
require 'liquid/utils'
require 'liquid/tokenizer'
require 'liquid/parse_context'
+require 'liquid/partial_cache'
# Load all the tags of the standard library
#
diff --git a/lib/liquid/context.rb b/lib/liquid/context.rb
index a05cdaa..1b15ca7 100644
--- a/lib/liquid/context.rb
+++ b/lib/liquid/context.rb
@@ -12,22 +12,25 @@ module Liquid
#
# context['bob'] #=> nil class Context
class Context
- attr_reader :scopes, :errors, :registers, :environments, :resource_limits, :static_registers
+ attr_reader :scopes, :errors, :registers, :environments, :resource_limits, :static_registers, :static_environments
attr_accessor :exception_renderer, :template_name, :partial, :global_filter, :strict_variables, :strict_filters
- def self.build(environments: {}, outer_scope: {}, registers: {}, rethrow_errors: false, resource_limits: nil, static_registers: {})
- new(environments, outer_scope, registers, rethrow_errors, resource_limits, static_registers)
+ # rubocop:disable Metrics/ParameterLists
+ def self.build(environments: {}, outer_scope: {}, registers: {}, rethrow_errors: false, resource_limits: nil, static_registers: {}, static_environments: {})
+ new(environments, outer_scope, registers, rethrow_errors, resource_limits, static_registers, static_environments)
end
- def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = nil, static_registers = {})
- @environments = [environments].flatten
- @scopes = [(outer_scope || {})]
- @registers = registers
- @static_registers = static_registers.tap(&:freeze)
- @errors = []
- @partial = false
- @strict_variables = false
- @resource_limits = resource_limits || ResourceLimits.new(Template.default_resource_limits)
+ def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = nil, static_registers = {}, static_environments = {})
+ @environments = [environments].flatten
+ @static_environments = [static_environments].flatten.map(&:freeze).freeze
+ @scopes = [(outer_scope || {})]
+ @registers = registers
+ @static_registers = static_registers.freeze
+ @errors = []
+ @partial = false
+ @strict_variables = false
+ @resource_limits = resource_limits || ResourceLimits.new(Template.default_resource_limits)
+ @base_scope_depth = 0
squash_instance_assigns_with_environments
@this_stack_used = false
@@ -41,6 +44,7 @@ module Liquid
@filters = []
@global_filter = nil
end
+ # rubocop:enable Metrics/ParameterLists
def warnings
@warnings ||= []
@@ -94,7 +98,7 @@ module Liquid
# Push new local scope on the stack. use Context#stack instead
def push(new_scope = {})
@scopes.unshift(new_scope)
- raise StackLevelError, "Nesting too deep".freeze if @scopes.length > Block::MAX_DEPTH
+ check_overflow
end
# Merge a hash of variables in the current local scope
@@ -134,13 +138,19 @@ module Liquid
# Creates a new context inheriting resource limits, filters, environment etc.,
# but with an isolated scope.
def new_isolated_subcontext
+ check_overflow
+
Context.build(
- environments: environments,
resource_limits: resource_limits,
+ static_environments: static_environments,
static_registers: static_registers
).tap do |subcontext|
+ subcontext.base_scope_depth = base_scope_depth + 1
subcontext.exception_renderer = exception_renderer
- subcontext.add_filters(@filters)
+ subcontext.filters = @filters
+ subcontext.strainer = nil
+ subcontext.errors = errors
+ subcontext.warnings = warnings
end
end
@@ -182,25 +192,13 @@ module Liquid
# This was changed from find() to find_index() because this is a very hot
# path and find_index() is optimized in MRI to reduce object allocation
index = @scopes.find_index { |s| s.key?(key) }
- scope = @scopes[index] if index
- variable = nil
-
- if scope.nil?
- @environments.each do |e|
- variable = lookup_and_evaluate(e, key, raise_on_not_found: raise_on_not_found)
- # When lookup returned a value OR there is no value but the lookup also did not raise
- # then it is the value we are looking for.
- if !variable.nil? || @strict_variables && raise_on_not_found
- scope = e
- break
- end
- end
+ variable = if index
+ lookup_and_evaluate(@scopes[index], key, raise_on_not_found: raise_on_not_found)
+ else
+ try_variable_find_in_environments(key, raise_on_not_found: raise_on_not_found)
end
- scope ||= @environments.last || @scopes.last
- variable ||= lookup_and_evaluate(scope, key, raise_on_not_found: raise_on_not_found)
-
variable = variable.to_liquid
variable.context = self if variable.respond_to?(:context=)
@@ -221,8 +219,38 @@ module Liquid
end
end
+ protected
+
+ attr_writer :base_scope_depth, :warnings, :errors, :strainer, :filters
+
private
+ attr_reader :base_scope_depth
+
+ def try_variable_find_in_environments(key, raise_on_not_found:)
+ @environments.each do |environment|
+ found_variable = lookup_and_evaluate(environment, key, raise_on_not_found: raise_on_not_found)
+ if !found_variable.nil? || @strict_variables && raise_on_not_found
+ return found_variable
+ end
+ end
+ @static_environments.each do |environment|
+ found_variable = lookup_and_evaluate(environment, key, raise_on_not_found: raise_on_not_found)
+ if !found_variable.nil? || @strict_variables && raise_on_not_found
+ return found_variable
+ end
+ end
+ nil
+ end
+
+ def check_overflow
+ raise StackLevelError, "Nesting too deep".freeze if overflow?
+ end
+
+ def overflow?
+ base_scope_depth + @scopes.length > Block::MAX_DEPTH
+ end
+
def internal_error
# raise and catch to set backtrace and cause on exception
raise Liquid::InternalError, 'internal'
diff --git a/lib/liquid/locales/en.yml b/lib/liquid/locales/en.yml
index 48b3b1d..c0a9aff 100644
--- a/lib/liquid/locales/en.yml
+++ b/lib/liquid/locales/en.yml
@@ -22,5 +22,6 @@
tag_never_closed: "'%{block_name}' tag was never closed"
meta_syntax_error: "Liquid syntax error: #{e.message}"
table_row: "Syntax Error in 'table_row loop' - Valid syntax: table_row [item] in [collection] cols=3"
+ render: "Syntax error in tag 'render' - Template name must be a quoted string"
argument:
include: "Argument error in tag 'include' - Illegal template name"
diff --git a/lib/liquid/partial_cache.rb b/lib/liquid/partial_cache.rb
new file mode 100644
index 0000000..d0b8845
--- /dev/null
+++ b/lib/liquid/partial_cache.rb
@@ -0,0 +1,18 @@
+module Liquid
+ class PartialCache
+ def self.load(template_name, context:, parse_context:)
+ cached_partials = (context.registers[:cached_partials] ||= {})
+ cached = cached_partials[template_name]
+ return cached if cached
+
+ file_system = (context.registers[:file_system] ||= Liquid::Template.file_system)
+ source = file_system.read_template_file(template_name)
+ parse_context.partial = true
+
+ partial = Liquid::Template.parse(source, parse_context)
+ cached_partials[template_name] = partial
+ ensure
+ parse_context.partial = false
+ end
+ end
+end
diff --git a/lib/liquid/tags/include.rb b/lib/liquid/tags/include.rb
index 24acf9d..fd86ee4 100644
--- a/lib/liquid/tags/include.rb
+++ b/lib/liquid/tags/include.rb
@@ -46,7 +46,12 @@ module Liquid
template_name = context.evaluate(@template_name_expr)
raise ArgumentError.new(options[:locale].t("errors.argument.include")) unless template_name
- partial = load_cached_partial(template_name, context)
+ partial = PartialCache.load(
+ template_name,
+ context: context,
+ parse_context: parse_context
+ )
+
context_variable_name = template_name.split('/'.freeze).last
variable = if @variable_name_expr
@@ -83,35 +88,9 @@ module Liquid
output
end
- private
-
alias_method :parse_context, :options
private :parse_context
- def load_cached_partial(template_name, context)
- cached_partials = context.registers[:cached_partials] || {}
-
- if cached = cached_partials[template_name]
- return cached
- end
- source = read_template_from_file_system(context)
- begin
- parse_context.partial = true
- partial = Liquid::Template.parse(source, parse_context)
- ensure
- parse_context.partial = false
- end
- cached_partials[template_name] = partial
- context.registers[:cached_partials] = cached_partials
- partial
- end
-
- def read_template_from_file_system(context)
- file_system = context.registers[:file_system] || Liquid::Template.file_system
-
- file_system.read_template_file(context.evaluate(@template_name_expr))
- end
-
class ParseTreeVisitor < Liquid::ParseTreeVisitor
def children
[
diff --git a/lib/liquid/tags/increment.rb b/lib/liquid/tags/increment.rb
index 5af1242..95875aa 100644
--- a/lib/liquid/tags/increment.rb
+++ b/lib/liquid/tags/increment.rb
@@ -23,6 +23,7 @@ module Liquid
def render_to_output_buffer(context, output)
value = context.environments.first[@variable] ||= 0
context.environments.first[@variable] = value + 1
+
output << value.to_s
output
end
diff --git a/lib/liquid/tags/render.rb b/lib/liquid/tags/render.rb
index f0f6f10..2e5310b 100644
--- a/lib/liquid/tags/render.rb
+++ b/lib/liquid/tags/render.rb
@@ -1,81 +1,46 @@
module Liquid
- #
- # TODO: docs
- #
class Render < Tag
- Syntax = /(#{QuotedFragment}+)/o
+ Syntax = /(#{QuotedString})#{QuotedFragment}*/o
attr_reader :template_name_expr, :attributes
def initialize(tag_name, markup, options)
super
- if markup =~ Syntax
- template_name = $1
+ raise SyntaxError.new(options[:locale].t("errors.syntax.render".freeze)) unless markup =~ Syntax
- @template_name_expr = Expression.parse(template_name)
+ template_name = $1
- @attributes = {}
- markup.scan(TagAttributes) do |key, value|
- @attributes[key] = Expression.parse(value)
- end
+ @template_name_expr = Expression.parse(template_name)
- else
- raise SyntaxError.new(options[:locale].t("errors.syntax.include".freeze))
+ @attributes = {}
+ markup.scan(TagAttributes) do |key, value|
+ @attributes[key] = Expression.parse(value)
end
end
- def parse(_tokens)
- end
-
def render_to_output_buffer(context, output)
+ # Though we evaluate this here we will only ever parse it as a string literal.
template_name = context.evaluate(@template_name_expr)
raise ArgumentError.new(options[:locale].t("errors.argument.include")) unless template_name
- partial = load_cached_partial(template_name, context)
+ partial = PartialCache.load(
+ template_name,
+ context: context,
+ parse_context: parse_context
+ )
- inner_context = Context.new
+ inner_context = context.new_isolated_subcontext
inner_context.template_name = template_name
inner_context.partial = true
@attributes.each do |key, value|
inner_context[key] = context.evaluate(value)
end
partial.render_to_output_buffer(inner_context, output)
-
- # TODO: Put into a new #isolated_stack method in Context?
- inner_context.errors.each { |e| context.errors << e }
output
end
- private
-
- alias_method :parse_context, :options
- private :parse_context
-
- def load_cached_partial(template_name, context)
- cached_partials = context.registers[:cached_partials] || {}
-
- if cached = cached_partials[template_name]
- return cached
- end
- source = read_template_from_file_system(context)
- begin
- parse_context.partial = true
- partial = Liquid::Template.parse(source, parse_context)
- ensure
- parse_context.partial = false
- end
- cached_partials[template_name] = partial
- context.registers[:cached_partials] = cached_partials
- partial
- end
-
- def read_template_from_file_system(context)
- file_system = context.registers[:file_system] || Liquid::Template.file_system
- file_system.read_template_file(context.evaluate(@template_name_expr))
- end
-
class ParseTreeVisitor < Liquid::ParseTreeVisitor
def children
[
diff --git a/test/integration/tags/render_rag_test.rb b/test/integration/tags/render_rag_test.rb
deleted file mode 100644
index 2352bc1..0000000
--- a/test/integration/tags/render_rag_test.rb
+++ /dev/null
@@ -1,255 +0,0 @@
-require 'test_helper'
-
-class TestFileSystem
- def read_template_file(template_path)
- case template_path
- when "product"
- "Product: {{ product.title }} "
-
- when "locale_variables"
- "Locale: {{echo1}} {{echo2}}"
-
- when "variant"
- "Variant: {{ variant.title }}"
-
- when "nested_template"
- "{% include 'header' %} {% include 'body' %} {% include 'footer' %}"
-
- when "body"
- "body {% include 'body_detail' %}"
-
- when "nested_product_template"
- "Product: {{ nested_product_template.title }} {%include 'details'%} "
-
- when "recursively_nested_template"
- "-{% include 'recursively_nested_template' %}"
-
- when "pick_a_source"
- "from TestFileSystem"
-
- when 'assignments'
- "{% assign foo = 'bar' %}"
-
- when 'break'
- "{% break %}"
-
- else
- template_path
- end
- end
-end
-
-class OtherFileSystem
- def read_template_file(template_path)
- 'from OtherFileSystem'
- end
-end
-
-class CountingFileSystem
- attr_reader :count
- def read_template_file(template_path)
- @count ||= 0
- @count += 1
- 'from CountingFileSystem'
- end
-end
-
-class CustomInclude < Liquid::Tag
- Syntax = /(#{Liquid::QuotedFragment}+)(\s+(?:with|for)\s+(#{Liquid::QuotedFragment}+))?/o
-
- def initialize(tag_name, markup, tokens)
- markup =~ Syntax
- @template_name = $1
- super
- end
-
- def parse(tokens)
- end
-
- def render_to_output_buffer(context, output)
- output << @template_name[1..-2]
- output
- end
-end
-
-class IncludeTagTest < Minitest::Test
- include Liquid
-
- def setup
- Liquid::Template.file_system = TestFileSystem.new
- end
-
- def test_include_tag_looks_for_file_system_in_registers_first
- assert_equal 'from OtherFileSystem',
- Template.parse("{% include 'pick_a_source' %}").render!({}, registers: { file_system: OtherFileSystem.new })
- end
-
- def test_include_tag_with
- assert_template_result "Product: Draft 151cm ",
- "{% include 'product' with products[0] %}", "products" => [ { 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' } ]
- end
-
- def test_include_tag_with_default_name
- assert_template_result "Product: Draft 151cm ",
- "{% include 'product' %}", "product" => { 'title' => 'Draft 151cm' }
- end
-
- def test_include_tag_for
- assert_template_result "Product: Draft 151cm Product: Element 155cm ",
- "{% include 'product' for products %}", "products" => [ { 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' } ]
- end
-
- def test_include_tag_with_local_variables
- assert_template_result "Locale: test123 ", "{% include 'locale_variables' echo1: 'test123' %}"
- end
-
- def test_include_tag_with_multiple_local_variables
- assert_template_result "Locale: test123 test321",
- "{% include 'locale_variables' echo1: 'test123', echo2: 'test321' %}"
- end
-
- def test_include_tag_with_multiple_local_variables_from_context
- assert_template_result "Locale: test123 test321",
- "{% include 'locale_variables' echo1: echo1, echo2: more_echos.echo2 %}",
- 'echo1' => 'test123', 'more_echos' => { "echo2" => 'test321' }
- end
-
- def test_included_templates_assigns_variables
- assert_template_result "bar", "{% include 'assignments' %}{{ foo }}"
- end
-
- def test_nested_include_tag
- assert_template_result "body body_detail", "{% include 'body' %}"
-
- assert_template_result "header body body_detail footer", "{% include 'nested_template' %}"
- end
-
- def test_nested_include_with_variable
- assert_template_result "Product: Draft 151cm details ",
- "{% include 'nested_product_template' with product %}", "product" => { "title" => 'Draft 151cm' }
-
- assert_template_result "Product: Draft 151cm details Product: Element 155cm details ",
- "{% include 'nested_product_template' for products %}", "products" => [{ "title" => 'Draft 151cm' }, { "title" => 'Element 155cm' }]
- end
-
- def test_recursively_included_template_does_not_produce_endless_loop
- infinite_file_system = Class.new do
- def read_template_file(template_path)
- "-{% include 'loop' %}"
- end
- end
-
- Liquid::Template.file_system = infinite_file_system.new
-
- assert_raises(Liquid::StackLevelError) do
- Template.parse("{% include 'loop' %}").render!
- end
- end
-
- def test_dynamically_choosen_template
- assert_template_result "Test123", "{% include template %}", "template" => 'Test123'
- assert_template_result "Test321", "{% include template %}", "template" => 'Test321'
-
- assert_template_result "Product: Draft 151cm ", "{% include template for product %}",
- "template" => 'product', 'product' => { 'title' => 'Draft 151cm' }
- end
-
- def test_include_tag_caches_second_read_of_same_partial
- file_system = CountingFileSystem.new
- assert_equal 'from CountingFileSystemfrom CountingFileSystem',
- Template.parse("{% include 'pick_a_source' %}{% include 'pick_a_source' %}").render!({}, registers: { file_system: file_system })
- assert_equal 1, file_system.count
- end
-
- def test_include_tag_doesnt_cache_partials_across_renders
- file_system = CountingFileSystem.new
- assert_equal 'from CountingFileSystem',
- Template.parse("{% include 'pick_a_source' %}").render!({}, registers: { file_system: file_system })
- assert_equal 1, file_system.count
-
- assert_equal 'from CountingFileSystem',
- Template.parse("{% include 'pick_a_source' %}").render!({}, registers: { file_system: file_system })
- assert_equal 2, file_system.count
- end
-
- def test_include_tag_within_if_statement
- assert_template_result "foo_if_true", "{% if true %}{% include 'foo_if_true' %}{% endif %}"
- end
-
- def test_custom_include_tag
- original_tag = Liquid::Template.tags['include']
- Liquid::Template.tags['include'] = CustomInclude
- begin
- assert_equal "custom_foo",
- Template.parse("{% include 'custom_foo' %}").render!
- ensure
- Liquid::Template.tags['include'] = original_tag
- end
- end
-
- def test_custom_include_tag_within_if_statement
- original_tag = Liquid::Template.tags['include']
- Liquid::Template.tags['include'] = CustomInclude
- begin
- assert_equal "custom_foo_if_true",
- Template.parse("{% if true %}{% include 'custom_foo_if_true' %}{% endif %}").render!
- ensure
- Liquid::Template.tags['include'] = original_tag
- end
- end
-
- def test_does_not_add_error_in_strict_mode_for_missing_variable
- Liquid::Template.file_system = TestFileSystem.new
-
- a = Liquid::Template.parse(' {% include "nested_template" %}')
- a.render!
- assert_empty a.errors
- end
-
- def test_passing_options_to_included_templates
- assert_raises(Liquid::SyntaxError) do
- Template.parse("{% include template %}", error_mode: :strict).render!("template" => '{{ "X" || downcase }}')
- end
- with_error_mode(:lax) do
- assert_equal 'x', Template.parse("{% include template %}", error_mode: :strict, include_options_blacklist: true).render!("template" => '{{ "X" || downcase }}')
- end
- assert_raises(Liquid::SyntaxError) do
- Template.parse("{% include template %}", error_mode: :strict, include_options_blacklist: [:locale]).render!("template" => '{{ "X" || downcase }}')
- end
- with_error_mode(:lax) do
- assert_equal 'x', Template.parse("{% include template %}", error_mode: :strict, include_options_blacklist: [:error_mode]).render!("template" => '{{ "X" || downcase }}')
- end
- end
-
- def test_render_raise_argument_error_when_template_is_undefined
- assert_raises(Liquid::ArgumentError) do
- template = Liquid::Template.parse('{% include undefined_variable %}')
- template.render!
- end
- assert_raises(Liquid::ArgumentError) do
- template = Liquid::Template.parse('{% include nil %}')
- template.render!
- end
- end
-
- def test_including_via_variable_value
- assert_template_result "from TestFileSystem", "{% assign page = 'pick_a_source' %}{% include page %}"
-
- assert_template_result "Product: Draft 151cm ", "{% assign page = 'product' %}{% include page %}", "product" => { 'title' => 'Draft 151cm' }
-
- assert_template_result "Product: Draft 151cm ", "{% assign page = 'product' %}{% include page for foo %}", "foo" => { 'title' => 'Draft 151cm' }
- end
-
- def test_including_with_strict_variables
- template = Liquid::Template.parse("{% include 'simple' %}", error_mode: :warn)
- template.render(nil, strict_variables: true)
-
- assert_equal [], template.errors
- end
-
- def test_break_through_include
- assert_template_result "1", "{% for i in (1..3) %}{{ i }}{% break %}{{ i }}{% endfor %}"
- assert_template_result "1", "{% for i in (1..3) %}{{ i }}{% include 'break' %}{{ i }}{% endfor %}"
- end
-end # IncludeTagTest
-
diff --git a/test/integration/tags/render_tag_test.rb b/test/integration/tags/render_tag_test.rb
index 928dc38..a31d018 100644
--- a/test/integration/tags/render_tag_test.rb
+++ b/test/integration/tags/render_tag_test.rb
@@ -1,75 +1,69 @@
require 'test_helper'
-class StubFileSystem
- def initialize(values)
- @values = values
- end
-
- def read_template_file(template_path)
- @values.fetch(template_path)
- end
-end
-
class RenderTagTest < Minitest::Test
include Liquid
def test_render_with_no_arguments
Liquid::Template.file_system = StubFileSystem.new('source' => 'rendered content')
- assert_template_result 'rendered content', "{% render 'source' %}"
+ assert_template_result 'rendered content', '{% render "source" %}'
end
def test_render_tag_looks_for_file_system_in_registers_first
file_system = StubFileSystem.new('pick_a_source' => 'from register file system')
assert_equal 'from register file system',
- Template.parse("{% render 'pick_a_source' %}").render!({}, registers: { file_system: file_system })
+ Template.parse('{% render "pick_a_source" %}').render!({}, registers: { file_system: file_system })
end
def test_render_passes_named_arguments_into_inner_scope
Liquid::Template.file_system = StubFileSystem.new('product' => '{{ inner_product.title }}')
- assert_template_result 'My Product', "{% render 'product', inner_product: outer_product %}",
+ assert_template_result 'My Product', '{% render "product", inner_product: outer_product %}',
'outer_product' => { 'title' => 'My Product' }
end
def test_render_accepts_literals_as_arguments
Liquid::Template.file_system = StubFileSystem.new('snippet' => '{{ price }}')
- assert_template_result '123', "{% render 'snippet', price: 123 %}"
+ assert_template_result '123', '{% render "snippet", price: 123 %}'
end
def test_render_accepts_multiple_named_arguments
Liquid::Template.file_system = StubFileSystem.new('snippet' => '{{ one }} {{ two }}')
- assert_template_result '1 2', "{% render 'snippet', one: 1, two: 2 %}"
+ assert_template_result '1 2', '{% render "snippet", one: 1, two: 2 %}'
end
- def test_render_does_inherit_parent_scope_variables
+ def test_render_does_not_inherit_parent_scope_variables
Liquid::Template.file_system = StubFileSystem.new('snippet' => '{{ outer_variable }}')
- assert_template_result '', "{% render 'snippet' %}", 'outer_variable' => 'should not be visible'
+ assert_template_result '', '{% assign outer_variable = "should not be visible" %}{% render "snippet" %}'
end
def test_render_does_not_inherit_variable_with_same_name_as_snippet
Liquid::Template.file_system = StubFileSystem.new('snippet' => '{{ snippet }}')
- assert_template_result '', "{% render 'snippet' %}", 'snippet' => 'should not be visible'
+ assert_template_result '', "{% assign snippet = 'should not be visible' %}{% render 'snippet' %}"
end
def test_render_sets_the_correct_template_name_for_errors
Liquid::Template.file_system = StubFileSystem.new('snippet' => '{{ unsafe }}')
- Liquid::Template.taint_mode = :error
- template = Liquid::Template.parse("{% render 'snippet', unsafe: unsafe %}")
- template.render('unsafe' => String.new('unsafe').tap(&:taint))
- refute_empty template.errors
+ with_taint_mode :error do
+ template = Liquid::Template.parse('{% render "snippet", unsafe: unsafe %}')
+ context = Context.new('unsafe' => (+'unsafe').tap(&:taint))
+ template.render(context)
- assert_equal 'snippet', template.errors.first.template_name
+ assert_equal [Liquid::TaintedError], template.errors.map(&:class)
+ assert_equal 'snippet', template.errors.first.template_name
+ end
end
def test_render_sets_the_correct_template_name_for_warnings
Liquid::Template.file_system = StubFileSystem.new('snippet' => '{{ unsafe }}')
- Liquid::Template.taint_mode = :warn
- template = Liquid::Template.parse("{% render 'snippet', unsafe: unsafe %}")
- template.render('unsafe' => String.new('unsafe').tap(&:taint))
- refute_empty template.warnings
+ with_taint_mode :warn do
+ template = Liquid::Template.parse('{% render "snippet", unsafe: unsafe %}')
+ context = Context.new('unsafe' => (+'unsafe').tap(&:taint))
+ template.render(context)
- assert_equal 'snippet', template.errors.first.template_name
+ assert_equal [Liquid::TaintedError], context.warnings.map(&:class)
+ assert_equal 'snippet', context.warnings.first.template_name
+ end
end
def test_render_does_not_mutate_parent_scope
@@ -79,152 +73,77 @@ class RenderTagTest < Minitest::Test
def test_nested_render_tag
Liquid::Template.file_system = StubFileSystem.new(
- 'one' => "one {{ render 'two' }}",
+ 'one' => "one {% render 'two' %}",
'two' => 'two'
)
- assert_template_result 'one two', "{% include 'one' %}"
+ assert_template_result 'one two', "{% render 'one' %}"
end
- def test_nested_include_with_variable
- skip 'To be implemented'
- assert_template_result "Product: Draft 151cm details ",
- "{% include 'nested_product_template' with product %}", "product" => { "title" => 'Draft 151cm' }
+ def test_recursively_rendered_template_does_not_produce_endless_loop
+ Liquid::Template.file_system = StubFileSystem.new('loop' => '{% render "loop" %}')
- assert_template_result "Product: Draft 151cm details Product: Element 155cm details ",
- "{% include 'nested_product_template' for products %}", "products" => [{ "title" => 'Draft 151cm' }, { "title" => 'Element 155cm' }]
- end
-
- def test_recursively_included_template_does_not_produce_endless_loop
- skip 'To be implemented'
- infinite_file_system = Class.new do
- def read_template_file(template_path)
- "-{% include 'loop' %}"
- end
- end
-
- Liquid::Template.file_system = infinite_file_system.new
-
- assert_raises(Liquid::StackLevelError) do
- Template.parse("{% include 'loop' %}").render!
+ assert_raises Liquid::StackLevelError do
+ Template.parse('{% render "loop" %}').render!
end
end
- def test_dynamically_choosen_template
- skip 'To be implemented'
- assert_template_result "Test123", "{% include template %}", "template" => 'Test123'
- assert_template_result "Test321", "{% include template %}", "template" => 'Test321'
+ def test_includes_and_renders_count_towards_the_same_recursion_limit
+ Liquid::Template.file_system = StubFileSystem.new(
+ 'loop_render' => '{% render "loop_include" %}',
+ 'loop_include' => '{% include "loop_render" %}'
+ )
- assert_template_result "Product: Draft 151cm ", "{% include template for product %}",
- "template" => 'product', 'product' => { 'title' => 'Draft 151cm' }
+ assert_raises Liquid::StackLevelError do
+ Template.parse('{% render "loop_include" %}').render!
+ end
+ end
+
+ def test_dynamically_choosen_templates_are_not_allowed
+ Liquid::Template.file_system = StubFileSystem.new('snippet' => 'should not be rendered')
+
+ assert_raises Liquid::SyntaxError do
+ Liquid::Template.parse("{% assign name = 'snippet' %}{% render name %}")
+ end
end
def test_include_tag_caches_second_read_of_same_partial
- skip 'To be implemented'
- file_system = CountingFileSystem.new
- assert_equal 'from CountingFileSystemfrom CountingFileSystem',
- Template.parse("{% include 'pick_a_source' %}{% include 'pick_a_source' %}").render!({}, registers: { file_system: file_system })
- assert_equal 1, file_system.count
+ file_system = StubFileSystem.new('snippet' => 'echo')
+ assert_equal 'echoecho',
+ Template.parse('{% render "snippet" %}{% render "snippet" %}')
+ .render!({}, registers: { file_system: file_system })
+ assert_equal 1, file_system.file_read_count
end
- def test_include_tag_doesnt_cache_partials_across_renders
- skip 'To be implemented'
- file_system = CountingFileSystem.new
- assert_equal 'from CountingFileSystem',
- Template.parse("{% include 'pick_a_source' %}").render!({}, registers: { file_system: file_system })
- assert_equal 1, file_system.count
+ def test_render_tag_doesnt_cache_partials_across_renders
+ file_system = StubFileSystem.new('snippet' => 'my message')
- assert_equal 'from CountingFileSystem',
- Template.parse("{% include 'pick_a_source' %}").render!({}, registers: { file_system: file_system })
- assert_equal 2, file_system.count
+ assert_equal 'my message',
+ Template.parse('{% include "snippet" %}').render!({}, registers: { file_system: file_system })
+ assert_equal 1, file_system.file_read_count
+
+ assert_equal 'my message',
+ Template.parse('{% include "snippet" %}').render!({}, registers: { file_system: file_system })
+ assert_equal 2, file_system.file_read_count
end
- def test_include_tag_within_if_statement
- skip 'To be implemented'
- assert_template_result "foo_if_true", "{% if true %}{% include 'foo_if_true' %}{% endif %}"
+ def test_render_tag_within_if_statement
+ Liquid::Template.file_system = StubFileSystem.new('snippet' => 'my message')
+ assert_template_result 'my message', '{% if true %}{% render "snippet" %}{% endif %}'
end
- def test_custom_include_tag
- skip 'To be implemented'
- original_tag = Liquid::Template.tags['include']
- Liquid::Template.tags['include'] = CustomInclude
- begin
- assert_equal "custom_foo",
- Template.parse("{% include 'custom_foo' %}").render!
- ensure
- Liquid::Template.tags['include'] = original_tag
- end
+ def test_break_through_render
+ Liquid::Template.file_system = StubFileSystem.new('break' => '{% break %}')
+ assert_template_result '1', '{% for i in (1..3) %}{{ i }}{% break %}{{ i }}{% endfor %}'
+ assert_template_result '112233', '{% for i in (1..3) %}{{ i }}{% render "break" %}{{ i }}{% endfor %}'
end
- def test_custom_include_tag_within_if_statement
- skip 'To be implemented'
- original_tag = Liquid::Template.tags['include']
- Liquid::Template.tags['include'] = CustomInclude
- begin
- assert_equal "custom_foo_if_true",
- Template.parse("{% if true %}{% include 'custom_foo_if_true' %}{% endif %}").render!
- ensure
- Liquid::Template.tags['include'] = original_tag
- end
+ def test_increment_is_isolated_between_renders
+ Liquid::Template.file_system = StubFileSystem.new('incr' => '{% increment %}')
+ assert_template_result '010', '{% increment %}{% increment %}{% render "incr" %}'
end
- def test_does_not_add_error_in_strict_mode_for_missing_variable
- skip 'To be implemented'
- Liquid::Template.file_system = TestFileSystem.new
-
- a = Liquid::Template.parse(' {% include "nested_template" %}')
- a.render!
- assert_empty a.errors
+ def test_decrement_is_isolated_between_renders
+ Liquid::Template.file_system = StubFileSystem.new('decr' => '{% decrement %}')
+ assert_template_result '-1-2-1', '{% decrement %}{% decrement %}{% render "decr" %}'
end
-
- def test_passing_options_to_included_templates
- skip 'To be implemented'
- assert_raises(Liquid::SyntaxError) do
- Template.parse("{% include template %}", error_mode: :strict).render!("template" => '{{ "X" || downcase }}')
- end
- with_error_mode(:lax) do
- assert_equal 'x', Template.parse("{% include template %}", error_mode: :strict, include_options_blacklist: true).render!("template" => '{{ "X" || downcase }}')
- end
- assert_raises(Liquid::SyntaxError) do
- Template.parse("{% include template %}", error_mode: :strict, include_options_blacklist: [:locale]).render!("template" => '{{ "X" || downcase }}')
- end
- with_error_mode(:lax) do
- assert_equal 'x', Template.parse("{% include template %}", error_mode: :strict, include_options_blacklist: [:error_mode]).render!("template" => '{{ "X" || downcase }}')
- end
- end
-
- def test_render_raise_argument_error_when_template_is_undefined
- skip 'To be implemented'
- assert_raises(Liquid::ArgumentError) do
- template = Liquid::Template.parse('{% include undefined_variable %}')
- template.render!
- end
- assert_raises(Liquid::ArgumentError) do
- template = Liquid::Template.parse('{% include nil %}')
- template.render!
- end
- end
-
- def test_including_via_variable_value
- skip 'To be implemented'
- assert_template_result "from TestFileSystem", "{% assign page = 'pick_a_source' %}{% include page %}"
-
- assert_template_result "Product: Draft 151cm ", "{% assign page = 'product' %}{% include page %}", "product" => { 'title' => 'Draft 151cm' }
-
- assert_template_result "Product: Draft 151cm ", "{% assign page = 'product' %}{% include page for foo %}", "foo" => { 'title' => 'Draft 151cm' }
- end
-
- def test_including_with_strict_variables
- skip 'To be implemented'
- template = Liquid::Template.parse("{% include 'simple' %}", error_mode: :warn)
- template.render(nil, strict_variables: true)
-
- assert_equal [], template.errors
- end
-
- def test_break_through_include
- skip 'To be implemented'
- assert_template_result "1", "{% for i in (1..3) %}{{ i }}{% break %}{{ i }}{% endfor %}"
- assert_template_result "1", "{% for i in (1..3) %}{{ i }}{% include 'break' %}{{ i }}{% endfor %}"
- end
-end # IncludeTagTest
-
+end
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 210333d..27a2434 100755
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -121,3 +121,17 @@ class ErrorDrop < Liquid::Drop
raise Exception, 'exception'
end
end
+
+class StubFileSystem
+ attr_reader :file_read_count
+
+ def initialize(values)
+ @file_read_count = 0
+ @values = values
+ end
+
+ def read_template_file(template_path)
+ @file_read_count += 1
+ @values.fetch(template_path)
+ end
+end
diff --git a/test/unit/context_unit_test.rb b/test/unit/context_unit_test.rb
index 1545763..9252eb5 100644
--- a/test/unit/context_unit_test.rb
+++ b/test/unit/context_unit_test.rb
@@ -468,6 +468,16 @@ class ContextUnitTest < Minitest::Test
assert_equal 'hi filtered', context.apply_global_filter('hi')
end
+ def test_static_environments_are_read_with_lower_priority_than_environments
+ context = Context.build(
+ static_environments: { 'shadowed' => 'static', 'unshadowed' => 'static' },
+ environments: { 'shadowed' => 'dynamic' }
+ )
+
+ assert_equal 'dynamic', context['shadowed']
+ assert_equal 'static', context['unshadowed']
+ end
+
def test_apply_global_filter_when_no_global_filter_exist
context = Context.new
assert_equal 'hi', context.apply_global_filter('hi')
@@ -481,11 +491,11 @@ class ContextUnitTest < Minitest::Test
assert_nil subcontext['my_variable']
end
- def test_new_isolated_subcontext_inherits_environment
- super_context = Context.new('my_environment_value' => 'my value')
+ def test_new_isolated_subcontext_inherits_static_environment
+ super_context = Context.build(static_environments: { 'my_environment_value' => 'my value' })
subcontext = super_context.new_isolated_subcontext
- assert_equal 'my value',subcontext['my_environment_value']
+ assert_equal 'my value', subcontext['my_environment_value']
end
def test_new_isolated_subcontext_inherits_resource_limits
@@ -497,7 +507,7 @@ class ContextUnitTest < Minitest::Test
def test_new_isolated_subcontext_inherits_exception_renderer
super_context = Context.new
- super_context.exception_renderer = -> (_e) { 'my exception message' }
+ super_context.exception_renderer = ->(_e) { 'my exception message' }
subcontext = super_context.new_isolated_subcontext
assert_equal 'my exception message', subcontext.handle_error(Liquid::Error.new)
end
diff --git a/test/unit/partial_cache_unit_test.rb b/test/unit/partial_cache_unit_test.rb
new file mode 100644
index 0000000..29f1144
--- /dev/null
+++ b/test/unit/partial_cache_unit_test.rb
@@ -0,0 +1,91 @@
+require 'test_helper'
+
+class PartialCacheUnitTest < Minitest::Test
+ def test_uses_the_file_system_register_if_present
+ context = Liquid::Context.build(
+ registers: {
+ file_system: StubFileSystem.new('my_partial' => 'my partial body')
+ }
+ )
+
+ partial = Liquid::PartialCache.load(
+ 'my_partial',
+ context: context,
+ parse_context: Liquid::ParseContext.new
+ )
+
+ assert_equal 'my partial body', partial.render
+ end
+
+ def test_reads_from_the_file_system_only_once_per_file
+ file_system = StubFileSystem.new('my_partial' => 'some partial body')
+ context = Liquid::Context.build(
+ registers: { file_system: file_system }
+ )
+
+ 2.times do
+ Liquid::PartialCache.load(
+ 'my_partial',
+ context: context,
+ parse_context: Liquid::ParseContext.new
+ )
+ end
+
+ assert_equal 1, file_system.file_read_count
+ end
+
+ def test_cache_state_is_stored_per_context
+ parse_context = Liquid::ParseContext.new
+ shared_file_system = StubFileSystem.new(
+ 'my_partial' => 'my shared value'
+ )
+ context_one = Liquid::Context.build(
+ registers: {
+ file_system: shared_file_system
+ }
+ )
+ context_two = Liquid::Context.build(
+ registers: {
+ file_system: shared_file_system
+ }
+ )
+
+ 2.times do
+ Liquid::PartialCache.load(
+ 'my_partial',
+ context: context_one,
+ parse_context: parse_context
+ )
+ end
+
+ Liquid::PartialCache.load(
+ 'my_partial',
+ context: context_two,
+ parse_context: parse_context
+ )
+
+ assert_equal 2, shared_file_system.file_read_count
+ end
+
+ def test_cache_is_not_broken_when_a_different_parse_context_is_used
+ file_system = StubFileSystem.new('my_partial' => 'some partial body')
+ context = Liquid::Context.build(
+ registers: { file_system: file_system }
+ )
+
+ Liquid::PartialCache.load(
+ 'my_partial',
+ context: context,
+ parse_context: Liquid::ParseContext.new(my_key: 'value one')
+ )
+ Liquid::PartialCache.load(
+ 'my_partial',
+ context: context,
+ parse_context: Liquid::ParseContext.new(my_key: 'value two')
+ )
+
+ # Technically what we care about is that the file was parsed twice,
+ # but measuring file reads is an OK proxy for this.
+ assert_equal 1, file_system.file_read_count
+ end
+end
From 8750b4b006fb56e90154a12b2cb0442260be8caf Mon Sep 17 00:00:00 2001
From: Ashwin Maroli
Date: Fri, 30 Aug 2019 09:01:47 +0530
Subject: [PATCH 54/74] Reduce allocations from `Liquid::Context.new`
---
lib/liquid/context.rb | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/lib/liquid/context.rb b/lib/liquid/context.rb
index 1b15ca7..90e6b78 100644
--- a/lib/liquid/context.rb
+++ b/lib/liquid/context.rb
@@ -21,8 +21,10 @@ module Liquid
end
def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = nil, static_registers = {}, static_environments = {})
- @environments = [environments].flatten
- @static_environments = [static_environments].flatten.map(&:freeze).freeze
+ @environments = [environments]
+ @environments.flatten!
+
+ @static_environments = [static_environments].flat_map(&:freeze).freeze
@scopes = [(outer_scope || {})]
@registers = registers
@static_registers = static_registers.freeze
From dafbb4ae904b93de93bd80a555bcf4fcc2a31f4f Mon Sep 17 00:00:00 2001
From: Mike Angell
Date: Sat, 31 Aug 2019 20:03:54 +1000
Subject: [PATCH 55/74] Remove hasnling false scopes
---
lib/liquid/context.rb | 19 ++-----------------
1 file changed, 2 insertions(+), 17 deletions(-)
diff --git a/lib/liquid/context.rb b/lib/liquid/context.rb
index b341a31..bf12dc1 100644
--- a/lib/liquid/context.rb
+++ b/lib/liquid/context.rb
@@ -109,26 +109,11 @@ module Liquid
# end
#
# context['var] #=> nil
- #
- # false or {} can be used to control if a new scope is needed
- #
- # Example:
- # new_scope = false
- # context.stack(new_scope) do
- # # no scope created
- # end
- #
- # Example:
- # new_scope = {}
- # context.stack(new_scope) do
- # # scope created
- # end
- #
def stack(new_scope = {})
- push(new_scope) unless new_scope == false
+ push(new_scope)
yield
ensure
- pop unless new_scope == false
+ pop
end
def clear_instance_assigns
From 799da202dfab5cf1066ce45471d1dad46287b9f8 Mon Sep 17 00:00:00 2001
From: Mike Angell
Date: Sat, 31 Aug 2019 21:58:33 +1000
Subject: [PATCH 56/74] Apply simple rubocop fixes
---
.rubocop_todo.yml | 347 +-------------------
Rakefile | 14 +-
example/server/example_servlet.rb | 2 +-
example/server/liquid_servlet.rb | 4 +-
example/server/server.rb | 2 +-
lib/liquid/block.rb | 12 +-
lib/liquid/block_body.rb | 18 +-
lib/liquid/condition.rb | 14 +-
lib/liquid/context.rb | 4 +-
lib/liquid/document.rb | 6 +-
lib/liquid/drop.rb | 2 +-
lib/liquid/errors.rb | 6 +-
lib/liquid/expression.rb | 10 +-
lib/liquid/file_system.rb | 2 +-
lib/liquid/i18n.rb | 4 +-
lib/liquid/interrupts.rb | 4 +-
lib/liquid/lexer.rb | 15 +-
lib/liquid/parse_context.rb | 2 +-
lib/liquid/parse_tree_visitor.rb | 2 +-
lib/liquid/parser.rb | 2 +-
lib/liquid/standardfilters.rb | 10 +-
lib/liquid/strainer.rb | 4 +-
lib/liquid/tags/assign.rb | 6 +-
lib/liquid/tags/capture.rb | 4 +-
lib/liquid/tags/case.rb | 16 +-
lib/liquid/tags/cycle.rb | 8 +-
lib/liquid/tags/for.rb | 21 +-
lib/liquid/tags/if.rb | 10 +-
lib/liquid/tags/include.rb | 10 +-
lib/liquid/tags/raw.rb | 8 +-
lib/liquid/tags/render.rb | 6 +-
lib/liquid/tags/table_row.rb | 8 +-
lib/liquid/template.rb | 2 +-
lib/liquid/tokenizer.rb | 4 +-
lib/liquid/utils.rb | 2 +-
lib/liquid/variable.rb | 8 +-
lib/liquid/variable_lookup.rb | 4 +-
liquid.gemspec | 6 +-
performance/shopify/comment_form.rb | 8 +-
performance/shopify/database.rb | 13 +-
performance/shopify/json_filter.rb | 2 +-
performance/shopify/liquid.rb | 16 +-
performance/shopify/money_filter.rb | 4 +-
performance/shopify/paginate.rb | 22 +-
performance/shopify/shop_filter.rb | 16 +-
performance/shopify/tag_filter.rb | 4 +-
performance/shopify/weight_filter.rb | 2 +-
performance/theme_runner.rb | 2 +-
test/integration/blank_test.rb | 2 +-
test/integration/drop_test.rb | 10 +-
test/integration/error_handling_test.rb | 29 +-
test/integration/filter_test.rb | 12 +-
test/integration/hash_ordering_test.rb | 4 +-
test/integration/output_test.rb | 4 +-
test/integration/parse_tree_visitor_test.rb | 2 +-
test/integration/render_profiling_test.rb | 4 +-
test/integration/standard_filter_test.rb | 50 +--
test/integration/tags/echo_test.rb | 2 +-
test/integration/tags/for_tag_test.rb | 12 +-
test/integration/tags/if_else_tag_test.rb | 2 +-
test/integration/tags/include_tag_test.rb | 14 +-
test/integration/tags/increment_tag_test.rb | 4 +-
test/integration/tags/render_tag_test.rb | 2 +-
test/integration/tags/standard_tag_test.rb | 42 +--
test/integration/template_test.rb | 18 +-
test/integration/trim_mode_test.rb | 60 ++--
test/integration/variable_test.rb | 2 +-
test/test_helper.rb | 2 +-
test/unit/condition_unit_test.rb | 14 +-
test/unit/context_unit_test.rb | 20 +-
test/unit/partial_cache_unit_test.rb | 6 +-
test/unit/strainer_unit_test.rb | 7 +-
test/unit/tags/if_tag_unit_test.rb | 2 +-
73 files changed, 341 insertions(+), 683 deletions(-)
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 22330ae..0bd77b1 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -1,92 +1,17 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
-# on 2019-08-29 12:16:25 +1000 using RuboCop version 0.74.0.
+# on 2019-08-31 21:54:20 +1000 using RuboCop version 0.74.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
-# Offense count: 13
-# Cop supports --auto-correct.
-# Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle.
-# SupportedHashRocketStyles: key, separator, table
-# SupportedColonStyles: key, separator, table
-# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit
-Layout/AlignHash:
- Exclude:
- - 'lib/liquid/condition.rb'
- - 'lib/liquid/expression.rb'
- - 'performance/shopify/comment_form.rb'
- - 'performance/shopify/database.rb'
- - 'performance/shopify/paginate.rb'
- - 'test/unit/context_unit_test.rb'
-
-# Offense count: 3
-# Cop supports --auto-correct.
-# Configuration parameters: AllowForAlignment, AllowBeforeTrailingComments, ForceEqualSignAlignment.
-Layout/ExtraSpacing:
- Exclude:
- - 'performance/shopify/paginate.rb'
-
-# Offense count: 5
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: squiggly, active_support, powerpack, unindent
-Layout/IndentHeredoc:
- Exclude:
- - 'test/integration/tags/for_tag_test.rb'
- - 'test/integration/trim_mode_test.rb'
-
-# Offense count: 6
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: symmetrical, new_line, same_line
-Layout/MultilineMethodCallBraceLayout:
- Exclude:
- - 'test/integration/error_handling_test.rb'
- - 'test/unit/strainer_unit_test.rb'
-
-# Offense count: 4
-# Cop supports --auto-correct.
-# Configuration parameters: AllowForAlignment.
-Layout/SpaceAroundOperators:
- Exclude:
- - 'lib/liquid/condition.rb'
- - 'performance/shopify/paginate.rb'
-
-# Offense count: 9
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces.
-# SupportedStyles: space, no_space
-# SupportedStylesForEmptyBraces: space, no_space
-Layout/SpaceBeforeBlockBraces:
- Exclude:
- - 'example/server/server.rb'
- - 'lib/liquid/variable.rb'
- - 'test/integration/drop_test.rb'
- - 'test/integration/standard_filter_test.rb'
- - 'test/integration/tags/if_else_tag_test.rb'
-
-# Offense count: 19
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBrackets.
-# SupportedStyles: space, no_space, compact
-# SupportedStylesForEmptyBrackets: space, no_space
-Layout/SpaceInsideArrayLiteralBrackets:
- Exclude:
- - 'test/integration/drop_test.rb'
- - 'test/integration/standard_filter_test.rb'
- - 'test/integration/tags/for_tag_test.rb'
- - 'test/integration/tags/include_tag_test.rb'
- - 'test/integration/tags/standard_tag_test.rb'
- - 'test/unit/context_unit_test.rb'
-
# Offense count: 2
Lint/AmbiguousOperator:
Exclude:
- 'test/unit/condition_unit_test.rb'
-# Offense count: 16
+# Offense count: 21
# Configuration parameters: AllowSafeAssignment.
Lint/AssignmentInCondition:
Exclude:
@@ -95,51 +20,12 @@ Lint/AssignmentInCondition:
- 'lib/liquid/standardfilters.rb'
- 'lib/liquid/tags/for.rb'
- 'lib/liquid/tags/if.rb'
- - 'lib/liquid/tags/include.rb'
- 'lib/liquid/tags/raw.rb'
- 'lib/liquid/variable.rb'
- 'performance/profile.rb'
- 'test/test_helper.rb'
- 'test/unit/tokenizer_unit_test.rb'
-# Offense count: 2
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: runtime_error, standard_error
-Lint/InheritException:
- Exclude:
- - 'lib/liquid/interrupts.rb'
-
-# Offense count: 10
-# Cop supports --auto-correct.
-# Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments.
-Lint/UnusedBlockArgument:
- Exclude:
- - 'lib/liquid/condition.rb'
- - 'lib/liquid/context.rb'
- - 'lib/liquid/document.rb'
- - 'lib/liquid/parse_context.rb'
- - 'lib/liquid/template.rb'
- - 'performance/shopify/json_filter.rb'
- - 'test/integration/filter_test.rb'
- - 'test/integration/render_profiling_test.rb'
- - 'test/integration/variable_test.rb'
- - 'test/unit/condition_unit_test.rb'
-
-# Offense count: 12
-# Cop supports --auto-correct.
-# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods.
-Lint/UnusedMethodArgument:
- Exclude:
- - 'example/server/liquid_servlet.rb'
- - 'test/integration/blank_test.rb'
- - 'test/integration/error_handling_test.rb'
- - 'test/integration/filter_test.rb'
- - 'test/integration/output_test.rb'
- - 'test/integration/standard_filter_test.rb'
- - 'test/integration/tags/include_tag_test.rb'
- - 'test/unit/strainer_unit_test.rb'
-
# Offense count: 2
Lint/UselessAssignment:
Exclude:
@@ -151,64 +37,16 @@ Lint/Void:
Exclude:
- 'lib/liquid/parse_context.rb'
-# Offense count: 95
+# Offense count: 98
# Cop supports --auto-correct.
# Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
# URISchemes: http, https
Metrics/LineLength:
Max: 294
-# Offense count: 44
+# Offense count: 45
Naming/ConstantName:
- Exclude:
- - 'lib/liquid.rb'
- - 'lib/liquid/block_body.rb'
- - 'lib/liquid/tags/assign.rb'
- - 'lib/liquid/tags/capture.rb'
- - 'lib/liquid/tags/case.rb'
- - 'lib/liquid/tags/cycle.rb'
- - 'lib/liquid/tags/for.rb'
- - 'lib/liquid/tags/if.rb'
- - 'lib/liquid/tags/include.rb'
- - 'lib/liquid/tags/raw.rb'
- - 'lib/liquid/tags/table_row.rb'
- - 'lib/liquid/variable.rb'
- - 'performance/shopify/comment_form.rb'
- - 'performance/shopify/paginate.rb'
- - 'test/integration/tags/include_tag_test.rb'
-
-# Offense count: 2
-# Configuration parameters: .
-# SupportedStyles: snake_case, camelCase
-Naming/MethodName:
- EnforcedStyle: snake_case
-
-# Offense count: 3
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: always, conditionals
-Style/AndOr:
- Exclude:
- - 'lib/liquid/i18n.rb'
- - 'lib/liquid/tags/table_row.rb'
- - 'lib/liquid/tokenizer.rb'
-
-# Offense count: 40
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: braces, no_braces, context_dependent
-Style/BracesAroundHashParameters:
- Exclude:
- - 'test/integration/error_handling_test.rb'
- - 'test/integration/filter_test.rb'
- - 'test/integration/render_profiling_test.rb'
- - 'test/integration/standard_filter_test.rb'
- - 'test/integration/tags/echo_test.rb'
- - 'test/integration/tags/increment_tag_test.rb'
- - 'test/integration/tags/standard_tag_test.rb'
- - 'test/integration/template_test.rb'
- - 'test/unit/condition_unit_test.rb'
- - 'test/unit/context_unit_test.rb'
+ Enabled: false
# Offense count: 5
Style/ClassVars:
@@ -217,195 +55,24 @@ Style/ClassVars:
- 'lib/liquid/strainer.rb'
- 'lib/liquid/template.rb'
-# Offense count: 2
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, SingleLineConditionsOnly, IncludeTernaryExpressions.
-# SupportedStyles: assign_to_condition, assign_inside_condition
-Style/ConditionalAssignment:
- Exclude:
- - 'lib/liquid/errors.rb'
- - 'performance/shopify/shop_filter.rb'
-
# Offense count: 1
# Configuration parameters: AllowCoercion.
Style/DateTime:
Exclude:
- 'test/unit/context_unit_test.rb'
-# Offense count: 2
-# Cop supports --auto-correct.
-Style/EachWithObject:
- Exclude:
- - 'performance/shopify/database.rb'
-
-# Offense count: 1
-# Cop supports --auto-correct.
-Style/EmptyCaseCondition:
- Exclude:
- - 'lib/liquid/lexer.rb'
-
-# Offense count: 1
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: each, for
-Style/For:
- Exclude:
- - 'performance/shopify/shop_filter.rb'
-
-# Offense count: 9
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: format, sprintf, percent
-Style/FormatString:
- Exclude:
- - 'example/server/example_servlet.rb'
- - 'performance/shopify/money_filter.rb'
- - 'performance/shopify/weight_filter.rb'
- - 'test/integration/filter_test.rb'
- - 'test/integration/hash_ordering_test.rb'
-
-# Offense count: 115
+# Offense count: 119
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: always, never
Style/FrozenStringLiteralComment:
Enabled: false
-# Offense count: 30
-# Cop supports --auto-correct.
-# Configuration parameters: IgnoreMacros, IgnoredMethods, IncludedMacros, AllowParenthesesInMultilineCall, AllowParenthesesInChaining, AllowParenthesesInCamelCaseMethod, EnforcedStyle.
-# SupportedStyles: require_parentheses, omit_parentheses
-Style/MethodCallWithArgsParentheses:
- Exclude:
- - 'Gemfile'
- - 'Rakefile'
- - 'lib/liquid/block_body.rb'
- - 'lib/liquid/parser.rb'
- - 'lib/liquid/tags/for.rb'
- - 'liquid.gemspec'
- - 'performance/shopify/database.rb'
- - 'performance/shopify/liquid.rb'
- - 'test/test_helper.rb'
- - 'test/unit/condition_unit_test.rb'
- - 'test/unit/tags/if_tag_unit_test.rb'
-
-# Offense count: 1
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, MinBodyLength.
-# SupportedStyles: skip_modifier_ifs, always
-Style/Next:
- Exclude:
- - 'lib/liquid/tags/for.rb'
-
-# Offense count: 52
-# Cop supports --auto-correct.
-Style/PerlBackrefs:
- Enabled: false
-
-# Offense count: 33
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: compact, exploded
-Style/RaiseArgs:
- Enabled: false
-
-# Offense count: 1
-# Cop supports --auto-correct.
-Style/RedundantSelf:
- Exclude:
- - 'lib/liquid/strainer.rb'
-
-# Offense count: 5
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, AllowInnerSlashes.
-# SupportedStyles: slashes, percent_r, mixed
-Style/RegexpLiteral:
- Exclude:
- - 'lib/liquid/file_system.rb'
- - 'lib/liquid/standardfilters.rb'
- - 'performance/shopify/shop_filter.rb'
- - 'test/unit/condition_unit_test.rb'
-
-# Offense count: 3
-# Cop supports --auto-correct.
-# Configuration parameters: ConvertCodeThatCanStartToReturnNil, Whitelist.
-# Whitelist: present?, blank?, presence, try, try!
-Style/SafeNavigation:
- Exclude:
- - 'lib/liquid/drop.rb'
- - 'lib/liquid/strainer.rb'
- - 'lib/liquid/tokenizer.rb'
-
-# Offense count: 10
+# Offense count: 9
# Cop supports --auto-correct.
# Configuration parameters: AllowAsExpressionSeparator.
Style/Semicolon:
Exclude:
- - 'performance/shopify/database.rb'
- 'test/integration/error_handling_test.rb'
- 'test/integration/template_test.rb'
- 'test/unit/context_unit_test.rb'
-
-# Offense count: 1
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: use_perl_names, use_english_names
-Style/SpecialGlobalVars:
- Exclude:
- - 'performance/shopify/liquid.rb'
-
-# Offense count: 2
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: single_quotes, double_quotes
-Style/StringLiteralsInInterpolation:
- Exclude:
- - 'performance/shopify/tag_filter.rb'
-
-# Offense count: 2
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, AllowSafeAssignment.
-# SupportedStyles: require_parentheses, require_no_parentheses, require_parentheses_when_complex
-Style/TernaryParentheses:
- Exclude:
- - 'lib/liquid/context.rb'
- - 'lib/liquid/utils.rb'
-
-# Offense count: 21
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyleForMultiline.
-# SupportedStylesForMultiline: comma, consistent_comma, no_comma
-Style/TrailingCommaInArrayLiteral:
- Exclude:
- - 'lib/liquid/parse_tree_visitor.rb'
- - 'lib/liquid/tags/include.rb'
- - 'test/integration/parse_tree_visitor_test.rb'
- - 'test/integration/standard_filter_test.rb'
-
-# Offense count: 9
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyleForMultiline.
-# SupportedStylesForMultiline: comma, consistent_comma, no_comma
-Style/TrailingCommaInHashLiteral:
- Exclude:
- - 'lib/liquid/condition.rb'
- - 'lib/liquid/lexer.rb'
- - 'lib/liquid/standardfilters.rb'
- - 'performance/shopify/comment_form.rb'
- - 'performance/shopify/database.rb'
- - 'performance/shopify/paginate.rb'
- - 'performance/theme_runner.rb'
- - 'test/integration/output_test.rb'
- - 'test/unit/context_unit_test.rb'
-
-# Offense count: 2
-# Cop supports --auto-correct.
-Style/UnneededPercentQ:
- Exclude:
- - 'test/integration/error_handling_test.rb'
-
-# Offense count: 1
-# Cop supports --auto-correct.
-Style/WhileUntilModifier:
- Exclude:
- - 'lib/liquid/tags/case.rb'
diff --git a/Rakefile b/Rakefile
index f7186eb..f2a0d07 100755
--- a/Rakefile
+++ b/Rakefile
@@ -1,18 +1,18 @@
require 'rake'
require 'rake/testtask'
-$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
+$LOAD_PATH.unshift(File.expand_path("../lib", __FILE__))
require "liquid/version"
-task default: [:test, :rubocop]
+task(default: [:test, :rubocop])
-desc 'run test suite with default parser'
+desc('run test suite with default parser')
Rake::TestTask.new(:base_test) do |t|
t.libs << '.' << 'lib' << 'test'
t.test_files = FileList['test/{integration,unit}/**/*_test.rb']
t.verbose = false
end
-desc 'run test suite with warn error mode'
+desc('run test suite with warn error mode')
task :warn_test do
ENV['LIQUID_PARSER_MODE'] = 'warn'
Rake::Task['base_test'].invoke
@@ -25,7 +25,7 @@ task :rubocop do
end
end
-desc 'runs test suite with both strict and lax parsers'
+desc('runs test suite with both strict and lax parsers')
task :test do
ENV['LIQUID_PARSER_MODE'] = 'lax'
Rake::Task['base_test'].invoke
@@ -47,7 +47,7 @@ task :test do
end
end
-task gem: :build
+task(gem: :build)
task :build do
system "gem build liquid.gemspec"
end
@@ -94,7 +94,7 @@ namespace :memory_profile do
end
end
-desc "Run example"
+desc("Run example")
task :example do
ruby "-w -d -Ilib example/server/server.rb"
end
diff --git a/example/server/example_servlet.rb b/example/server/example_servlet.rb
index dbc7a4b..9f8c58a 100644
--- a/example/server/example_servlet.rb
+++ b/example/server/example_servlet.rb
@@ -1,6 +1,6 @@
module ProductsFilter
def price(integer)
- sprintf("$%.2d USD", integer / 100.0)
+ format("$%.2d USD", integer / 100.0)
end
def prettyprint(text)
diff --git a/example/server/liquid_servlet.rb b/example/server/liquid_servlet.rb
index b2bf515..895f274 100644
--- a/example/server/liquid_servlet.rb
+++ b/example/server/liquid_servlet.rb
@@ -9,12 +9,12 @@ class LiquidServlet < WEBrick::HTTPServlet::AbstractServlet
private
- def handle(type, req, res)
+ def handle(_type, req, res)
@request = req
@response = res
@request.path_info =~ /(\w+)\z/
- @action = $1 || 'index'
+ @action = Regexp.last_match(1) || 'index'
@assigns = send(@action) if respond_to?(@action)
@response['Content-Type'] = "text/html"
diff --git a/example/server/server.rb b/example/server/server.rb
index 703b361..f2f89a4 100644
--- a/example/server/server.rb
+++ b/example/server/server.rb
@@ -8,5 +8,5 @@ require_relative 'example_servlet'
# Setup webrick
server = WEBrick::HTTPServer.new(Port: ARGV[1] || 3000)
server.mount('/', Servlet)
-trap("INT"){ server.shutdown }
+trap("INT") { server.shutdown }
server.start
diff --git a/lib/liquid/block.rb b/lib/liquid/block.rb
index 549a3a3..0036d7b 100644
--- a/lib/liquid/block.rb
+++ b/lib/liquid/block.rb
@@ -28,15 +28,15 @@ module Liquid
def unknown_tag(tag, _params, _tokens)
if tag == 'else'.freeze
- raise SyntaxError.new(parse_context.locale.t("errors.syntax.unexpected_else".freeze,
- block_name: block_name))
+ raise SyntaxError, parse_context.locale.t("errors.syntax.unexpected_else".freeze,
+ block_name: block_name)
elsif tag.start_with?('end'.freeze)
- raise SyntaxError.new(parse_context.locale.t("errors.syntax.invalid_delimiter".freeze,
+ raise SyntaxError, parse_context.locale.t("errors.syntax.invalid_delimiter".freeze,
tag: tag,
block_name: block_name,
- block_delimiter: block_delimiter))
+ block_delimiter: block_delimiter)
else
- raise SyntaxError.new(parse_context.locale.t("errors.syntax.unknown_tag".freeze, tag: tag))
+ raise SyntaxError, parse_context.locale.t("errors.syntax.unknown_tag".freeze, tag: tag)
end
end
@@ -61,7 +61,7 @@ module Liquid
return false if end_tag_name == block_delimiter
unless end_tag_name
- raise SyntaxError.new(parse_context.locale.t("errors.syntax.tag_never_closed".freeze, block_name: block_name))
+ raise SyntaxError, parse_context.locale.t("errors.syntax.tag_never_closed".freeze, block_name: block_name)
end
# this tag is not registered with the system
diff --git a/lib/liquid/block_body.rb b/lib/liquid/block_body.rb
index 27b4eef..a52eb62 100644
--- a/lib/liquid/block_body.rb
+++ b/lib/liquid/block_body.rb
@@ -32,8 +32,8 @@ module Liquid
# caller raise a syntax error
return yield token, token
end
- tag_name = $1
- markup = $2
+ tag_name = Regexp.last_match(1)
+ markup = Regexp.last_match(2)
unless tag = registered_tags[tag_name]
# end parsing if we reach an unknown tag and let the caller decide
# determine how to proceed
@@ -58,13 +58,13 @@ module Liquid
unless token =~ FullToken
raise_missing_tag_terminator(token, parse_context)
end
- tag_name = $2
- markup = $4
+ tag_name = Regexp.last_match(2)
+ markup = Regexp.last_match(4)
if parse_context.line_number
# newlines inside the tag should increase the line number,
# particularly important for multiline {% liquid %} tags
- parse_context.line_number += $1.count("\n".freeze) + $3.count("\n".freeze)
+ parse_context.line_number += Regexp.last_match(1).count("\n".freeze) + Regexp.last_match(3).count("\n".freeze)
end
if tag_name == 'liquid'.freeze
@@ -101,7 +101,7 @@ module Liquid
def whitespace_handler(token, parse_context)
if token[2] == WhitespaceControl
previous_token = @nodelist.last
- if previous_token.is_a? String
+ if previous_token.is_a?(String)
previous_token.rstrip!
end
end
@@ -163,7 +163,7 @@ module Liquid
def raise_if_resource_limits_reached(context, length)
context.resource_limits.render_length += length
return unless context.resource_limits.reached?
- raise MemoryError.new("Memory limits exceeded".freeze)
+ raise MemoryError, "Memory limits exceeded".freeze
end
def create_variable(token, parse_context)
@@ -175,11 +175,11 @@ module Liquid
end
def raise_missing_tag_terminator(token, parse_context)
- raise SyntaxError.new(parse_context.locale.t("errors.syntax.tag_termination".freeze, token: token, tag_end: TagEnd.inspect))
+ raise SyntaxError, parse_context.locale.t("errors.syntax.tag_termination".freeze, token: token, tag_end: TagEnd.inspect)
end
def raise_missing_variable_terminator(token, parse_context)
- raise SyntaxError.new(parse_context.locale.t("errors.syntax.variable_termination".freeze, token: token, tag_end: VariableEnd.inspect))
+ raise SyntaxError, parse_context.locale.t("errors.syntax.variable_termination".freeze, token: token, tag_end: VariableEnd.inspect)
end
def registered_tags
diff --git a/lib/liquid/condition.rb b/lib/liquid/condition.rb
index 3b51682..c6e29ae 100644
--- a/lib/liquid/condition.rb
+++ b/lib/liquid/condition.rb
@@ -11,18 +11,18 @@ module Liquid
'=='.freeze => ->(cond, left, right) { cond.send(:equal_variables, left, right) },
'!='.freeze => ->(cond, left, right) { !cond.send(:equal_variables, left, right) },
'<>'.freeze => ->(cond, left, right) { !cond.send(:equal_variables, left, right) },
- '<'.freeze => :<,
- '>'.freeze => :>,
+ '<'.freeze => :<,
+ '>'.freeze => :>,
'>='.freeze => :>=,
'<='.freeze => :<=,
- 'contains'.freeze => lambda do |cond, left, right|
+ 'contains'.freeze => lambda do |_cond, left, right|
if left && right && left.respond_to?(:include?)
right = right.to_s if left.is_a?(String)
left.include?(right)
else
false
end
- end
+ end,
}
def self.operators
@@ -36,7 +36,7 @@ module Liquid
@left = left
@operator = operator
@right = right
- @child_relation = nil
+ @child_relation = nil
@child_condition = nil
end
@@ -116,7 +116,7 @@ module Liquid
left = context.evaluate(left)
right = context.evaluate(right)
- operation = self.class.operators[op] || raise(Liquid::ArgumentError.new("Unknown operator #{op}"))
+ operation = self.class.operators[op] || raise(Liquid::ArgumentError, "Unknown operator #{op}")
if operation.respond_to?(:call)
operation.call(self, left, right)
@@ -124,7 +124,7 @@ module Liquid
begin
left.send(operation, right)
rescue ::ArgumentError => e
- raise Liquid::ArgumentError.new(e.message)
+ raise Liquid::ArgumentError, e.message
end
end
end
diff --git a/lib/liquid/context.rb b/lib/liquid/context.rb
index 90e6b78..b5d5638 100644
--- a/lib/liquid/context.rb
+++ b/lib/liquid/context.rb
@@ -39,7 +39,7 @@ module Liquid
self.exception_renderer = Template.default_exception_renderer
if rethrow_errors
- self.exception_renderer = ->(e) { raise }
+ self.exception_renderer = ->(_e) { raise }
end
@interrupts = []
@@ -215,7 +215,7 @@ module Liquid
value = obj[key]
if value.is_a?(Proc) && obj.respond_to?(:[]=)
- obj[key] = (value.arity == 0) ? value.call : value.call(self)
+ obj[key] = value.arity == 0 ? value.call : value.call(self)
else
value
end
diff --git a/lib/liquid/document.rb b/lib/liquid/document.rb
index d035dd4..afd4e99 100644
--- a/lib/liquid/document.rb
+++ b/lib/liquid/document.rb
@@ -7,7 +7,7 @@ module Liquid
end
def parse(tokens, parse_context)
- super do |end_tag_name, end_tag_params|
+ super do |end_tag_name, _end_tag_params|
unknown_tag(end_tag_name, parse_context) if end_tag_name
end
rescue SyntaxError => e
@@ -18,9 +18,9 @@ module Liquid
def unknown_tag(tag, parse_context)
case tag
when 'else'.freeze, 'end'.freeze
- raise SyntaxError.new(parse_context.locale.t("errors.syntax.unexpected_outer_tag".freeze, tag: tag))
+ raise SyntaxError, parse_context.locale.t("errors.syntax.unexpected_outer_tag".freeze, tag: tag)
else
- raise SyntaxError.new(parse_context.locale.t("errors.syntax.unknown_tag".freeze, tag: tag))
+ raise SyntaxError, parse_context.locale.t("errors.syntax.unknown_tag".freeze, tag: tag)
end
end
end
diff --git a/lib/liquid/drop.rb b/lib/liquid/drop.rb
index 6b5aa99..14d6eac 100644
--- a/lib/liquid/drop.rb
+++ b/lib/liquid/drop.rb
@@ -25,7 +25,7 @@ module Liquid
# Catch all for the method
def liquid_method_missing(method)
- return nil unless @context && @context.strict_variables
+ return nil unless @context&.strict_variables
raise Liquid::UndefinedDropMethod, "undefined method #{method}"
end
diff --git a/lib/liquid/errors.rb b/lib/liquid/errors.rb
index defa5ea..4239746 100644
--- a/lib/liquid/errors.rb
+++ b/lib/liquid/errors.rb
@@ -21,10 +21,10 @@ module Liquid
def message_prefix
str = ""
- if is_a?(SyntaxError)
- str << "Liquid syntax error"
+ str << if is_a?(SyntaxError)
+ "Liquid syntax error"
else
- str << "Liquid error"
+ "Liquid error"
end
if line_number
diff --git a/lib/liquid/expression.rb b/lib/liquid/expression.rb
index 98be6db..5568199 100644
--- a/lib/liquid/expression.rb
+++ b/lib/liquid/expression.rb
@@ -15,7 +15,7 @@ module Liquid
LITERALS = {
nil => nil, 'nil'.freeze => nil, 'null'.freeze => nil, ''.freeze => nil,
- 'true'.freeze => true,
+ 'true'.freeze => true,
'false'.freeze => false,
'blank'.freeze => MethodLiteral.new(:blank?, '').freeze,
'empty'.freeze => MethodLiteral.new(:empty?, '').freeze
@@ -33,13 +33,13 @@ module Liquid
else
case markup
when SINGLE_QUOTED_STRING, DOUBLE_QUOTED_STRING
- $1
+ Regexp.last_match(1)
when INTEGERS_REGEX
- $1.to_i
+ Regexp.last_match(1).to_i
when RANGES_REGEX
- RangeLookup.parse($1, $2)
+ RangeLookup.parse(Regexp.last_match(1), Regexp.last_match(2))
when FLOATS_REGEX
- $1.to_f
+ Regexp.last_match(1).to_f
else
VariableLookup.parse(markup)
end
diff --git a/lib/liquid/file_system.rb b/lib/liquid/file_system.rb
index 13f1f46..a2aa9b7 100644
--- a/lib/liquid/file_system.rb
+++ b/lib/liquid/file_system.rb
@@ -57,7 +57,7 @@ module Liquid
end
def full_path(template_path)
- raise FileSystemError, "Illegal template name '#{template_path}'" unless template_path =~ /\A[^.\/][a-zA-Z0-9_\/]+\z/
+ raise FileSystemError, "Illegal template name '#{template_path}'" unless template_path =~ %r{\A[^./][a-zA-Z0-9_/]+\z}
full_path = if template_path.include?('/'.freeze)
File.join(root, File.dirname(template_path), @pattern % File.basename(template_path))
diff --git a/lib/liquid/i18n.rb b/lib/liquid/i18n.rb
index 2671507..b2bb51b 100644
--- a/lib/liquid/i18n.rb
+++ b/lib/liquid/i18n.rb
@@ -26,13 +26,13 @@ module Liquid
def interpolate(name, vars)
name.gsub(/%\{(\w+)\}/) do
# raise TranslationError, "Undefined key #{$1} for interpolation in translation #{name}" unless vars[$1.to_sym]
- (vars[$1.to_sym]).to_s
+ (vars[Regexp.last_match(1).to_sym]).to_s
end
end
def deep_fetch_translation(name)
name.split('.'.freeze).reduce(locale) do |level, cur|
- level[cur] or raise TranslationError, "Translation for #{name} does not exist in locale #{path}"
+ level[cur] || raise(TranslationError, "Translation for #{name} does not exist in locale #{path}")
end
end
end
diff --git a/lib/liquid/interrupts.rb b/lib/liquid/interrupts.rb
index 41359d7..f3005e4 100644
--- a/lib/liquid/interrupts.rb
+++ b/lib/liquid/interrupts.rb
@@ -9,8 +9,8 @@ module Liquid
end
# Interrupt that is thrown whenever a {% break %} is called.
- class BreakInterrupt < Interrupt; end
+ class BreakInterrupt < RuntimeError; end
# Interrupt that is thrown whenever a {% continue %} is called.
- class ContinueInterrupt < Interrupt; end
+ class ContinueInterrupt < RuntimeError; end
end
diff --git a/lib/liquid/lexer.rb b/lib/liquid/lexer.rb
index f290744..367f99e 100644
--- a/lib/liquid/lexer.rb
+++ b/lib/liquid/lexer.rb
@@ -11,7 +11,7 @@ module Liquid
'('.freeze => :open_round,
')'.freeze => :close_round,
'?'.freeze => :question,
- '-'.freeze => :dash
+ '-'.freeze => :dash,
}.freeze
IDENTIFIER = /[a-zA-Z_][\w-]*\??/
SINGLE_STRING_LITERAL = /'[^\']*'/
@@ -31,13 +31,12 @@ module Liquid
until @ss.eos?
@ss.skip(WHITESPACE_OR_NOTHING)
break if @ss.eos?
- tok = case
- when t = @ss.scan(COMPARISON_OPERATOR) then [:comparison, t]
- when t = @ss.scan(SINGLE_STRING_LITERAL) then [:string, t]
- when t = @ss.scan(DOUBLE_STRING_LITERAL) then [:string, t]
- when t = @ss.scan(NUMBER_LITERAL) then [:number, t]
- when t = @ss.scan(IDENTIFIER) then [:id, t]
- when t = @ss.scan(DOTDOT) then [:dotdot, t]
+ tok = if t = @ss.scan(COMPARISON_OPERATOR) then [:comparison, t]
+ elsif t = @ss.scan(SINGLE_STRING_LITERAL) then [:string, t]
+ elsif t = @ss.scan(DOUBLE_STRING_LITERAL) then [:string, t]
+ elsif t = @ss.scan(NUMBER_LITERAL) then [:number, t]
+ elsif t = @ss.scan(IDENTIFIER) then [:id, t]
+ elsif t = @ss.scan(DOTDOT) then [:dotdot, t]
else
c = @ss.getch
if s = SPECIALS[c]
diff --git a/lib/liquid/parse_context.rb b/lib/liquid/parse_context.rb
index abcdaeb..58437f4 100644
--- a/lib/liquid/parse_context.rb
+++ b/lib/liquid/parse_context.rb
@@ -28,7 +28,7 @@ module Liquid
if dont_pass == true
{ locale: locale }
elsif dont_pass.is_a?(Array)
- @template_options.reject { |k, v| dont_pass.include?(k) }
+ @template_options.reject { |k, _v| dont_pass.include?(k) }
else
@template_options
end
diff --git a/lib/liquid/parse_tree_visitor.rb b/lib/liquid/parse_tree_visitor.rb
index 74f5563..d50943f 100644
--- a/lib/liquid/parse_tree_visitor.rb
+++ b/lib/liquid/parse_tree_visitor.rb
@@ -28,7 +28,7 @@ module Liquid
item, new_context = @callbacks[node.class].call(node, context)
[
item,
- ParseTreeVisitor.for(node, @callbacks).visit(new_context || context)
+ ParseTreeVisitor.for(node, @callbacks).visit(new_context || context),
]
end
end
diff --git a/lib/liquid/parser.rb b/lib/liquid/parser.rb
index 16df6e9..c36de86 100644
--- a/lib/liquid/parser.rb
+++ b/lib/liquid/parser.rb
@@ -51,7 +51,7 @@ module Liquid
token = @tokens[@p]
if token[0] == :id
variable_signature
- elsif SINGLE_TOKEN_EXPRESSION_TYPES.include? token[0]
+ elsif SINGLE_TOKEN_EXPRESSION_TYPES.include?(token[0])
consume
elsif token.first == :open_round
consume
diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb
index afcf479..b13d089 100644
--- a/lib/liquid/standardfilters.rb
+++ b/lib/liquid/standardfilters.rb
@@ -8,13 +8,13 @@ module Liquid
'>'.freeze => '>'.freeze,
'<'.freeze => '<'.freeze,
'"'.freeze => '"'.freeze,
- "'".freeze => '''.freeze
+ "'".freeze => '''.freeze,
}.freeze
HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/
STRIP_HTML_BLOCKS = Regexp.union(
- //m,
+ %r{}m,
//m,
- //m
+ %r{}m
)
STRIP_HTML_TAGS = /<.*?>/m
@@ -276,7 +276,7 @@ module Liquid
def concat(input, array)
unless array.respond_to?(:to_ary)
- raise ArgumentError.new("concat filter requires an array argument")
+ raise ArgumentError, "concat filter requires an array argument"
end
InputIterator.new(input).concat(array)
end
@@ -430,7 +430,7 @@ module Liquid
private
def raise_property_error(property)
- raise Liquid::ArgumentError.new("cannot select the property '#{property}'")
+ raise Liquid::ArgumentError, "cannot select the property '#{property}'"
end
def apply_operation(input, operand, operation)
diff --git a/lib/liquid/strainer.rb b/lib/liquid/strainer.rb
index 76d56d2..d885ae4 100644
--- a/lib/liquid/strainer.rb
+++ b/lib/liquid/strainer.rb
@@ -27,7 +27,7 @@ module Liquid
def self.add_filter(filter)
raise ArgumentError, "Expected module but got: #{filter.class}" unless filter.is_a?(Module)
- unless self.include?(filter)
+ unless include?(filter)
invokable_non_public_methods = (filter.private_instance_methods + filter.protected_instance_methods).select { |m| invokable?(m) }
if invokable_non_public_methods.any?
raise MethodOverrideError, "Filter overrides registered public methods as non public: #{invokable_non_public_methods.join(', ')}"
@@ -54,7 +54,7 @@ module Liquid
def invoke(method, *args)
if self.class.invokable?(method)
send(method, *args)
- elsif @context && @context.strict_filters
+ elsif @context&.strict_filters
raise Liquid::UndefinedFilter, "undefined filter #{method}"
else
args.first
diff --git a/lib/liquid/tags/assign.rb b/lib/liquid/tags/assign.rb
index 50a9553..6ff65d5 100644
--- a/lib/liquid/tags/assign.rb
+++ b/lib/liquid/tags/assign.rb
@@ -19,10 +19,10 @@ module Liquid
def initialize(tag_name, markup, options)
super
if markup =~ Syntax
- @to = $1
- @from = Variable.new($2, options)
+ @to = Regexp.last_match(1)
+ @from = Variable.new(Regexp.last_match(2), options)
else
- raise SyntaxError.new(options[:locale].t(self.class.syntax_error_translation_key))
+ raise SyntaxError, options[:locale].t(self.class.syntax_error_translation_key)
end
end
diff --git a/lib/liquid/tags/capture.rb b/lib/liquid/tags/capture.rb
index d717b76..a97e42a 100644
--- a/lib/liquid/tags/capture.rb
+++ b/lib/liquid/tags/capture.rb
@@ -16,9 +16,9 @@ module Liquid
def initialize(tag_name, markup, options)
super
if markup =~ Syntax
- @to = $1
+ @to = Regexp.last_match(1)
else
- raise SyntaxError.new(options[:locale].t("errors.syntax.capture"))
+ raise SyntaxError, options[:locale].t("errors.syntax.capture")
end
end
diff --git a/lib/liquid/tags/case.rb b/lib/liquid/tags/case.rb
index 92b2ed0..7d43019 100644
--- a/lib/liquid/tags/case.rb
+++ b/lib/liquid/tags/case.rb
@@ -10,17 +10,15 @@ module Liquid
@blocks = []
if markup =~ Syntax
- @left = Expression.parse($1)
+ @left = Expression.parse(Regexp.last_match(1))
else
- raise SyntaxError.new(options[:locale].t("errors.syntax.case".freeze))
+ raise SyntaxError, options[:locale].t("errors.syntax.case".freeze)
end
end
def parse(tokens)
body = BlockBody.new
- while parse_body(body, tokens)
- body = @blocks.last.attachment
- end
+ body = @blocks.last.attachment while parse_body(body, tokens)
end
def nodelist
@@ -62,12 +60,12 @@ module Liquid
while markup
unless markup =~ WhenSyntax
- raise SyntaxError.new(options[:locale].t("errors.syntax.case_invalid_when".freeze))
+ raise SyntaxError, options[:locale].t("errors.syntax.case_invalid_when".freeze)
end
- markup = $2
+ markup = Regexp.last_match(2)
- block = Condition.new(@left, '=='.freeze, Expression.parse($1))
+ block = Condition.new(@left, '=='.freeze, Expression.parse(Regexp.last_match(1)))
block.attach(body)
@blocks << block
end
@@ -75,7 +73,7 @@ module Liquid
def record_else_condition(markup)
unless markup.strip.empty?
- raise SyntaxError.new(options[:locale].t("errors.syntax.case_invalid_else".freeze))
+ raise SyntaxError, options[:locale].t("errors.syntax.case_invalid_else".freeze)
end
block = ElseCondition.new
diff --git a/lib/liquid/tags/cycle.rb b/lib/liquid/tags/cycle.rb
index e42244d..3399902 100644
--- a/lib/liquid/tags/cycle.rb
+++ b/lib/liquid/tags/cycle.rb
@@ -21,13 +21,13 @@ module Liquid
super
case markup
when NamedSyntax
- @variables = variables_from_string($2)
- @name = Expression.parse($1)
+ @variables = variables_from_string(Regexp.last_match(2))
+ @name = Expression.parse(Regexp.last_match(1))
when SimpleSyntax
@variables = variables_from_string(markup)
@name = @variables.to_s
else
- raise SyntaxError.new(options[:locale].t("errors.syntax.cycle".freeze))
+ raise SyntaxError, options[:locale].t("errors.syntax.cycle".freeze)
end
end
@@ -61,7 +61,7 @@ module Liquid
def variables_from_string(markup)
markup.split(',').collect do |var|
var =~ /\s*(#{QuotedFragment})\s*/o
- $1 ? Expression.parse($1) : nil
+ Regexp.last_match(1) ? Expression.parse(Regexp.last_match(1)) : nil
end.compact
end
diff --git a/lib/liquid/tags/for.rb b/lib/liquid/tags/for.rb
index 71c2f91..f20953f 100644
--- a/lib/liquid/tags/for.rb
+++ b/lib/liquid/tags/for.rb
@@ -86,23 +86,23 @@ module Liquid
def lax_parse(markup)
if markup =~ Syntax
- @variable_name = $1
- collection_name = $2
- @reversed = !!$3
+ @variable_name = Regexp.last_match(1)
+ collection_name = Regexp.last_match(2)
+ @reversed = !!Regexp.last_match(3)
@name = "#{@variable_name}-#{collection_name}"
@collection_name = Expression.parse(collection_name)
markup.scan(TagAttributes) do |key, value|
set_attribute(key, value)
end
else
- raise SyntaxError.new(options[:locale].t("errors.syntax.for".freeze))
+ raise SyntaxError, options[:locale].t("errors.syntax.for".freeze)
end
end
def strict_parse(markup)
p = Parser.new(markup)
@variable_name = p.consume(:id)
- raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_in".freeze)) unless p.id?('in'.freeze)
+ raise SyntaxError, options[:locale].t("errors.syntax.for_invalid_in".freeze) unless p.id?('in'.freeze)
collection_name = p.expression
@name = "#{@variable_name}-#{collection_name}"
@collection_name = Expression.parse(collection_name)
@@ -110,7 +110,7 @@ module Liquid
while p.look(:id) && p.look(:colon, 1)
unless attribute = p.id?('limit'.freeze) || p.id?('offset'.freeze)
- raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_attribute".freeze))
+ raise SyntaxError, options[:locale].t("errors.syntax.for_invalid_attribute".freeze)
end
p.consume
set_attribute(attribute, p.expression)
@@ -170,11 +170,10 @@ module Liquid
loop_vars.send(:increment!)
# Handle any interrupts if they exist.
- if context.interrupt?
- interrupt = context.pop_interrupt
- break if interrupt.is_a? BreakInterrupt
- next if interrupt.is_a? ContinueInterrupt
- end
+ next unless context.interrupt?
+ interrupt = context.pop_interrupt
+ break if interrupt.is_a?(BreakInterrupt)
+ next if interrupt.is_a?(ContinueInterrupt)
end
ensure
for_stack.pop
diff --git a/lib/liquid/tags/if.rb b/lib/liquid/tags/if.rb
index 25534a9..5c9b8bb 100644
--- a/lib/liquid/tags/if.rb
+++ b/lib/liquid/tags/if.rb
@@ -66,17 +66,17 @@ module Liquid
def lax_parse(markup)
expressions = markup.scan(ExpressionsAndOperators)
- raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.pop =~ Syntax
+ raise SyntaxError, options[:locale].t("errors.syntax.if".freeze) unless expressions.pop =~ Syntax
- condition = Condition.new(Expression.parse($1), $2, Expression.parse($3))
+ condition = Condition.new(Expression.parse(Regexp.last_match(1)), Regexp.last_match(2), Expression.parse(Regexp.last_match(3)))
until expressions.empty?
operator = expressions.pop.to_s.strip
- raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.pop.to_s =~ Syntax
+ raise SyntaxError, options[:locale].t("errors.syntax.if".freeze) unless expressions.pop.to_s =~ Syntax
- new_condition = Condition.new(Expression.parse($1), $2, Expression.parse($3))
- raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless BOOLEAN_OPERATORS.include?(operator)
+ new_condition = Condition.new(Expression.parse(Regexp.last_match(1)), Regexp.last_match(2), Expression.parse(Regexp.last_match(3)))
+ raise SyntaxError, options[:locale].t("errors.syntax.if".freeze) unless BOOLEAN_OPERATORS.include?(operator)
new_condition.send(operator, condition)
condition = new_condition
end
diff --git a/lib/liquid/tags/include.rb b/lib/liquid/tags/include.rb
index fd86ee4..d2c6cd2 100644
--- a/lib/liquid/tags/include.rb
+++ b/lib/liquid/tags/include.rb
@@ -23,8 +23,8 @@ module Liquid
if markup =~ Syntax
- template_name = $1
- variable_name = $3
+ template_name = Regexp.last_match(1)
+ variable_name = Regexp.last_match(3)
@variable_name_expr = variable_name ? Expression.parse(variable_name) : nil
@template_name_expr = Expression.parse(template_name)
@@ -35,7 +35,7 @@ module Liquid
end
else
- raise SyntaxError.new(options[:locale].t("errors.syntax.include".freeze))
+ raise SyntaxError, options[:locale].t("errors.syntax.include".freeze)
end
end
@@ -44,7 +44,7 @@ module Liquid
def render_to_output_buffer(context, output)
template_name = context.evaluate(@template_name_expr)
- raise ArgumentError.new(options[:locale].t("errors.argument.include")) unless template_name
+ raise ArgumentError, options[:locale].t("errors.argument.include") unless template_name
partial = PartialCache.load(
template_name,
@@ -95,7 +95,7 @@ module Liquid
def children
[
@node.template_name_expr,
- @node.variable_name_expr
+ @node.variable_name_expr,
] + @node.attributes.values
end
end
diff --git a/lib/liquid/tags/raw.rb b/lib/liquid/tags/raw.rb
index 4fa75d9..6991002 100644
--- a/lib/liquid/tags/raw.rb
+++ b/lib/liquid/tags/raw.rb
@@ -13,13 +13,13 @@ module Liquid
@body = ''
while token = tokens.shift
if token =~ FullTokenPossiblyInvalid
- @body << $1 if $1 != "".freeze
- return if block_delimiter == $2
+ @body << Regexp.last_match(1) if Regexp.last_match(1) != "".freeze
+ return if block_delimiter == Regexp.last_match(2)
end
@body << token unless token.empty?
end
- raise SyntaxError.new(parse_context.locale.t("errors.syntax.tag_never_closed".freeze, block_name: block_name))
+ raise SyntaxError, parse_context.locale.t("errors.syntax.tag_never_closed".freeze, block_name: block_name)
end
def render_to_output_buffer(_context, output)
@@ -39,7 +39,7 @@ module Liquid
def ensure_valid_markup(tag_name, markup, parse_context)
unless markup =~ Syntax
- raise SyntaxError.new(parse_context.locale.t("errors.syntax.tag_unexpected_args".freeze, tag: tag_name))
+ raise SyntaxError, parse_context.locale.t("errors.syntax.tag_unexpected_args".freeze, tag: tag_name)
end
end
end
diff --git a/lib/liquid/tags/render.rb b/lib/liquid/tags/render.rb
index 2e5310b..d728898 100644
--- a/lib/liquid/tags/render.rb
+++ b/lib/liquid/tags/render.rb
@@ -7,9 +7,9 @@ module Liquid
def initialize(tag_name, markup, options)
super
- raise SyntaxError.new(options[:locale].t("errors.syntax.render".freeze)) unless markup =~ Syntax
+ raise SyntaxError, options[:locale].t("errors.syntax.render".freeze) unless markup =~ Syntax
- template_name = $1
+ template_name = Regexp.last_match(1)
@template_name_expr = Expression.parse(template_name)
@@ -22,7 +22,7 @@ module Liquid
def render_to_output_buffer(context, output)
# Though we evaluate this here we will only ever parse it as a string literal.
template_name = context.evaluate(@template_name_expr)
- raise ArgumentError.new(options[:locale].t("errors.argument.include")) unless template_name
+ raise ArgumentError, options[:locale].t("errors.argument.include") unless template_name
partial = PartialCache.load(
template_name,
diff --git a/lib/liquid/tags/table_row.rb b/lib/liquid/tags/table_row.rb
index 9532102..9393527 100644
--- a/lib/liquid/tags/table_row.rb
+++ b/lib/liquid/tags/table_row.rb
@@ -7,19 +7,19 @@ module Liquid
def initialize(tag_name, markup, options)
super
if markup =~ Syntax
- @variable_name = $1
- @collection_name = Expression.parse($2)
+ @variable_name = Regexp.last_match(1)
+ @collection_name = Expression.parse(Regexp.last_match(2))
@attributes = {}
markup.scan(TagAttributes) do |key, value|
@attributes[key] = Expression.parse(value)
end
else
- raise SyntaxError.new(options[:locale].t("errors.syntax.table_row".freeze))
+ raise SyntaxError, options[:locale].t("errors.syntax.table_row".freeze)
end
end
def render_to_output_buffer(context, output)
- collection = context.evaluate(@collection_name) or return ''.freeze
+ (collection = context.evaluate(@collection_name)) || (return ''.freeze)
from = @attributes.key?('offset'.freeze) ? context.evaluate(@attributes['offset'.freeze]).to_i : 0
to = @attributes.key?('limit'.freeze) ? from + context.evaluate(@attributes['limit'.freeze]).to_i : nil
diff --git a/lib/liquid/template.rb b/lib/liquid/template.rb
index 91e30fb..62250b2 100644
--- a/lib/liquid/template.rb
+++ b/lib/liquid/template.rb
@@ -172,7 +172,7 @@ module Liquid
c = args.shift
if @rethrow_errors
- c.exception_renderer = ->(e) { raise }
+ c.exception_renderer = ->(_e) { raise }
end
c
diff --git a/lib/liquid/tokenizer.rb b/lib/liquid/tokenizer.rb
index d3fd676..9511420 100644
--- a/lib/liquid/tokenizer.rb
+++ b/lib/liquid/tokenizer.rb
@@ -10,7 +10,7 @@ module Liquid
end
def shift
- token = @tokens.shift or return
+ (token = @tokens.shift) || return
if @line_number
@line_number += @for_liquid_tag ? 1 : token.count("\n")
@@ -29,7 +29,7 @@ module Liquid
tokens = @source.split(TemplateParser)
# removes the rogue empty element at the beginning of the array
- tokens.shift if tokens[0] && tokens[0].empty?
+ tokens.shift if tokens[0]&.empty?
tokens
end
diff --git a/lib/liquid/utils.rb b/lib/liquid/utils.rb
index 516ac0c..ada4f39 100644
--- a/lib/liquid/utils.rb
+++ b/lib/liquid/utils.rb
@@ -50,7 +50,7 @@ module Liquid
when Numeric
obj
when String
- (obj.strip =~ /\A-?\d+\.\d+\z/) ? BigDecimal(obj) : obj.to_i
+ obj.strip =~ /\A-?\d+\.\d+\z/ ? BigDecimal(obj) : obj.to_i
else
if obj.respond_to?(:to_number)
obj.to_number
diff --git a/lib/liquid/variable.rb b/lib/liquid/variable.rb
index cbf9986..6efcf70 100644
--- a/lib/liquid/variable.rb
+++ b/lib/liquid/variable.rb
@@ -43,11 +43,11 @@ module Liquid
@filters = []
return unless markup =~ MarkupWithQuotedFragment
- name_markup = $1
- filter_markup = $2
+ name_markup = Regexp.last_match(1)
+ filter_markup = Regexp.last_match(2)
@name = Expression.parse(name_markup)
if filter_markup =~ FilterMarkupRegex
- filters = $1.scan(FilterParser)
+ filters = Regexp.last_match(1).scan(FilterParser)
filters.each do |f|
next unless f =~ /\w+/
filtername = Regexp.last_match(0)
@@ -121,7 +121,7 @@ module Liquid
end
def evaluate_filter_expressions(context, filter_args, filter_kwargs)
- parsed_args = filter_args.map{ |expr| context.evaluate(expr) }
+ parsed_args = filter_args.map { |expr| context.evaluate(expr) }
if filter_kwargs
parsed_kwargs = {}
filter_kwargs.each do |key, expr|
diff --git a/lib/liquid/variable_lookup.rb b/lib/liquid/variable_lookup.rb
index 62f4877..ab06bb6 100644
--- a/lib/liquid/variable_lookup.rb
+++ b/lib/liquid/variable_lookup.rb
@@ -14,7 +14,7 @@ module Liquid
name = lookups.shift
if name =~ SQUARE_BRACKETED
- name = Expression.parse($1)
+ name = Expression.parse(Regexp.last_match(1))
end
@name = name
@@ -24,7 +24,7 @@ module Liquid
@lookups.each_index do |i|
lookup = lookups[i]
if lookup =~ SQUARE_BRACKETED
- lookups[i] = Expression.parse($1)
+ lookups[i] = Expression.parse(Regexp.last_match(1))
elsif COMMAND_METHODS.include?(lookup)
@command_flags |= 1 << i
end
diff --git a/liquid.gemspec b/liquid.gemspec
index 89df19a..27b24aa 100644
--- a/liquid.gemspec
+++ b/liquid.gemspec
@@ -1,7 +1,7 @@
# encoding: utf-8
lib = File.expand_path('../lib/', __FILE__)
-$LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib)
+$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require "liquid/version"
@@ -26,6 +26,6 @@ Gem::Specification.new do |s|
s.require_path = "lib"
- s.add_development_dependency 'rake', '~> 11.3'
- s.add_development_dependency 'minitest'
+ s.add_development_dependency('rake', '~> 11.3')
+ s.add_development_dependency('minitest')
end
diff --git a/performance/shopify/comment_form.rb b/performance/shopify/comment_form.rb
index 7b5bd53..65af1b5 100644
--- a/performance/shopify/comment_form.rb
+++ b/performance/shopify/comment_form.rb
@@ -5,10 +5,10 @@ class CommentForm < Liquid::Block
super
if markup =~ Syntax
- @variable_name = $1
+ @variable_name = Regexp.last_match(1)
@attributes = {}
else
- raise SyntaxError.new("Syntax Error in 'comment_form' - Valid syntax: comment_form [article]")
+ raise SyntaxError, "Syntax Error in 'comment_form' - Valid syntax: comment_form [article]"
end
end
@@ -20,8 +20,8 @@ class CommentForm < Liquid::Block
'posted_successfully?' => context.registers[:posted_successfully],
'errors' => context['comment.errors'],
'author' => context['comment.author'],
- 'email' => context['comment.email'],
- 'body' => context['comment.body']
+ 'email' => context['comment.email'],
+ 'body' => context['comment.body'],
}
output << wrap_in_form(article, render_all(@nodelist, context, output))
diff --git a/performance/shopify/database.rb b/performance/shopify/database.rb
index 2b5bca4..c9f18c3 100644
--- a/performance/shopify/database.rb
+++ b/performance/shopify/database.rb
@@ -16,9 +16,10 @@ module Database
end
# key the tables by handles, as this is how liquid expects it.
- db = db.inject({}) do |assigns, (key, values)|
- assigns[key] = values.inject({}) { |h, v| h[v['handle']] = v; h; }
- assigns
+ db = db.each_with_object({}) do |(key, values), assigns|
+ assigns[key] = values.each_with_object({}) do |v, h|
+ h[v['handle']] = v
+ end
end
# Some standard direct accessors so that the specialized templates
@@ -30,8 +31,8 @@ module Database
db['cart'] = {
'total_price' => db['line_items'].values.inject(0) { |sum, item| sum += item['line_price'] * item['quantity'] },
- 'item_count' => db['line_items'].values.inject(0) { |sum, item| sum += item['quantity'] },
- 'items' => db['line_items'].values
+ 'item_count' => db['line_items'].values.inject(0) { |sum, item| sum += item['quantity'] },
+ 'items' => db['line_items'].values,
}
db
@@ -40,6 +41,6 @@ module Database
end
if __FILE__ == $PROGRAM_NAME
- p Database.tables['collections']['frontpage'].keys
+ p(Database.tables['collections']['frontpage'].keys)
# p Database.tables['blog']['articles']
end
diff --git a/performance/shopify/json_filter.rb b/performance/shopify/json_filter.rb
index 8fbb5b6..3258316 100644
--- a/performance/shopify/json_filter.rb
+++ b/performance/shopify/json_filter.rb
@@ -2,6 +2,6 @@ require 'json'
module JsonFilter
def json(object)
- JSON.dump(object.reject { |k, v| k == "collections" })
+ JSON.dump(object.reject { |k, _v| k == "collections" })
end
end
diff --git a/performance/shopify/liquid.rb b/performance/shopify/liquid.rb
index 7716deb..f9d5200 100644
--- a/performance/shopify/liquid.rb
+++ b/performance/shopify/liquid.rb
@@ -1,4 +1,4 @@
-$:.unshift __dir__ + '/../../lib'
+$LOAD_PATH.unshift(__dir__ + '/../../lib')
require_relative '../../lib/liquid'
require_relative 'comment_form'
@@ -9,11 +9,11 @@ require_relative 'shop_filter'
require_relative 'tag_filter'
require_relative 'weight_filter'
-Liquid::Template.register_tag 'paginate', Paginate
-Liquid::Template.register_tag 'form', CommentForm
+Liquid::Template.register_tag('paginate', Paginate)
+Liquid::Template.register_tag('form', CommentForm)
-Liquid::Template.register_filter JsonFilter
-Liquid::Template.register_filter MoneyFilter
-Liquid::Template.register_filter WeightFilter
-Liquid::Template.register_filter ShopFilter
-Liquid::Template.register_filter TagFilter
+Liquid::Template.register_filter(JsonFilter)
+Liquid::Template.register_filter(MoneyFilter)
+Liquid::Template.register_filter(WeightFilter)
+Liquid::Template.register_filter(ShopFilter)
+Liquid::Template.register_filter(TagFilter)
diff --git a/performance/shopify/money_filter.rb b/performance/shopify/money_filter.rb
index 8dad789..4cc7280 100644
--- a/performance/shopify/money_filter.rb
+++ b/performance/shopify/money_filter.rb
@@ -1,12 +1,12 @@
module MoneyFilter
def money_with_currency(money)
return '' if money.nil?
- sprintf("$ %.2f USD", money / 100.0)
+ format("$ %.2f USD", money / 100.0)
end
def money(money)
return '' if money.nil?
- sprintf("$ %.2f", money / 100.0)
+ format("$ %.2f", money / 100.0)
end
private
diff --git a/performance/shopify/paginate.rb b/performance/shopify/paginate.rb
index 0abd11f..29e7c9e 100644
--- a/performance/shopify/paginate.rb
+++ b/performance/shopify/paginate.rb
@@ -1,13 +1,13 @@
class Paginate < Liquid::Block
- Syntax = /(#{Liquid::QuotedFragment})\s*(by\s*(\d+))?/
+ Syntax = /(#{Liquid::QuotedFragment})\s*(by\s*(\d+))?/
def initialize(tag_name, markup, options)
super
if markup =~ Syntax
- @collection_name = $1
- @page_size = if $2
- $3.to_i
+ @collection_name = Regexp.last_match(1)
+ @page_size = if Regexp.last_match(2)
+ Regexp.last_match(3).to_i
else
20
end
@@ -17,7 +17,7 @@ class Paginate < Liquid::Block
@attributes[key] = value
end
else
- raise SyntaxError.new("Syntax Error in tag 'paginate' - Valid syntax: paginate [collection] by number")
+ raise SyntaxError, "Syntax Error in tag 'paginate' - Valid syntax: paginate [collection] by number"
end
end
@@ -25,19 +25,19 @@ class Paginate < Liquid::Block
@context = context
context.stack do
- current_page = context['current_page'].to_i
+ current_page = context['current_page'].to_i
pagination = {
- 'page_size' => @page_size,
- 'current_page' => 5,
- 'current_offset' => @page_size * 5
+ 'page_size' => @page_size,
+ 'current_page' => 5,
+ 'current_offset' => @page_size * 5,
}
context['paginate'] = pagination
- collection_size = context[@collection_name].size
+ collection_size = context[@collection_name].size
- raise ArgumentError.new("Cannot paginate array '#{@collection_name}'. Not found.") if collection_size.nil?
+ raise ArgumentError, "Cannot paginate array '#{@collection_name}'. Not found." if collection_size.nil?
page_count = (collection_size.to_f / @page_size.to_f).to_f.ceil + 1
diff --git a/performance/shopify/shop_filter.rb b/performance/shopify/shop_filter.rb
index 89c9083..b2a0a9d 100644
--- a/performance/shopify/shop_filter.rb
+++ b/performance/shopify/shop_filter.rb
@@ -52,7 +52,7 @@ module ShopFilter
end
def product_img_url(url, style = 'small')
- unless url =~ /\Aproducts\/([\w\-\_]+)\.(\w{2,4})/
+ unless url =~ %r{\Aproducts/([\w\-\_]+)\.(\w{2,4})}
raise ArgumentError, 'filter "size" can only be called on product images'
end
@@ -60,7 +60,7 @@ module ShopFilter
when 'original'
return '/files/shops/random_number/' + url
when 'grande', 'large', 'medium', 'compact', 'small', 'thumb', 'icon'
- "/files/shops/random_number/products/#{$1}_#{style}.#{$2}"
+ "/files/shops/random_number/products/#{Regexp.last_match(1)}_#{style}.#{Regexp.last_match(2)}"
else
raise ArgumentError, 'valid parameters for filter "size" are: original, grande, large, medium, compact, small, thumb and icon '
end
@@ -70,16 +70,14 @@ module ShopFilter
html = []
html << %(#{link_to(paginate['previous']['title'], paginate['previous']['url'])}) if paginate['previous']
- for part in paginate['parts']
-
- if part['is_link']
- html << %(#{link_to(part['title'], part['url'])})
+ paginate['parts'].each do |part|
+ html << if part['is_link']
+ %(#{link_to(part['title'], part['url'])})
elsif part['title'].to_i == paginate['current_page'].to_i
- html << %(#{part['title']})
+ %(#{part['title']})
else
- html << %(#{part['title']})
+ %(#{part['title']})
end
-
end
html << %(#{link_to(paginate['next']['title'], paginate['next']['url'])}) if paginate['next']
diff --git a/performance/shopify/tag_filter.rb b/performance/shopify/tag_filter.rb
index ab5aef6..34b426f 100644
--- a/performance/shopify/tag_filter.rb
+++ b/performance/shopify/tag_filter.rb
@@ -13,11 +13,11 @@ module TagFilter
def link_to_add_tag(label, tag)
tags = (@context['current_tags'] + [tag]).uniq
- "#{label}"
+ "#{label}"
end
def link_to_remove_tag(label, tag)
tags = (@context['current_tags'] - [tag]).uniq
- "#{label}"
+ "#{label}"
end
end
diff --git a/performance/shopify/weight_filter.rb b/performance/shopify/weight_filter.rb
index a0a15fc..b05bcce 100644
--- a/performance/shopify/weight_filter.rb
+++ b/performance/shopify/weight_filter.rb
@@ -1,6 +1,6 @@
module WeightFilter
def weight(grams)
- sprintf("%.2f", grams / 1000)
+ format("%.2f", grams / 1000)
end
def weight_with_unit(grams)
diff --git a/performance/theme_runner.rb b/performance/theme_runner.rb
index 9f6a1fc..9268558 100644
--- a/performance/theme_runner.rb
+++ b/performance/theme_runner.rb
@@ -31,7 +31,7 @@ class ThemeRunner
{
liquid: File.read(test),
layout: (File.file?(theme_path) ? File.read(theme_path) : nil),
- template_name: test
+ template_name: test,
}
end.compact
diff --git a/test/integration/blank_test.rb b/test/integration/blank_test.rb
index 2b46ad7..654ee98 100644
--- a/test/integration/blank_test.rb
+++ b/test/integration/blank_test.rb
@@ -1,7 +1,7 @@
require 'test_helper'
class FoobarTag < Liquid::Tag
- def render_to_output_buffer(context, output)
+ def render_to_output_buffer(_context, output)
output << ' '
output
end
diff --git a/test/integration/drop_test.rb b/test/integration/drop_test.rb
index 2de4a5a..9294b2f 100644
--- a/test/integration/drop_test.rb
+++ b/test/integration/drop_test.rb
@@ -201,9 +201,9 @@ class DropsTest < Minitest::Test
end
def test_scope_though_proc
- assert_equal '1', Liquid::Template.parse('{{ s }}').render!('context' => ContextDrop.new, 's' => proc{ |c| c['context.scopes'] })
- assert_equal '2', Liquid::Template.parse('{%for i in dummy%}{{ s }}{%endfor%}').render!('context' => ContextDrop.new, 's' => proc{ |c| c['context.scopes'] }, 'dummy' => [1])
- assert_equal '3', Liquid::Template.parse('{%for i in dummy%}{%for i in dummy%}{{ s }}{%endfor%}{%endfor%}').render!('context' => ContextDrop.new, 's' => proc{ |c| c['context.scopes'] }, 'dummy' => [1])
+ assert_equal '1', Liquid::Template.parse('{{ s }}').render!('context' => ContextDrop.new, 's' => proc { |c| c['context.scopes'] })
+ assert_equal '2', Liquid::Template.parse('{%for i in dummy%}{{ s }}{%endfor%}').render!('context' => ContextDrop.new, 's' => proc { |c| c['context.scopes'] }, 'dummy' => [1])
+ assert_equal '3', Liquid::Template.parse('{%for i in dummy%}{%for i in dummy%}{{ s }}{%endfor%}{%endfor%}').render!('context' => ContextDrop.new, 's' => proc { |c| c['context.scopes'] }, 'dummy' => [1])
end
def test_scope_with_assigns
@@ -241,7 +241,7 @@ class DropsTest < Minitest::Test
end
def test_some_enumerable_methods_still_get_invoked
- [ :count, :max ].each do |method|
+ [:count, :max].each do |method|
assert_equal "3", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new)
assert_equal "3", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => RealEnumerableDrop.new)
assert_equal "3", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new)
@@ -250,7 +250,7 @@ class DropsTest < Minitest::Test
assert_equal "yes", Liquid::Template.parse("{% if collection contains 3 %}yes{% endif %}").render!('collection' => RealEnumerableDrop.new)
- [ :min, :first ].each do |method|
+ [:min, :first].each do |method|
assert_equal "1", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new)
assert_equal "1", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => RealEnumerableDrop.new)
assert_equal "1", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new)
diff --git a/test/integration/error_handling_test.rb b/test/integration/error_handling_test.rb
index b2d186c..875f426 100644
--- a/test/integration/error_handling_test.rb
+++ b/test/integration/error_handling_test.rb
@@ -83,15 +83,14 @@ class ErrorHandlingTest < Minitest::Test
def test_with_line_numbers_adds_numbers_to_parser_errors
err = assert_raises(SyntaxError) do
- Liquid::Template.parse(%q(
+ Liquid::Template.parse('
foobar
{% "cat" | foobar %}
bla
- ),
- line_numbers: true
- )
+ ',
+ line_numbers: true)
end
assert_match(/Liquid syntax error \(line 4\)/, err.message)
@@ -99,15 +98,14 @@ class ErrorHandlingTest < Minitest::Test
def test_with_line_numbers_adds_numbers_to_parser_errors_with_whitespace_trim
err = assert_raises(SyntaxError) do
- Liquid::Template.parse(%q(
+ Liquid::Template.parse('
foobar
{%- "cat" | foobar -%}
bla
- ),
- line_numbers: true
- )
+ ',
+ line_numbers: true)
end
assert_match(/Liquid syntax error \(line 4\)/, err.message)
@@ -122,8 +120,7 @@ class ErrorHandlingTest < Minitest::Test
bla
',
error_mode: :warn,
- line_numbers: true
- )
+ line_numbers: true)
assert_equal ['Liquid syntax error (line 4): Unexpected character = in "1 =! 2"'],
template.warnings.map(&:message)
@@ -139,8 +136,7 @@ class ErrorHandlingTest < Minitest::Test
bla
',
error_mode: :strict,
- line_numbers: true
- )
+ line_numbers: true)
end
assert_equal 'Liquid syntax error (line 4): Unexpected character = in "1 =! 2"', err.message
@@ -157,8 +153,7 @@ class ErrorHandlingTest < Minitest::Test
bla
',
- line_numbers: true
- )
+ line_numbers: true)
end
assert_equal "Liquid syntax error (line 5): Unknown tag 'foo'", err.message
@@ -205,7 +200,7 @@ class ErrorHandlingTest < Minitest::Test
def test_default_exception_renderer_with_internal_error
template = Liquid::Template.parse('This is a runtime error: {{ errors.runtime_error }}', line_numbers: true)
- output = template.render({ 'errors' => ErrorDrop.new })
+ output = template.render('errors' => ErrorDrop.new)
assert_equal 'This is a runtime error: Liquid error (line 1): internal', output
assert_equal [Liquid::InternalError], template.errors.map(&:class)
@@ -217,7 +212,7 @@ class ErrorHandlingTest < Minitest::Test
Liquid::Template.default_exception_renderer = ->(e) { exceptions << e; '' }
template = Liquid::Template.parse('This is a runtime error: {{ errors.argument_error }}')
- output = template.render({ 'errors' => ErrorDrop.new })
+ output = template.render('errors' => ErrorDrop.new)
assert_equal 'This is a runtime error: ', output
assert_equal [Liquid::ArgumentError], template.errors.map(&:class)
@@ -239,7 +234,7 @@ class ErrorHandlingTest < Minitest::Test
end
class TestFileSystem
- def read_template_file(template_path)
+ def read_template_file(_template_path)
"{{ errors.argument_error }}"
end
end
diff --git a/test/integration/filter_test.rb b/test/integration/filter_test.rb
index d3c880e..0af29ef 100644
--- a/test/integration/filter_test.rb
+++ b/test/integration/filter_test.rb
@@ -2,23 +2,23 @@ require 'test_helper'
module MoneyFilter
def money(input)
- sprintf(' %d$ ', input)
+ format(' %d$ ', input)
end
def money_with_underscore(input)
- sprintf(' %d$ ', input)
+ format(' %d$ ', input)
end
end
module CanadianMoneyFilter
def money(input)
- sprintf(' %d$ CAD ', input)
+ format(' %d$ CAD ', input)
end
end
module SubstituteFilter
def substitute(input, params = {})
- input.gsub(/%\{(\w+)\}/) { |match| params[$1] }
+ input.gsub(/%\{(\w+)\}/) { |_match| params[Regexp.last_match(1)] }
end
end
@@ -26,7 +26,7 @@ class FiltersTest < Minitest::Test
include Liquid
module OverrideObjectMethodFilter
- def tap(input)
+ def tap(_input)
"tap overridden"
end
end
@@ -149,7 +149,7 @@ class FiltersTest < Minitest::Test
assert_equal "tap overridden", Template.parse("{{var | tap}}").render!({ 'var' => 1000 }, filters: [OverrideObjectMethodFilter])
# tap still treated as a non-existent filter
- assert_equal "1000", Template.parse("{{var | tap}}").render!({ 'var' => 1000 })
+ assert_equal "1000", Template.parse("{{var | tap}}").render!('var' => 1000)
end
end
diff --git a/test/integration/hash_ordering_test.rb b/test/integration/hash_ordering_test.rb
index dfc1c29..8592395 100644
--- a/test/integration/hash_ordering_test.rb
+++ b/test/integration/hash_ordering_test.rb
@@ -3,13 +3,13 @@ require 'test_helper'
class HashOrderingTest < Minitest::Test
module MoneyFilter
def money(input)
- sprintf(' %d$ ', input)
+ format(' %d$ ', input)
end
end
module CanadianMoneyFilter
def money(input)
- sprintf(' %d$ CAD ', input)
+ format(' %d$ CAD ', input)
end
end
diff --git a/test/integration/output_test.rb b/test/integration/output_test.rb
index b4cf9d7..d94b0f8 100644
--- a/test/integration/output_test.rb
+++ b/test/integration/output_test.rb
@@ -1,7 +1,7 @@
require 'test_helper'
module FunnyFilter
- def make_funny(input)
+ def make_funny(_input)
'LOL'
end
@@ -32,7 +32,7 @@ class OutputTest < Minitest::Test
def setup
@assigns = {
'best_cars' => 'bmw',
- 'car' => { 'bmw' => 'good', 'gm' => 'bad' }
+ 'car' => { 'bmw' => 'good', 'gm' => 'bad' },
}
end
diff --git a/test/integration/parse_tree_visitor_test.rb b/test/integration/parse_tree_visitor_test.rb
index 6ad6a2d..d1af123 100644
--- a/test/integration/parse_tree_visitor_test.rb
+++ b/test/integration/parse_tree_visitor_test.rb
@@ -227,7 +227,7 @@ class ParseTreeVisitorTest < Minitest::Test
[[nil, [
[nil, [[nil, [["other", []]]]]],
["test", []],
- ["xs", []]
+ ["xs", []],
]]],
traversal(%({% for x in xs offset: test %}{{ other }}{% endfor %})).visit
)
diff --git a/test/integration/render_profiling_test.rb b/test/integration/render_profiling_test.rb
index d0111e7..283b8bd 100644
--- a/test/integration/render_profiling_test.rb
+++ b/test/integration/render_profiling_test.rb
@@ -128,7 +128,7 @@ class RenderProfilingTest < Minitest::Test
t.render!
timing_count = 0
- t.profiler.each do |timing|
+ t.profiler.each do |_timing|
timing_count += 1
end
@@ -145,7 +145,7 @@ class RenderProfilingTest < Minitest::Test
def test_profiling_marks_children_of_for_blocks
t = Template.parse("{% for item in collection %} {{ item }} {% endfor %}", profile: true)
- t.render!({ "collection" => ["one", "two"] })
+ t.render!("collection" => ["one", "two"])
assert_equal 1, t.profiler.length
# Will profile each invocation of the for block
diff --git a/test/integration/standard_filter_test.rb b/test/integration/standard_filter_test.rb
index 6090951..7863cfe 100644
--- a/test/integration/standard_filter_test.rb
+++ b/test/integration/standard_filter_test.rb
@@ -17,7 +17,7 @@ class TestThing
"woot: #{@foo}"
end
- def [](whatever)
+ def [](_whatever)
to_s
end
@@ -37,7 +37,7 @@ class TestEnumerable < Liquid::Drop
include Enumerable
def each(&block)
- [ { "foo" => 1, "bar" => 2 }, { "foo" => 2, "bar" => 1 }, { "foo" => 3, "bar" => 3 } ].each(&block)
+ [{ "foo" => 1, "bar" => 2 }, { "foo" => 2, "bar" => 1 }, { "foo" => 3, "bar" => 3 }].each(&block)
end
end
@@ -208,14 +208,14 @@ class StandardFiltersTest < Minitest::Test
{ "handle" => "beta" },
{ "price" => 1, "handle" => "gamma" },
{ "handle" => "delta" },
- { "price" => 2, "handle" => "epsilon" }
+ { "price" => 2, "handle" => "epsilon" },
]
expectation = [
{ "price" => 1, "handle" => "gamma" },
{ "price" => 2, "handle" => "epsilon" },
{ "price" => 4, "handle" => "alpha" },
{ "handle" => "delta" },
- { "handle" => "beta" }
+ { "handle" => "beta" },
]
assert_equal expectation, @filters.sort(input, "price")
end
@@ -236,14 +236,14 @@ class StandardFiltersTest < Minitest::Test
{ "handle" => "beta" },
{ "price" => "1", "handle" => "gamma" },
{ "handle" => "delta" },
- { "price" => 2, "handle" => "epsilon" }
+ { "price" => 2, "handle" => "epsilon" },
]
expectation = [
{ "price" => "1", "handle" => "gamma" },
{ "price" => 2, "handle" => "epsilon" },
{ "price" => "4", "handle" => "alpha" },
{ "handle" => "delta" },
- { "handle" => "beta" }
+ { "handle" => "beta" },
]
assert_equal expectation, @filters.sort_natural(input, "price")
end
@@ -256,7 +256,7 @@ class StandardFiltersTest < Minitest::Test
{ "fake" => "t" },
{ "key" => "a" },
{ "key" => "b" },
- { "key" => "c" }
+ { "key" => "c" },
]
expectation = [
{ "key" => "a" },
@@ -265,7 +265,7 @@ class StandardFiltersTest < Minitest::Test
{ "key" => "X" },
{ "key" => "Y" },
{ "key" => "Z" },
- { "fake" => "t" }
+ { "fake" => "t" },
]
assert_equal expectation, @filters.sort_natural(input, "key")
assert_equal ["a", "b", "c", "X", "Y", "Z"], @filters.sort_natural(["X", "Y", "Z", "a", "b", "c"])
@@ -279,7 +279,7 @@ class StandardFiltersTest < Minitest::Test
foo = [
[1],
[2],
- [3]
+ [3],
]
assert_raises Liquid::ArgumentError do
@@ -295,7 +295,7 @@ class StandardFiltersTest < Minitest::Test
foo = [
[1],
[2],
- [3]
+ [3],
]
assert_raises Liquid::ArgumentError do
@@ -304,7 +304,7 @@ class StandardFiltersTest < Minitest::Test
end
def test_legacy_sort_hash
- assert_equal [{ a: 1, b: 2 }], @filters.sort({ a: 1, b: 2 })
+ assert_equal [{ a: 1, b: 2 }], @filters.sort(a: 1, b: 2)
end
def test_numerical_vs_lexicographical_sort
@@ -330,7 +330,7 @@ class StandardFiltersTest < Minitest::Test
foo = [
[1],
[2],
- [3]
+ [3],
]
assert_raises Liquid::ArgumentError do
@@ -346,7 +346,7 @@ class StandardFiltersTest < Minitest::Test
foo = [
[1],
[2],
- [3]
+ [3],
]
assert_raises Liquid::ArgumentError do
@@ -380,7 +380,7 @@ class StandardFiltersTest < Minitest::Test
def test_map_on_hashes
assert_template_result "4217", '{{ thing | map: "foo" | map: "bar" }}',
- "thing" => { "foo" => [ { "bar" => 42 }, { "bar" => 17 } ] }
+ "thing" => { "foo" => [{ "bar" => 42 }, { "bar" => 17 }] }
end
def test_legacy_map_on_hashes_with_dynamic_key
@@ -397,7 +397,7 @@ class StandardFiltersTest < Minitest::Test
def test_map_over_proc
drop = TestDrop.new
- p = proc{ drop }
+ p = proc { drop }
templ = '{{ procs | map: "test" }}'
assert_template_result "testfoo", templ, "procs" => [p]
end
@@ -405,10 +405,10 @@ class StandardFiltersTest < Minitest::Test
def test_map_over_drops_returning_procs
drops = [
{
- "proc" => ->{ "foo" },
+ "proc" => -> { "foo" },
},
{
- "proc" => ->{ "bar" },
+ "proc" => -> { "bar" },
},
]
templ = '{{ drops | map: "proc" }}'
@@ -423,7 +423,7 @@ class StandardFiltersTest < Minitest::Test
foo = [
[1],
[2],
- [3]
+ [3],
]
assert_raises Liquid::ArgumentError do
@@ -435,7 +435,7 @@ class StandardFiltersTest < Minitest::Test
foo = [
[1],
[2],
- [3]
+ [3],
]
assert_raises Liquid::ArgumentError do
@filters.map(foo, nil)
@@ -697,12 +697,12 @@ class StandardFiltersTest < Minitest::Test
{ "handle" => "alpha", "ok" => true },
{ "handle" => "beta", "ok" => false },
{ "handle" => "gamma", "ok" => false },
- { "handle" => "delta", "ok" => true }
+ { "handle" => "delta", "ok" => true },
]
expectation = [
{ "handle" => "alpha", "ok" => true },
- { "handle" => "delta", "ok" => true }
+ { "handle" => "delta", "ok" => true },
]
assert_equal expectation, @filters.where(input, "ok", true)
@@ -714,12 +714,12 @@ class StandardFiltersTest < Minitest::Test
{ "handle" => "alpha", "ok" => true },
{ "handle" => "beta" },
{ "handle" => "gamma" },
- { "handle" => "delta", "ok" => true }
+ { "handle" => "delta", "ok" => true },
]
expectation = [
{ "handle" => "alpha", "ok" => true },
- { "handle" => "delta", "ok" => true }
+ { "handle" => "delta", "ok" => true },
]
assert_equal expectation, @filters.where(input, "ok", true)
@@ -740,7 +740,7 @@ class StandardFiltersTest < Minitest::Test
input = [
{ "message" => "Bonjour!", "language" => "French" },
{ "message" => "Hello!", "language" => "English" },
- { "message" => "Hallo!", "language" => "German" }
+ { "message" => "Hallo!", "language" => "German" },
]
assert_equal [{ "message" => "Bonjour!", "language" => "French" }], @filters.where(input, "language", "French")
@@ -758,7 +758,7 @@ class StandardFiltersTest < Minitest::Test
{ "foo" => false },
{ "foo" => true },
{ "foo" => "for sure" },
- { "bar" => true }
+ { "bar" => true },
]
assert_equal [{ "foo" => true }, { "foo" => "for sure" }], @filters.where(input, "foo")
diff --git a/test/integration/tags/echo_test.rb b/test/integration/tags/echo_test.rb
index ed5b821..eab329d 100644
--- a/test/integration/tags/echo_test.rb
+++ b/test/integration/tags/echo_test.rb
@@ -4,7 +4,7 @@ class EchoTest < Minitest::Test
include Liquid
def test_echo_outputs_its_input
- assert_template_result('BAR', <<~LIQUID, { 'variable-name' => 'bar' })
+ assert_template_result('BAR', <<~LIQUID, 'variable-name' => 'bar')
{%- echo variable-name | upcase -%}
LIQUID
end
diff --git a/test/integration/tags/for_tag_test.rb b/test/integration/tags/for_tag_test.rb
index 9980e25..47e3e5f 100644
--- a/test/integration/tags/for_tag_test.rb
+++ b/test/integration/tags/for_tag_test.rb
@@ -23,16 +23,16 @@ class ForTagTest < Minitest::Test
yo
HERE
- template = < [1, 2, 3])
end
def test_for_reversed
- assigns = { 'array' => [ 1, 2, 3] }
+ assigns = { 'array' => [1, 2, 3] }
assert_template_result('321', '{%for item in array reversed %}{{item}}{%endfor%}', assigns)
end
diff --git a/test/integration/tags/if_else_tag_test.rb b/test/integration/tags/if_else_tag_test.rb
index 45a5d3a..276b15b 100644
--- a/test/integration/tags/if_else_tag_test.rb
+++ b/test/integration/tags/if_else_tag_test.rb
@@ -132,7 +132,7 @@ class IfElseTagTest < Minitest::Test
end
def test_syntax_error_no_variable
- assert_raises(SyntaxError){ assert_template_result('', '{% if jerry == 1 %}') }
+ assert_raises(SyntaxError) { assert_template_result('', '{% if jerry == 1 %}') }
end
def test_syntax_error_no_expression
diff --git a/test/integration/tags/include_tag_test.rb b/test/integration/tags/include_tag_test.rb
index 14bb8c3..dea932a 100644
--- a/test/integration/tags/include_tag_test.rb
+++ b/test/integration/tags/include_tag_test.rb
@@ -40,14 +40,14 @@ class TestFileSystem
end
class OtherFileSystem
- def read_template_file(template_path)
+ def read_template_file(_template_path)
'from OtherFileSystem'
end
end
class CountingFileSystem
attr_reader :count
- def read_template_file(template_path)
+ def read_template_file(_template_path)
@count ||= 0
@count += 1
'from CountingFileSystem'
@@ -59,14 +59,14 @@ class CustomInclude < Liquid::Tag
def initialize(tag_name, markup, tokens)
markup =~ Syntax
- @template_name = $1
+ @template_name = Regexp.last_match(1)
super
end
def parse(tokens)
end
- def render_to_output_buffer(context, output)
+ def render_to_output_buffer(_context, output)
output << @template_name[1..-2]
output
end
@@ -86,7 +86,7 @@ class IncludeTagTest < Minitest::Test
def test_include_tag_with
assert_template_result "Product: Draft 151cm ",
- "{% include 'product' with products[0] %}", "products" => [ { 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' } ]
+ "{% include 'product' with products[0] %}", "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }]
end
def test_include_tag_with_default_name
@@ -96,7 +96,7 @@ class IncludeTagTest < Minitest::Test
def test_include_tag_for
assert_template_result "Product: Draft 151cm Product: Element 155cm ",
- "{% include 'product' for products %}", "products" => [ { 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' } ]
+ "{% include 'product' for products %}", "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }]
end
def test_include_tag_with_local_variables
@@ -134,7 +134,7 @@ class IncludeTagTest < Minitest::Test
def test_recursively_included_template_does_not_produce_endless_loop
infinite_file_system = Class.new do
- def read_template_file(template_path)
+ def read_template_file(_template_path)
"-{% include 'loop' %}"
end
end
diff --git a/test/integration/tags/increment_tag_test.rb b/test/integration/tags/increment_tag_test.rb
index 97c51ac..a793b6d 100644
--- a/test/integration/tags/increment_tag_test.rb
+++ b/test/integration/tags/increment_tag_test.rb
@@ -13,11 +13,11 @@ class IncrementTagTest < Minitest::Test
end
def test_dec
- assert_template_result('9', '{%decrement port %}', { 'port' => 10 })
+ assert_template_result('9', '{%decrement port %}', 'port' => 10)
assert_template_result('-1 -2', '{%decrement port %} {%decrement port%}', {})
assert_template_result('1 5 2 2 5',
'{%increment port %} {%increment starboard%} ' \
'{%increment port %} {%decrement port%} ' \
- '{%decrement starboard %}', { 'port' => 1, 'starboard' => 5 })
+ '{%decrement starboard %}', 'port' => 1, 'starboard' => 5)
end
end
diff --git a/test/integration/tags/render_tag_test.rb b/test/integration/tags/render_tag_test.rb
index a31d018..ea14477 100644
--- a/test/integration/tags/render_tag_test.rb
+++ b/test/integration/tags/render_tag_test.rb
@@ -110,7 +110,7 @@ class RenderTagTest < Minitest::Test
file_system = StubFileSystem.new('snippet' => 'echo')
assert_equal 'echoecho',
Template.parse('{% render "snippet" %}{% render "snippet" %}')
- .render!({}, registers: { file_system: file_system })
+ .render!({}, registers: { file_system: file_system })
assert_equal 1, file_system.file_read_count
end
diff --git a/test/integration/tags/standard_tag_test.rb b/test/integration/tags/standard_tag_test.rb
index 4b4703a..cee4cac 100644
--- a/test/integration/tags/standard_tag_test.rb
+++ b/test/integration/tags/standard_tag_test.rb
@@ -69,7 +69,7 @@ class StandardTagTest < Minitest::Test
assert_raises(SyntaxError) do
assert_template_result('content foo content foo ',
'{{ var2 }}{% capture %}{{ var }} foo {% endcapture %}{{ var2 }}{{ var2 }}',
- { 'var' => 'content' })
+ 'var' => 'content')
end
end
@@ -183,32 +183,32 @@ class StandardTagTest < Minitest::Test
def test_case_when_or
code = '{% case condition %}{% when 1 or 2 or 3 %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 1 })
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 2 })
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 3 })
- assert_template_result(' its 4 ', code, { 'condition' => 4 })
- assert_template_result('', code, { 'condition' => 5 })
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 1)
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 2)
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 3)
+ assert_template_result(' its 4 ', code, 'condition' => 4)
+ assert_template_result('', code, 'condition' => 5)
code = '{% case condition %}{% when 1 or "string" or null %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 1 })
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 'string' })
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => nil })
- assert_template_result('', code, { 'condition' => 'something else' })
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 1)
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 'string')
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => nil)
+ assert_template_result('', code, 'condition' => 'something else')
end
def test_case_when_comma
code = '{% case condition %}{% when 1, 2, 3 %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 1 })
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 2 })
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 3 })
- assert_template_result(' its 4 ', code, { 'condition' => 4 })
- assert_template_result('', code, { 'condition' => 5 })
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 1)
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 2)
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 3)
+ assert_template_result(' its 4 ', code, 'condition' => 4)
+ assert_template_result('', code, 'condition' => 5)
code = '{% case condition %}{% when 1, "string", null %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 1 })
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 'string' })
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => nil })
- assert_template_result('', code, { 'condition' => 'something else' })
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 1)
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 'string')
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => nil)
+ assert_template_result('', code, 'condition' => 'something else')
end
def test_assign
@@ -283,10 +283,10 @@ class StandardTagTest < Minitest::Test
end
def test_ifchanged
- assigns = { 'array' => [ 1, 1, 2, 2, 3, 3] }
+ assigns = { 'array' => [1, 1, 2, 2, 3, 3] }
assert_template_result('123', '{%for item in array%}{%ifchanged%}{{item}}{% endifchanged %}{%endfor%}', assigns)
- assigns = { 'array' => [ 1, 1, 1, 1] }
+ assigns = { 'array' => [1, 1, 1, 1] }
assert_template_result('1', '{%for item in array%}{%ifchanged%}{{item}}{% endifchanged %}{%endfor%}', assigns)
end
diff --git a/test/integration/template_test.rb b/test/integration/template_test.rb
index 0dc0ae5..e2b54c7 100644
--- a/test/integration/template_test.rb
+++ b/test/integration/template_test.rb
@@ -224,7 +224,7 @@ class TemplateTest < Minitest::Test
end
def test_render_bang_force_rethrow_errors_on_passed_context
- context = Context.new({ 'drop' => ErroneousDrop.new })
+ context = Context.new('drop' => ErroneousDrop.new)
t = Template.new.parse('{{ drop.bad_method }}')
e = assert_raises RuntimeError do
@@ -267,7 +267,7 @@ class TemplateTest < Minitest::Test
def test_undefined_variables
t = Template.parse("{{x}} {{y}} {{z.a}} {{z.b}} {{z.c.d}}")
- result = t.render({ 'x' => 33, 'z' => { 'a' => 32, 'c' => { 'e' => 31 } } }, { strict_variables: true })
+ result = t.render({ 'x' => 33, 'z' => { 'a' => 32, 'c' => { 'e' => 31 } } }, strict_variables: true)
assert_equal '33 32 ', result
assert_equal 3, t.errors.count
@@ -292,14 +292,14 @@ class TemplateTest < Minitest::Test
t = Template.parse("{{x}} {{y}} {{z.a}} {{z.b}} {{z.c.d}}")
assert_raises UndefinedVariable do
- t.render!({ 'x' => 33, 'z' => { 'a' => 32, 'c' => { 'e' => 31 } } }, { strict_variables: true })
+ t.render!({ 'x' => 33, 'z' => { 'a' => 32, 'c' => { 'e' => 31 } } }, strict_variables: true)
end
end
def test_undefined_drop_methods
d = DropWithUndefinedMethod.new
t = Template.new.parse('{{ foo }} {{ woot }}')
- result = t.render(d, { strict_variables: true })
+ result = t.render(d, strict_variables: true)
assert_equal 'foo ', result
assert_equal 1, t.errors.count
@@ -311,7 +311,7 @@ class TemplateTest < Minitest::Test
t = Template.new.parse('{{ foo }} {{ woot }}')
assert_raises UndefinedDropMethod do
- t.render!(d, { strict_variables: true })
+ t.render!(d, strict_variables: true)
end
end
@@ -322,7 +322,7 @@ class TemplateTest < Minitest::Test
"-#{v}-"
end
end
- result = t.render({ 'a' => 123, 'x' => 'foo' }, { filters: [filters], strict_filters: true })
+ result = t.render({ 'a' => 123, 'x' => 'foo' }, filters: [filters], strict_filters: true)
assert_equal '123 ', result
assert_equal 1, t.errors.count
@@ -334,17 +334,17 @@ class TemplateTest < Minitest::Test
t = Template.parse("{{x | somefilter1 | upcase | somefilter2}}")
assert_raises UndefinedFilter do
- t.render!({ 'x' => 'foo' }, { strict_filters: true })
+ t.render!({ 'x' => 'foo' }, strict_filters: true)
end
end
def test_using_range_literal_works_as_expected
t = Template.parse("{% assign foo = (x..y) %}{{ foo }}")
- result = t.render({ 'x' => 1, 'y' => 5 })
+ result = t.render('x' => 1, 'y' => 5)
assert_equal '1..5', result
t = Template.parse("{% assign nums = (x..y) %}{% for num in nums %}{{ num }}{% endfor %}")
- result = t.render({ 'x' => 1, 'y' => 5 })
+ result = t.render('x' => 1, 'y' => 5)
assert_equal '12345', result
end
end
diff --git a/test/integration/trim_mode_test.rb b/test/integration/trim_mode_test.rb
index 52248cf..4e35dee 100644
--- a/test/integration/trim_mode_test.rb
+++ b/test/integration/trim_mode_test.rb
@@ -76,14 +76,14 @@ class TrimModeTest < Minitest::Test
END_TEMPLATE
- expected = <<-END_EXPECTED
-
-
-#{whitespace}
- yes
-#{whitespace}
-
-
+ expected = <<~END_EXPECTED
+
+
+ #{whitespace}
+ yes
+ #{whitespace}
+
+
END_EXPECTED
assert_template_result(expected, text)
@@ -96,12 +96,12 @@ class TrimModeTest < Minitest::Test
END_TEMPLATE
- expected = <<-END_EXPECTED
-
+ expected = <<~END_EXPECTED
+
END_EXPECTED
assert_template_result(expected, text)
end
@@ -337,12 +337,12 @@ class TrimModeTest < Minitest::Test
END_TEMPLATE
- expected = <<-END_EXPECTED
-
+ expected = <<~END_EXPECTED
+
END_EXPECTED
assert_template_result(expected, text)
end
@@ -513,16 +513,16 @@ class TrimModeTest < Minitest::Test
{% endraw %}
END_TEMPLATE
- expected = <<-END_EXPECTED
-
-#{whitespace}
- {%- if true -%}
-
- {{- 'John' -}}
-
- {%- endif -%}
-#{whitespace}
-
+ expected = <<~END_EXPECTED
+
+ #{whitespace}
+ {%- if true -%}
+
+ {{- 'John' -}}
+
+ {%- endif -%}
+ #{whitespace}
+
END_EXPECTED
assert_template_result(expected, text)
end
diff --git a/test/integration/variable_test.rb b/test/integration/variable_test.rb
index abd6e70..244ba95 100644
--- a/test/integration/variable_test.rb
+++ b/test/integration/variable_test.rb
@@ -76,7 +76,7 @@ class VariableTest < Minitest::Test
def test_hash_with_default_proc
template = Template.parse(%(Hello {{ test }}))
- assigns = Hash.new { |h, k| raise "Unknown variable '#{k}'" }
+ assigns = Hash.new { |_h, k| raise "Unknown variable '#{k}'" }
assigns['test'] = 'Tobi'
assert_equal 'Hello Tobi', template.render!(assigns)
assigns.delete('test')
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 27a2434..defc67e 100755
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -41,7 +41,7 @@ module Minitest
end
def assert_template_result_matches(expected, template, assigns = {}, message = nil)
- return assert_template_result(expected, template, assigns, message) unless expected.is_a? Regexp
+ return assert_template_result(expected, template, assigns, message) unless expected.is_a?(Regexp)
assert_match expected, Template.parse(template, line_numbers: true).render!(assigns), message
end
diff --git a/test/unit/condition_unit_test.rb b/test/unit/condition_unit_test.rb
index b3b90e8..165a7cf 100644
--- a/test/unit/condition_unit_test.rb
+++ b/test/unit/condition_unit_test.rb
@@ -68,7 +68,7 @@ class ConditionUnitTest < Minitest::Test
assert_nil Condition.new({}, '>', 2).evaluate
assert_nil Condition.new(2, '>', {}).evaluate
assert_equal false, Condition.new({}, '==', 2).evaluate
- assert_equal true, Condition.new({ 'a' => 1 }, '==', { 'a' => 1 }).evaluate
+ assert_equal true, Condition.new({ 'a' => 1 }, '==', 'a' => 1).evaluate
assert_equal true, Condition.new({ 'a' => 2 }, 'contains', 'a').evaluate
end
@@ -107,11 +107,11 @@ class ConditionUnitTest < Minitest::Test
assert_equal false, condition.evaluate
- condition.or Condition.new(2, '==', 1)
+ condition.or(Condition.new(2, '==', 1))
assert_equal false, condition.evaluate
- condition.or Condition.new(1, '==', 1)
+ condition.or(Condition.new(1, '==', 1))
assert_equal true, condition.evaluate
end
@@ -121,22 +121,22 @@ class ConditionUnitTest < Minitest::Test
assert_equal true, condition.evaluate
- condition.and Condition.new(2, '==', 2)
+ condition.and(Condition.new(2, '==', 2))
assert_equal true, condition.evaluate
- condition.and Condition.new(2, '==', 1)
+ condition.and(Condition.new(2, '==', 1))
assert_equal false, condition.evaluate
end
def test_should_allow_custom_proc_operator
- Condition.operators['starts_with'] = proc { |cond, left, right| left =~ %r{^#{right}} }
+ Condition.operators['starts_with'] = proc { |_cond, left, right| left =~ /^#{right}/ }
assert_evaluates_true 'bob', 'starts_with', 'b'
assert_evaluates_false 'bob', 'starts_with', 'o'
ensure
- Condition.operators.delete 'starts_with'
+ Condition.operators.delete('starts_with')
end
def test_left_or_right_may_contain_operators
diff --git a/test/unit/context_unit_test.rb b/test/unit/context_unit_test.rb
index 9252eb5..6d7042c 100644
--- a/test/unit/context_unit_test.rb
+++ b/test/unit/context_unit_test.rb
@@ -206,9 +206,9 @@ class ContextUnitTest < Minitest::Test
end
def test_merge
- @context.merge({ "test" => "test" })
+ @context.merge("test" => "test")
assert_equal 'test', @context['test']
- @context.merge({ "test" => "newvalue", "foo" => "bar" })
+ @context.merge("test" => "newvalue", "foo" => "bar")
assert_equal 'newvalue', @context['test']
assert_equal 'bar', @context['foo']
end
@@ -235,10 +235,10 @@ class ContextUnitTest < Minitest::Test
def test_hash_to_array_transition
@context['colors'] = {
- 'Blue' => ['003366', '336699', '6699CC', '99CCFF'],
- 'Green' => ['003300', '336633', '669966', '99CC99'],
- 'Yellow' => ['CC9900', 'FFCC00', 'FFFF99', 'FFFFCC'],
- 'Red' => ['660000', '993333', 'CC6666', 'FF9999']
+ 'Blue' => ['003366', '336699', '6699CC', '99CCFF'],
+ 'Green' => ['003300', '336633', '669966', '99CC99'],
+ 'Yellow' => ['CC9900', 'FFCC00', 'FFFF99', 'FFFFCC'],
+ 'Red' => ['660000', '993333', 'CC6666', 'FF9999'],
}
assert_equal '003366', @context['colors.Blue[0]']
@@ -263,7 +263,7 @@ class ContextUnitTest < Minitest::Test
def test_access_hashes_with_hash_notation
@context['products'] = { 'count' => 5, 'tags' => ['deepsnow', 'freestyle'] }
- @context['product'] = { 'variants' => [ { 'title' => 'draft151cm' }, { 'title' => 'element151cm' } ] }
+ @context['product'] = { 'variants' => [{ 'title' => 'draft151cm' }, { 'title' => 'element151cm' }] }
assert_equal 5, @context['products["count"]']
assert_equal 'deepsnow', @context['products["tags"][0]']
@@ -301,7 +301,7 @@ class ContextUnitTest < Minitest::Test
end
def test_first_can_appear_in_middle_of_callchain
- @context['product'] = { 'variants' => [ { 'title' => 'draft151cm' }, { 'title' => 'element151cm' } ] }
+ @context['product'] = { 'variants' => [{ 'title' => 'draft151cm' }, { 'title' => 'element151cm' }] }
assert_equal 'draft151cm', @context['product.variants[0].title']
assert_equal 'element151cm', @context['product.variants[1].title']
@@ -453,7 +453,7 @@ class ContextUnitTest < Minitest::Test
end
def test_context_initialization_with_a_proc_in_environment
- contx = Context.new([test: ->(c) { c['poutine'] }], { test: :foo })
+ contx = Context.new([test: ->(c) { c['poutine'] }], test: :foo)
assert contx
assert_nil contx['poutine']
@@ -514,7 +514,7 @@ class ContextUnitTest < Minitest::Test
def test_new_isolated_subcontext_does_not_inherit_non_static_registers
registers = {
- my_register: :my_value
+ my_register: :my_value,
}
super_context = Context.new({}, {}, registers)
subcontext = super_context.new_isolated_subcontext
diff --git a/test/unit/partial_cache_unit_test.rb b/test/unit/partial_cache_unit_test.rb
index 29f1144..5778efb 100644
--- a/test/unit/partial_cache_unit_test.rb
+++ b/test/unit/partial_cache_unit_test.rb
@@ -4,7 +4,7 @@ class PartialCacheUnitTest < Minitest::Test
def test_uses_the_file_system_register_if_present
context = Liquid::Context.build(
registers: {
- file_system: StubFileSystem.new('my_partial' => 'my partial body')
+ file_system: StubFileSystem.new('my_partial' => 'my partial body'),
}
)
@@ -41,12 +41,12 @@ class PartialCacheUnitTest < Minitest::Test
)
context_one = Liquid::Context.build(
registers: {
- file_system: shared_file_system
+ file_system: shared_file_system,
}
)
context_two = Liquid::Context.build(
registers: {
- file_system: shared_file_system
+ file_system: shared_file_system,
}
)
diff --git a/test/unit/strainer_unit_test.rb b/test/unit/strainer_unit_test.rb
index 5ce2100..5ae2660 100644
--- a/test/unit/strainer_unit_test.rb
+++ b/test/unit/strainer_unit_test.rb
@@ -36,7 +36,8 @@ class StrainerUnitTest < Minitest::Test
rescue Liquid::ArgumentError => e
assert_match(
/\ALiquid error: wrong number of arguments \((1 for 0|given 1, expected 0)\)\z/,
- e.message)
+ e.message
+ )
assert_equal e.backtrace[0].split(':')[0], __FILE__
end
end
@@ -135,7 +136,7 @@ class StrainerUnitTest < Minitest::Test
end
module LateAddedFilter
- def late_added_filter(input)
+ def late_added_filter(_input)
"filtered"
end
end
@@ -150,7 +151,7 @@ class StrainerUnitTest < Minitest::Test
mod = Module.new do
class << self
attr_accessor :include_count
- def included(mod)
+ def included(_mod)
self.include_count += 1
end
end
diff --git a/test/unit/tags/if_tag_unit_test.rb b/test/unit/tags/if_tag_unit_test.rb
index 7ecfc40..71408b3 100644
--- a/test/unit/tags/if_tag_unit_test.rb
+++ b/test/unit/tags/if_tag_unit_test.rb
@@ -3,6 +3,6 @@ require 'test_helper'
class IfTagUnitTest < Minitest::Test
def test_if_nodelist
template = Liquid::Template.parse('{% if true %}IF{% else %}ELSE{% endif %}')
- assert_equal ['IF', 'ELSE'], template.root.nodelist[0].nodelist.map(&:nodelist).flatten
+ assert_equal(['IF', 'ELSE'], template.root.nodelist[0].nodelist.map(&:nodelist).flatten)
end
end
From 604d899496a0c11ebf54465c68ef64ad5f2ac874 Mon Sep 17 00:00:00 2001
From: Mike Angell
Date: Sat, 31 Aug 2019 22:48:25 +1000
Subject: [PATCH 57/74] Render tag styling fixes
---
lib/liquid/tags/render.rb | 4 ++--
test/integration/tags/render_tag_test.rb | 2 +-
test/unit/partial_cache_unit_test.rb | 6 +++---
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/lib/liquid/tags/render.rb b/lib/liquid/tags/render.rb
index 2e5310b..8f9a91c 100644
--- a/lib/liquid/tags/render.rb
+++ b/lib/liquid/tags/render.rb
@@ -1,13 +1,13 @@
module Liquid
class Render < Tag
- Syntax = /(#{QuotedString})#{QuotedFragment}*/o
+ SYNTAX = /(#{QuotedString})#{QuotedFragment}*/o
attr_reader :template_name_expr, :attributes
def initialize(tag_name, markup, options)
super
- raise SyntaxError.new(options[:locale].t("errors.syntax.render".freeze)) unless markup =~ Syntax
+ raise SyntaxError.new(options[:locale].t("errors.syntax.render".freeze)) unless markup =~ SYNTAX
template_name = $1
diff --git a/test/integration/tags/render_tag_test.rb b/test/integration/tags/render_tag_test.rb
index a31d018..ea14477 100644
--- a/test/integration/tags/render_tag_test.rb
+++ b/test/integration/tags/render_tag_test.rb
@@ -110,7 +110,7 @@ class RenderTagTest < Minitest::Test
file_system = StubFileSystem.new('snippet' => 'echo')
assert_equal 'echoecho',
Template.parse('{% render "snippet" %}{% render "snippet" %}')
- .render!({}, registers: { file_system: file_system })
+ .render!({}, registers: { file_system: file_system })
assert_equal 1, file_system.file_read_count
end
diff --git a/test/unit/partial_cache_unit_test.rb b/test/unit/partial_cache_unit_test.rb
index 29f1144..5778efb 100644
--- a/test/unit/partial_cache_unit_test.rb
+++ b/test/unit/partial_cache_unit_test.rb
@@ -4,7 +4,7 @@ class PartialCacheUnitTest < Minitest::Test
def test_uses_the_file_system_register_if_present
context = Liquid::Context.build(
registers: {
- file_system: StubFileSystem.new('my_partial' => 'my partial body')
+ file_system: StubFileSystem.new('my_partial' => 'my partial body'),
}
)
@@ -41,12 +41,12 @@ class PartialCacheUnitTest < Minitest::Test
)
context_one = Liquid::Context.build(
registers: {
- file_system: shared_file_system
+ file_system: shared_file_system,
}
)
context_two = Liquid::Context.build(
registers: {
- file_system: shared_file_system
+ file_system: shared_file_system,
}
)
From 806b2622da6acdfd236478a2e90bedf999868f8d Mon Sep 17 00:00:00 2001
From: Justin Li
Date: Wed, 4 Sep 2019 15:12:51 -0400
Subject: [PATCH 58/74] Switch back to Liquid-C master, since
https://github.com/Shopify/liquid-c/pull/50 is merged
---
Gemfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Gemfile b/Gemfile
index d77a738..00c1326 100644
--- a/Gemfile
+++ b/Gemfile
@@ -20,6 +20,6 @@ group :test do
gem 'rubocop-performance', require: false
platform :mri, :truffleruby do
- gem 'liquid-c', github: 'Shopify/liquid-c', ref: 'liquid-tag'
+ gem 'liquid-c', github: 'Shopify/liquid-c', ref: 'master'
end
end
From b316ff8413a4d69b8a9443aa7430478e6b4c165f Mon Sep 17 00:00:00 2001
From: Mike Angell
Date: Wed, 11 Sep 2019 04:20:34 +1000
Subject: [PATCH 59/74] Add usage tracking
---
README.md | 6 ++++++
lib/liquid/standardfilters.rb | 1 +
lib/liquid/usage.rb | 6 ++++++
3 files changed, 13 insertions(+)
create mode 100644 lib/liquid/usage.rb
diff --git a/README.md b/README.md
index 77e9ff4..75b1d5f 100644
--- a/README.md
+++ b/README.md
@@ -106,3 +106,9 @@ template = Liquid::Template.parse("{{x}} {{y}}")
template.render!({ 'x' => 1}, { strict_variables: true })
#=> Liquid::UndefinedVariable: Liquid error: undefined variable y
```
+
+### Usage tracking
+
+To help determine if a feature or code path is used in production we have included opt-in usage tracking. To achieve this we provide an empty `Liquid::Usage.increment` method that can be implemented. This was designed to be paired with https://github.com/Shopify/statsd-instrument , however it's implementation is up to you.
+
+Once you have enabled usage tracking we recommend reporting any logged events through Github Issues that your system may be reporting. It is highly likely this event has been added to consider deprecating or improving code specific to this event, so please raise any concerns.
diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb
index afcf479..f0c9868 100644
--- a/lib/liquid/standardfilters.rb
+++ b/lib/liquid/standardfilters.rb
@@ -421,6 +421,7 @@ module Liquid
def default(input, default_value = ''.freeze)
if !input || input.respond_to?(:empty?) && input.empty?
+ Usage.increment("liquid.default_filter_received_false_value") if input == false # See https://github.com/Shopify/liquid/issues/1127
default_value
else
input
diff --git a/lib/liquid/usage.rb b/lib/liquid/usage.rb
new file mode 100644
index 0000000..4876ce9
--- /dev/null
+++ b/lib/liquid/usage.rb
@@ -0,0 +1,6 @@
+module Liquid
+ module Usage
+ def self.increment(name, sample_rate: 0.1, tags: {})
+ end
+ end
+end
From b6547f322eb9d3b83908bc463dc3dd79e37cb3e4 Mon Sep 17 00:00:00 2001
From: Mike Angell
Date: Wed, 11 Sep 2019 04:56:25 +1000
Subject: [PATCH 60/74] Simplify usage
---
lib/liquid.rb | 1 +
lib/liquid/standardfilters.rb | 2 +-
lib/liquid/usage.rb | 2 +-
3 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/lib/liquid.rb b/lib/liquid.rb
index 0e198bb..b98d4d9 100644
--- a/lib/liquid.rb
+++ b/lib/liquid.rb
@@ -75,6 +75,7 @@ require 'liquid/utils'
require 'liquid/tokenizer'
require 'liquid/parse_context'
require 'liquid/partial_cache'
+require 'liquid/usage'
# Load all the tags of the standard library
#
diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb
index f0c9868..cf72dba 100644
--- a/lib/liquid/standardfilters.rb
+++ b/lib/liquid/standardfilters.rb
@@ -421,7 +421,7 @@ module Liquid
def default(input, default_value = ''.freeze)
if !input || input.respond_to?(:empty?) && input.empty?
- Usage.increment("liquid.default_filter_received_false_value") if input == false # See https://github.com/Shopify/liquid/issues/1127
+ Usage.increment("default_filter_received_false_value") if input == false # See https://github.com/Shopify/liquid/issues/1127
default_value
else
input
diff --git a/lib/liquid/usage.rb b/lib/liquid/usage.rb
index 4876ce9..e3267eb 100644
--- a/lib/liquid/usage.rb
+++ b/lib/liquid/usage.rb
@@ -1,6 +1,6 @@
module Liquid
module Usage
- def self.increment(name, sample_rate: 0.1, tags: {})
+ def self.increment(name)
end
end
end
From 8318be2edc0c4a2aaf1a47085a7aa65950eb6c81 Mon Sep 17 00:00:00 2001
From: Mike Angell
Date: Wed, 11 Sep 2019 05:20:05 +1000
Subject: [PATCH 61/74] Update readme
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 75b1d5f..6802a71 100644
--- a/README.md
+++ b/README.md
@@ -109,6 +109,6 @@ template.render!({ 'x' => 1}, { strict_variables: true })
### Usage tracking
-To help determine if a feature or code path is used in production we have included opt-in usage tracking. To achieve this we provide an empty `Liquid::Usage.increment` method that can be implemented. This was designed to be paired with https://github.com/Shopify/statsd-instrument , however it's implementation is up to you.
+To help track usages of a feature or code path in production, we have released opt-in usage tracking. To enable this, we provide an empty `Liquid:: Usage.increment` method which you can customize to your needs. The feature is well suited to https://github.com/Shopify/statsd-instrument. However, the choice of implementation is up to you.
-Once you have enabled usage tracking we recommend reporting any logged events through Github Issues that your system may be reporting. It is highly likely this event has been added to consider deprecating or improving code specific to this event, so please raise any concerns.
+Once you have enabled usage tracking, we recommend reporting any events through Github Issues that your system may be logging. It is highly likely this event has been added to consider deprecating or improving code specific to this event, so please raise any concerns.
\ No newline at end of file
From a5b387cdd4baaa04d205da4a218d1ce8ec637d34 Mon Sep 17 00:00:00 2001
From: Mike Angell
Date: Wed, 11 Sep 2019 06:32:31 +1000
Subject: [PATCH 62/74] Remove reserved word Interrupt to avoid confusion
Also resolves rubocop conflicts
---
lib/liquid/interrupts.rb | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/lib/liquid/interrupts.rb b/lib/liquid/interrupts.rb
index f3005e4..48a820c 100644
--- a/lib/liquid/interrupts.rb
+++ b/lib/liquid/interrupts.rb
@@ -1,6 +1,6 @@
module Liquid
- # An interrupt is any command that breaks processing of a block (ex: a for loop).
- class Interrupt
+ # A block interrupt is any command that breaks processing of a block (ex: a for loop).
+ class BlockInterrupt
attr_reader :message
def initialize(message = nil)
@@ -9,8 +9,8 @@ module Liquid
end
# Interrupt that is thrown whenever a {% break %} is called.
- class BreakInterrupt < RuntimeError; end
+ class BreakInterrupt < BlockInterrupt; end
# Interrupt that is thrown whenever a {% continue %} is called.
- class ContinueInterrupt < RuntimeError; end
+ class ContinueInterrupt < BlockInterrupt; end
end
From 724d02e9b3f94169252094cad962e56012329726 Mon Sep 17 00:00:00 2001
From: Mike Angell
Date: Wed, 11 Sep 2019 06:35:08 +1000
Subject: [PATCH 63/74] Disable interrupt fix in this round
---
.rubocop_todo.yml | 29 ++++++++++++++++++++++++++---
lib/liquid/interrupts.rb | 8 ++++----
2 files changed, 30 insertions(+), 7 deletions(-)
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 0bd77b1..83ced97 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
-# on 2019-08-31 21:54:20 +1000 using RuboCop version 0.74.0.
+# on 2019-09-11 06:34:25 +1000 using RuboCop version 0.74.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
@@ -26,6 +26,14 @@ Lint/AssignmentInCondition:
- 'test/test_helper.rb'
- 'test/unit/tokenizer_unit_test.rb'
+# Offense count: 2
+# Cop supports --auto-correct.
+# Configuration parameters: EnforcedStyle.
+# SupportedStyles: runtime_error, standard_error
+Lint/InheritException:
+ Exclude:
+ - 'lib/liquid/interrupts.rb'
+
# Offense count: 2
Lint/UselessAssignment:
Exclude:
@@ -44,9 +52,24 @@ Lint/Void:
Metrics/LineLength:
Max: 294
-# Offense count: 45
+# Offense count: 44
Naming/ConstantName:
- Enabled: false
+ Exclude:
+ - 'lib/liquid.rb'
+ - 'lib/liquid/block_body.rb'
+ - 'lib/liquid/tags/assign.rb'
+ - 'lib/liquid/tags/capture.rb'
+ - 'lib/liquid/tags/case.rb'
+ - 'lib/liquid/tags/cycle.rb'
+ - 'lib/liquid/tags/for.rb'
+ - 'lib/liquid/tags/if.rb'
+ - 'lib/liquid/tags/include.rb'
+ - 'lib/liquid/tags/raw.rb'
+ - 'lib/liquid/tags/table_row.rb'
+ - 'lib/liquid/variable.rb'
+ - 'performance/shopify/comment_form.rb'
+ - 'performance/shopify/paginate.rb'
+ - 'test/integration/tags/include_tag_test.rb'
# Offense count: 5
Style/ClassVars:
diff --git a/lib/liquid/interrupts.rb b/lib/liquid/interrupts.rb
index 48a820c..41359d7 100644
--- a/lib/liquid/interrupts.rb
+++ b/lib/liquid/interrupts.rb
@@ -1,6 +1,6 @@
module Liquid
- # A block interrupt is any command that breaks processing of a block (ex: a for loop).
- class BlockInterrupt
+ # An interrupt is any command that breaks processing of a block (ex: a for loop).
+ class Interrupt
attr_reader :message
def initialize(message = nil)
@@ -9,8 +9,8 @@ module Liquid
end
# Interrupt that is thrown whenever a {% break %} is called.
- class BreakInterrupt < BlockInterrupt; end
+ class BreakInterrupt < Interrupt; end
# Interrupt that is thrown whenever a {% continue %} is called.
- class ContinueInterrupt < BlockInterrupt; end
+ class ContinueInterrupt < Interrupt; end
end
From c0ffee59197cb3ab1609cbe61f6758269b6ad6ca Mon Sep 17 00:00:00 2001
From: Thierry Joyal
Date: Thu, 12 Sep 2019 12:29:56 +0000
Subject: [PATCH 64/74] Invokable methods for enumerable reject include?
---
lib/liquid/drop.rb | 2 +-
test/integration/drop_test.rb | 7 +++++++
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/lib/liquid/drop.rb b/lib/liquid/drop.rb
index 6b5aa99..1586c93 100644
--- a/lib/liquid/drop.rb
+++ b/lib/liquid/drop.rb
@@ -67,7 +67,7 @@ module Liquid
if include?(Enumerable)
blacklist += Enumerable.public_instance_methods
- blacklist -= [:sort, :count, :first, :min, :max, :include?]
+ blacklist -= [:sort, :count, :first, :min, :max]
end
whitelist = [:to_liquid] + (public_instance_methods - blacklist)
diff --git a/test/integration/drop_test.rb b/test/integration/drop_test.rb
index 2de4a5a..5a2253b 100644
--- a/test/integration/drop_test.rb
+++ b/test/integration/drop_test.rb
@@ -270,4 +270,11 @@ class DropsTest < Minitest::Test
assert_equal 'ProductDrop', Liquid::Template.parse("{{ product }}").render!('product' => ProductDrop.new)
assert_equal 'EnumerableDrop', Liquid::Template.parse('{{ collection }}').render!('collection' => EnumerableDrop.new)
end
+
+ def test_invokable_methods
+ assert_equal %w(to_liquid catchall user_input context texts).to_set, ProductDrop.invokable_methods
+ assert_equal %w(to_liquid scopes_as_array loop_pos scopes).to_set, ContextDrop.invokable_methods
+ assert_equal %w(to_liquid size max min first count).to_set, EnumerableDrop.invokable_methods
+ assert_equal %w(to_liquid max min sort count first).to_set, RealEnumerableDrop.invokable_methods
+ end
end # DropsTest
From 0d26f05bb83a72e9b737ebbd81008e5631c4e85f Mon Sep 17 00:00:00 2001
From: Mike Angell <53470248+shopmike@users.noreply.github.com>
Date: Wed, 18 Sep 2019 13:19:45 +1000
Subject: [PATCH 65/74] Enabled frozen string literals (#1154)
* Enabled frozen string literals
* Update rubocop config
* Prefer string interpolation in simple cases
Co-Authored-By: Dylan Thacker-Smith
---
.rubocop_todo.yml | 7 ----
Gemfile | 2 +
Rakefile | 2 +
example/server/example_servlet.rb | 2 +
example/server/liquid_servlet.rb | 2 +
example/server/server.rb | 2 +
lib/liquid.rb | 10 +++--
lib/liquid/block.rb | 16 ++++----
lib/liquid/block_body.rb | 20 +++++-----
lib/liquid/condition.rb | 20 +++++-----
lib/liquid/context.rb | 4 +-
lib/liquid/document.rb | 8 ++--
lib/liquid/drop.rb | 2 +
lib/liquid/errors.rb | 6 ++-
lib/liquid/expression.rb | 12 +++---
lib/liquid/extensions.rb | 2 +
lib/liquid/file_system.rb | 6 ++-
lib/liquid/forloop_drop.rb | 2 +
lib/liquid/i18n.rb | 4 +-
lib/liquid/interrupts.rb | 4 +-
lib/liquid/lexer.rb | 22 ++++++-----
lib/liquid/parse_context.rb | 2 +
lib/liquid/parser.rb | 6 ++-
lib/liquid/parser_switching.rb | 2 +
lib/liquid/partial_cache.rb | 2 +
lib/liquid/profiler.rb | 2 +
lib/liquid/profiler/hooks.rb | 2 +
lib/liquid/range_lookup.rb | 2 +
lib/liquid/resource_limits.rb | 2 +
lib/liquid/standardfilters.rb | 38 ++++++++++---------
lib/liquid/strainer.rb | 2 +
lib/liquid/tablerowloop_drop.rb | 2 +
lib/liquid/tag.rb | 4 +-
lib/liquid/tags/assign.rb | 6 ++-
lib/liquid/tags/break.rb | 4 +-
lib/liquid/tags/capture.rb | 4 +-
lib/liquid/tags/case.rb | 16 ++++----
lib/liquid/tags/comment.rb | 4 +-
lib/liquid/tags/continue.rb | 4 +-
lib/liquid/tags/cycle.rb | 4 +-
lib/liquid/tags/decrement.rb | 4 +-
lib/liquid/tags/echo.rb | 6 ++-
lib/liquid/tags/for.rb | 24 ++++++------
lib/liquid/tags/if.rb | 18 +++++----
lib/liquid/tags/ifchanged.rb | 6 ++-
lib/liquid/tags/include.rb | 8 ++--
lib/liquid/tags/increment.rb | 4 +-
lib/liquid/tags/raw.rb | 12 +++---
lib/liquid/tags/render.rb | 6 ++-
lib/liquid/tags/table_row.rb | 16 ++++----
lib/liquid/tags/unless.rb | 4 +-
lib/liquid/template.rb | 6 ++-
lib/liquid/tokenizer.rb | 2 +
lib/liquid/usage.rb | 2 +
lib/liquid/utils.rb | 4 +-
lib/liquid/variable.rb | 2 +
lib/liquid/variable_lookup.rb | 4 +-
lib/liquid/version.rb | 3 +-
liquid.gemspec | 1 +
performance/benchmark.rb | 2 +
performance/profile.rb | 2 +
performance/shopify/comment_form.rb | 2 +
performance/shopify/database.rb | 2 +
performance/shopify/json_filter.rb | 2 +
performance/shopify/liquid.rb | 2 +
performance/shopify/money_filter.rb | 2 +
performance/shopify/paginate.rb | 2 +
performance/shopify/shop_filter.rb | 2 +
performance/shopify/tag_filter.rb | 2 +
performance/shopify/weight_filter.rb | 2 +
performance/theme_runner.rb | 2 +
test/integration/assign_test.rb | 2 +
test/integration/blank_test.rb | 2 +
test/integration/block_test.rb | 2 +
test/integration/capture_test.rb | 2 +
test/integration/context_test.rb | 2 +
test/integration/document_test.rb | 2 +
test/integration/drop_test.rb | 6 ++-
test/integration/error_handling_test.rb | 2 +
test/integration/filter_test.rb | 2 +
test/integration/hash_ordering_test.rb | 2 +
test/integration/output_test.rb | 2 +
test/integration/parsing_quirks_test.rb | 2 +
test/integration/render_profiling_test.rb | 2 +
test/integration/security_test.rb | 2 +
test/integration/standard_filter_test.rb | 1 +
test/integration/tags/break_tag_test.rb | 2 +
test/integration/tags/continue_tag_test.rb | 2 +
test/integration/tags/echo_test.rb | 2 +
test/integration/tags/for_tag_test.rb | 2 +
test/integration/tags/if_else_tag_test.rb | 2 +
test/integration/tags/include_tag_test.rb | 2 +
test/integration/tags/increment_tag_test.rb | 2 +
test/integration/tags/liquid_tag_test.rb | 2 +
test/integration/tags/raw_tag_test.rb | 2 +
test/integration/tags/render_tag_test.rb | 2 +
test/integration/tags/standard_tag_test.rb | 2 +
test/integration/tags/statements_test.rb | 2 +
test/integration/tags/table_row_test.rb | 2 +
test/integration/tags/unless_else_tag_test.rb | 2 +
test/integration/template_test.rb | 2 +
test/integration/trim_mode_test.rb | 2 +
test/integration/variable_test.rb | 2 +
test/test_helper.rb | 1 +
test/unit/block_unit_test.rb | 6 ++-
test/unit/condition_unit_test.rb | 2 +
test/unit/context_unit_test.rb | 2 +
test/unit/file_system_unit_test.rb | 2 +
test/unit/i18n_unit_test.rb | 2 +
test/unit/lexer_unit_test.rb | 2 +
test/unit/parser_unit_test.rb | 2 +
test/unit/partial_cache_unit_test.rb | 2 +
test/unit/regexp_unit_test.rb | 2 +
test/unit/strainer_unit_test.rb | 2 +
test/unit/tag_unit_test.rb | 6 ++-
test/unit/tags/case_tag_unit_test.rb | 2 +
test/unit/tags/for_tag_unit_test.rb | 2 +
test/unit/tags/if_tag_unit_test.rb | 2 +
test/unit/template_unit_test.rb | 2 +
test/unit/tokenizer_unit_test.rb | 2 +
test/unit/variable_unit_test.rb | 2 +
121 files changed, 379 insertions(+), 150 deletions(-)
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 83ced97..1271628 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -84,13 +84,6 @@ Style/DateTime:
Exclude:
- 'test/unit/context_unit_test.rb'
-# Offense count: 119
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: always, never
-Style/FrozenStringLiteralComment:
- Enabled: false
-
# Offense count: 9
# Cop supports --auto-correct.
# Configuration parameters: AllowAsExpressionSeparator.
diff --git a/Gemfile b/Gemfile
index 00c1326..f520934 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
source 'https://rubygems.org'
git_source(:github) do |repo_name|
"https://github.com/#{repo_name}.git"
diff --git a/Rakefile b/Rakefile
index f2a0d07..66ae0fa 100755
--- a/Rakefile
+++ b/Rakefile
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rake'
require 'rake/testtask'
$LOAD_PATH.unshift(File.expand_path("../lib", __FILE__))
diff --git a/example/server/example_servlet.rb b/example/server/example_servlet.rb
index 9f8c58a..b09e3bb 100644
--- a/example/server/example_servlet.rb
+++ b/example/server/example_servlet.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ProductsFilter
def price(integer)
format("$%.2d USD", integer / 100.0)
diff --git a/example/server/liquid_servlet.rb b/example/server/liquid_servlet.rb
index 895f274..55e21d2 100644
--- a/example/server/liquid_servlet.rb
+++ b/example/server/liquid_servlet.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class LiquidServlet < WEBrick::HTTPServlet::AbstractServlet
def do_GET(req, res)
handle(:get, req, res)
diff --git a/example/server/server.rb b/example/server/server.rb
index f2f89a4..bb7a4bc 100644
--- a/example/server/server.rb
+++ b/example/server/server.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'webrick'
require 'rexml/document'
diff --git a/lib/liquid.rb b/lib/liquid.rb
index b98d4d9..6689566 100644
--- a/lib/liquid.rb
+++ b/lib/liquid.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Copyright (c) 2005 Tobias Luetke
#
# Permission is hereby granted, free of charge, to any person obtaining
@@ -21,10 +23,10 @@
module Liquid
FilterSeparator = /\|/
- ArgumentSeparator = ','.freeze
- FilterArgumentSeparator = ':'.freeze
- VariableAttributeSeparator = '.'.freeze
- WhitespaceControl = '-'.freeze
+ ArgumentSeparator = ','
+ FilterArgumentSeparator = ':'
+ VariableAttributeSeparator = '.'
+ WhitespaceControl = '-'
TagStart = /\{\%/
TagEnd = /\%\}/
VariableSignature = /\(?[\w\-\.\[\]]\)?/
diff --git a/lib/liquid/block.rb b/lib/liquid/block.rb
index 0036d7b..f669844 100644
--- a/lib/liquid/block.rb
+++ b/lib/liquid/block.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
class Block < Tag
MAX_DEPTH = 100
@@ -27,16 +29,16 @@ module Liquid
end
def unknown_tag(tag, _params, _tokens)
- if tag == 'else'.freeze
- raise SyntaxError, parse_context.locale.t("errors.syntax.unexpected_else".freeze,
+ if tag == 'else'
+ raise SyntaxError, parse_context.locale.t("errors.syntax.unexpected_else",
block_name: block_name)
- elsif tag.start_with?('end'.freeze)
- raise SyntaxError, parse_context.locale.t("errors.syntax.invalid_delimiter".freeze,
+ elsif tag.start_with?('end')
+ raise SyntaxError, parse_context.locale.t("errors.syntax.invalid_delimiter",
tag: tag,
block_name: block_name,
block_delimiter: block_delimiter)
else
- raise SyntaxError, parse_context.locale.t("errors.syntax.unknown_tag".freeze, tag: tag)
+ raise SyntaxError, parse_context.locale.t("errors.syntax.unknown_tag", tag: tag)
end
end
@@ -52,7 +54,7 @@ module Liquid
def parse_body(body, tokens)
if parse_context.depth >= MAX_DEPTH
- raise StackLevelError, "Nesting too deep".freeze
+ raise StackLevelError, "Nesting too deep"
end
parse_context.depth += 1
begin
@@ -61,7 +63,7 @@ module Liquid
return false if end_tag_name == block_delimiter
unless end_tag_name
- raise SyntaxError, parse_context.locale.t("errors.syntax.tag_never_closed".freeze, block_name: block_name)
+ raise SyntaxError, parse_context.locale.t("errors.syntax.tag_never_closed", block_name: block_name)
end
# this tag is not registered with the system
diff --git a/lib/liquid/block_body.rb b/lib/liquid/block_body.rb
index a52eb62..c4ce267 100644
--- a/lib/liquid/block_body.rb
+++ b/lib/liquid/block_body.rb
@@ -1,11 +1,13 @@
+# frozen_string_literal: true
+
module Liquid
class BlockBody
LiquidTagToken = /\A\s*(\w+)\s*(.*?)\z/o
FullToken = /\A#{TagStart}#{WhitespaceControl}?(\s*)(\w+)(\s*)(.*?)#{WhitespaceControl}?#{TagEnd}\z/om
ContentOfVariable = /\A#{VariableStart}#{WhitespaceControl}?(.*?)#{WhitespaceControl}?#{VariableEnd}\z/om
WhitespaceOrNothing = /\A\s*\z/
- TAGSTART = "{%".freeze
- VARSTART = "{{".freeze
+ TAGSTART = "{%"
+ VARSTART = "{{"
attr_reader :nodelist
@@ -64,10 +66,10 @@ module Liquid
if parse_context.line_number
# newlines inside the tag should increase the line number,
# particularly important for multiline {% liquid %} tags
- parse_context.line_number += Regexp.last_match(1).count("\n".freeze) + Regexp.last_match(3).count("\n".freeze)
+ parse_context.line_number += Regexp.last_match(1).count("\n") + Regexp.last_match(3).count("\n")
end
- if tag_name == 'liquid'.freeze
+ if tag_name == 'liquid'
liquid_tag_tokenizer = Tokenizer.new(markup, line_number: parse_context.line_number, for_liquid_tag: true)
next parse_for_liquid_tag(liquid_tag_tokenizer, parse_context, &block)
end
@@ -113,7 +115,7 @@ module Liquid
end
def render(context)
- render_to_output_buffer(context, '')
+ render_to_output_buffer(context, +'')
end
def render_to_output_buffer(context, output)
@@ -129,7 +131,7 @@ module Liquid
when Variable
render_node(context, output, node)
when Block
- render_node(context, node.blank? ? '' : output, node)
+ render_node(context, node.blank? ? +'' : output, node)
break if context.interrupt? # might have happened in a for-block
when Continue, Break
# If we get an Interrupt that means the block must stop processing. An
@@ -163,7 +165,7 @@ module Liquid
def raise_if_resource_limits_reached(context, length)
context.resource_limits.render_length += length
return unless context.resource_limits.reached?
- raise MemoryError, "Memory limits exceeded".freeze
+ raise MemoryError, "Memory limits exceeded"
end
def create_variable(token, parse_context)
@@ -175,11 +177,11 @@ module Liquid
end
def raise_missing_tag_terminator(token, parse_context)
- raise SyntaxError, parse_context.locale.t("errors.syntax.tag_termination".freeze, token: token, tag_end: TagEnd.inspect)
+ raise SyntaxError, parse_context.locale.t("errors.syntax.tag_termination", token: token, tag_end: TagEnd.inspect)
end
def raise_missing_variable_terminator(token, parse_context)
- raise SyntaxError, parse_context.locale.t("errors.syntax.variable_termination".freeze, token: token, tag_end: VariableEnd.inspect)
+ raise SyntaxError, parse_context.locale.t("errors.syntax.variable_termination", token: token, tag_end: VariableEnd.inspect)
end
def registered_tags
diff --git a/lib/liquid/condition.rb b/lib/liquid/condition.rb
index c6e29ae..93ec68b 100644
--- a/lib/liquid/condition.rb
+++ b/lib/liquid/condition.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
# Container for liquid nodes which conveniently wraps decision making logic
#
@@ -8,14 +10,14 @@ module Liquid
#
class Condition #:nodoc:
@@operators = {
- '=='.freeze => ->(cond, left, right) { cond.send(:equal_variables, left, right) },
- '!='.freeze => ->(cond, left, right) { !cond.send(:equal_variables, left, right) },
- '<>'.freeze => ->(cond, left, right) { !cond.send(:equal_variables, left, right) },
- '<'.freeze => :<,
- '>'.freeze => :>,
- '>='.freeze => :>=,
- '<='.freeze => :<=,
- 'contains'.freeze => lambda do |_cond, left, right|
+ '==' => ->(cond, left, right) { cond.send(:equal_variables, left, right) },
+ '!=' => ->(cond, left, right) { !cond.send(:equal_variables, left, right) },
+ '<>' => ->(cond, left, right) { !cond.send(:equal_variables, left, right) },
+ '<' => :<,
+ '>' => :>,
+ '>=' => :>=,
+ '<=' => :<=,
+ 'contains' => lambda do |_cond, left, right|
if left && right && left.respond_to?(:include?)
right = right.to_s if left.is_a?(String)
left.include?(right)
@@ -78,7 +80,7 @@ module Liquid
end
def inspect
- "#"
+ "#"
end
protected
diff --git a/lib/liquid/context.rb b/lib/liquid/context.rb
index daae5de..7e4350a 100644
--- a/lib/liquid/context.rb
+++ b/lib/liquid/context.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
# Context keeps the variable stack and resolves variables, as well as keywords
#
@@ -232,7 +234,7 @@ module Liquid
end
def check_overflow
- raise StackLevelError, "Nesting too deep".freeze if overflow?
+ raise StackLevelError, "Nesting too deep" if overflow?
end
def overflow?
diff --git a/lib/liquid/document.rb b/lib/liquid/document.rb
index afd4e99..e160886 100644
--- a/lib/liquid/document.rb
+++ b/lib/liquid/document.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
class Document < BlockBody
def self.parse(tokens, parse_context)
@@ -17,10 +19,10 @@ module Liquid
def unknown_tag(tag, parse_context)
case tag
- when 'else'.freeze, 'end'.freeze
- raise SyntaxError, parse_context.locale.t("errors.syntax.unexpected_outer_tag".freeze, tag: tag)
+ when 'else', 'end'
+ raise SyntaxError, parse_context.locale.t("errors.syntax.unexpected_outer_tag", tag: tag)
else
- raise SyntaxError, parse_context.locale.t("errors.syntax.unknown_tag".freeze, tag: tag)
+ raise SyntaxError, parse_context.locale.t("errors.syntax.unknown_tag", tag: tag)
end
end
end
diff --git a/lib/liquid/drop.rb b/lib/liquid/drop.rb
index 669eae6..d4d8950 100644
--- a/lib/liquid/drop.rb
+++ b/lib/liquid/drop.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'set'
module Liquid
diff --git a/lib/liquid/errors.rb b/lib/liquid/errors.rb
index 4239746..eda0bd2 100644
--- a/lib/liquid/errors.rb
+++ b/lib/liquid/errors.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
class Error < ::StandardError
attr_accessor :line_number
@@ -5,7 +7,7 @@ module Liquid
attr_accessor :markup_context
def to_s(with_prefix = true)
- str = ""
+ str = +""
str << message_prefix if with_prefix
str << super()
@@ -20,7 +22,7 @@ module Liquid
private
def message_prefix
- str = ""
+ str = +""
str << if is_a?(SyntaxError)
"Liquid syntax error"
else
diff --git a/lib/liquid/expression.rb b/lib/liquid/expression.rb
index 5568199..9670906 100644
--- a/lib/liquid/expression.rb
+++ b/lib/liquid/expression.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
class Expression
class MethodLiteral
@@ -14,11 +16,11 @@ module Liquid
end
LITERALS = {
- nil => nil, 'nil'.freeze => nil, 'null'.freeze => nil, ''.freeze => nil,
- 'true'.freeze => true,
- 'false'.freeze => false,
- 'blank'.freeze => MethodLiteral.new(:blank?, '').freeze,
- 'empty'.freeze => MethodLiteral.new(:empty?, '').freeze
+ nil => nil, 'nil' => nil, 'null' => nil, '' => nil,
+ 'true' => true,
+ 'false' => false,
+ 'blank' => MethodLiteral.new(:blank?, '').freeze,
+ 'empty' => MethodLiteral.new(:empty?, '').freeze
}.freeze
SINGLE_QUOTED_STRING = /\A'(.*)'\z/m
diff --git a/lib/liquid/extensions.rb b/lib/liquid/extensions.rb
index 0907819..d185498 100644
--- a/lib/liquid/extensions.rb
+++ b/lib/liquid/extensions.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'time'
require 'date'
diff --git a/lib/liquid/file_system.rb b/lib/liquid/file_system.rb
index a2aa9b7..b2093ae 100644
--- a/lib/liquid/file_system.rb
+++ b/lib/liquid/file_system.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
# A Liquid file system is a way to let your templates retrieve other templates for use with the include tag.
#
@@ -44,7 +46,7 @@ module Liquid
class LocalFileSystem
attr_accessor :root
- def initialize(root, pattern = "_%s.liquid".freeze)
+ def initialize(root, pattern = "_%s.liquid")
@root = root
@pattern = pattern
end
@@ -59,7 +61,7 @@ module Liquid
def full_path(template_path)
raise FileSystemError, "Illegal template name '#{template_path}'" unless template_path =~ %r{\A[^./][a-zA-Z0-9_/]+\z}
- full_path = if template_path.include?('/'.freeze)
+ full_path = if template_path.include?('/')
File.join(root, File.dirname(template_path), @pattern % File.basename(template_path))
else
File.join(root, @pattern % template_path)
diff --git a/lib/liquid/forloop_drop.rb b/lib/liquid/forloop_drop.rb
index 81b2d1a..0ffa255 100644
--- a/lib/liquid/forloop_drop.rb
+++ b/lib/liquid/forloop_drop.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
class ForloopDrop < Drop
def initialize(name, length, parentloop)
diff --git a/lib/liquid/i18n.rb b/lib/liquid/i18n.rb
index b2bb51b..4a2885e 100644
--- a/lib/liquid/i18n.rb
+++ b/lib/liquid/i18n.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'yaml'
module Liquid
@@ -31,7 +33,7 @@ module Liquid
end
def deep_fetch_translation(name)
- name.split('.'.freeze).reduce(locale) do |level, cur|
+ name.split('.').reduce(locale) do |level, cur|
level[cur] || raise(TranslationError, "Translation for #{name} does not exist in locale #{path}")
end
end
diff --git a/lib/liquid/interrupts.rb b/lib/liquid/interrupts.rb
index 41359d7..28355b8 100644
--- a/lib/liquid/interrupts.rb
+++ b/lib/liquid/interrupts.rb
@@ -1,10 +1,12 @@
+# frozen_string_literal: true
+
module Liquid
# An interrupt is any command that breaks processing of a block (ex: a for loop).
class Interrupt
attr_reader :message
def initialize(message = nil)
- @message = message || "interrupt".freeze
+ @message = message || "interrupt"
end
end
diff --git a/lib/liquid/lexer.rb b/lib/liquid/lexer.rb
index 367f99e..04e0c11 100644
--- a/lib/liquid/lexer.rb
+++ b/lib/liquid/lexer.rb
@@ -1,17 +1,19 @@
+# frozen_string_literal: true
+
require "strscan"
module Liquid
class Lexer
SPECIALS = {
- '|'.freeze => :pipe,
- '.'.freeze => :dot,
- ':'.freeze => :colon,
- ','.freeze => :comma,
- '['.freeze => :open_square,
- ']'.freeze => :close_square,
- '('.freeze => :open_round,
- ')'.freeze => :close_round,
- '?'.freeze => :question,
- '-'.freeze => :dash,
+ '|' => :pipe,
+ '.' => :dot,
+ ':' => :colon,
+ ',' => :comma,
+ '[' => :open_square,
+ ']' => :close_square,
+ '(' => :open_round,
+ ')' => :close_round,
+ '?' => :question,
+ '-' => :dash,
}.freeze
IDENTIFIER = /[a-zA-Z_][\w-]*\??/
SINGLE_STRING_LITERAL = /'[^\']*'/
diff --git a/lib/liquid/parse_context.rb b/lib/liquid/parse_context.rb
index 58437f4..2da3ad7 100644
--- a/lib/liquid/parse_context.rb
+++ b/lib/liquid/parse_context.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
class ParseContext
attr_accessor :locale, :line_number, :trim_whitespace, :depth
diff --git a/lib/liquid/parser.rb b/lib/liquid/parser.rb
index c36de86..6b9e837 100644
--- a/lib/liquid/parser.rb
+++ b/lib/liquid/parser.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
class Parser
def initialize(input)
@@ -66,10 +68,10 @@ module Liquid
end
def argument
- str = ""
+ str = +""
# might be a keyword argument (identifier: expression)
if look(:id) && look(:colon, 1)
- str << consume << consume << ' '.freeze
+ str << consume << consume << ' '
end
str << expression
diff --git a/lib/liquid/parser_switching.rb b/lib/liquid/parser_switching.rb
index 3aa664a..402b056 100644
--- a/lib/liquid/parser_switching.rb
+++ b/lib/liquid/parser_switching.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
module ParserSwitching
def parse_with_selected_parser(markup)
diff --git a/lib/liquid/partial_cache.rb b/lib/liquid/partial_cache.rb
index d0b8845..43c2e39 100644
--- a/lib/liquid/partial_cache.rb
+++ b/lib/liquid/partial_cache.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
class PartialCache
def self.load(template_name, context:, parse_context:)
diff --git a/lib/liquid/profiler.rb b/lib/liquid/profiler.rb
index dc9db60..dc3f1db 100644
--- a/lib/liquid/profiler.rb
+++ b/lib/liquid/profiler.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'liquid/profiler/hooks'
module Liquid
diff --git a/lib/liquid/profiler/hooks.rb b/lib/liquid/profiler/hooks.rb
index cda166b..e708653 100644
--- a/lib/liquid/profiler/hooks.rb
+++ b/lib/liquid/profiler/hooks.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
class BlockBody
def render_node_with_profiling(context, output, node)
diff --git a/lib/liquid/range_lookup.rb b/lib/liquid/range_lookup.rb
index 93bb420..8e4d765 100644
--- a/lib/liquid/range_lookup.rb
+++ b/lib/liquid/range_lookup.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
class RangeLookup
def self.parse(start_markup, end_markup)
diff --git a/lib/liquid/resource_limits.rb b/lib/liquid/resource_limits.rb
index 08b359b..5b7e8e4 100644
--- a/lib/liquid/resource_limits.rb
+++ b/lib/liquid/resource_limits.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
class ResourceLimits
attr_accessor :render_length, :render_score, :assign_score,
diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb
index 45cf3a0..517857a 100644
--- a/lib/liquid/standardfilters.rb
+++ b/lib/liquid/standardfilters.rb
@@ -1,14 +1,16 @@
+# frozen_string_literal: true
+
require 'cgi'
require 'bigdecimal'
module Liquid
module StandardFilters
HTML_ESCAPE = {
- '&'.freeze => '&'.freeze,
- '>'.freeze => '>'.freeze,
- '<'.freeze => '<'.freeze,
- '"'.freeze => '"'.freeze,
- "'".freeze => '''.freeze,
+ '&' => '&',
+ '>' => '>',
+ '<' => '<',
+ '"' => '"',
+ "'" => ''',
}.freeze
HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/
STRIP_HTML_BLOCKS = Regexp.union(
@@ -72,7 +74,7 @@ module Liquid
end
# Truncate a string down to x characters
- def truncate(input, length = 50, truncate_string = "...".freeze)
+ def truncate(input, length = 50, truncate_string = "...")
return if input.nil?
input_str = input.to_s
length = Utils.to_integer(length)
@@ -82,13 +84,13 @@ module Liquid
input_str.length > length ? input_str[0...l].concat(truncate_string_str) : input_str
end
- def truncatewords(input, words = 15, truncate_string = "...".freeze)
+ def truncatewords(input, words = 15, truncate_string = "...")
return if input.nil?
wordlist = input.to_s.split
words = Utils.to_integer(words)
l = words - 1
l = 0 if l < 0
- wordlist.length > l ? wordlist[0..l].join(" ".freeze).concat(truncate_string.to_s) : input
+ wordlist.length > l ? wordlist[0..l].join(" ").concat(truncate_string.to_s) : input
end
# Split input string into an array of substrings separated by given pattern.
@@ -113,7 +115,7 @@ module Liquid
end
def strip_html(input)
- empty = ''.freeze
+ empty = ''
result = input.to_s.gsub(STRIP_HTML_BLOCKS, empty)
result.gsub!(STRIP_HTML_TAGS, empty)
result
@@ -121,11 +123,11 @@ module Liquid
# Remove all newlines from the string
def strip_newlines(input)
- input.to_s.gsub(/\r?\n/, ''.freeze)
+ input.to_s.gsub(/\r?\n/, '')
end
# Join elements of the array with certain character between them
- def join(input, glue = ' '.freeze)
+ def join(input, glue = ' ')
InputIterator.new(input).join(glue)
end
@@ -220,7 +222,7 @@ module Liquid
InputIterator.new(input).map do |e|
e = e.call if e.is_a?(Proc)
- if property == "to_liquid".freeze
+ if property == "to_liquid"
e
elsif e.respond_to?(:[])
r = e[property]
@@ -250,23 +252,23 @@ module Liquid
end
# Replace occurrences of a string with another
- def replace(input, string, replacement = ''.freeze)
+ def replace(input, string, replacement = '')
input.to_s.gsub(string.to_s, replacement.to_s)
end
# Replace the first occurrences of a string with another
- def replace_first(input, string, replacement = ''.freeze)
+ def replace_first(input, string, replacement = '')
input.to_s.sub(string.to_s, replacement.to_s)
end
# remove a substring
def remove(input, string)
- input.to_s.gsub(string.to_s, ''.freeze)
+ input.to_s.gsub(string.to_s, '')
end
# remove the first occurrences of a substring
def remove_first(input, string)
- input.to_s.sub(string.to_s, ''.freeze)
+ input.to_s.sub(string.to_s, '')
end
# add one string to another
@@ -288,7 +290,7 @@ module Liquid
# Add
tags in front of all newlines in input string
def newline_to_br(input)
- input.to_s.gsub(/\n/, "
\n".freeze)
+ input.to_s.gsub(/\n/, "
\n")
end
# Reformat a date using Ruby's core Time#strftime( string ) -> string
@@ -419,7 +421,7 @@ module Liquid
result.is_a?(BigDecimal) ? result.to_f : result
end
- def default(input, default_value = ''.freeze)
+ def default(input, default_value = '')
if !input || input.respond_to?(:empty?) && input.empty?
Usage.increment("default_filter_received_false_value") if input == false # See https://github.com/Shopify/liquid/issues/1127
default_value
diff --git a/lib/liquid/strainer.rb b/lib/liquid/strainer.rb
index d885ae4..3f3417e 100644
--- a/lib/liquid/strainer.rb
+++ b/lib/liquid/strainer.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'set'
module Liquid
diff --git a/lib/liquid/tablerowloop_drop.rb b/lib/liquid/tablerowloop_drop.rb
index cda4a1e..0d00b6f 100644
--- a/lib/liquid/tablerowloop_drop.rb
+++ b/lib/liquid/tablerowloop_drop.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
class TablerowloopDrop < Drop
def initialize(length, cols)
diff --git a/lib/liquid/tag.rb b/lib/liquid/tag.rb
index 13b7e4b..1460639 100644
--- a/lib/liquid/tag.rb
+++ b/lib/liquid/tag.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
class Tag
attr_reader :nodelist, :tag_name, :line_number, :parse_context
@@ -33,7 +35,7 @@ module Liquid
end
def render(_context)
- ''.freeze
+ ''
end
# For backwards compatibility with custom tags. In a future release, the semantics
diff --git a/lib/liquid/tags/assign.rb b/lib/liquid/tags/assign.rb
index 6ff65d5..aaad14c 100644
--- a/lib/liquid/tags/assign.rb
+++ b/lib/liquid/tags/assign.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
# Assign sets a variable in your template.
#
@@ -11,7 +13,7 @@ module Liquid
Syntax = /(#{VariableSignature}+)\s*=\s*(.*)\s*/om
def self.syntax_error_translation_key
- "errors.syntax.assign".freeze
+ "errors.syntax.assign"
end
attr_reader :to, :from
@@ -59,5 +61,5 @@ module Liquid
end
end
- Template.register_tag('assign'.freeze, Assign)
+ Template.register_tag('assign', Assign)
end
diff --git a/lib/liquid/tags/break.rb b/lib/liquid/tags/break.rb
index 6fe0969..80f4627 100644
--- a/lib/liquid/tags/break.rb
+++ b/lib/liquid/tags/break.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
# Break tag to be used to break out of a for loop.
#
@@ -14,5 +16,5 @@ module Liquid
end
end
- Template.register_tag('break'.freeze, Break)
+ Template.register_tag('break', Break)
end
diff --git a/lib/liquid/tags/capture.rb b/lib/liquid/tags/capture.rb
index a97e42a..1cace9c 100644
--- a/lib/liquid/tags/capture.rb
+++ b/lib/liquid/tags/capture.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
# Capture stores the result of a block into a variable without rendering it inplace.
#
@@ -35,5 +37,5 @@ module Liquid
end
end
- Template.register_tag('capture'.freeze, Capture)
+ Template.register_tag('capture', Capture)
end
diff --git a/lib/liquid/tags/case.rb b/lib/liquid/tags/case.rb
index 2a72a18..30484c6 100644
--- a/lib/liquid/tags/case.rb
+++ b/lib/liquid/tags/case.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
class Case < Block
Syntax = /(#{QuotedFragment})/o
@@ -12,7 +14,7 @@ module Liquid
if markup =~ Syntax
@left = Expression.parse(Regexp.last_match(1))
else
- raise SyntaxError, options[:locale].t("errors.syntax.case".freeze)
+ raise SyntaxError, options[:locale].t("errors.syntax.case")
end
end
@@ -27,9 +29,9 @@ module Liquid
def unknown_tag(tag, markup, tokens)
case tag
- when 'when'.freeze
+ when 'when'
record_when_condition(markup)
- when 'else'.freeze
+ when 'else'
record_else_condition(markup)
else
super
@@ -58,12 +60,12 @@ module Liquid
while markup
unless markup =~ WhenSyntax
- raise SyntaxError, options[:locale].t("errors.syntax.case_invalid_when".freeze)
+ raise SyntaxError, options[:locale].t("errors.syntax.case_invalid_when")
end
markup = Regexp.last_match(2)
- block = Condition.new(@left, '=='.freeze, Expression.parse(Regexp.last_match(1)))
+ block = Condition.new(@left, '==', Expression.parse(Regexp.last_match(1)))
block.attach(body)
@blocks << block
end
@@ -71,7 +73,7 @@ module Liquid
def record_else_condition(markup)
unless markup.strip.empty?
- raise SyntaxError, options[:locale].t("errors.syntax.case_invalid_else".freeze)
+ raise SyntaxError, options[:locale].t("errors.syntax.case_invalid_else")
end
block = ElseCondition.new
@@ -86,5 +88,5 @@ module Liquid
end
end
- Template.register_tag('case'.freeze, Case)
+ Template.register_tag('case', Case)
end
diff --git a/lib/liquid/tags/comment.rb b/lib/liquid/tags/comment.rb
index cad3931..a5460f9 100644
--- a/lib/liquid/tags/comment.rb
+++ b/lib/liquid/tags/comment.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
class Comment < Block
def render_to_output_buffer(_context, output)
@@ -12,5 +14,5 @@ module Liquid
end
end
- Template.register_tag('comment'.freeze, Comment)
+ Template.register_tag('comment', Comment)
end
diff --git a/lib/liquid/tags/continue.rb b/lib/liquid/tags/continue.rb
index 9c81ec2..fb1f371 100644
--- a/lib/liquid/tags/continue.rb
+++ b/lib/liquid/tags/continue.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
# Continue tag to be used to break out of a for loop.
#
@@ -14,5 +16,5 @@ module Liquid
end
end
- Template.register_tag('continue'.freeze, Continue)
+ Template.register_tag('continue', Continue)
end
diff --git a/lib/liquid/tags/cycle.rb b/lib/liquid/tags/cycle.rb
index adc6e3d..b203c78 100644
--- a/lib/liquid/tags/cycle.rb
+++ b/lib/liquid/tags/cycle.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
# Cycle is usually used within a loop to alternate between values, like colors or DOM classes.
#
@@ -27,7 +29,7 @@ module Liquid
@variables = variables_from_string(markup)
@name = @variables.to_s
else
- raise SyntaxError, options[:locale].t("errors.syntax.cycle".freeze)
+ raise SyntaxError, options[:locale].t("errors.syntax.cycle")
end
end
diff --git a/lib/liquid/tags/decrement.rb b/lib/liquid/tags/decrement.rb
index 08ddd4d..d761a0c 100644
--- a/lib/liquid/tags/decrement.rb
+++ b/lib/liquid/tags/decrement.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
# decrement is used in a place where one needs to insert a counter
# into a template, and needs the counter to survive across
@@ -32,5 +34,5 @@ module Liquid
end
end
- Template.register_tag('decrement'.freeze, Decrement)
+ Template.register_tag('decrement', Decrement)
end
diff --git a/lib/liquid/tags/echo.rb b/lib/liquid/tags/echo.rb
index d3d30e3..1f78937 100644
--- a/lib/liquid/tags/echo.rb
+++ b/lib/liquid/tags/echo.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
# Echo outputs an expression
#
@@ -16,9 +18,9 @@ module Liquid
end
def render(context)
- @variable.render_to_output_buffer(context, '')
+ @variable.render_to_output_buffer(context, +'')
end
end
- Template.register_tag('echo'.freeze, Echo)
+ Template.register_tag('echo', Echo)
end
diff --git a/lib/liquid/tags/for.rb b/lib/liquid/tags/for.rb
index f20953f..d961369 100644
--- a/lib/liquid/tags/for.rb
+++ b/lib/liquid/tags/for.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
# "For" iterates over an array or collection.
# Several useful variables are available to you within the loop.
@@ -66,7 +68,7 @@ module Liquid
end
def unknown_tag(tag, markup, tokens)
- return super unless tag == 'else'.freeze
+ return super unless tag == 'else'
@else_block = BlockBody.new
end
@@ -95,22 +97,22 @@ module Liquid
set_attribute(key, value)
end
else
- raise SyntaxError, options[:locale].t("errors.syntax.for".freeze)
+ raise SyntaxError, options[:locale].t("errors.syntax.for")
end
end
def strict_parse(markup)
p = Parser.new(markup)
@variable_name = p.consume(:id)
- raise SyntaxError, options[:locale].t("errors.syntax.for_invalid_in".freeze) unless p.id?('in'.freeze)
+ raise SyntaxError, options[:locale].t("errors.syntax.for_invalid_in") unless p.id?('in')
collection_name = p.expression
@name = "#{@variable_name}-#{collection_name}"
@collection_name = Expression.parse(collection_name)
- @reversed = p.id?('reversed'.freeze)
+ @reversed = p.id?('reversed')
while p.look(:id) && p.look(:colon, 1)
- unless attribute = p.id?('limit'.freeze) || p.id?('offset'.freeze)
- raise SyntaxError, options[:locale].t("errors.syntax.for_invalid_attribute".freeze)
+ unless attribute = p.id?('limit') || p.id?('offset')
+ raise SyntaxError, options[:locale].t("errors.syntax.for_invalid_attribute")
end
p.consume
set_attribute(attribute, p.expression)
@@ -162,7 +164,7 @@ module Liquid
for_stack.push(loop_vars)
begin
- context['forloop'.freeze] = loop_vars
+ context['forloop'] = loop_vars
segment.each do |item|
context[@variable_name] = item
@@ -185,13 +187,13 @@ module Liquid
def set_attribute(key, expr)
case key
- when 'offset'.freeze
- @from = if expr == 'continue'.freeze
+ when 'offset'
+ @from = if expr == 'continue'
:continue
else
Expression.parse(expr)
end
- when 'limit'.freeze
+ when 'limit'
@limit = Expression.parse(expr)
end
end
@@ -211,5 +213,5 @@ module Liquid
end
end
- Template.register_tag('for'.freeze, For)
+ Template.register_tag('for', For)
end
diff --git a/lib/liquid/tags/if.rb b/lib/liquid/tags/if.rb
index 1a31395..c3d1a77 100644
--- a/lib/liquid/tags/if.rb
+++ b/lib/liquid/tags/if.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
# If is the conditional block
#
@@ -19,7 +21,7 @@ module Liquid
def initialize(tag_name, markup, options)
super
@blocks = []
- push_block('if'.freeze, markup)
+ push_block('if', markup)
end
def nodelist
@@ -32,7 +34,7 @@ module Liquid
end
def unknown_tag(tag, markup, tokens)
- if ['elsif'.freeze, 'else'.freeze].include?(tag)
+ if ['elsif', 'else'].include?(tag)
push_block(tag, markup)
else
super
@@ -52,7 +54,7 @@ module Liquid
private
def push_block(tag, markup)
- block = if tag == 'else'.freeze
+ block = if tag == 'else'
ElseCondition.new
else
parse_with_selected_parser(markup)
@@ -64,17 +66,17 @@ module Liquid
def lax_parse(markup)
expressions = markup.scan(ExpressionsAndOperators)
- raise SyntaxError, options[:locale].t("errors.syntax.if".freeze) unless expressions.pop =~ Syntax
+ raise SyntaxError, options[:locale].t("errors.syntax.if") unless expressions.pop =~ Syntax
condition = Condition.new(Expression.parse(Regexp.last_match(1)), Regexp.last_match(2), Expression.parse(Regexp.last_match(3)))
until expressions.empty?
operator = expressions.pop.to_s.strip
- raise SyntaxError, options[:locale].t("errors.syntax.if".freeze) unless expressions.pop.to_s =~ Syntax
+ raise SyntaxError, options[:locale].t("errors.syntax.if") unless expressions.pop.to_s =~ Syntax
new_condition = Condition.new(Expression.parse(Regexp.last_match(1)), Regexp.last_match(2), Expression.parse(Regexp.last_match(3)))
- raise SyntaxError, options[:locale].t("errors.syntax.if".freeze) unless BOOLEAN_OPERATORS.include?(operator)
+ raise SyntaxError, options[:locale].t("errors.syntax.if") unless BOOLEAN_OPERATORS.include?(operator)
new_condition.send(operator, condition)
condition = new_condition
end
@@ -92,7 +94,7 @@ module Liquid
def parse_binary_comparisons(p)
condition = parse_comparison(p)
first_condition = condition
- while op = (p.id?('and'.freeze) || p.id?('or'.freeze))
+ while op = (p.id?('and') || p.id?('or'))
child_condition = parse_comparison(p)
condition.send(op, child_condition)
condition = child_condition
@@ -117,5 +119,5 @@ module Liquid
end
end
- Template.register_tag('if'.freeze, If)
+ Template.register_tag('if', If)
end
diff --git a/lib/liquid/tags/ifchanged.rb b/lib/liquid/tags/ifchanged.rb
index ddd276c..dd3be53 100644
--- a/lib/liquid/tags/ifchanged.rb
+++ b/lib/liquid/tags/ifchanged.rb
@@ -1,7 +1,9 @@
+# frozen_string_literal: true
+
module Liquid
class Ifchanged < Block
def render_to_output_buffer(context, output)
- block_output = ''
+ block_output = +''
super(context, block_output)
if block_output != context.registers[:ifchanged]
@@ -13,5 +15,5 @@ module Liquid
end
end
- Template.register_tag('ifchanged'.freeze, Ifchanged)
+ Template.register_tag('ifchanged', Ifchanged)
end
diff --git a/lib/liquid/tags/include.rb b/lib/liquid/tags/include.rb
index d2c6cd2..bbcfb1c 100644
--- a/lib/liquid/tags/include.rb
+++ b/lib/liquid/tags/include.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
# Include allows templates to relate with other templates
#
@@ -35,7 +37,7 @@ module Liquid
end
else
- raise SyntaxError, options[:locale].t("errors.syntax.include".freeze)
+ raise SyntaxError, options[:locale].t("errors.syntax.include")
end
end
@@ -52,7 +54,7 @@ module Liquid
parse_context: parse_context
)
- context_variable_name = template_name.split('/'.freeze).last
+ context_variable_name = template_name.split('/').last
variable = if @variable_name_expr
context.evaluate(@variable_name_expr)
@@ -101,5 +103,5 @@ module Liquid
end
end
- Template.register_tag('include'.freeze, Include)
+ Template.register_tag('include', Include)
end
diff --git a/lib/liquid/tags/increment.rb b/lib/liquid/tags/increment.rb
index 95875aa..241b316 100644
--- a/lib/liquid/tags/increment.rb
+++ b/lib/liquid/tags/increment.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
# increment is used in a place where one needs to insert a counter
# into a template, and needs the counter to survive across
@@ -29,5 +31,5 @@ module Liquid
end
end
- Template.register_tag('increment'.freeze, Increment)
+ Template.register_tag('increment', Increment)
end
diff --git a/lib/liquid/tags/raw.rb b/lib/liquid/tags/raw.rb
index 6991002..093a37e 100644
--- a/lib/liquid/tags/raw.rb
+++ b/lib/liquid/tags/raw.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
class Raw < Block
Syntax = /\A\s*\z/
@@ -10,16 +12,16 @@ module Liquid
end
def parse(tokens)
- @body = ''
+ @body = +''
while token = tokens.shift
if token =~ FullTokenPossiblyInvalid
- @body << Regexp.last_match(1) if Regexp.last_match(1) != "".freeze
+ @body << Regexp.last_match(1) if Regexp.last_match(1) != ""
return if block_delimiter == Regexp.last_match(2)
end
@body << token unless token.empty?
end
- raise SyntaxError, parse_context.locale.t("errors.syntax.tag_never_closed".freeze, block_name: block_name)
+ raise SyntaxError, parse_context.locale.t("errors.syntax.tag_never_closed", block_name: block_name)
end
def render_to_output_buffer(_context, output)
@@ -39,10 +41,10 @@ module Liquid
def ensure_valid_markup(tag_name, markup, parse_context)
unless markup =~ Syntax
- raise SyntaxError, parse_context.locale.t("errors.syntax.tag_unexpected_args".freeze, tag: tag_name)
+ raise SyntaxError, parse_context.locale.t("errors.syntax.tag_unexpected_args", tag: tag_name)
end
end
end
- Template.register_tag('raw'.freeze, Raw)
+ Template.register_tag('raw', Raw)
end
diff --git a/lib/liquid/tags/render.rb b/lib/liquid/tags/render.rb
index d9b8002..e6c6223 100644
--- a/lib/liquid/tags/render.rb
+++ b/lib/liquid/tags/render.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
class Render < Tag
SYNTAX = /(#{QuotedString})#{QuotedFragment}*/o
@@ -7,7 +9,7 @@ module Liquid
def initialize(tag_name, markup, options)
super
- raise SyntaxError, options[:locale].t("errors.syntax.render".freeze) unless markup =~ SYNTAX
+ raise SyntaxError, options[:locale].t("errors.syntax.render") unless markup =~ SYNTAX
template_name = Regexp.last_match(1)
@@ -50,5 +52,5 @@ module Liquid
end
end
- Template.register_tag('render'.freeze, Render)
+ Template.register_tag('render', Render)
end
diff --git a/lib/liquid/tags/table_row.rb b/lib/liquid/tags/table_row.rb
index 9393527..7c59bd3 100644
--- a/lib/liquid/tags/table_row.rb
+++ b/lib/liquid/tags/table_row.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
class TableRow < Block
Syntax = /(\w+)\s+in\s+(#{QuotedFragment}+)/o
@@ -14,26 +16,26 @@ module Liquid
@attributes[key] = Expression.parse(value)
end
else
- raise SyntaxError, options[:locale].t("errors.syntax.table_row".freeze)
+ raise SyntaxError, options[:locale].t("errors.syntax.table_row")
end
end
def render_to_output_buffer(context, output)
- (collection = context.evaluate(@collection_name)) || (return ''.freeze)
+ (collection = context.evaluate(@collection_name)) || (return '')
- from = @attributes.key?('offset'.freeze) ? context.evaluate(@attributes['offset'.freeze]).to_i : 0
- to = @attributes.key?('limit'.freeze) ? from + context.evaluate(@attributes['limit'.freeze]).to_i : nil
+ from = @attributes.key?('offset') ? context.evaluate(@attributes['offset']).to_i : 0
+ to = @attributes.key?('limit') ? from + context.evaluate(@attributes['limit']).to_i : nil
collection = Utils.slice_collection(collection, from, to)
length = collection.length
- cols = context.evaluate(@attributes['cols'.freeze]).to_i
+ cols = context.evaluate(@attributes['cols']).to_i
output << "\n"
context.stack do
tablerowloop = Liquid::TablerowloopDrop.new(length, cols)
- context['tablerowloop'.freeze] = tablerowloop
+ context['tablerowloop'] = tablerowloop
collection.each do |item|
context[@variable_name] = item
@@ -61,5 +63,5 @@ module Liquid
end
end
- Template.register_tag('tablerow'.freeze, TableRow)
+ Template.register_tag('tablerow', TableRow)
end
diff --git a/lib/liquid/tags/unless.rb b/lib/liquid/tags/unless.rb
index 32aa3a4..f67f57a 100644
--- a/lib/liquid/tags/unless.rb
+++ b/lib/liquid/tags/unless.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require_relative 'if'
module Liquid
@@ -24,5 +26,5 @@ module Liquid
end
end
- Template.register_tag('unless'.freeze, Unless)
+ Template.register_tag('unless', Unless)
end
diff --git a/lib/liquid/template.rb b/lib/liquid/template.rb
index 62250b2..e77ba8a 100644
--- a/lib/liquid/template.rb
+++ b/lib/liquid/template.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
# Templates are central to liquid.
# Interpretating templates is a two step process. First you compile the
@@ -165,7 +167,7 @@ module Liquid
# filters and tags and might be useful to integrate liquid more with its host application
#
def render(*args)
- return ''.freeze if @root.nil?
+ return '' if @root.nil?
context = case args.first
when Liquid::Context
@@ -208,7 +210,7 @@ module Liquid
# render the nodelist.
# for performance reasons we get an array back here. join will make a string out of it.
with_profiling(context) do
- @root.render_to_output_buffer(context, output || '')
+ @root.render_to_output_buffer(context, output || +'')
end
rescue Liquid::MemoryError => e
context.handle_error(e)
diff --git a/lib/liquid/tokenizer.rb b/lib/liquid/tokenizer.rb
index 9511420..a89c789 100644
--- a/lib/liquid/tokenizer.rb
+++ b/lib/liquid/tokenizer.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
class Tokenizer
attr_reader :line_number, :for_liquid_tag
diff --git a/lib/liquid/usage.rb b/lib/liquid/usage.rb
index e3267eb..141eccb 100644
--- a/lib/liquid/usage.rb
+++ b/lib/liquid/usage.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
module Usage
def self.increment(name)
diff --git a/lib/liquid/utils.rb b/lib/liquid/utils.rb
index ada4f39..406d667 100644
--- a/lib/liquid/utils.rb
+++ b/lib/liquid/utils.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
module Utils
def self.slice_collection(collection, from, to)
@@ -69,7 +71,7 @@ module Liquid
end
case obj
- when 'now'.freeze, 'today'.freeze
+ when 'now', 'today'
Time.now
when /\A\d+\z/, Integer
Time.at(obj.to_i)
diff --git a/lib/liquid/variable.rb b/lib/liquid/variable.rb
index 6efcf70..2fc2ea8 100644
--- a/lib/liquid/variable.rb
+++ b/lib/liquid/variable.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
# Holds variables. Variables are only loaded "just in time"
# and are not evaluated as part of the render stage
diff --git a/lib/liquid/variable_lookup.rb b/lib/liquid/variable_lookup.rb
index ab06bb6..112373d 100644
--- a/lib/liquid/variable_lookup.rb
+++ b/lib/liquid/variable_lookup.rb
@@ -1,7 +1,9 @@
+# frozen_string_literal: true
+
module Liquid
class VariableLookup
SQUARE_BRACKETED = /\A\[(.*)\]\z/m
- COMMAND_METHODS = ['size'.freeze, 'first'.freeze, 'last'.freeze].freeze
+ COMMAND_METHODS = ['size', 'first', 'last'].freeze
attr_reader :name, :lookups
diff --git a/lib/liquid/version.rb b/lib/liquid/version.rb
index da01c47..9af2973 100644
--- a/lib/liquid/version.rb
+++ b/lib/liquid/version.rb
@@ -1,5 +1,6 @@
# encoding: utf-8
+# frozen_string_literal: true
module Liquid
- VERSION = "4.0.3".freeze
+ VERSION = "4.0.3"
end
diff --git a/liquid.gemspec b/liquid.gemspec
index 27b24aa..54a11fb 100644
--- a/liquid.gemspec
+++ b/liquid.gemspec
@@ -1,4 +1,5 @@
# encoding: utf-8
+# frozen_string_literal: true
lib = File.expand_path('../lib/', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
diff --git a/performance/benchmark.rb b/performance/benchmark.rb
index 68c568c..4d28b9a 100644
--- a/performance/benchmark.rb
+++ b/performance/benchmark.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'benchmark/ips'
require_relative 'theme_runner'
diff --git a/performance/profile.rb b/performance/profile.rb
index c6fb193..101f6e5 100644
--- a/performance/profile.rb
+++ b/performance/profile.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'stackprof'
require_relative 'theme_runner'
diff --git a/performance/shopify/comment_form.rb b/performance/shopify/comment_form.rb
index 65af1b5..7648e1a 100644
--- a/performance/shopify/comment_form.rb
+++ b/performance/shopify/comment_form.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class CommentForm < Liquid::Block
Syntax = /(#{Liquid::VariableSignature}+)/
diff --git a/performance/shopify/database.rb b/performance/shopify/database.rb
index c9f18c3..9836cd4 100644
--- a/performance/shopify/database.rb
+++ b/performance/shopify/database.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'yaml'
module Database
diff --git a/performance/shopify/json_filter.rb b/performance/shopify/json_filter.rb
index 3258316..c7c25d8 100644
--- a/performance/shopify/json_filter.rb
+++ b/performance/shopify/json_filter.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'json'
module JsonFilter
diff --git a/performance/shopify/liquid.rb b/performance/shopify/liquid.rb
index f9d5200..40444c3 100644
--- a/performance/shopify/liquid.rb
+++ b/performance/shopify/liquid.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
$LOAD_PATH.unshift(__dir__ + '/../../lib')
require_relative '../../lib/liquid'
diff --git a/performance/shopify/money_filter.rb b/performance/shopify/money_filter.rb
index 4cc7280..b0135e3 100644
--- a/performance/shopify/money_filter.rb
+++ b/performance/shopify/money_filter.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MoneyFilter
def money_with_currency(money)
return '' if money.nil?
diff --git a/performance/shopify/paginate.rb b/performance/shopify/paginate.rb
index 29e7c9e..f723823 100644
--- a/performance/shopify/paginate.rb
+++ b/performance/shopify/paginate.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Paginate < Liquid::Block
Syntax = /(#{Liquid::QuotedFragment})\s*(by\s*(\d+))?/
diff --git a/performance/shopify/shop_filter.rb b/performance/shopify/shop_filter.rb
index b2a0a9d..9f0cdc2 100644
--- a/performance/shopify/shop_filter.rb
+++ b/performance/shopify/shop_filter.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ShopFilter
def asset_url(input)
"/files/1/[shop_id]/[shop_id]/assets/#{input}"
diff --git a/performance/shopify/tag_filter.rb b/performance/shopify/tag_filter.rb
index 34b426f..58f066b 100644
--- a/performance/shopify/tag_filter.rb
+++ b/performance/shopify/tag_filter.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module TagFilter
def link_to_tag(label, tag)
"#{label}"
diff --git a/performance/shopify/weight_filter.rb b/performance/shopify/weight_filter.rb
index b05bcce..6ba95f3 100644
--- a/performance/shopify/weight_filter.rb
+++ b/performance/shopify/weight_filter.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module WeightFilter
def weight(grams)
format("%.2f", grams / 1000)
diff --git a/performance/theme_runner.rb b/performance/theme_runner.rb
index 9268558..5ad01c5 100644
--- a/performance/theme_runner.rb
+++ b/performance/theme_runner.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# This profiler run simulates Shopify.
# We are looking in the tests directory for liquid files and render them within the designated layout file.
# We will also export a substantial database to liquid which the templates can render values of.
diff --git a/test/integration/assign_test.rb b/test/integration/assign_test.rb
index 5502289..ffcb8a3 100644
--- a/test/integration/assign_test.rb
+++ b/test/integration/assign_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class AssignTest < Minitest::Test
diff --git a/test/integration/blank_test.rb b/test/integration/blank_test.rb
index 654ee98..f92490b 100644
--- a/test/integration/blank_test.rb
+++ b/test/integration/blank_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class FoobarTag < Liquid::Tag
diff --git a/test/integration/block_test.rb b/test/integration/block_test.rb
index 0824530..5603b53 100644
--- a/test/integration/block_test.rb
+++ b/test/integration/block_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class BlockTest < Minitest::Test
diff --git a/test/integration/capture_test.rb b/test/integration/capture_test.rb
index 8d965b3..f28e1b1 100644
--- a/test/integration/capture_test.rb
+++ b/test/integration/capture_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class CaptureTest < Minitest::Test
diff --git a/test/integration/context_test.rb b/test/integration/context_test.rb
index 2d109bb..cd6d7a8 100644
--- a/test/integration/context_test.rb
+++ b/test/integration/context_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class ContextTest < Minitest::Test
diff --git a/test/integration/document_test.rb b/test/integration/document_test.rb
index bcc4a21..375ccfa 100644
--- a/test/integration/document_test.rb
+++ b/test/integration/document_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class DocumentTest < Minitest::Test
diff --git a/test/integration/drop_test.rb b/test/integration/drop_test.rb
index e540559..3fe6175 100644
--- a/test/integration/drop_test.rb
+++ b/test/integration/drop_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class ContextDrop < Liquid::Drop
@@ -31,7 +33,7 @@ class ProductDrop < Liquid::Drop
class CatchallDrop < Liquid::Drop
def liquid_method_missing(method)
- 'catchall_method: ' << method.to_s
+ "catchall_method: #{method}"
end
end
@@ -48,7 +50,7 @@ class ProductDrop < Liquid::Drop
end
def user_input
- "foo".taint
+ (+"foo").taint
end
protected
diff --git a/test/integration/error_handling_test.rb b/test/integration/error_handling_test.rb
index 875f426..265632c 100644
--- a/test/integration/error_handling_test.rb
+++ b/test/integration/error_handling_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class ErrorHandlingTest < Minitest::Test
diff --git a/test/integration/filter_test.rb b/test/integration/filter_test.rb
index 0af29ef..270477e 100644
--- a/test/integration/filter_test.rb
+++ b/test/integration/filter_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
module MoneyFilter
diff --git a/test/integration/hash_ordering_test.rb b/test/integration/hash_ordering_test.rb
index 8592395..27d0b9b 100644
--- a/test/integration/hash_ordering_test.rb
+++ b/test/integration/hash_ordering_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class HashOrderingTest < Minitest::Test
diff --git a/test/integration/output_test.rb b/test/integration/output_test.rb
index d94b0f8..687cad8 100644
--- a/test/integration/output_test.rb
+++ b/test/integration/output_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
module FunnyFilter
diff --git a/test/integration/parsing_quirks_test.rb b/test/integration/parsing_quirks_test.rb
index 29cb6d6..c210b48 100644
--- a/test/integration/parsing_quirks_test.rb
+++ b/test/integration/parsing_quirks_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class ParsingQuirksTest < Minitest::Test
diff --git a/test/integration/render_profiling_test.rb b/test/integration/render_profiling_test.rb
index 283b8bd..753b2be 100644
--- a/test/integration/render_profiling_test.rb
+++ b/test/integration/render_profiling_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class RenderProfilingTest < Minitest::Test
diff --git a/test/integration/security_test.rb b/test/integration/security_test.rb
index f603ff0..28e9d39 100644
--- a/test/integration/security_test.rb
+++ b/test/integration/security_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
module SecurityFilter
diff --git a/test/integration/standard_filter_test.rb b/test/integration/standard_filter_test.rb
index 7863cfe..bf28539 100644
--- a/test/integration/standard_filter_test.rb
+++ b/test/integration/standard_filter_test.rb
@@ -1,4 +1,5 @@
# encoding: utf-8
+# frozen_string_literal: true
require 'test_helper'
diff --git a/test/integration/tags/break_tag_test.rb b/test/integration/tags/break_tag_test.rb
index 0fbde83..c3a4679 100644
--- a/test/integration/tags/break_tag_test.rb
+++ b/test/integration/tags/break_tag_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class BreakTagTest < Minitest::Test
diff --git a/test/integration/tags/continue_tag_test.rb b/test/integration/tags/continue_tag_test.rb
index ce4c158..00cca17 100644
--- a/test/integration/tags/continue_tag_test.rb
+++ b/test/integration/tags/continue_tag_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class ContinueTagTest < Minitest::Test
diff --git a/test/integration/tags/echo_test.rb b/test/integration/tags/echo_test.rb
index eab329d..c64932e 100644
--- a/test/integration/tags/echo_test.rb
+++ b/test/integration/tags/echo_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class EchoTest < Minitest::Test
diff --git a/test/integration/tags/for_tag_test.rb b/test/integration/tags/for_tag_test.rb
index 47e3e5f..667efac 100644
--- a/test/integration/tags/for_tag_test.rb
+++ b/test/integration/tags/for_tag_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class ThingWithValue < Liquid::Drop
diff --git a/test/integration/tags/if_else_tag_test.rb b/test/integration/tags/if_else_tag_test.rb
index 276b15b..d54b2fb 100644
--- a/test/integration/tags/if_else_tag_test.rb
+++ b/test/integration/tags/if_else_tag_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class IfElseTagTest < Minitest::Test
diff --git a/test/integration/tags/include_tag_test.rb b/test/integration/tags/include_tag_test.rb
index dea932a..45410a7 100644
--- a/test/integration/tags/include_tag_test.rb
+++ b/test/integration/tags/include_tag_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class TestFileSystem
diff --git a/test/integration/tags/increment_tag_test.rb b/test/integration/tags/increment_tag_test.rb
index a793b6d..d561a1b 100644
--- a/test/integration/tags/increment_tag_test.rb
+++ b/test/integration/tags/increment_tag_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class IncrementTagTest < Minitest::Test
diff --git a/test/integration/tags/liquid_tag_test.rb b/test/integration/tags/liquid_tag_test.rb
index 628eb85..b5f6b49 100644
--- a/test/integration/tags/liquid_tag_test.rb
+++ b/test/integration/tags/liquid_tag_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class LiquidTagTest < Minitest::Test
diff --git a/test/integration/tags/raw_tag_test.rb b/test/integration/tags/raw_tag_test.rb
index 634d052..461e5bf 100644
--- a/test/integration/tags/raw_tag_test.rb
+++ b/test/integration/tags/raw_tag_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class RawTagTest < Minitest::Test
diff --git a/test/integration/tags/render_tag_test.rb b/test/integration/tags/render_tag_test.rb
index ea14477..154783a 100644
--- a/test/integration/tags/render_tag_test.rb
+++ b/test/integration/tags/render_tag_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class RenderTagTest < Minitest::Test
diff --git a/test/integration/tags/standard_tag_test.rb b/test/integration/tags/standard_tag_test.rb
index cee4cac..7939cd3 100644
--- a/test/integration/tags/standard_tag_test.rb
+++ b/test/integration/tags/standard_tag_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class StandardTagTest < Minitest::Test
diff --git a/test/integration/tags/statements_test.rb b/test/integration/tags/statements_test.rb
index eeff166..0d024d0 100644
--- a/test/integration/tags/statements_test.rb
+++ b/test/integration/tags/statements_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class StatementsTest < Minitest::Test
diff --git a/test/integration/tags/table_row_test.rb b/test/integration/tags/table_row_test.rb
index d7bc14c..71df4f3 100644
--- a/test/integration/tags/table_row_test.rb
+++ b/test/integration/tags/table_row_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class TableRowTest < Minitest::Test
diff --git a/test/integration/tags/unless_else_tag_test.rb b/test/integration/tags/unless_else_tag_test.rb
index c414a71..469d1c0 100644
--- a/test/integration/tags/unless_else_tag_test.rb
+++ b/test/integration/tags/unless_else_tag_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class UnlessElseTagTest < Minitest::Test
diff --git a/test/integration/template_test.rb b/test/integration/template_test.rb
index e2b54c7..75dd95b 100644
--- a/test/integration/template_test.rb
+++ b/test/integration/template_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
require 'timeout'
diff --git a/test/integration/trim_mode_test.rb b/test/integration/trim_mode_test.rb
index 4e35dee..438f86b 100644
--- a/test/integration/trim_mode_test.rb
+++ b/test/integration/trim_mode_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class TrimModeTest < Minitest::Test
diff --git a/test/integration/variable_test.rb b/test/integration/variable_test.rb
index 244ba95..94ed1ec 100644
--- a/test/integration/variable_test.rb
+++ b/test/integration/variable_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class VariableTest < Minitest::Test
diff --git a/test/test_helper.rb b/test/test_helper.rb
index defc67e..d7a6641 100755
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -1,4 +1,5 @@
#!/usr/bin/env ruby
+# frozen_string_literal: true
ENV["MT_NO_EXPECTATIONS"] = "1"
require 'minitest/autorun'
diff --git a/test/unit/block_unit_test.rb b/test/unit/block_unit_test.rb
index 9f7b94f..fa06a87 100644
--- a/test/unit/block_unit_test.rb
+++ b/test/unit/block_unit_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class BlockUnitTest < Minitest::Test
@@ -61,7 +63,7 @@ class BlockUnitTest < Minitest::Test
assert_equal 'hello', template.render
- buf = ''
+ buf = +''
output = template.render({}, output: buf)
assert_equal 'hello', output
assert_equal 'hello', buf
@@ -79,7 +81,7 @@ class BlockUnitTest < Minitest::Test
assert_equal 'foohellobar', template.render
- buf = ''
+ buf = +''
output = template.render({}, output: buf)
assert_equal 'foohellobar', output
assert_equal 'foohellobar', buf
diff --git a/test/unit/condition_unit_test.rb b/test/unit/condition_unit_test.rb
index 165a7cf..69f6b90 100644
--- a/test/unit/condition_unit_test.rb
+++ b/test/unit/condition_unit_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class ConditionUnitTest < Minitest::Test
diff --git a/test/unit/context_unit_test.rb b/test/unit/context_unit_test.rb
index 6d7042c..67a8c91 100644
--- a/test/unit/context_unit_test.rb
+++ b/test/unit/context_unit_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class HundredCentes
diff --git a/test/unit/file_system_unit_test.rb b/test/unit/file_system_unit_test.rb
index 2c7250b..c76a7ed 100644
--- a/test/unit/file_system_unit_test.rb
+++ b/test/unit/file_system_unit_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class FileSystemUnitTest < Minitest::Test
diff --git a/test/unit/i18n_unit_test.rb b/test/unit/i18n_unit_test.rb
index b57500e..338787e 100644
--- a/test/unit/i18n_unit_test.rb
+++ b/test/unit/i18n_unit_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class I18nUnitTest < Minitest::Test
diff --git a/test/unit/lexer_unit_test.rb b/test/unit/lexer_unit_test.rb
index 5adcf2b..7a2a4a5 100644
--- a/test/unit/lexer_unit_test.rb
+++ b/test/unit/lexer_unit_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class LexerUnitTest < Minitest::Test
diff --git a/test/unit/parser_unit_test.rb b/test/unit/parser_unit_test.rb
index 9f23337..7456bf3 100644
--- a/test/unit/parser_unit_test.rb
+++ b/test/unit/parser_unit_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class ParserUnitTest < Minitest::Test
diff --git a/test/unit/partial_cache_unit_test.rb b/test/unit/partial_cache_unit_test.rb
index 5778efb..dd43185 100644
--- a/test/unit/partial_cache_unit_test.rb
+++ b/test/unit/partial_cache_unit_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class PartialCacheUnitTest < Minitest::Test
diff --git a/test/unit/regexp_unit_test.rb b/test/unit/regexp_unit_test.rb
index 0821229..666bc66 100644
--- a/test/unit/regexp_unit_test.rb
+++ b/test/unit/regexp_unit_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class RegexpUnitTest < Minitest::Test
diff --git a/test/unit/strainer_unit_test.rb b/test/unit/strainer_unit_test.rb
index 5ae2660..2fb9ad4 100644
--- a/test/unit/strainer_unit_test.rb
+++ b/test/unit/strainer_unit_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class StrainerUnitTest < Minitest::Test
diff --git a/test/unit/tag_unit_test.rb b/test/unit/tag_unit_test.rb
index a3fb40e..c9543e9 100644
--- a/test/unit/tag_unit_test.rb
+++ b/test/unit/tag_unit_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class TagUnitTest < Minitest::Test
@@ -31,7 +33,7 @@ class TagUnitTest < Minitest::Test
assert_equal 'hello', template.render
- buf = ''
+ buf = +''
output = template.render({}, output: buf)
assert_equal 'hello', output
assert_equal 'hello', buf
@@ -49,7 +51,7 @@ class TagUnitTest < Minitest::Test
assert_equal 'foohellobar', template.render
- buf = ''
+ buf = +''
output = template.render({}, output: buf)
assert_equal 'foohellobar', output
assert_equal 'foohellobar', buf
diff --git a/test/unit/tags/case_tag_unit_test.rb b/test/unit/tags/case_tag_unit_test.rb
index 7110308..0f3a61f 100644
--- a/test/unit/tags/case_tag_unit_test.rb
+++ b/test/unit/tags/case_tag_unit_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class CaseTagUnitTest < Minitest::Test
diff --git a/test/unit/tags/for_tag_unit_test.rb b/test/unit/tags/for_tag_unit_test.rb
index b8fc520..e6306c3 100644
--- a/test/unit/tags/for_tag_unit_test.rb
+++ b/test/unit/tags/for_tag_unit_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class ForTagUnitTest < Minitest::Test
diff --git a/test/unit/tags/if_tag_unit_test.rb b/test/unit/tags/if_tag_unit_test.rb
index 71408b3..32243b7 100644
--- a/test/unit/tags/if_tag_unit_test.rb
+++ b/test/unit/tags/if_tag_unit_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class IfTagUnitTest < Minitest::Test
diff --git a/test/unit/template_unit_test.rb b/test/unit/template_unit_test.rb
index 6328be5..bc02896 100644
--- a/test/unit/template_unit_test.rb
+++ b/test/unit/template_unit_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class TemplateUnitTest < Minitest::Test
diff --git a/test/unit/tokenizer_unit_test.rb b/test/unit/tokenizer_unit_test.rb
index de84c1f..d094aa1 100644
--- a/test/unit/tokenizer_unit_test.rb
+++ b/test/unit/tokenizer_unit_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class TokenizerTest < Minitest::Test
diff --git a/test/unit/variable_unit_test.rb b/test/unit/variable_unit_test.rb
index 5a21ace..da1d4ea 100644
--- a/test/unit/variable_unit_test.rb
+++ b/test/unit/variable_unit_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class VariableUnitTest < Minitest::Test
From d8403af515bfe929d616044f87e0e48a4fae6c2b Mon Sep 17 00:00:00 2001
From: Mike Angell <53470248+shopmike@users.noreply.github.com>
Date: Wed, 18 Sep 2019 13:25:55 +1000
Subject: [PATCH 66/74] Reimplementation of Static Registers (#1157)
---
lib/liquid.rb | 1 +
lib/liquid/context.rb | 9 +-
lib/liquid/static_registers.rb | 34 ++++
test/unit/context_unit_test.rb | 16 +-
test/unit/static_registers_unit_test.rb | 209 ++++++++++++++++++++++++
5 files changed, 260 insertions(+), 9 deletions(-)
create mode 100644 lib/liquid/static_registers.rb
create mode 100644 test/unit/static_registers_unit_test.rb
diff --git a/lib/liquid.rb b/lib/liquid.rb
index 6689566..d102530 100644
--- a/lib/liquid.rb
+++ b/lib/liquid.rb
@@ -78,6 +78,7 @@ require 'liquid/tokenizer'
require 'liquid/parse_context'
require 'liquid/partial_cache'
require 'liquid/usage'
+require 'liquid/static_registers'
# Load all the tags of the standard library
#
diff --git a/lib/liquid/context.rb b/lib/liquid/context.rb
index 7e4350a..88e4671 100644
--- a/lib/liquid/context.rb
+++ b/lib/liquid/context.rb
@@ -18,18 +18,17 @@ module Liquid
attr_accessor :exception_renderer, :template_name, :partial, :global_filter, :strict_variables, :strict_filters
# rubocop:disable Metrics/ParameterLists
- def self.build(environments: {}, outer_scope: {}, registers: {}, rethrow_errors: false, resource_limits: nil, static_registers: {}, static_environments: {})
- new(environments, outer_scope, registers, rethrow_errors, resource_limits, static_registers, static_environments)
+ def self.build(environments: {}, outer_scope: {}, registers: {}, rethrow_errors: false, resource_limits: nil, static_environments: {})
+ new(environments, outer_scope, registers, rethrow_errors, resource_limits, static_environments)
end
- def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = nil, static_registers = {}, static_environments = {})
+ def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = nil, static_environments = {})
@environments = [environments]
@environments.flatten!
@static_environments = [static_environments].flat_map(&:freeze).freeze
@scopes = [(outer_scope || {})]
@registers = registers
- @static_registers = static_registers.freeze
@errors = []
@partial = false
@strict_variables = false
@@ -137,7 +136,7 @@ module Liquid
Context.build(
resource_limits: resource_limits,
static_environments: static_environments,
- static_registers: static_registers
+ registers: StaticRegisters.new(registers)
).tap do |subcontext|
subcontext.base_scope_depth = base_scope_depth + 1
subcontext.exception_renderer = exception_renderer
diff --git a/lib/liquid/static_registers.rb b/lib/liquid/static_registers.rb
new file mode 100644
index 0000000..b05056d
--- /dev/null
+++ b/lib/liquid/static_registers.rb
@@ -0,0 +1,34 @@
+module Liquid
+ class StaticRegisters
+ attr_reader :static_registers, :registers
+
+ def initialize(registers = {})
+ @static_registers = registers.is_a?(StaticRegisters) ? registers.static_registers : registers.freeze
+ @registers = {}
+ end
+
+ def []=(key, value)
+ @registers[key] = value
+ end
+
+ def [](key)
+ if @registers.key?(key)
+ @registers[key]
+ else
+ @static_registers[key]
+ end
+ end
+
+ def delete(key)
+ @registers.delete(key)
+ end
+
+ def fetch(key, default = nil)
+ key?(key) ? self[key] : default
+ end
+
+ def key?(key)
+ @registers.key?(key) || @static_registers.key?(key)
+ end
+ end
+end
diff --git a/test/unit/context_unit_test.rb b/test/unit/context_unit_test.rb
index 67a8c91..fe790cf 100644
--- a/test/unit/context_unit_test.rb
+++ b/test/unit/context_unit_test.rb
@@ -518,15 +518,23 @@ class ContextUnitTest < Minitest::Test
registers = {
my_register: :my_value,
}
- super_context = Context.new({}, {}, registers)
+ super_context = Context.new({}, {}, StaticRegisters.new(registers))
+ super_context.registers[:my_register] = :my_alt_value
subcontext = super_context.new_isolated_subcontext
- assert_nil subcontext.registers[:my_register]
+ assert_equal :my_value, subcontext.registers[:my_register]
end
def test_new_isolated_subcontext_inherits_static_registers
- super_context = Context.build(static_registers: { my_register: :my_value })
+ super_context = Context.build(registers: { my_register: :my_value })
subcontext = super_context.new_isolated_subcontext
- assert_equal :my_value, subcontext.static_registers[:my_register]
+ assert_equal :my_value, subcontext.registers[:my_register]
+ end
+
+ def test_new_isolated_subcontext_registers_do_not_pollute_context
+ super_context = Context.build(registers: { my_register: :my_value })
+ subcontext = super_context.new_isolated_subcontext
+ subcontext.registers[:my_register] = :my_alt_value
+ assert_equal :my_value, super_context.registers[:my_register]
end
def test_new_isolated_subcontext_inherits_filters
diff --git a/test/unit/static_registers_unit_test.rb b/test/unit/static_registers_unit_test.rb
new file mode 100644
index 0000000..389cb3f
--- /dev/null
+++ b/test/unit/static_registers_unit_test.rb
@@ -0,0 +1,209 @@
+require 'test_helper'
+
+class StaticRegistersUnitTest < Minitest::Test
+ include Liquid
+
+ def set
+ static_register = StaticRegisters.new
+ static_register[nil] = true
+ static_register[1] = :one
+ static_register[:one] = "one"
+ static_register["two"] = "three"
+ static_register["two"] = 3
+ static_register[false] = nil
+
+ assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil }, static_register.registers)
+
+ static_register
+ end
+
+ def test_get
+ static_register = set
+
+ assert_equal true, static_register[nil]
+ assert_equal :one, static_register[1]
+ assert_equal "one", static_register[:one]
+ assert_equal 3, static_register["two"]
+ assert_nil static_register[false]
+ assert_nil static_register["unknown"]
+ end
+
+ def test_delete
+ static_register = set
+
+ assert_equal true, static_register.delete(nil)
+ assert_equal :one, static_register.delete(1)
+ assert_equal "one", static_register.delete(:one)
+ assert_equal 3, static_register.delete("two")
+ assert_nil static_register.delete(false)
+ assert_nil static_register.delete("unknown")
+
+ assert_equal({}, static_register.registers)
+ end
+
+ def test_fetch
+ static_register = set
+
+ assert_equal true, static_register.fetch(nil)
+ assert_equal :one, static_register.fetch(1)
+ assert_equal "one", static_register.fetch(:one)
+ assert_equal 3, static_register.fetch("two")
+ assert_nil static_register.fetch(false)
+ assert_nil static_register.fetch("unknown")
+ end
+
+ def test_fetch_default
+ static_register = StaticRegisters.new
+
+ assert_equal true, static_register.fetch(nil, true)
+ assert_equal :one, static_register.fetch(1, :one)
+ assert_equal "one", static_register.fetch(:one, "one")
+ assert_equal 3, static_register.fetch("two", 3)
+ assert_nil static_register.fetch(false, nil)
+ end
+
+ def test_key
+ static_register = set
+
+ assert_equal true, static_register.key?(nil)
+ assert_equal true, static_register.key?(1)
+ assert_equal true, static_register.key?(:one)
+ assert_equal true, static_register.key?("two")
+ assert_equal true, static_register.key?(false)
+ assert_equal false, static_register.key?("unknown")
+ assert_equal false, static_register.key?(true)
+ end
+
+ def set_with_static
+ static_register = StaticRegisters.new(nil => true, 1 => :one, :one => "one", "two" => 3, false => nil)
+ static_register[nil] = false
+ static_register["two"] = 4
+ static_register[true] = "foo"
+
+ assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil }, static_register.static_registers)
+ assert_equal({ nil => false, "two" => 4, true => "foo" }, static_register.registers)
+
+ static_register
+ end
+
+ def test_get_with_static
+ static_register = set_with_static
+
+ assert_equal false, static_register[nil]
+ assert_equal :one, static_register[1]
+ assert_equal "one", static_register[:one]
+ assert_equal 4, static_register["two"]
+ assert_equal "foo", static_register[true]
+ assert_nil static_register[false]
+ end
+
+ def test_delete_with_static
+ static_register = set_with_static
+
+ assert_equal false, static_register.delete(nil)
+ assert_equal 4, static_register.delete("two")
+ assert_equal "foo", static_register.delete(true)
+ assert_nil static_register.delete("unknown")
+ assert_nil static_register.delete(:one)
+
+ assert_equal({}, static_register.registers)
+ assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil }, static_register.static_registers)
+ end
+
+ def test_fetch_with_static
+ static_register = set_with_static
+
+ assert_equal false, static_register.fetch(nil)
+ assert_equal :one, static_register.fetch(1)
+ assert_equal "one", static_register.fetch(:one)
+ assert_equal 4, static_register.fetch("two")
+ assert_equal "foo", static_register.fetch(true)
+ assert_nil static_register.fetch(false)
+ end
+
+ def test_key_with_static
+ static_register = set_with_static
+
+ assert_equal true, static_register.key?(nil)
+ assert_equal true, static_register.key?(1)
+ assert_equal true, static_register.key?(:one)
+ assert_equal true, static_register.key?("two")
+ assert_equal true, static_register.key?(false)
+ assert_equal false, static_register.key?("unknown")
+ assert_equal true, static_register.key?(true)
+ end
+
+ def test_static_register_frozen
+ static_register = set_with_static
+
+ static = static_register.static_registers
+
+ assert_raises(RuntimeError) do
+ static["two"] = "foo"
+ end
+
+ assert_raises(RuntimeError) do
+ static["unknown"] = "foo"
+ end
+
+ assert_raises(RuntimeError) do
+ static.delete("two")
+ end
+ end
+
+ def test_new_static_retains_static
+ static_register = StaticRegisters.new(nil => true, 1 => :one, :one => "one", "two" => 3, false => nil)
+ static_register["one"] = 1
+ static_register["two"] = 2
+ static_register["three"] = 3
+
+ new_register = StaticRegisters.new(static_register)
+ assert_equal({}, new_register.registers)
+
+ new_register["one"] = 4
+ new_register["two"] = 5
+ new_register["three"] = 6
+
+ newest_register = StaticRegisters.new(new_register)
+ assert_equal({}, newest_register.registers)
+
+ newest_register["one"] = 7
+ newest_register["two"] = 8
+ newest_register["three"] = 9
+
+ assert_equal({ "one" => 1, "two" => 2, "three" => 3 }, static_register.registers)
+ assert_equal({ "one" => 4, "two" => 5, "three" => 6 }, new_register.registers)
+ assert_equal({ "one" => 7, "two" => 8, "three" => 9 }, newest_register.registers)
+ assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil }, static_register.static_registers)
+ assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil }, new_register.static_registers)
+ assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil }, newest_register.static_registers)
+ end
+
+ def test_multiple_instances_are_unique
+ static_register = StaticRegisters.new(nil => true, 1 => :one, :one => "one", "two" => 3, false => nil)
+ static_register["one"] = 1
+ static_register["two"] = 2
+ static_register["three"] = 3
+
+ new_register = StaticRegisters.new(foo: :bar)
+ assert_equal({}, new_register.registers)
+
+ new_register["one"] = 4
+ new_register["two"] = 5
+ new_register["three"] = 6
+
+ newest_register = StaticRegisters.new(bar: :foo)
+ assert_equal({}, newest_register.registers)
+
+ newest_register["one"] = 7
+ newest_register["two"] = 8
+ newest_register["three"] = 9
+
+ assert_equal({ "one" => 1, "two" => 2, "three" => 3 }, static_register.registers)
+ assert_equal({ "one" => 4, "two" => 5, "three" => 6 }, new_register.registers)
+ assert_equal({ "one" => 7, "two" => 8, "three" => 9 }, newest_register.registers)
+ assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil }, static_register.static_registers)
+ assert_equal({ foo: :bar }, new_register.static_registers)
+ assert_equal({ bar: :foo }, newest_register.static_registers)
+ end
+end
From adb40c41b7177fe0f84358ee50558126d1444214 Mon Sep 17 00:00:00 2001
From: Mike Angell <53470248+shopmike@users.noreply.github.com>
Date: Wed, 18 Sep 2019 13:40:07 +1000
Subject: [PATCH 67/74] Enable frozen_string_literal
---
lib/liquid/static_registers.rb | 2 ++
test/unit/static_registers_unit_test.rb | 2 ++
2 files changed, 4 insertions(+)
diff --git a/lib/liquid/static_registers.rb b/lib/liquid/static_registers.rb
index b05056d..6f22f70 100644
--- a/lib/liquid/static_registers.rb
+++ b/lib/liquid/static_registers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Liquid
class StaticRegisters
attr_reader :static_registers, :registers
diff --git a/test/unit/static_registers_unit_test.rb b/test/unit/static_registers_unit_test.rb
index 389cb3f..0db80cd 100644
--- a/test/unit/static_registers_unit_test.rb
+++ b/test/unit/static_registers_unit_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'test_helper'
class StaticRegistersUnitTest < Minitest::Test
From ef133435913436c491f8dfddeb6ab56dedcd3c77 Mon Sep 17 00:00:00 2001
From: Mike Angell <53470248+shopmike@users.noreply.github.com>
Date: Fri, 20 Sep 2019 00:24:48 +1000
Subject: [PATCH 68/74] Changes static registers to not be frozen (#1163)
* Changes static registers to not be frozen
* Add frozen test to static registers
---
lib/liquid/static_registers.rb | 8 ++--
test/unit/static_registers_unit_test.rb | 57 ++++++++++++++++++++-----
2 files changed, 51 insertions(+), 14 deletions(-)
diff --git a/lib/liquid/static_registers.rb b/lib/liquid/static_registers.rb
index 6f22f70..06c52ab 100644
--- a/lib/liquid/static_registers.rb
+++ b/lib/liquid/static_registers.rb
@@ -2,10 +2,10 @@
module Liquid
class StaticRegisters
- attr_reader :static_registers, :registers
+ attr_reader :static, :registers
def initialize(registers = {})
- @static_registers = registers.is_a?(StaticRegisters) ? registers.static_registers : registers.freeze
+ @static = registers.is_a?(StaticRegisters) ? registers.static : registers
@registers = {}
end
@@ -17,7 +17,7 @@ module Liquid
if @registers.key?(key)
@registers[key]
else
- @static_registers[key]
+ @static[key]
end
end
@@ -30,7 +30,7 @@ module Liquid
end
def key?(key)
- @registers.key?(key) || @static_registers.key?(key)
+ @registers.key?(key) || @static.key?(key)
end
end
end
diff --git a/test/unit/static_registers_unit_test.rb b/test/unit/static_registers_unit_test.rb
index 0db80cd..125440f 100644
--- a/test/unit/static_registers_unit_test.rb
+++ b/test/unit/static_registers_unit_test.rb
@@ -82,7 +82,7 @@ class StaticRegistersUnitTest < Minitest::Test
static_register["two"] = 4
static_register[true] = "foo"
- assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil }, static_register.static_registers)
+ assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil }, static_register.static)
assert_equal({ nil => false, "two" => 4, true => "foo" }, static_register.registers)
static_register
@@ -109,7 +109,7 @@ class StaticRegistersUnitTest < Minitest::Test
assert_nil static_register.delete(:one)
assert_equal({}, static_register.registers)
- assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil }, static_register.static_registers)
+ assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil }, static_register.static)
end
def test_fetch_with_static
@@ -135,10 +135,10 @@ class StaticRegistersUnitTest < Minitest::Test
assert_equal true, static_register.key?(true)
end
- def test_static_register_frozen
+ def test_static_register_can_be_frozen
static_register = set_with_static
- static = static_register.static_registers
+ static = static_register.static.freeze
assert_raises(RuntimeError) do
static["two"] = "foo"
@@ -176,9 +176,9 @@ class StaticRegistersUnitTest < Minitest::Test
assert_equal({ "one" => 1, "two" => 2, "three" => 3 }, static_register.registers)
assert_equal({ "one" => 4, "two" => 5, "three" => 6 }, new_register.registers)
assert_equal({ "one" => 7, "two" => 8, "three" => 9 }, newest_register.registers)
- assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil }, static_register.static_registers)
- assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil }, new_register.static_registers)
- assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil }, newest_register.static_registers)
+ assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil }, static_register.static)
+ assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil }, new_register.static)
+ assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil }, newest_register.static)
end
def test_multiple_instances_are_unique
@@ -204,8 +204,45 @@ class StaticRegistersUnitTest < Minitest::Test
assert_equal({ "one" => 1, "two" => 2, "three" => 3 }, static_register.registers)
assert_equal({ "one" => 4, "two" => 5, "three" => 6 }, new_register.registers)
assert_equal({ "one" => 7, "two" => 8, "three" => 9 }, newest_register.registers)
- assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil }, static_register.static_registers)
- assert_equal({ foo: :bar }, new_register.static_registers)
- assert_equal({ bar: :foo }, newest_register.static_registers)
+ assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil }, static_register.static)
+ assert_equal({ foo: :bar }, new_register.static)
+ assert_equal({ bar: :foo }, newest_register.static)
+ end
+
+ def test_can_update_static_directly_and_updates_all_instances
+ static_register = StaticRegisters.new(nil => true, 1 => :one, :one => "one", "two" => 3, false => nil)
+ static_register["one"] = 1
+ static_register["two"] = 2
+ static_register["three"] = 3
+
+ new_register = StaticRegisters.new(static_register)
+ assert_equal({}, new_register.registers)
+
+ assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil }, static_register.static)
+
+ new_register["one"] = 4
+ new_register["two"] = 5
+ new_register["three"] = 6
+ new_register.static["four"] = 10
+
+ newest_register = StaticRegisters.new(new_register)
+ assert_equal({}, newest_register.registers)
+
+ assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil, "four" => 10 }, new_register.static)
+
+ newest_register["one"] = 7
+ newest_register["two"] = 8
+ newest_register["three"] = 9
+ new_register.static["four"] = 5
+ new_register.static["five"] = 15
+
+ assert_equal({ "one" => 1, "two" => 2, "three" => 3 }, static_register.registers)
+ assert_equal({ "one" => 4, "two" => 5, "three" => 6 }, new_register.registers)
+ assert_equal({ "one" => 7, "two" => 8, "three" => 9 }, newest_register.registers)
+
+ assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil, "four" => 5, "five" => 15 }, newest_register.static)
+
+ assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil, "four" => 5, "five" => 15 }, static_register.static)
+ assert_equal({ nil => true, 1 => :one, :one => "one", "two" => 3, false => nil, "four" => 5, "five" => 15 }, new_register.static)
end
end
From ca207ed93f03c86f2cbcd348a25eaea6f5e7cd89 Mon Sep 17 00:00:00 2001
From: Ashwin Maroli
Date: Thu, 19 Sep 2019 20:25:01 +0530
Subject: [PATCH 69/74] Cleanup RuboCop configuration file (#1161)
---
.rubocop.yml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/.rubocop.yml b/.rubocop.yml
index 6b9aa9f..b231624 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -1,5 +1,5 @@
inherit_from:
- - https://shopify.github.io/ruby-style-guide/rubocop.yml
+ - 'https://shopify.github.io/ruby-style-guide/rubocop.yml'
- .rubocop_todo.yml
require: rubocop-performance
@@ -10,7 +10,7 @@ Performance:
AllCops:
Exclude:
- 'vendor/bundle/**/*'
-
+
Naming/MethodName:
Exclude:
- - 'example/server/liquid_servlet.rb'
\ No newline at end of file
+ - 'example/server/liquid_servlet.rb'
From 2c14e0b2ba0ce1a4f4b940175f1962a027ab77bd Mon Sep 17 00:00:00 2001
From: Ashwin Maroli
Date: Thu, 19 Sep 2019 21:37:52 +0530
Subject: [PATCH 70/74] Use `Regexp#match?` when `MatchData` is not used
(#1165)
* Use `Regexp#match?` when `MatchData` is not used
* Add `TargetRubyVersion: 2.4` to RuboCop config
---
.rubocop.yml | 1 +
lib/liquid/file_system.rb | 2 +-
lib/liquid/tags/raw.rb | 2 +-
lib/liquid/utils.rb | 2 +-
4 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/.rubocop.yml b/.rubocop.yml
index b231624..1c0f832 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -8,6 +8,7 @@ Performance:
Enabled: true
AllCops:
+ TargetRubyVersion: 2.4
Exclude:
- 'vendor/bundle/**/*'
diff --git a/lib/liquid/file_system.rb b/lib/liquid/file_system.rb
index b2093ae..27ab632 100644
--- a/lib/liquid/file_system.rb
+++ b/lib/liquid/file_system.rb
@@ -59,7 +59,7 @@ module Liquid
end
def full_path(template_path)
- raise FileSystemError, "Illegal template name '#{template_path}'" unless template_path =~ %r{\A[^./][a-zA-Z0-9_/]+\z}
+ raise FileSystemError, "Illegal template name '#{template_path}'" unless %r{\A[^./][a-zA-Z0-9_/]+\z}.match?(template_path)
full_path = if template_path.include?('/')
File.join(root, File.dirname(template_path), @pattern % File.basename(template_path))
diff --git a/lib/liquid/tags/raw.rb b/lib/liquid/tags/raw.rb
index 093a37e..fde3ee1 100644
--- a/lib/liquid/tags/raw.rb
+++ b/lib/liquid/tags/raw.rb
@@ -40,7 +40,7 @@ module Liquid
protected
def ensure_valid_markup(tag_name, markup, parse_context)
- unless markup =~ Syntax
+ unless Syntax.match?(markup)
raise SyntaxError, parse_context.locale.t("errors.syntax.tag_unexpected_args", tag: tag_name)
end
end
diff --git a/lib/liquid/utils.rb b/lib/liquid/utils.rb
index 406d667..709fb00 100644
--- a/lib/liquid/utils.rb
+++ b/lib/liquid/utils.rb
@@ -52,7 +52,7 @@ module Liquid
when Numeric
obj
when String
- obj.strip =~ /\A-?\d+\.\d+\z/ ? BigDecimal(obj) : obj.to_i
+ /\A-?\d+\.\d+\z/.match?(obj.strip) ? BigDecimal(obj) : obj.to_i
else
if obj.respond_to?(:to_number)
obj.to_number
From b667bcb48b26dab6c87827bd23ea99c6216bc7b4 Mon Sep 17 00:00:00 2001
From: Mike Angell <53470248+shopmike@users.noreply.github.com>
Date: Fri, 20 Sep 2019 02:08:11 +1000
Subject: [PATCH 71/74] Shopify stye guide fixes (#1160)
---
.rubocop_todo.yml | 48 +------------------------
lib/liquid/block_body.rb | 10 +++---
lib/liquid/lexer.rb | 20 +++++++----
lib/liquid/parse_context.rb | 1 -
lib/liquid/standardfilters.rb | 2 +-
lib/liquid/tags/for.rb | 2 +-
lib/liquid/tags/if.rb | 4 +--
lib/liquid/tags/raw.rb | 2 +-
lib/liquid/variable.rb | 2 +-
performance/profile.rb | 2 +-
performance/shopify/database.rb | 4 +--
test/integration/error_handling_test.rb | 10 ++++--
test/integration/template_test.rb | 20 ++++++++---
test/test_helper.rb | 2 +-
test/unit/condition_unit_test.rb | 4 +--
test/unit/context_unit_test.rb | 20 ++++++++---
test/unit/tokenizer_unit_test.rb | 2 +-
17 files changed, 72 insertions(+), 83 deletions(-)
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 1271628..34a2e24 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -6,26 +6,6 @@
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
-# Offense count: 2
-Lint/AmbiguousOperator:
- Exclude:
- - 'test/unit/condition_unit_test.rb'
-
-# Offense count: 21
-# Configuration parameters: AllowSafeAssignment.
-Lint/AssignmentInCondition:
- Exclude:
- - 'lib/liquid/block_body.rb'
- - 'lib/liquid/lexer.rb'
- - 'lib/liquid/standardfilters.rb'
- - 'lib/liquid/tags/for.rb'
- - 'lib/liquid/tags/if.rb'
- - 'lib/liquid/tags/raw.rb'
- - 'lib/liquid/variable.rb'
- - 'performance/profile.rb'
- - 'test/test_helper.rb'
- - 'test/unit/tokenizer_unit_test.rb'
-
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
@@ -34,17 +14,6 @@ Lint/InheritException:
Exclude:
- 'lib/liquid/interrupts.rb'
-# Offense count: 2
-Lint/UselessAssignment:
- Exclude:
- - 'performance/shopify/database.rb'
-
-# Offense count: 1
-# Configuration parameters: CheckForMethodsWithNoSideEffects.
-Lint/Void:
- Exclude:
- - 'lib/liquid/parse_context.rb'
-
# Offense count: 98
# Cop supports --auto-correct.
# Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
@@ -76,19 +45,4 @@ Style/ClassVars:
Exclude:
- 'lib/liquid/condition.rb'
- 'lib/liquid/strainer.rb'
- - 'lib/liquid/template.rb'
-
-# Offense count: 1
-# Configuration parameters: AllowCoercion.
-Style/DateTime:
- Exclude:
- - 'test/unit/context_unit_test.rb'
-
-# Offense count: 9
-# Cop supports --auto-correct.
-# Configuration parameters: AllowAsExpressionSeparator.
-Style/Semicolon:
- Exclude:
- - 'test/integration/error_handling_test.rb'
- - 'test/integration/template_test.rb'
- - 'test/unit/context_unit_test.rb'
+ - 'lib/liquid/template.rb'
\ No newline at end of file
diff --git a/lib/liquid/block_body.rb b/lib/liquid/block_body.rb
index c4ce267..9400e38 100644
--- a/lib/liquid/block_body.rb
+++ b/lib/liquid/block_body.rb
@@ -27,7 +27,7 @@ module Liquid
end
private def parse_for_liquid_tag(tokenizer, parse_context)
- while token = tokenizer.shift
+ while (token = tokenizer.shift)
unless token.empty? || token =~ WhitespaceOrNothing
unless token =~ LiquidTagToken
# line isn't empty but didn't match tag syntax, yield and let the
@@ -36,7 +36,7 @@ module Liquid
end
tag_name = Regexp.last_match(1)
markup = Regexp.last_match(2)
- unless tag = registered_tags[tag_name]
+ unless (tag = registered_tags[tag_name])
# end parsing if we reach an unknown tag and let the caller decide
# determine how to proceed
return yield tag_name, markup
@@ -52,7 +52,7 @@ module Liquid
end
private def parse_for_document(tokenizer, parse_context, &block)
- while token = tokenizer.shift
+ while (token = tokenizer.shift)
next if token.empty?
case
when token.start_with?(TAGSTART)
@@ -74,7 +74,7 @@ module Liquid
next parse_for_liquid_tag(liquid_tag_tokenizer, parse_context, &block)
end
- unless tag = registered_tags[tag_name]
+ unless (tag = registered_tags[tag_name])
# end parsing if we reach an unknown tag and let the caller decide
# determine how to proceed
return yield tag_name, markup
@@ -122,7 +122,7 @@ module Liquid
context.resource_limits.render_score += @nodelist.length
idx = 0
- while node = @nodelist[idx]
+ while (node = @nodelist[idx])
previous_output_size = output.bytesize
case node
diff --git a/lib/liquid/lexer.rb b/lib/liquid/lexer.rb
index 04e0c11..a251c3e 100644
--- a/lib/liquid/lexer.rb
+++ b/lib/liquid/lexer.rb
@@ -33,15 +33,21 @@ module Liquid
until @ss.eos?
@ss.skip(WHITESPACE_OR_NOTHING)
break if @ss.eos?
- tok = if t = @ss.scan(COMPARISON_OPERATOR) then [:comparison, t]
- elsif t = @ss.scan(SINGLE_STRING_LITERAL) then [:string, t]
- elsif t = @ss.scan(DOUBLE_STRING_LITERAL) then [:string, t]
- elsif t = @ss.scan(NUMBER_LITERAL) then [:number, t]
- elsif t = @ss.scan(IDENTIFIER) then [:id, t]
- elsif t = @ss.scan(DOTDOT) then [:dotdot, t]
+ tok = if (t = @ss.scan(COMPARISON_OPERATOR))
+ [:comparison, t]
+ elsif (t = @ss.scan(SINGLE_STRING_LITERAL))
+ [:string, t]
+ elsif (t = @ss.scan(DOUBLE_STRING_LITERAL))
+ [:string, t]
+ elsif (t = @ss.scan(NUMBER_LITERAL))
+ [:number, t]
+ elsif (t = @ss.scan(IDENTIFIER))
+ [:id, t]
+ elsif (t = @ss.scan(DOTDOT))
+ [:dotdot, t]
else
c = @ss.getch
- if s = SPECIALS[c]
+ if (s = SPECIALS[c])
[s, c]
else
raise SyntaxError, "Unexpected character #{c}"
diff --git a/lib/liquid/parse_context.rb b/lib/liquid/parse_context.rb
index 2da3ad7..4afdbe5 100644
--- a/lib/liquid/parse_context.rb
+++ b/lib/liquid/parse_context.rb
@@ -21,7 +21,6 @@ module Liquid
@partial = value
@options = value ? partial_options : @template_options
@error_mode = @options[:error_mode] || Template.error_mode
- value
end
def partial_options
diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb
index 517857a..6855cd2 100644
--- a/lib/liquid/standardfilters.rb
+++ b/lib/liquid/standardfilters.rb
@@ -327,7 +327,7 @@ module Liquid
def date(input, format)
return input if format.to_s.empty?
- return input unless date = Utils.to_date(input)
+ return input unless (date = Utils.to_date(input))
date.strftime(format.to_s)
end
diff --git a/lib/liquid/tags/for.rb b/lib/liquid/tags/for.rb
index d961369..5c7b560 100644
--- a/lib/liquid/tags/for.rb
+++ b/lib/liquid/tags/for.rb
@@ -111,7 +111,7 @@ module Liquid
@reversed = p.id?('reversed')
while p.look(:id) && p.look(:colon, 1)
- unless attribute = p.id?('limit') || p.id?('offset')
+ unless (attribute = p.id?('limit') || p.id?('offset'))
raise SyntaxError, options[:locale].t("errors.syntax.for_invalid_attribute")
end
p.consume
diff --git a/lib/liquid/tags/if.rb b/lib/liquid/tags/if.rb
index c3d1a77..b68e309 100644
--- a/lib/liquid/tags/if.rb
+++ b/lib/liquid/tags/if.rb
@@ -94,7 +94,7 @@ module Liquid
def parse_binary_comparisons(p)
condition = parse_comparison(p)
first_condition = condition
- while op = (p.id?('and') || p.id?('or'))
+ while (op = (p.id?('and') || p.id?('or')))
child_condition = parse_comparison(p)
condition.send(op, child_condition)
condition = child_condition
@@ -104,7 +104,7 @@ module Liquid
def parse_comparison(p)
a = Expression.parse(p.expression)
- if op = p.consume?(:comparison)
+ if (op = p.consume?(:comparison))
b = Expression.parse(p.expression)
Condition.new(a, op, b)
else
diff --git a/lib/liquid/tags/raw.rb b/lib/liquid/tags/raw.rb
index fde3ee1..e4a78a8 100644
--- a/lib/liquid/tags/raw.rb
+++ b/lib/liquid/tags/raw.rb
@@ -13,7 +13,7 @@ module Liquid
def parse(tokens)
@body = +''
- while token = tokens.shift
+ while (token = tokens.shift)
if token =~ FullTokenPossiblyInvalid
@body << Regexp.last_match(1) if Regexp.last_match(1) != ""
return if block_delimiter == Regexp.last_match(2)
diff --git a/lib/liquid/variable.rb b/lib/liquid/variable.rb
index 2fc2ea8..265748d 100644
--- a/lib/liquid/variable.rb
+++ b/lib/liquid/variable.rb
@@ -110,7 +110,7 @@ module Liquid
filter_args = []
keyword_args = nil
unparsed_args.each do |a|
- if matches = a.match(JustTagAttributes)
+ if (matches = a.match(JustTagAttributes))
keyword_args ||= {}
keyword_args[matches[1]] = Expression.parse(matches[2])
else
diff --git a/performance/profile.rb b/performance/profile.rb
index 101f6e5..7074077 100644
--- a/performance/profile.rb
+++ b/performance/profile.rb
@@ -15,7 +15,7 @@ profiler.run
end
end
- if profile_type == :cpu && graph_filename = ENV['GRAPH_FILENAME']
+ if profile_type == :cpu && (graph_filename = ENV['GRAPH_FILENAME'])
File.open(graph_filename, 'w') do |f|
StackProf::Report.new(results).print_graphviz(nil, f)
end
diff --git a/performance/shopify/database.rb b/performance/shopify/database.rb
index 9836cd4..2db6d30 100644
--- a/performance/shopify/database.rb
+++ b/performance/shopify/database.rb
@@ -32,8 +32,8 @@ module Database
db['article'] = db['blog']['articles'].first
db['cart'] = {
- 'total_price' => db['line_items'].values.inject(0) { |sum, item| sum += item['line_price'] * item['quantity'] },
- 'item_count' => db['line_items'].values.inject(0) { |sum, item| sum += item['quantity'] },
+ 'total_price' => db['line_items'].values.inject(0) { |sum, item| sum + item['line_price'] * item['quantity'] },
+ 'item_count' => db['line_items'].values.inject(0) { |sum, item| sum + item['quantity'] },
'items' => db['line_items'].values,
}
diff --git a/test/integration/error_handling_test.rb b/test/integration/error_handling_test.rb
index 265632c..7abaec0 100644
--- a/test/integration/error_handling_test.rb
+++ b/test/integration/error_handling_test.rb
@@ -211,7 +211,10 @@ class ErrorHandlingTest < Minitest::Test
def test_setting_default_exception_renderer
old_exception_renderer = Liquid::Template.default_exception_renderer
exceptions = []
- Liquid::Template.default_exception_renderer = ->(e) { exceptions << e; '' }
+ Liquid::Template.default_exception_renderer = ->(e) {
+ exceptions << e
+ ''
+ }
template = Liquid::Template.parse('This is a runtime error: {{ errors.argument_error }}')
output = template.render('errors' => ErrorDrop.new)
@@ -225,7 +228,10 @@ class ErrorHandlingTest < Minitest::Test
def test_exception_renderer_exposing_non_liquid_error
template = Liquid::Template.parse('This is a runtime error: {{ errors.runtime_error }}', line_numbers: true)
exceptions = []
- handler = ->(e) { exceptions << e; e.cause }
+ handler = ->(e) {
+ exceptions << e
+ e.cause
+ }
output = template.render({ 'errors' => ErrorDrop.new }, exception_renderer: handler)
diff --git a/test/integration/template_test.rb b/test/integration/template_test.rb
index 75dd95b..48549f5 100644
--- a/test/integration/template_test.rb
+++ b/test/integration/template_test.rb
@@ -81,7 +81,10 @@ class TemplateTest < Minitest::Test
def test_lambda_is_called_once_from_persistent_assigns_over_multiple_parses_and_renders
t = Template.new
- t.assigns['number'] = -> { @global ||= 0; @global += 1 }
+ t.assigns['number'] = -> {
+ @global ||= 0
+ @global += 1
+ }
assert_equal '1', t.parse("{{number}}").render!
assert_equal '1', t.parse("{{number}}").render!
assert_equal '1', t.render!
@@ -90,7 +93,10 @@ class TemplateTest < Minitest::Test
def test_lambda_is_called_once_from_custom_assigns_over_multiple_parses_and_renders
t = Template.new
- assigns = { 'number' => -> { @global ||= 0; @global += 1 } }
+ assigns = { 'number' => -> {
+ @global ||= 0
+ @global += 1
+ } }
assert_equal '1', t.parse("{{number}}").render!(assigns)
assert_equal '1', t.parse("{{number}}").render!(assigns)
assert_equal '1', t.render!(assigns)
@@ -237,7 +243,10 @@ class TemplateTest < Minitest::Test
def test_exception_renderer_that_returns_string
exception = nil
- handler = ->(e) { exception = e; '' }
+ handler = ->(e) {
+ exception = e
+ ''
+ }
output = Template.parse("{{ 1 | divided_by: 0 }}").render({}, exception_renderer: handler)
@@ -248,7 +257,10 @@ class TemplateTest < Minitest::Test
def test_exception_renderer_that_raises
exception = nil
assert_raises(Liquid::ZeroDivisionError) do
- Template.parse("{{ 1 | divided_by: 0 }}").render({}, exception_renderer: ->(e) { exception = e; raise })
+ Template.parse("{{ 1 | divided_by: 0 }}").render({}, exception_renderer: ->(e) {
+ exception = e
+ raise
+ })
end
assert exception.is_a?(Liquid::ZeroDivisionError)
end
diff --git a/test/test_helper.rb b/test/test_helper.rb
index d7a6641..9606ef8 100755
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -9,7 +9,7 @@ require 'liquid.rb'
require 'liquid/profiler'
mode = :strict
-if env_mode = ENV['LIQUID_PARSER_MODE']
+if (env_mode = ENV['LIQUID_PARSER_MODE'])
puts "-- #{env_mode.upcase} ERROR MODE"
mode = env_mode.to_sym
end
diff --git a/test/unit/condition_unit_test.rb b/test/unit/condition_unit_test.rb
index 69f6b90..8d4e02f 100644
--- a/test/unit/condition_unit_test.rb
+++ b/test/unit/condition_unit_test.rb
@@ -26,9 +26,9 @@ class ConditionUnitTest < Minitest::Test
assert_evaluates_true 1, '<=', 1
# negative numbers
assert_evaluates_true 1, '>', -1
- assert_evaluates_true -1, '<', 1
+ assert_evaluates_true(-1, '<', 1)
assert_evaluates_true 1.0, '>', -1.0
- assert_evaluates_true -1.0, '<', 1.0
+ assert_evaluates_true(-1.0, '<', 1.0)
end
def test_default_operators_evalute_false
diff --git a/test/unit/context_unit_test.rb b/test/unit/context_unit_test.rb
index fe790cf..3b460d7 100644
--- a/test/unit/context_unit_test.rb
+++ b/test/unit/context_unit_test.rb
@@ -85,7 +85,7 @@ class ContextUnitTest < Minitest::Test
@context['date'] = Date.today
assert_equal Date.today, @context['date']
- now = DateTime.now
+ now = Time.now
@context['datetime'] = now
assert_equal now, @context['datetime']
@@ -405,7 +405,11 @@ class ContextUnitTest < Minitest::Test
end
def test_lambda_is_called_once
- @context['callcount'] = proc { @global ||= 0; @global += 1; @global.to_s }
+ @context['callcount'] = proc {
+ @global ||= 0
+ @global += 1
+ @global.to_s
+ }
assert_equal '1', @context['callcount']
assert_equal '1', @context['callcount']
@@ -415,7 +419,11 @@ class ContextUnitTest < Minitest::Test
end
def test_nested_lambda_is_called_once
- @context['callcount'] = { "lambda" => proc { @global ||= 0; @global += 1; @global.to_s } }
+ @context['callcount'] = { "lambda" => proc {
+ @global ||= 0
+ @global += 1
+ @global.to_s
+ } }
assert_equal '1', @context['callcount.lambda']
assert_equal '1', @context['callcount.lambda']
@@ -425,7 +433,11 @@ class ContextUnitTest < Minitest::Test
end
def test_lambda_in_array_is_called_once
- @context['callcount'] = [1, 2, proc { @global ||= 0; @global += 1; @global.to_s }, 4, 5]
+ @context['callcount'] = [1, 2, proc {
+ @global ||= 0
+ @global += 1
+ @global.to_s
+ }, 4, 5]
assert_equal '1', @context['callcount[2]']
assert_equal '1', @context['callcount[2]']
diff --git a/test/unit/tokenizer_unit_test.rb b/test/unit/tokenizer_unit_test.rb
index d094aa1..44342d6 100644
--- a/test/unit/tokenizer_unit_test.rb
+++ b/test/unit/tokenizer_unit_test.rb
@@ -35,7 +35,7 @@ class TokenizerTest < Minitest::Test
def tokenize(source)
tokenizer = Liquid::Tokenizer.new(source)
tokens = []
- while t = tokenizer.shift
+ while (t = tokenizer.shift)
tokens << t
end
tokens
From f4d134cd5cc920945e47acfcfe446492fc93bd3a Mon Sep 17 00:00:00 2001
From: Mike Angell <53470248+shopmike@users.noreply.github.com>
Date: Fri, 20 Sep 2019 02:28:43 +1000
Subject: [PATCH 72/74] Remove jruby and truffleruby testing (#1167)
---
.travis.yml | 4 ----
1 file changed, 4 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index b6a7db0..f9c8c7f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,8 +7,6 @@ rvm:
- &latest_ruby 2.6
- 2.7
- ruby-head
- - jruby-head
- - truffleruby
matrix:
include:
@@ -17,8 +15,6 @@ matrix:
name: Profiling Memory Usage
allow_failures:
- rvm: ruby-head
- - rvm: jruby-head
- - rvm: truffleruby
branches:
only:
From 0db9c56f348f5325c52b1a86f71d7b9b92092569 Mon Sep 17 00:00:00 2001
From: Mike Angell <53470248+shopmike@users.noreply.github.com>
Date: Thu, 26 Sep 2019 00:18:30 +1000
Subject: [PATCH 73/74] Disable rendering of tag based on register (#1162)
* Disable rendering of tag based on register
* Improvements to disable tag
* Resolve disbale tag tests
* Test disable_tags register
* disabled_tags is now always avaiable
* Allow multiple tags to be disabled at once
* Move disabled check to block_body
* Code improvements
* Remove redundant nil check
* Improve disabled tag error output
* Improve disable tag API
* Code improvements
* Switch disabled? to not mutate output
* Fix array handling shortcut in disable_tags
---
lib/liquid.rb | 2 ++
lib/liquid/block_body.rb | 13 ++++++-
lib/liquid/locales/en.yml | 2 ++
lib/liquid/register.rb | 6 ++++
lib/liquid/registers/disabled_tags.rb | 32 +++++++++++++++++
lib/liquid/tag.rb | 20 +++++++++++
lib/liquid/tags/render.rb | 6 ++++
lib/liquid/template.rb | 18 +++++++++-
lib/liquid/variable.rb | 8 +++++
.../registers/disabled_tags_test.rb | 27 ++++++++++++++
test/integration/tags/render_tag_test.rb | 29 +++++++++++----
.../unit/registers/disabled_tags_unit_test.rb | 36 +++++++++++++++++++
12 files changed, 191 insertions(+), 8 deletions(-)
create mode 100644 lib/liquid/register.rb
create mode 100644 lib/liquid/registers/disabled_tags.rb
create mode 100644 test/integration/registers/disabled_tags_test.rb
create mode 100644 test/unit/registers/disabled_tags_unit_test.rb
diff --git a/lib/liquid.rb b/lib/liquid.rb
index d102530..cfaccee 100644
--- a/lib/liquid.rb
+++ b/lib/liquid.rb
@@ -78,8 +78,10 @@ require 'liquid/tokenizer'
require 'liquid/parse_context'
require 'liquid/partial_cache'
require 'liquid/usage'
+require 'liquid/register'
require 'liquid/static_registers'
# Load all the tags of the standard library
#
Dir["#{__dir__}/liquid/tags/*.rb"].each { |f| require f }
+Dir["#{__dir__}/liquid/registers/*.rb"].each { |f| require f }
diff --git a/lib/liquid/block_body.rb b/lib/liquid/block_body.rb
index 9400e38..c543d82 100644
--- a/lib/liquid/block_body.rb
+++ b/lib/liquid/block_body.rb
@@ -154,7 +154,13 @@ module Liquid
private
def render_node(context, output, node)
- node.render_to_output_buffer(context, output)
+ if node.disabled?(context)
+ output << node.disabled_error_message
+ return
+ end
+ disable_tags(context, node.disabled_tags) do
+ node.render_to_output_buffer(context, output)
+ end
rescue UndefinedVariable, UndefinedDropMethod, UndefinedFilter => e
context.handle_error(e, node.line_number)
rescue ::StandardError => e
@@ -162,6 +168,11 @@ module Liquid
output << context.handle_error(e, line_number)
end
+ def disable_tags(context, tags, &block)
+ return yield if tags.empty?
+ context.registers['disabled_tags'].disable(tags, &block)
+ end
+
def raise_if_resource_limits_reached(context, length)
context.resource_limits.render_length += length
return unless context.resource_limits.reached?
diff --git a/lib/liquid/locales/en.yml b/lib/liquid/locales/en.yml
index c0a9aff..a26320b 100644
--- a/lib/liquid/locales/en.yml
+++ b/lib/liquid/locales/en.yml
@@ -25,3 +25,5 @@
render: "Syntax error in tag 'render' - Template name must be a quoted string"
argument:
include: "Argument error in tag 'include' - Illegal template name"
+ disabled:
+ tag: "usage is not allowed in this context"
diff --git a/lib/liquid/register.rb b/lib/liquid/register.rb
new file mode 100644
index 0000000..92d0226
--- /dev/null
+++ b/lib/liquid/register.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+module Liquid
+ class Register
+ end
+end
diff --git a/lib/liquid/registers/disabled_tags.rb b/lib/liquid/registers/disabled_tags.rb
new file mode 100644
index 0000000..79b6472
--- /dev/null
+++ b/lib/liquid/registers/disabled_tags.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+module Liquid
+ class DisabledTags < Register
+ def initialize
+ @disabled_tags = {}
+ end
+
+ def disabled?(tag)
+ @disabled_tags.key?(tag) && @disabled_tags[tag] > 0
+ end
+
+ def disable(tags)
+ tags.each(&method(:increment))
+ yield
+ ensure
+ tags.each(&method(:decrement))
+ end
+
+ private
+
+ def increment(tag)
+ @disabled_tags[tag] ||= 0
+ @disabled_tags[tag] += 1
+ end
+
+ def decrement(tag)
+ @disabled_tags[tag] -= 1
+ end
+ end
+
+ Template.add_register('disabled_tags', DisabledTags.new)
+end
diff --git a/lib/liquid/tag.rb b/lib/liquid/tag.rb
index 1460639..832e32c 100644
--- a/lib/liquid/tag.rb
+++ b/lib/liquid/tag.rb
@@ -13,7 +13,15 @@ module Liquid
tag
end
+ def disable_tags(*tags)
+ disabled_tags.push(*tags)
+ end
+
private :new
+
+ def disabled_tags
+ @disabled_tags ||= []
+ end
end
def initialize(tag_name, markup, parse_context)
@@ -38,6 +46,14 @@ module Liquid
''
end
+ def disabled?(context)
+ context.registers['disabled_tags'].disabled?(tag_name)
+ end
+
+ def disabled_error_message
+ "#{tag_name} #{options[:locale].t('errors.disabled.tag')}"
+ end
+
# For backwards compatibility with custom tags. In a future release, the semantics
# of the `render_to_output_buffer` method will become the default and the `render`
# method will be removed.
@@ -49,5 +65,9 @@ module Liquid
def blank?
false
end
+
+ def disabled_tags
+ self.class.disabled_tags
+ end
end
end
diff --git a/lib/liquid/tags/render.rb b/lib/liquid/tags/render.rb
index e6c6223..1403b58 100644
--- a/lib/liquid/tags/render.rb
+++ b/lib/liquid/tags/render.rb
@@ -4,6 +4,8 @@ module Liquid
class Render < Tag
SYNTAX = /(#{QuotedString})#{QuotedFragment}*/o
+ disable_tags "include"
+
attr_reader :template_name_expr, :attributes
def initialize(tag_name, markup, options)
@@ -22,6 +24,10 @@ module Liquid
end
def render_to_output_buffer(context, output)
+ render_tag(context, output)
+ end
+
+ def render_tag(context, output)
# Though we evaluate this here we will only ever parse it as a string literal.
template_name = context.evaluate(@template_name_expr)
raise ArgumentError, options[:locale].t("errors.argument.include") unless template_name
diff --git a/lib/liquid/template.rb b/lib/liquid/template.rb
index e77ba8a..2f0bed4 100644
--- a/lib/liquid/template.rb
+++ b/lib/liquid/template.rb
@@ -92,6 +92,14 @@ module Liquid
@tags ||= TagRegistry.new
end
+ def add_register(name, klass)
+ registers[name.to_s] = klass
+ end
+
+ def registers
+ @registers ||= {}
+ end
+
def error_mode
@error_mode ||= :lax
end
@@ -191,18 +199,26 @@ module Liquid
output = nil
+ context_register = context.registers.is_a?(StaticRegisters) ? context.registers.static : context.registers
+
case args.last
when Hash
options = args.pop
output = options[:output] if options[:output]
- registers.merge!(options[:registers]) if options[:registers].is_a?(Hash)
+ options[:registers]&.each do |key, register|
+ context_register[key] = register
+ end
apply_options_to_context(context, options)
when Module, Array
context.add_filters(args.pop)
end
+ Template.registers.each do |key, register|
+ context_register[key] = register
+ end
+
# Retrying a render resets resource usage
context.resource_limits.reset
diff --git a/lib/liquid/variable.rb b/lib/liquid/variable.rb
index 265748d..5b686e2 100644
--- a/lib/liquid/variable.rb
+++ b/lib/liquid/variable.rb
@@ -104,6 +104,14 @@ module Liquid
output
end
+ def disabled?(_context)
+ false
+ end
+
+ def disabled_tags
+ []
+ end
+
private
def parse_filter_expressions(filter_name, unparsed_args)
diff --git a/test/integration/registers/disabled_tags_test.rb b/test/integration/registers/disabled_tags_test.rb
new file mode 100644
index 0000000..1fb2458
--- /dev/null
+++ b/test/integration/registers/disabled_tags_test.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'test_helper'
+
+class DisabledTagsTest < Minitest::Test
+ include Liquid
+
+ class DisableRaw < Block
+ disable_tags "raw"
+ end
+
+ class DisableRawEcho < Block
+ disable_tags "raw", "echo"
+ end
+
+ def test_disables_raw
+ with_custom_tag('disable', DisableRaw) do
+ assert_template_result 'raw usage is not allowed in this contextfoo', '{% disable %}{% raw %}Foobar{% endraw %}{% echo "foo" %}{% enddisable %}'
+ end
+ end
+
+ def test_disables_echo_and_raw
+ with_custom_tag('disable', DisableRawEcho) do
+ assert_template_result 'raw usage is not allowed in this contextecho usage is not allowed in this context', '{% disable %}{% raw %}Foobar{% endraw %}{% echo "foo" %}{% enddisable %}'
+ end
+ end
+end
diff --git a/test/integration/tags/render_tag_test.rb b/test/integration/tags/render_tag_test.rb
index 154783a..87373a2 100644
--- a/test/integration/tags/render_tag_test.rb
+++ b/test/integration/tags/render_tag_test.rb
@@ -89,14 +89,12 @@ class RenderTagTest < Minitest::Test
end
end
- def test_includes_and_renders_count_towards_the_same_recursion_limit
+ def test_sub_contexts_count_towards_the_same_recursion_limit
Liquid::Template.file_system = StubFileSystem.new(
- 'loop_render' => '{% render "loop_include" %}',
- 'loop_include' => '{% include "loop_render" %}'
+ 'loop_render' => '{% render "loop_render" %}',
)
-
- assert_raises Liquid::StackLevelError do
- Template.parse('{% render "loop_include" %}').render!
+ assert_raises Liquid::StackLevelError do
+ Template.parse('{% render "loop_render" %}').render!
end
end
@@ -148,4 +146,23 @@ class RenderTagTest < Minitest::Test
Liquid::Template.file_system = StubFileSystem.new('decr' => '{% decrement %}')
assert_template_result '-1-2-1', '{% decrement %}{% decrement %}{% render "decr" %}'
end
+
+ def test_includes_will_not_render_inside_render_tag
+ Liquid::Template.file_system = StubFileSystem.new(
+ 'foo' => 'bar',
+ 'test_include' => '{% include "foo" %}'
+ )
+
+ assert_template_result 'include usage is not allowed in this context', '{% render "test_include" %}'
+ end
+
+ def test_includes_will_not_render_inside_nested_sibling_tags
+ Liquid::Template.file_system = StubFileSystem.new(
+ 'foo' => 'bar',
+ 'nested_render_with_sibling_include' => '{% render "test_include" %}{% include "foo" %}',
+ 'test_include' => '{% include "foo" %}'
+ )
+
+ assert_template_result 'include usage is not allowed in this contextinclude usage is not allowed in this context', '{% render "nested_render_with_sibling_include" %}'
+ end
end
diff --git a/test/unit/registers/disabled_tags_unit_test.rb b/test/unit/registers/disabled_tags_unit_test.rb
new file mode 100644
index 0000000..90ac016
--- /dev/null
+++ b/test/unit/registers/disabled_tags_unit_test.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'test_helper'
+
+class DisabledTagsUnitTest < Minitest::Test
+ include Liquid
+
+ def test_disables_tag_specified
+ register = DisabledTags.new
+ register.disable(%w(foo bar)) do
+ assert_equal true, register.disabled?("foo")
+ assert_equal true, register.disabled?("bar")
+ assert_equal false, register.disabled?("unknown")
+ end
+ end
+
+ def test_disables_nested_tags
+ register = DisabledTags.new
+ register.disable(["foo"]) do
+ register.disable(["foo"]) do
+ assert_equal true, register.disabled?("foo")
+ assert_equal false, register.disabled?("bar")
+ end
+ register.disable(["bar"]) do
+ assert_equal true, register.disabled?("foo")
+ assert_equal true, register.disabled?("bar")
+ register.disable(["foo"]) do
+ assert_equal true, register.disabled?("foo")
+ assert_equal true, register.disabled?("bar")
+ end
+ end
+ assert_equal true, register.disabled?("foo")
+ assert_equal false, register.disabled?("bar")
+ end
+ end
+end
From 1aa7d3d2bab67defbf61b0f3d014a610b233e506 Mon Sep 17 00:00:00 2001
From: Mike Angell <53470248+shopmike@users.noreply.github.com>
Date: Fri, 27 Sep 2019 04:32:24 +1000
Subject: [PATCH 74/74] Change registers to by symbols (#1178)
---
lib/liquid/block_body.rb | 2 +-
lib/liquid/registers/disabled_tags.rb | 2 +-
lib/liquid/tag.rb | 2 +-
lib/liquid/template.rb | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/lib/liquid/block_body.rb b/lib/liquid/block_body.rb
index c543d82..45be8b8 100644
--- a/lib/liquid/block_body.rb
+++ b/lib/liquid/block_body.rb
@@ -170,7 +170,7 @@ module Liquid
def disable_tags(context, tags, &block)
return yield if tags.empty?
- context.registers['disabled_tags'].disable(tags, &block)
+ context.registers[:disabled_tags].disable(tags, &block)
end
def raise_if_resource_limits_reached(context, length)
diff --git a/lib/liquid/registers/disabled_tags.rb b/lib/liquid/registers/disabled_tags.rb
index 79b6472..b1cd3bd 100644
--- a/lib/liquid/registers/disabled_tags.rb
+++ b/lib/liquid/registers/disabled_tags.rb
@@ -28,5 +28,5 @@ module Liquid
end
end
- Template.add_register('disabled_tags', DisabledTags.new)
+ Template.add_register(:disabled_tags, DisabledTags.new)
end
diff --git a/lib/liquid/tag.rb b/lib/liquid/tag.rb
index 832e32c..ffd2286 100644
--- a/lib/liquid/tag.rb
+++ b/lib/liquid/tag.rb
@@ -47,7 +47,7 @@ module Liquid
end
def disabled?(context)
- context.registers['disabled_tags'].disabled?(tag_name)
+ context.registers[:disabled_tags].disabled?(tag_name)
end
def disabled_error_message
diff --git a/lib/liquid/template.rb b/lib/liquid/template.rb
index 2f0bed4..e23df24 100644
--- a/lib/liquid/template.rb
+++ b/lib/liquid/template.rb
@@ -93,7 +93,7 @@ module Liquid
end
def add_register(name, klass)
- registers[name.to_s] = klass
+ registers[name.to_sym] = klass
end
def registers