liquid 4.0.0 → 5.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/History.md +235 -2
- data/README.md +58 -8
- data/lib/liquid/block.rb +51 -20
- data/lib/liquid/block_body.rb +216 -82
- data/lib/liquid/condition.rb +83 -32
- data/lib/liquid/const.rb +8 -0
- data/lib/liquid/context.rb +130 -59
- data/lib/liquid/deprecations.rb +22 -0
- data/lib/liquid/document.rb +47 -9
- data/lib/liquid/drop.rb +8 -2
- data/lib/liquid/environment.rb +159 -0
- data/lib/liquid/errors.rb +23 -20
- data/lib/liquid/expression.rb +114 -31
- data/lib/liquid/extensions.rb +8 -0
- data/lib/liquid/file_system.rb +6 -4
- data/lib/liquid/forloop_drop.rb +51 -4
- data/lib/liquid/i18n.rb +5 -3
- data/lib/liquid/interrupts.rb +3 -1
- data/lib/liquid/lexer.rb +165 -39
- data/lib/liquid/locales/en.yml +16 -6
- data/lib/liquid/parse_context.rb +62 -7
- data/lib/liquid/parse_tree_visitor.rb +42 -0
- data/lib/liquid/parser.rb +31 -19
- data/lib/liquid/parser_switching.rb +42 -3
- data/lib/liquid/partial_cache.rb +33 -0
- data/lib/liquid/profiler/hooks.rb +26 -14
- data/lib/liquid/profiler.rb +67 -86
- data/lib/liquid/range_lookup.rb +26 -6
- data/lib/liquid/registers.rb +51 -0
- data/lib/liquid/resource_limits.rb +47 -8
- data/lib/liquid/snippet_drop.rb +22 -0
- data/lib/liquid/standardfilters.rb +813 -137
- data/lib/liquid/strainer_template.rb +62 -0
- data/lib/liquid/tablerowloop_drop.rb +64 -5
- data/lib/liquid/tag/disableable.rb +22 -0
- data/lib/liquid/tag/disabler.rb +13 -0
- data/lib/liquid/tag.rb +42 -6
- data/lib/liquid/tags/assign.rb +46 -18
- data/lib/liquid/tags/break.rb +15 -4
- data/lib/liquid/tags/capture.rb +26 -18
- data/lib/liquid/tags/case.rb +108 -32
- data/lib/liquid/tags/comment.rb +76 -4
- data/lib/liquid/tags/continue.rb +15 -13
- data/lib/liquid/tags/cycle.rb +117 -34
- data/lib/liquid/tags/decrement.rb +30 -23
- data/lib/liquid/tags/doc.rb +81 -0
- data/lib/liquid/tags/echo.rb +39 -0
- data/lib/liquid/tags/for.rb +109 -96
- data/lib/liquid/tags/if.rb +72 -41
- data/lib/liquid/tags/ifchanged.rb +10 -11
- data/lib/liquid/tags/include.rb +89 -63
- data/lib/liquid/tags/increment.rb +31 -20
- data/lib/liquid/tags/inline_comment.rb +28 -0
- data/lib/liquid/tags/raw.rb +25 -13
- data/lib/liquid/tags/render.rb +151 -0
- data/lib/liquid/tags/snippet.rb +45 -0
- data/lib/liquid/tags/table_row.rb +104 -21
- data/lib/liquid/tags/unless.rb +37 -20
- data/lib/liquid/tags.rb +51 -0
- data/lib/liquid/template.rb +90 -106
- data/lib/liquid/template_factory.rb +9 -0
- data/lib/liquid/tokenizer.rb +143 -13
- data/lib/liquid/usage.rb +8 -0
- data/lib/liquid/utils.rb +114 -5
- data/lib/liquid/variable.rb +119 -45
- data/lib/liquid/variable_lookup.rb +35 -13
- data/lib/liquid/version.rb +3 -1
- data/lib/liquid.rb +31 -18
- metadata +56 -107
- data/lib/liquid/strainer.rb +0 -66
- data/test/fixtures/en_locale.yml +0 -9
- data/test/integration/assign_test.rb +0 -48
- data/test/integration/blank_test.rb +0 -106
- data/test/integration/capture_test.rb +0 -50
- data/test/integration/context_test.rb +0 -32
- data/test/integration/document_test.rb +0 -19
- data/test/integration/drop_test.rb +0 -273
- data/test/integration/error_handling_test.rb +0 -260
- data/test/integration/filter_test.rb +0 -178
- data/test/integration/hash_ordering_test.rb +0 -23
- data/test/integration/output_test.rb +0 -123
- data/test/integration/parsing_quirks_test.rb +0 -118
- data/test/integration/render_profiling_test.rb +0 -154
- data/test/integration/security_test.rb +0 -66
- data/test/integration/standard_filter_test.rb +0 -535
- data/test/integration/tags/break_tag_test.rb +0 -15
- data/test/integration/tags/continue_tag_test.rb +0 -15
- data/test/integration/tags/for_tag_test.rb +0 -410
- data/test/integration/tags/if_else_tag_test.rb +0 -188
- data/test/integration/tags/include_tag_test.rb +0 -238
- data/test/integration/tags/increment_tag_test.rb +0 -23
- data/test/integration/tags/raw_tag_test.rb +0 -31
- data/test/integration/tags/standard_tag_test.rb +0 -296
- data/test/integration/tags/statements_test.rb +0 -111
- data/test/integration/tags/table_row_test.rb +0 -64
- data/test/integration/tags/unless_else_tag_test.rb +0 -26
- data/test/integration/template_test.rb +0 -323
- data/test/integration/trim_mode_test.rb +0 -525
- data/test/integration/variable_test.rb +0 -92
- data/test/test_helper.rb +0 -117
- data/test/unit/block_unit_test.rb +0 -58
- data/test/unit/condition_unit_test.rb +0 -158
- data/test/unit/context_unit_test.rb +0 -483
- data/test/unit/file_system_unit_test.rb +0 -35
- data/test/unit/i18n_unit_test.rb +0 -37
- data/test/unit/lexer_unit_test.rb +0 -51
- data/test/unit/parser_unit_test.rb +0 -82
- data/test/unit/regexp_unit_test.rb +0 -44
- data/test/unit/strainer_unit_test.rb +0 -148
- data/test/unit/tag_unit_test.rb +0 -21
- data/test/unit/tags/case_tag_unit_test.rb +0 -10
- data/test/unit/tags/for_tag_unit_test.rb +0 -13
- data/test/unit/tags/if_tag_unit_test.rb +0 -8
- data/test/unit/template_unit_test.rb +0 -78
- data/test/unit/tokenizer_unit_test.rb +0 -55
- data/test/unit/variable_unit_test.rb +0 -162
|
@@ -1,54 +1,137 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Liquid
|
|
4
|
+
# @liquid_public_docs
|
|
5
|
+
# @liquid_type tag
|
|
6
|
+
# @liquid_category iteration
|
|
7
|
+
# @liquid_name tablerow
|
|
8
|
+
# @liquid_summary
|
|
9
|
+
# Generates HTML table rows for every item in an array.
|
|
10
|
+
# @liquid_description
|
|
11
|
+
# The `tablerow` tag must be wrapped in HTML `<table>` and `</table>` tags.
|
|
12
|
+
#
|
|
13
|
+
# > Tip:
|
|
14
|
+
# > Every `tablerow` loop has an associated [`tablerowloop` object](/docs/api/liquid/objects/tablerowloop) with information about the loop.
|
|
15
|
+
# @liquid_syntax
|
|
16
|
+
# {% tablerow variable in array %}
|
|
17
|
+
# expression
|
|
18
|
+
# {% endtablerow %}
|
|
19
|
+
# @liquid_syntax_keyword variable The current item in the array.
|
|
20
|
+
# @liquid_syntax_keyword array The array to iterate over.
|
|
21
|
+
# @liquid_syntax_keyword expression The expression to render.
|
|
22
|
+
# @liquid_optional_param cols: [number] The number of columns that the table should have.
|
|
23
|
+
# @liquid_optional_param limit: [number] The number of iterations to perform.
|
|
24
|
+
# @liquid_optional_param offset: [number] The 1-based index to start iterating at.
|
|
25
|
+
# @liquid_optional_param range [untyped] A custom numeric range to iterate over.
|
|
2
26
|
class TableRow < Block
|
|
3
27
|
Syntax = /(\w+)\s+in\s+(#{QuotedFragment}+)/o
|
|
28
|
+
ALLOWED_ATTRIBUTES = ['cols', 'limit', 'offset', 'range'].freeze
|
|
29
|
+
|
|
30
|
+
attr_reader :variable_name, :collection_name, :attributes
|
|
4
31
|
|
|
5
32
|
def initialize(tag_name, markup, options)
|
|
6
33
|
super
|
|
34
|
+
parse_with_selected_parser(markup)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def rigid_parse(markup)
|
|
38
|
+
p = @parse_context.new_parser(markup)
|
|
39
|
+
|
|
40
|
+
@variable_name = p.consume(:id)
|
|
41
|
+
|
|
42
|
+
unless p.id?("in")
|
|
43
|
+
raise SyntaxError, options[:locale].t("errors.syntax.for_invalid_in")
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
@collection_name = safe_parse_expression(p)
|
|
47
|
+
|
|
48
|
+
p.consume?(:comma)
|
|
49
|
+
|
|
50
|
+
@attributes = {}
|
|
51
|
+
while p.look(:id)
|
|
52
|
+
key = p.consume
|
|
53
|
+
unless ALLOWED_ATTRIBUTES.include?(key)
|
|
54
|
+
raise SyntaxError, options[:locale].t("errors.syntax.table_row_invalid_attribute", attribute: key)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
p.consume(:colon)
|
|
58
|
+
@attributes[key] = safe_parse_expression(p)
|
|
59
|
+
p.consume?(:comma)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
p.consume(:end_of_string)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def strict_parse(markup)
|
|
66
|
+
lax_parse(markup)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def lax_parse(markup)
|
|
7
70
|
if markup =~ Syntax
|
|
8
|
-
@variable_name
|
|
9
|
-
@collection_name =
|
|
10
|
-
@attributes
|
|
71
|
+
@variable_name = Regexp.last_match(1)
|
|
72
|
+
@collection_name = parse_expression(Regexp.last_match(2))
|
|
73
|
+
@attributes = {}
|
|
11
74
|
markup.scan(TagAttributes) do |key, value|
|
|
12
|
-
@attributes[key] =
|
|
75
|
+
@attributes[key] = parse_expression(value)
|
|
13
76
|
end
|
|
14
77
|
else
|
|
15
|
-
raise SyntaxError
|
|
78
|
+
raise SyntaxError, options[:locale].t("errors.syntax.table_row")
|
|
16
79
|
end
|
|
17
80
|
end
|
|
18
81
|
|
|
19
|
-
def
|
|
20
|
-
collection = context.evaluate(@collection_name)
|
|
82
|
+
def render_to_output_buffer(context, output)
|
|
83
|
+
(collection = context.evaluate(@collection_name)) || (return '')
|
|
21
84
|
|
|
22
|
-
from = @attributes.key?('offset'
|
|
23
|
-
to = @attributes.key?('limit'
|
|
85
|
+
from = @attributes.key?('offset') ? to_integer(context.evaluate(@attributes['offset'])) : 0
|
|
86
|
+
to = @attributes.key?('limit') ? from + to_integer(context.evaluate(@attributes['limit'])) : nil
|
|
24
87
|
|
|
25
88
|
collection = Utils.slice_collection(collection, from, to)
|
|
89
|
+
length = collection.length
|
|
26
90
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
cols = context.evaluate(@attributes['cols'.freeze]).to_i
|
|
91
|
+
cols = @attributes.key?('cols') ? to_integer(context.evaluate(@attributes['cols'])) : length
|
|
30
92
|
|
|
31
|
-
|
|
93
|
+
output << "<tr class=\"row1\">\n"
|
|
32
94
|
context.stack do
|
|
33
95
|
tablerowloop = Liquid::TablerowloopDrop.new(length, cols)
|
|
34
|
-
context['tablerowloop'
|
|
96
|
+
context['tablerowloop'] = tablerowloop
|
|
35
97
|
|
|
36
|
-
collection.
|
|
98
|
+
collection.each do |item|
|
|
37
99
|
context[@variable_name] = item
|
|
38
100
|
|
|
39
|
-
|
|
101
|
+
output << "<td class=\"col#{tablerowloop.col}\">"
|
|
102
|
+
super
|
|
103
|
+
output << '</td>'
|
|
104
|
+
|
|
105
|
+
# Handle any interrupts if they exist.
|
|
106
|
+
if context.interrupt?
|
|
107
|
+
interrupt = context.pop_interrupt
|
|
108
|
+
break if interrupt.is_a?(BreakInterrupt)
|
|
109
|
+
end
|
|
40
110
|
|
|
41
111
|
if tablerowloop.col_last && !tablerowloop.last
|
|
42
|
-
|
|
112
|
+
output << "</tr>\n<tr class=\"row#{tablerowloop.row + 1}\">"
|
|
43
113
|
end
|
|
44
114
|
|
|
45
115
|
tablerowloop.send(:increment!)
|
|
46
116
|
end
|
|
47
117
|
end
|
|
48
|
-
|
|
49
|
-
|
|
118
|
+
|
|
119
|
+
output << "</tr>\n"
|
|
120
|
+
output
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
|
124
|
+
def children
|
|
125
|
+
super + @node.attributes.values + [@node.collection_name]
|
|
126
|
+
end
|
|
50
127
|
end
|
|
51
|
-
end
|
|
52
128
|
|
|
53
|
-
|
|
129
|
+
private
|
|
130
|
+
|
|
131
|
+
def to_integer(value)
|
|
132
|
+
value.to_i
|
|
133
|
+
rescue NoMethodError
|
|
134
|
+
raise Liquid::ArgumentError, "invalid integer"
|
|
135
|
+
end
|
|
136
|
+
end
|
|
54
137
|
end
|
data/lib/liquid/tags/unless.rb
CHANGED
|
@@ -1,30 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require_relative 'if'
|
|
2
4
|
|
|
3
5
|
module Liquid
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
6
|
+
# @liquid_public_docs
|
|
7
|
+
# @liquid_type tag
|
|
8
|
+
# @liquid_category conditional
|
|
9
|
+
# @liquid_name unless
|
|
10
|
+
# @liquid_summary
|
|
11
|
+
# Renders an expression unless a specific condition is `true`.
|
|
12
|
+
# @liquid_description
|
|
13
|
+
# > Tip:
|
|
14
|
+
# > Similar to the [`if` tag](/docs/api/liquid/tags/if), you can use `elsif` to add more conditions to an `unless` tag.
|
|
15
|
+
# @liquid_syntax
|
|
16
|
+
# {% unless condition %}
|
|
17
|
+
# expression
|
|
18
|
+
# {% endunless %}
|
|
19
|
+
# @liquid_syntax_keyword condition The condition to evaluate.
|
|
20
|
+
# @liquid_syntax_keyword expression The expression to render unless the condition is met.
|
|
8
21
|
class Unless < If
|
|
9
|
-
def
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
end
|
|
22
|
+
def render_to_output_buffer(context, output)
|
|
23
|
+
# First condition is interpreted backwards ( if not )
|
|
24
|
+
first_block = @blocks.first
|
|
25
|
+
result = Liquid::Utils.to_liquid_value(
|
|
26
|
+
first_block.evaluate(context),
|
|
27
|
+
)
|
|
16
28
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return block.attachment.render(context)
|
|
21
|
-
end
|
|
22
|
-
end
|
|
29
|
+
unless result
|
|
30
|
+
return first_block.attachment.render_to_output_buffer(context, output)
|
|
31
|
+
end
|
|
23
32
|
|
|
24
|
-
|
|
33
|
+
# After the first condition unless works just like if
|
|
34
|
+
@blocks[1..-1].each do |block|
|
|
35
|
+
result = Liquid::Utils.to_liquid_value(
|
|
36
|
+
block.evaluate(context),
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
if result
|
|
40
|
+
return block.attachment.render_to_output_buffer(context, output)
|
|
41
|
+
end
|
|
25
42
|
end
|
|
43
|
+
|
|
44
|
+
output
|
|
26
45
|
end
|
|
27
46
|
end
|
|
28
|
-
|
|
29
|
-
Template.register_tag('unless'.freeze, Unless)
|
|
30
47
|
end
|
data/lib/liquid/tags.rb
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "tags/table_row"
|
|
4
|
+
require_relative "tags/echo"
|
|
5
|
+
require_relative "tags/if"
|
|
6
|
+
require_relative "tags/break"
|
|
7
|
+
require_relative "tags/inline_comment"
|
|
8
|
+
require_relative "tags/for"
|
|
9
|
+
require_relative "tags/assign"
|
|
10
|
+
require_relative "tags/ifchanged"
|
|
11
|
+
require_relative "tags/case"
|
|
12
|
+
require_relative "tags/include"
|
|
13
|
+
require_relative "tags/continue"
|
|
14
|
+
require_relative "tags/capture"
|
|
15
|
+
require_relative "tags/decrement"
|
|
16
|
+
require_relative "tags/unless"
|
|
17
|
+
require_relative "tags/increment"
|
|
18
|
+
require_relative "tags/comment"
|
|
19
|
+
require_relative "tags/raw"
|
|
20
|
+
require_relative "tags/render"
|
|
21
|
+
require_relative "tags/cycle"
|
|
22
|
+
require_relative "tags/doc"
|
|
23
|
+
require_relative "tags/snippet"
|
|
24
|
+
|
|
25
|
+
module Liquid
|
|
26
|
+
module Tags
|
|
27
|
+
STANDARD_TAGS = {
|
|
28
|
+
'cycle' => Cycle,
|
|
29
|
+
'render' => Render,
|
|
30
|
+
'raw' => Raw,
|
|
31
|
+
'comment' => Comment,
|
|
32
|
+
'increment' => Increment,
|
|
33
|
+
'unless' => Unless,
|
|
34
|
+
'decrement' => Decrement,
|
|
35
|
+
'capture' => Capture,
|
|
36
|
+
'continue' => Continue,
|
|
37
|
+
'include' => Include,
|
|
38
|
+
'case' => Case,
|
|
39
|
+
'ifchanged' => Ifchanged,
|
|
40
|
+
'assign' => Assign,
|
|
41
|
+
'for' => For,
|
|
42
|
+
'#' => InlineComment,
|
|
43
|
+
'break' => Break,
|
|
44
|
+
'if' => If,
|
|
45
|
+
'echo' => Echo,
|
|
46
|
+
'tablerow' => TableRow,
|
|
47
|
+
'doc' => Doc,
|
|
48
|
+
'snippet' => Snippet,
|
|
49
|
+
}.freeze
|
|
50
|
+
end
|
|
51
|
+
end
|
data/lib/liquid/template.rb
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Liquid
|
|
2
4
|
# Templates are central to liquid.
|
|
3
|
-
#
|
|
5
|
+
# Interpreting templates is a two step process. First you compile the
|
|
4
6
|
# source code you got. During compile time some extensive error checking is performed.
|
|
5
7
|
# your code should expect to get some SyntaxErrors.
|
|
6
8
|
#
|
|
@@ -13,124 +15,96 @@ module Liquid
|
|
|
13
15
|
# template.render('user_name' => 'bob')
|
|
14
16
|
#
|
|
15
17
|
class Template
|
|
16
|
-
attr_accessor :root
|
|
18
|
+
attr_accessor :root, :name
|
|
17
19
|
attr_reader :resource_limits, :warnings
|
|
18
20
|
|
|
19
|
-
@@file_system = BlankFileSystem.new
|
|
20
|
-
|
|
21
|
-
class TagRegistry
|
|
22
|
-
include Enumerable
|
|
23
|
-
|
|
24
|
-
def initialize
|
|
25
|
-
@tags = {}
|
|
26
|
-
@cache = {}
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def [](tag_name)
|
|
30
|
-
return nil unless @tags.key?(tag_name)
|
|
31
|
-
return @cache[tag_name] if Liquid.cache_classes
|
|
32
|
-
|
|
33
|
-
lookup_class(@tags[tag_name]).tap { |o| @cache[tag_name] = o }
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def []=(tag_name, klass)
|
|
37
|
-
@tags[tag_name] = klass.name
|
|
38
|
-
@cache[tag_name] = klass
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def delete(tag_name)
|
|
42
|
-
@tags.delete(tag_name)
|
|
43
|
-
@cache.delete(tag_name)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def each(&block)
|
|
47
|
-
@tags.each(&block)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
private
|
|
51
|
-
|
|
52
|
-
def lookup_class(name)
|
|
53
|
-
name.split("::").reject(&:empty?).reduce(Object) { |scope, const| scope.const_get(const) }
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
21
|
attr_reader :profiler
|
|
58
22
|
|
|
59
23
|
class << self
|
|
60
24
|
# Sets how strict the parser should be.
|
|
61
25
|
# :lax acts like liquid 2.5 and silently ignores malformed tags in most cases.
|
|
62
26
|
# :warn is the default and will give deprecation warnings when invalid syntax is used.
|
|
63
|
-
# :strict
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
# :error raises an error when tainted output is used
|
|
70
|
-
attr_writer :taint_mode
|
|
27
|
+
# :strict enforces correct syntax for most tags
|
|
28
|
+
# :rigid enforces correct syntax for all tags
|
|
29
|
+
def error_mode=(mode)
|
|
30
|
+
Deprecations.warn("Template.error_mode=", "Environment#error_mode=")
|
|
31
|
+
Environment.default.error_mode = mode
|
|
32
|
+
end
|
|
71
33
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
exception
|
|
34
|
+
def error_mode
|
|
35
|
+
Environment.default.error_mode
|
|
75
36
|
end
|
|
76
37
|
|
|
77
|
-
def
|
|
78
|
-
|
|
38
|
+
def default_exception_renderer=(renderer)
|
|
39
|
+
Deprecations.warn("Template.default_exception_renderer=", "Environment#exception_renderer=")
|
|
40
|
+
Environment.default.exception_renderer = renderer
|
|
79
41
|
end
|
|
80
42
|
|
|
81
|
-
def
|
|
82
|
-
|
|
43
|
+
def default_exception_renderer
|
|
44
|
+
Environment.default.exception_renderer
|
|
83
45
|
end
|
|
84
46
|
|
|
85
|
-
def
|
|
86
|
-
|
|
47
|
+
def file_system=(file_system)
|
|
48
|
+
Deprecations.warn("Template.file_system=", "Environment#file_system=")
|
|
49
|
+
Environment.default.file_system = file_system
|
|
87
50
|
end
|
|
88
51
|
|
|
89
|
-
def
|
|
90
|
-
|
|
52
|
+
def file_system
|
|
53
|
+
Environment.default.file_system
|
|
91
54
|
end
|
|
92
55
|
|
|
93
|
-
def
|
|
94
|
-
|
|
56
|
+
def tags
|
|
57
|
+
Environment.default.tags
|
|
95
58
|
end
|
|
96
59
|
|
|
97
|
-
def
|
|
98
|
-
|
|
60
|
+
def register_tag(name, klass)
|
|
61
|
+
Deprecations.warn("Template.register_tag", "Environment#register_tag")
|
|
62
|
+
Environment.default.register_tag(name, klass)
|
|
99
63
|
end
|
|
100
64
|
|
|
101
65
|
# Pass a module with filter methods which should be available
|
|
102
66
|
# to all liquid views. Good for registering the standard library
|
|
103
67
|
def register_filter(mod)
|
|
104
|
-
|
|
68
|
+
Deprecations.warn("Template.register_filter", "Environment#register_filter")
|
|
69
|
+
Environment.default.register_filter(mod)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private def default_resource_limits=(limits)
|
|
73
|
+
Deprecations.warn("Template.default_resource_limits=", "Environment#default_resource_limits=")
|
|
74
|
+
Environment.default.default_resource_limits = limits
|
|
105
75
|
end
|
|
106
76
|
|
|
107
77
|
def default_resource_limits
|
|
108
|
-
|
|
78
|
+
Environment.default.default_resource_limits
|
|
109
79
|
end
|
|
110
80
|
|
|
111
81
|
# creates a new <tt>Template</tt> object from liquid source code
|
|
112
82
|
# To enable profiling, pass in <tt>profile: true</tt> as an option.
|
|
113
83
|
# See Liquid::Profiler for more information
|
|
114
84
|
def parse(source, options = {})
|
|
115
|
-
|
|
116
|
-
|
|
85
|
+
environment = options[:environment] || Environment.default
|
|
86
|
+
new(environment: environment).parse(source, options)
|
|
117
87
|
end
|
|
118
88
|
end
|
|
119
89
|
|
|
120
|
-
def initialize
|
|
121
|
-
@
|
|
122
|
-
@
|
|
90
|
+
def initialize(environment: Environment.default)
|
|
91
|
+
@environment = environment
|
|
92
|
+
@rethrow_errors = false
|
|
93
|
+
@resource_limits = ResourceLimits.new(environment.default_resource_limits)
|
|
123
94
|
end
|
|
124
95
|
|
|
125
96
|
# Parse source code.
|
|
126
97
|
# Returns self for easy chaining
|
|
127
98
|
def parse(source, options = {})
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
99
|
+
parse_context = configure_options(options)
|
|
100
|
+
source = source.to_s.to_str
|
|
101
|
+
|
|
102
|
+
unless source.valid_encoding?
|
|
103
|
+
raise TemplateEncodingError, parse_context.locale.t("errors.syntax.invalid_template_encoding")
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
tokenizer = parse_context.new_tokenizer(source, start_line_number: @line_numbers && 1)
|
|
107
|
+
@root = Document.parse(tokenizer, parse_context)
|
|
134
108
|
self
|
|
135
109
|
end
|
|
136
110
|
|
|
@@ -165,33 +139,39 @@ module Liquid
|
|
|
165
139
|
# filters and tags and might be useful to integrate liquid more with its host application
|
|
166
140
|
#
|
|
167
141
|
def render(*args)
|
|
168
|
-
return ''
|
|
142
|
+
return '' if @root.nil?
|
|
169
143
|
|
|
170
144
|
context = case args.first
|
|
171
145
|
when Liquid::Context
|
|
172
146
|
c = args.shift
|
|
173
147
|
|
|
174
148
|
if @rethrow_errors
|
|
175
|
-
c.exception_renderer =
|
|
149
|
+
c.exception_renderer = Liquid::RAISE_EXCEPTION_LAMBDA
|
|
176
150
|
end
|
|
177
151
|
|
|
178
152
|
c
|
|
179
153
|
when Liquid::Drop
|
|
180
|
-
drop
|
|
181
|
-
drop.context = Context.new([drop, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits)
|
|
154
|
+
drop = args.shift
|
|
155
|
+
drop.context = Context.new([drop, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits, {}, @environment)
|
|
182
156
|
when Hash
|
|
183
|
-
Context.new([args.shift, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits)
|
|
157
|
+
Context.new([args.shift, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits, {}, @environment)
|
|
184
158
|
when nil
|
|
185
|
-
Context.new(assigns, instance_assigns, registers, @rethrow_errors, @resource_limits)
|
|
159
|
+
Context.new(assigns, instance_assigns, registers, @rethrow_errors, @resource_limits, {}, @environment)
|
|
186
160
|
else
|
|
187
161
|
raise ArgumentError, "Expected Hash or Liquid::Context as parameter"
|
|
188
162
|
end
|
|
189
163
|
|
|
164
|
+
output = nil
|
|
165
|
+
|
|
190
166
|
case args.last
|
|
191
167
|
when Hash
|
|
192
168
|
options = args.pop
|
|
169
|
+
output = options[:output] if options[:output]
|
|
170
|
+
static_registers = context.registers.static
|
|
193
171
|
|
|
194
|
-
|
|
172
|
+
options[:registers]&.each do |key, register|
|
|
173
|
+
static_registers[key] = register
|
|
174
|
+
end
|
|
195
175
|
|
|
196
176
|
apply_options_to_context(context, options)
|
|
197
177
|
when Module, Array
|
|
@@ -201,13 +181,15 @@ module Liquid
|
|
|
201
181
|
# Retrying a render resets resource usage
|
|
202
182
|
context.resource_limits.reset
|
|
203
183
|
|
|
184
|
+
if @profiling && context.profiler.nil?
|
|
185
|
+
@profiler = context.profiler = Liquid::Profiler.new
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
context.template_name ||= name
|
|
189
|
+
|
|
204
190
|
begin
|
|
205
191
|
# render the nodelist.
|
|
206
|
-
|
|
207
|
-
result = with_profiling(context) do
|
|
208
|
-
@root.render(context)
|
|
209
|
-
end
|
|
210
|
-
result.respond_to?(:join) ? result.join : result
|
|
192
|
+
@root.render_to_output_buffer(context, output || +'')
|
|
211
193
|
rescue Liquid::MemoryError => e
|
|
212
194
|
context.handle_error(e)
|
|
213
195
|
ensure
|
|
@@ -220,35 +202,37 @@ module Liquid
|
|
|
220
202
|
render(*args)
|
|
221
203
|
end
|
|
222
204
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
def tokenize(source)
|
|
226
|
-
Tokenizer.new(source, @line_numbers)
|
|
205
|
+
def render_to_output_buffer(context, output)
|
|
206
|
+
render(context, output: output)
|
|
227
207
|
end
|
|
228
208
|
|
|
229
|
-
|
|
230
|
-
if @profiling && !context.partial
|
|
231
|
-
raise "Profiler not loaded, require 'liquid/profiler' first" unless defined?(Liquid::Profiler)
|
|
209
|
+
private
|
|
232
210
|
|
|
233
|
-
|
|
234
|
-
|
|
211
|
+
def configure_options(options)
|
|
212
|
+
if (profiling = options[:profile])
|
|
213
|
+
raise "Profiler not loaded, require 'liquid/profiler' first" unless defined?(Liquid::Profiler)
|
|
214
|
+
end
|
|
235
215
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
216
|
+
@options = options
|
|
217
|
+
@profiling = profiling
|
|
218
|
+
@line_numbers = options[:line_numbers] || @profiling
|
|
219
|
+
parse_context = if options.is_a?(ParseContext)
|
|
220
|
+
options
|
|
241
221
|
else
|
|
242
|
-
|
|
222
|
+
opts = options.key?(:environment) ? options : options.merge(environment: @environment)
|
|
223
|
+
ParseContext.new(opts)
|
|
243
224
|
end
|
|
225
|
+
|
|
226
|
+
@warnings = parse_context.warnings
|
|
227
|
+
parse_context
|
|
244
228
|
end
|
|
245
229
|
|
|
246
230
|
def apply_options_to_context(context, options)
|
|
247
231
|
context.add_filters(options[:filters]) if options[:filters]
|
|
248
|
-
context.global_filter
|
|
232
|
+
context.global_filter = options[:global_filter] if options[:global_filter]
|
|
249
233
|
context.exception_renderer = options[:exception_renderer] if options[:exception_renderer]
|
|
250
|
-
context.strict_variables
|
|
251
|
-
context.strict_filters
|
|
234
|
+
context.strict_variables = options[:strict_variables] if options[:strict_variables]
|
|
235
|
+
context.strict_filters = options[:strict_filters] if options[:strict_filters]
|
|
252
236
|
end
|
|
253
237
|
end
|
|
254
238
|
end
|