liquid 4.0.0.rc3 → 5.0.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 +93 -2
- data/README.md +8 -0
- data/lib/liquid.rb +18 -5
- data/lib/liquid/block.rb +47 -20
- data/lib/liquid/block_body.rb +190 -76
- data/lib/liquid/condition.rb +69 -29
- data/lib/liquid/context.rb +122 -76
- data/lib/liquid/document.rb +47 -9
- data/lib/liquid/drop.rb +4 -2
- data/lib/liquid/errors.rb +20 -25
- data/lib/liquid/expression.rb +30 -31
- data/lib/liquid/extensions.rb +8 -0
- data/lib/liquid/file_system.rb +6 -4
- data/lib/liquid/forloop_drop.rb +11 -4
- data/lib/liquid/i18n.rb +5 -3
- data/lib/liquid/interrupts.rb +3 -1
- data/lib/liquid/lexer.rb +35 -26
- data/lib/liquid/locales/en.yml +4 -2
- data/lib/liquid/parse_context.rb +17 -4
- data/lib/liquid/parse_tree_visitor.rb +42 -0
- data/lib/liquid/parser.rb +30 -18
- data/lib/liquid/parser_switching.rb +17 -3
- data/lib/liquid/partial_cache.rb +24 -0
- data/lib/liquid/profiler.rb +67 -86
- data/lib/liquid/profiler/hooks.rb +26 -14
- data/lib/liquid/range_lookup.rb +5 -3
- data/lib/liquid/register.rb +6 -0
- data/lib/liquid/resource_limits.rb +47 -8
- data/lib/liquid/standardfilters.rb +171 -57
- data/lib/liquid/static_registers.rb +44 -0
- data/lib/liquid/strainer_factory.rb +36 -0
- data/lib/liquid/strainer_template.rb +53 -0
- data/lib/liquid/tablerowloop_drop.rb +6 -4
- data/lib/liquid/tag.rb +28 -6
- data/lib/liquid/tag/disableable.rb +22 -0
- data/lib/liquid/tag/disabler.rb +21 -0
- data/lib/liquid/tags/assign.rb +32 -10
- data/lib/liquid/tags/break.rb +8 -3
- data/lib/liquid/tags/capture.rb +11 -8
- data/lib/liquid/tags/case.rb +41 -27
- data/lib/liquid/tags/comment.rb +5 -3
- data/lib/liquid/tags/continue.rb +8 -3
- data/lib/liquid/tags/cycle.rb +35 -16
- data/lib/liquid/tags/decrement.rb +6 -3
- data/lib/liquid/tags/echo.rb +26 -0
- data/lib/liquid/tags/for.rb +79 -47
- data/lib/liquid/tags/if.rb +53 -30
- data/lib/liquid/tags/ifchanged.rb +11 -10
- data/lib/liquid/tags/include.rb +42 -44
- data/lib/liquid/tags/increment.rb +7 -3
- data/lib/liquid/tags/raw.rb +14 -11
- data/lib/liquid/tags/render.rb +84 -0
- data/lib/liquid/tags/table_row.rb +32 -20
- data/lib/liquid/tags/unless.rb +15 -15
- data/lib/liquid/template.rb +60 -71
- data/lib/liquid/template_factory.rb +9 -0
- data/lib/liquid/tokenizer.rb +17 -9
- data/lib/liquid/usage.rb +8 -0
- data/lib/liquid/utils.rb +6 -4
- data/lib/liquid/variable.rb +55 -38
- data/lib/liquid/variable_lookup.rb +14 -6
- data/lib/liquid/version.rb +3 -1
- data/test/integration/assign_test.rb +74 -5
- data/test/integration/blank_test.rb +11 -8
- data/test/integration/block_test.rb +58 -0
- data/test/integration/capture_test.rb +18 -10
- data/test/integration/context_test.rb +608 -5
- data/test/integration/document_test.rb +4 -2
- data/test/integration/drop_test.rb +67 -83
- data/test/integration/error_handling_test.rb +90 -60
- data/test/integration/expression_test.rb +46 -0
- data/test/integration/filter_test.rb +53 -42
- data/test/integration/hash_ordering_test.rb +5 -3
- data/test/integration/output_test.rb +26 -24
- data/test/integration/parsing_quirks_test.rb +24 -8
- data/test/integration/{render_profiling_test.rb → profiler_test.rb} +84 -25
- data/test/integration/security_test.rb +41 -18
- data/test/integration/standard_filter_test.rb +523 -205
- data/test/integration/tag/disableable_test.rb +59 -0
- data/test/integration/tag_test.rb +45 -0
- data/test/integration/tags/break_tag_test.rb +4 -2
- data/test/integration/tags/continue_tag_test.rb +4 -2
- data/test/integration/tags/echo_test.rb +13 -0
- data/test/integration/tags/for_tag_test.rb +109 -53
- data/test/integration/tags/if_else_tag_test.rb +5 -3
- data/test/integration/tags/include_tag_test.rb +83 -52
- data/test/integration/tags/increment_tag_test.rb +4 -2
- data/test/integration/tags/liquid_tag_test.rb +116 -0
- data/test/integration/tags/raw_tag_test.rb +14 -11
- data/test/integration/tags/render_tag_test.rb +213 -0
- data/test/integration/tags/standard_tag_test.rb +38 -31
- data/test/integration/tags/statements_test.rb +23 -21
- data/test/integration/tags/table_row_test.rb +2 -0
- data/test/integration/tags/unless_else_tag_test.rb +4 -2
- data/test/integration/template_test.rb +128 -121
- data/test/integration/trim_mode_test.rb +82 -44
- data/test/integration/variable_test.rb +46 -31
- data/test/test_helper.rb +75 -23
- data/test/unit/block_unit_test.rb +19 -24
- data/test/unit/condition_unit_test.rb +82 -72
- data/test/unit/file_system_unit_test.rb +6 -4
- data/test/unit/i18n_unit_test.rb +7 -5
- data/test/unit/lexer_unit_test.rb +12 -10
- data/test/unit/parse_tree_visitor_test.rb +247 -0
- data/test/unit/parser_unit_test.rb +37 -35
- data/test/unit/partial_cache_unit_test.rb +128 -0
- data/test/unit/regexp_unit_test.rb +17 -15
- data/test/unit/static_registers_unit_test.rb +156 -0
- data/test/unit/strainer_factory_unit_test.rb +100 -0
- data/test/unit/strainer_template_unit_test.rb +82 -0
- data/test/unit/tag_unit_test.rb +5 -3
- data/test/unit/tags/case_tag_unit_test.rb +3 -1
- data/test/unit/tags/for_tag_unit_test.rb +4 -2
- data/test/unit/tags/if_tag_unit_test.rb +3 -1
- data/test/unit/template_factory_unit_test.rb +12 -0
- data/test/unit/template_unit_test.rb +19 -10
- data/test/unit/tokenizer_unit_test.rb +19 -17
- data/test/unit/variable_unit_test.rb +51 -49
- metadata +83 -50
- data/lib/liquid/strainer.rb +0 -65
- data/test/unit/context_unit_test.rb +0 -483
- data/test/unit/strainer_unit_test.rb +0 -136
data/lib/liquid/template.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Liquid
|
2
4
|
# Templates are central to liquid.
|
3
5
|
# Interpretating templates is a two step process. First you compile the
|
@@ -16,13 +18,11 @@ module Liquid
|
|
16
18
|
attr_accessor :root
|
17
19
|
attr_reader :resource_limits, :warnings
|
18
20
|
|
19
|
-
@@file_system = BlankFileSystem.new
|
20
|
-
|
21
21
|
class TagRegistry
|
22
22
|
include Enumerable
|
23
23
|
|
24
24
|
def initialize
|
25
|
-
@tags
|
25
|
+
@tags = {}
|
26
26
|
@cache = {}
|
27
27
|
end
|
28
28
|
|
@@ -50,7 +50,7 @@ module Liquid
|
|
50
50
|
private
|
51
51
|
|
52
52
|
def lookup_class(name)
|
53
|
-
|
53
|
+
Object.const_get(name)
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
@@ -61,71 +61,53 @@ module Liquid
|
|
61
61
|
# :lax acts like liquid 2.5 and silently ignores malformed tags in most cases.
|
62
62
|
# :warn is the default and will give deprecation warnings when invalid syntax is used.
|
63
63
|
# :strict will enforce correct syntax.
|
64
|
-
|
65
|
-
|
66
|
-
# Sets how strict the taint checker should be.
|
67
|
-
# :lax is the default, and ignores the taint flag completely
|
68
|
-
# :warn adds a warning, but does not interrupt the rendering
|
69
|
-
# :error raises an error when tainted output is used
|
70
|
-
attr_writer :taint_mode
|
64
|
+
attr_accessor :error_mode
|
65
|
+
Template.error_mode = :lax
|
71
66
|
|
72
|
-
|
73
|
-
|
67
|
+
attr_accessor :default_exception_renderer
|
68
|
+
Template.default_exception_renderer = lambda do |exception|
|
69
|
+
exception
|
74
70
|
end
|
75
71
|
|
76
|
-
|
77
|
-
|
78
|
-
|
72
|
+
attr_accessor :file_system
|
73
|
+
Template.file_system = BlankFileSystem.new
|
74
|
+
|
75
|
+
attr_accessor :tags
|
76
|
+
Template.tags = TagRegistry.new
|
77
|
+
private :tags=
|
79
78
|
|
80
79
|
def register_tag(name, klass)
|
81
80
|
tags[name.to_s] = klass
|
82
81
|
end
|
83
82
|
|
84
|
-
def tags
|
85
|
-
@tags ||= TagRegistry.new
|
86
|
-
end
|
87
|
-
|
88
|
-
def error_mode
|
89
|
-
@error_mode ||= :lax
|
90
|
-
end
|
91
|
-
|
92
|
-
def taint_mode
|
93
|
-
@taint_mode ||= :lax
|
94
|
-
end
|
95
|
-
|
96
83
|
# Pass a module with filter methods which should be available
|
97
84
|
# to all liquid views. Good for registering the standard library
|
98
85
|
def register_filter(mod)
|
99
|
-
|
86
|
+
StrainerFactory.add_global_filter(mod)
|
100
87
|
end
|
101
88
|
|
102
|
-
|
103
|
-
|
104
|
-
|
89
|
+
attr_accessor :default_resource_limits
|
90
|
+
Template.default_resource_limits = {}
|
91
|
+
private :default_resource_limits=
|
105
92
|
|
106
93
|
# creates a new <tt>Template</tt> object from liquid source code
|
107
94
|
# To enable profiling, pass in <tt>profile: true</tt> as an option.
|
108
95
|
# See Liquid::Profiler for more information
|
109
96
|
def parse(source, options = {})
|
110
|
-
|
111
|
-
template.parse(source, options)
|
97
|
+
new.parse(source, options)
|
112
98
|
end
|
113
99
|
end
|
114
100
|
|
115
101
|
def initialize
|
116
|
-
@rethrow_errors
|
117
|
-
@resource_limits = ResourceLimits.new(
|
102
|
+
@rethrow_errors = false
|
103
|
+
@resource_limits = ResourceLimits.new(Template.default_resource_limits)
|
118
104
|
end
|
119
105
|
|
120
106
|
# Parse source code.
|
121
107
|
# Returns self for easy chaining
|
122
108
|
def parse(source, options = {})
|
123
|
-
|
124
|
-
@
|
125
|
-
@line_numbers = options[:line_numbers] || @profiling
|
126
|
-
parse_context = options.is_a?(ParseContext) ? options : ParseContext.new(options)
|
127
|
-
@root = Document.parse(tokenize(source), parse_context)
|
128
|
-
@warnings = parse_context.warnings
|
109
|
+
parse_context = configure_options(options)
|
110
|
+
@root = Document.parse(tokenize(source), parse_context)
|
129
111
|
self
|
130
112
|
end
|
131
113
|
|
@@ -160,19 +142,19 @@ module Liquid
|
|
160
142
|
# filters and tags and might be useful to integrate liquid more with its host application
|
161
143
|
#
|
162
144
|
def render(*args)
|
163
|
-
return ''
|
145
|
+
return '' if @root.nil?
|
164
146
|
|
165
147
|
context = case args.first
|
166
148
|
when Liquid::Context
|
167
149
|
c = args.shift
|
168
150
|
|
169
151
|
if @rethrow_errors
|
170
|
-
c.
|
152
|
+
c.exception_renderer = Liquid::RAISE_EXCEPTION_LAMBDA
|
171
153
|
end
|
172
154
|
|
173
155
|
c
|
174
156
|
when Liquid::Drop
|
175
|
-
drop
|
157
|
+
drop = args.shift
|
176
158
|
drop.context = Context.new([drop, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits)
|
177
159
|
when Hash
|
178
160
|
Context.new([args.shift, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits)
|
@@ -182,11 +164,18 @@ module Liquid
|
|
182
164
|
raise ArgumentError, "Expected Hash or Liquid::Context as parameter"
|
183
165
|
end
|
184
166
|
|
167
|
+
output = nil
|
168
|
+
|
169
|
+
context_register = context.registers.is_a?(StaticRegisters) ? context.registers.static : context.registers
|
170
|
+
|
185
171
|
case args.last
|
186
172
|
when Hash
|
187
173
|
options = args.pop
|
174
|
+
output = options[:output] if options[:output]
|
188
175
|
|
189
|
-
|
176
|
+
options[:registers]&.each do |key, register|
|
177
|
+
context_register[key] = register
|
178
|
+
end
|
190
179
|
|
191
180
|
apply_options_to_context(context, options)
|
192
181
|
when Module, Array
|
@@ -196,13 +185,13 @@ module Liquid
|
|
196
185
|
# Retrying a render resets resource usage
|
197
186
|
context.resource_limits.reset
|
198
187
|
|
188
|
+
if @profiling && context.profiler.nil?
|
189
|
+
@profiler = context.profiler = Liquid::Profiler.new
|
190
|
+
end
|
191
|
+
|
199
192
|
begin
|
200
193
|
# render the nodelist.
|
201
|
-
|
202
|
-
result = with_profiling(context) do
|
203
|
-
@root.render(context)
|
204
|
-
end
|
205
|
-
result.respond_to?(:join) ? result.join : result
|
194
|
+
@root.render_to_output_buffer(context, output || +'')
|
206
195
|
rescue Liquid::MemoryError => e
|
207
196
|
context.handle_error(e)
|
208
197
|
ensure
|
@@ -215,35 +204,35 @@ module Liquid
|
|
215
204
|
render(*args)
|
216
205
|
end
|
217
206
|
|
218
|
-
|
219
|
-
|
220
|
-
def tokenize(source)
|
221
|
-
Tokenizer.new(source, @line_numbers)
|
207
|
+
def render_to_output_buffer(context, output)
|
208
|
+
render(context, output: output)
|
222
209
|
end
|
223
210
|
|
224
|
-
|
225
|
-
|
211
|
+
private
|
212
|
+
|
213
|
+
def configure_options(options)
|
214
|
+
if (profiling = options[:profile])
|
226
215
|
raise "Profiler not loaded, require 'liquid/profiler' first" unless defined?(Liquid::Profiler)
|
216
|
+
end
|
227
217
|
|
228
|
-
|
229
|
-
|
218
|
+
@options = options
|
219
|
+
@profiling = profiling
|
220
|
+
@line_numbers = options[:line_numbers] || @profiling
|
221
|
+
parse_context = options.is_a?(ParseContext) ? options : ParseContext.new(options)
|
222
|
+
@warnings = parse_context.warnings
|
223
|
+
parse_context
|
224
|
+
end
|
230
225
|
|
231
|
-
|
232
|
-
|
233
|
-
ensure
|
234
|
-
@profiler.stop
|
235
|
-
end
|
236
|
-
else
|
237
|
-
yield
|
238
|
-
end
|
226
|
+
def tokenize(source)
|
227
|
+
Tokenizer.new(source, @line_numbers)
|
239
228
|
end
|
240
229
|
|
241
230
|
def apply_options_to_context(context, options)
|
242
231
|
context.add_filters(options[:filters]) if options[:filters]
|
243
|
-
context.global_filter
|
244
|
-
context.
|
245
|
-
context.strict_variables
|
246
|
-
context.strict_filters
|
232
|
+
context.global_filter = options[:global_filter] if options[:global_filter]
|
233
|
+
context.exception_renderer = options[:exception_renderer] if options[:exception_renderer]
|
234
|
+
context.strict_variables = options[:strict_variables] if options[:strict_variables]
|
235
|
+
context.strict_filters = options[:strict_filters] if options[:strict_filters]
|
247
236
|
end
|
248
237
|
end
|
249
238
|
end
|
data/lib/liquid/tokenizer.rb
CHANGED
@@ -1,29 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Liquid
|
2
4
|
class Tokenizer
|
3
|
-
attr_reader :line_number
|
5
|
+
attr_reader :line_number, :for_liquid_tag
|
4
6
|
|
5
|
-
def initialize(source, line_numbers = false)
|
6
|
-
@source
|
7
|
-
@line_number
|
8
|
-
@
|
7
|
+
def initialize(source, line_numbers = false, line_number: nil, for_liquid_tag: false)
|
8
|
+
@source = source
|
9
|
+
@line_number = line_number || (line_numbers ? 1 : nil)
|
10
|
+
@for_liquid_tag = for_liquid_tag
|
11
|
+
@tokens = tokenize
|
9
12
|
end
|
10
13
|
|
11
14
|
def shift
|
12
|
-
token = @tokens.shift
|
13
|
-
|
15
|
+
(token = @tokens.shift) || return
|
16
|
+
|
17
|
+
if @line_number
|
18
|
+
@line_number += @for_liquid_tag ? 1 : token.count("\n")
|
19
|
+
end
|
20
|
+
|
14
21
|
token
|
15
22
|
end
|
16
23
|
|
17
24
|
private
|
18
25
|
|
19
26
|
def tokenize
|
20
|
-
@source = @source.source if @source.respond_to?(:source)
|
21
27
|
return [] if @source.to_s.empty?
|
22
28
|
|
29
|
+
return @source.split("\n") if @for_liquid_tag
|
30
|
+
|
23
31
|
tokens = @source.split(TemplateParser)
|
24
32
|
|
25
33
|
# removes the rogue empty element at the beginning of the array
|
26
|
-
tokens.shift if tokens[0]
|
34
|
+
tokens.shift if tokens[0]&.empty?
|
27
35
|
|
28
36
|
tokens
|
29
37
|
end
|
data/lib/liquid/usage.rb
ADDED
data/lib/liquid/utils.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Liquid
|
2
4
|
module Utils
|
3
5
|
def self.slice_collection(collection, from, to)
|
@@ -10,7 +12,7 @@ module Liquid
|
|
10
12
|
|
11
13
|
def self.slice_collection_using_each(collection, from, to)
|
12
14
|
segments = []
|
13
|
-
index
|
15
|
+
index = 0
|
14
16
|
|
15
17
|
# Maintains Ruby 1.8.7 String#each behaviour on 1.9
|
16
18
|
if collection.is_a?(String)
|
@@ -46,11 +48,11 @@ module Liquid
|
|
46
48
|
def self.to_number(obj)
|
47
49
|
case obj
|
48
50
|
when Float
|
49
|
-
BigDecimal
|
51
|
+
BigDecimal(obj.to_s)
|
50
52
|
when Numeric
|
51
53
|
obj
|
52
54
|
when String
|
53
|
-
|
55
|
+
/\A-?\d+\.\d+\z/.match?(obj.strip) ? BigDecimal(obj) : obj.to_i
|
54
56
|
else
|
55
57
|
if obj.respond_to?(:to_number)
|
56
58
|
obj.to_number
|
@@ -69,7 +71,7 @@ module Liquid
|
|
69
71
|
end
|
70
72
|
|
71
73
|
case obj
|
72
|
-
when 'now'
|
74
|
+
when 'now', 'today'
|
73
75
|
Time.now
|
74
76
|
when /\A\d+\z/, Integer
|
75
77
|
Time.at(obj.to_i)
|
data/lib/liquid/variable.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Liquid
|
2
4
|
# Holds variables. Variables are only loaded "just in time"
|
3
5
|
# and are not evaluated as part of the render stage
|
@@ -10,19 +12,25 @@ module Liquid
|
|
10
12
|
# {{ user | link }}
|
11
13
|
#
|
12
14
|
class Variable
|
13
|
-
|
15
|
+
FilterMarkupRegex = /#{FilterSeparator}\s*(.*)/om
|
16
|
+
FilterParser = /(?:\s+|#{QuotedFragment}|#{ArgumentSeparator})+/o
|
17
|
+
FilterArgsRegex = /(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*((?:\w+\s*\:\s*)?#{QuotedFragment})/o
|
18
|
+
JustTagAttributes = /\A#{TagAttributes}\z/o
|
19
|
+
MarkupWithQuotedFragment = /(#{QuotedFragment})(.*)/om
|
20
|
+
|
14
21
|
attr_accessor :filters, :name, :line_number
|
15
22
|
attr_reader :parse_context
|
16
23
|
alias_method :options, :parse_context
|
24
|
+
|
17
25
|
include ParserSwitching
|
18
26
|
|
19
27
|
def initialize(markup, parse_context)
|
20
|
-
@markup
|
21
|
-
@name
|
28
|
+
@markup = markup
|
29
|
+
@name = nil
|
22
30
|
@parse_context = parse_context
|
23
|
-
@line_number
|
31
|
+
@line_number = parse_context.line_number
|
24
32
|
|
25
|
-
|
33
|
+
strict_parse_with_error_mode_fallback(markup)
|
26
34
|
end
|
27
35
|
|
28
36
|
def raw
|
@@ -35,17 +43,17 @@ module Liquid
|
|
35
43
|
|
36
44
|
def lax_parse(markup)
|
37
45
|
@filters = []
|
38
|
-
return unless markup =~
|
46
|
+
return unless markup =~ MarkupWithQuotedFragment
|
39
47
|
|
40
|
-
name_markup
|
41
|
-
filter_markup =
|
42
|
-
@name
|
43
|
-
if filter_markup =~
|
44
|
-
filters =
|
48
|
+
name_markup = Regexp.last_match(1)
|
49
|
+
filter_markup = Regexp.last_match(2)
|
50
|
+
@name = Expression.parse(name_markup)
|
51
|
+
if filter_markup =~ FilterMarkupRegex
|
52
|
+
filters = Regexp.last_match(1).scan(FilterParser)
|
45
53
|
filters.each do |f|
|
46
54
|
next unless f =~ /\w+/
|
47
55
|
filtername = Regexp.last_match(0)
|
48
|
-
filterargs = f.scan(
|
56
|
+
filterargs = f.scan(FilterArgsRegex).flatten
|
49
57
|
@filters << parse_filter_expressions(filtername, filterargs)
|
50
58
|
end
|
51
59
|
end
|
@@ -55,6 +63,8 @@ module Liquid
|
|
55
63
|
@filters = []
|
56
64
|
p = Parser.new(markup)
|
57
65
|
|
66
|
+
return if p.look(:end_of_string)
|
67
|
+
|
58
68
|
@name = Expression.parse(p.expression)
|
59
69
|
while p.consume?(:pipe)
|
60
70
|
filtername = p.consume(:id)
|
@@ -73,37 +83,57 @@ module Liquid
|
|
73
83
|
end
|
74
84
|
|
75
85
|
def render(context)
|
76
|
-
obj =
|
86
|
+
obj = context.evaluate(@name)
|
87
|
+
|
88
|
+
@filters.each do |filter_name, filter_args, filter_kwargs|
|
77
89
|
filter_args = evaluate_filter_expressions(context, filter_args, filter_kwargs)
|
78
|
-
context.invoke(filter_name,
|
90
|
+
obj = context.invoke(filter_name, obj, *filter_args)
|
79
91
|
end
|
80
92
|
|
81
|
-
|
93
|
+
context.apply_global_filter(obj)
|
94
|
+
end
|
95
|
+
|
96
|
+
def render_to_output_buffer(context, output)
|
97
|
+
obj = render(context)
|
82
98
|
|
83
|
-
|
99
|
+
if obj.is_a?(Array)
|
100
|
+
output << obj.join
|
101
|
+
elsif obj.nil?
|
102
|
+
else
|
103
|
+
output << obj.to_s
|
104
|
+
end
|
84
105
|
|
85
|
-
|
106
|
+
output
|
107
|
+
end
|
108
|
+
|
109
|
+
def disabled?(_context)
|
110
|
+
false
|
111
|
+
end
|
112
|
+
|
113
|
+
def disabled_tags
|
114
|
+
[]
|
86
115
|
end
|
87
116
|
|
88
117
|
private
|
89
118
|
|
90
119
|
def parse_filter_expressions(filter_name, unparsed_args)
|
91
|
-
filter_args
|
92
|
-
keyword_args =
|
120
|
+
filter_args = []
|
121
|
+
keyword_args = nil
|
93
122
|
unparsed_args.each do |a|
|
94
|
-
if matches = a.match(
|
123
|
+
if (matches = a.match(JustTagAttributes))
|
124
|
+
keyword_args ||= {}
|
95
125
|
keyword_args[matches[1]] = Expression.parse(matches[2])
|
96
126
|
else
|
97
127
|
filter_args << Expression.parse(a)
|
98
128
|
end
|
99
129
|
end
|
100
130
|
result = [filter_name, filter_args]
|
101
|
-
result << keyword_args
|
131
|
+
result << keyword_args if keyword_args
|
102
132
|
result
|
103
133
|
end
|
104
134
|
|
105
135
|
def evaluate_filter_expressions(context, filter_args, filter_kwargs)
|
106
|
-
parsed_args = filter_args.map{ |expr| context.evaluate(expr) }
|
136
|
+
parsed_args = filter_args.map { |expr| context.evaluate(expr) }
|
107
137
|
if filter_kwargs
|
108
138
|
parsed_kwargs = {}
|
109
139
|
filter_kwargs.each do |key, expr|
|
@@ -114,22 +144,9 @@ module Liquid
|
|
114
144
|
parsed_args
|
115
145
|
end
|
116
146
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
@markup =~ QuotedFragment
|
122
|
-
name = Regexp.last_match(0)
|
123
|
-
|
124
|
-
error = TaintedError.new("variable '#{name}' is tainted and was not escaped")
|
125
|
-
error.line_number = line_number
|
126
|
-
error.template_name = context.template_name
|
127
|
-
|
128
|
-
case Template.taint_mode
|
129
|
-
when :warn
|
130
|
-
context.warnings << error
|
131
|
-
when :error
|
132
|
-
raise error
|
147
|
+
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
148
|
+
def children
|
149
|
+
[@node.name] + @node.filters.flatten
|
133
150
|
end
|
134
151
|
end
|
135
152
|
end
|