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.
Files changed (123) hide show
  1. checksums.yaml +5 -5
  2. data/History.md +93 -2
  3. data/README.md +8 -0
  4. data/lib/liquid.rb +18 -5
  5. data/lib/liquid/block.rb +47 -20
  6. data/lib/liquid/block_body.rb +190 -76
  7. data/lib/liquid/condition.rb +69 -29
  8. data/lib/liquid/context.rb +122 -76
  9. data/lib/liquid/document.rb +47 -9
  10. data/lib/liquid/drop.rb +4 -2
  11. data/lib/liquid/errors.rb +20 -25
  12. data/lib/liquid/expression.rb +30 -31
  13. data/lib/liquid/extensions.rb +8 -0
  14. data/lib/liquid/file_system.rb +6 -4
  15. data/lib/liquid/forloop_drop.rb +11 -4
  16. data/lib/liquid/i18n.rb +5 -3
  17. data/lib/liquid/interrupts.rb +3 -1
  18. data/lib/liquid/lexer.rb +35 -26
  19. data/lib/liquid/locales/en.yml +4 -2
  20. data/lib/liquid/parse_context.rb +17 -4
  21. data/lib/liquid/parse_tree_visitor.rb +42 -0
  22. data/lib/liquid/parser.rb +30 -18
  23. data/lib/liquid/parser_switching.rb +17 -3
  24. data/lib/liquid/partial_cache.rb +24 -0
  25. data/lib/liquid/profiler.rb +67 -86
  26. data/lib/liquid/profiler/hooks.rb +26 -14
  27. data/lib/liquid/range_lookup.rb +5 -3
  28. data/lib/liquid/register.rb +6 -0
  29. data/lib/liquid/resource_limits.rb +47 -8
  30. data/lib/liquid/standardfilters.rb +171 -57
  31. data/lib/liquid/static_registers.rb +44 -0
  32. data/lib/liquid/strainer_factory.rb +36 -0
  33. data/lib/liquid/strainer_template.rb +53 -0
  34. data/lib/liquid/tablerowloop_drop.rb +6 -4
  35. data/lib/liquid/tag.rb +28 -6
  36. data/lib/liquid/tag/disableable.rb +22 -0
  37. data/lib/liquid/tag/disabler.rb +21 -0
  38. data/lib/liquid/tags/assign.rb +32 -10
  39. data/lib/liquid/tags/break.rb +8 -3
  40. data/lib/liquid/tags/capture.rb +11 -8
  41. data/lib/liquid/tags/case.rb +41 -27
  42. data/lib/liquid/tags/comment.rb +5 -3
  43. data/lib/liquid/tags/continue.rb +8 -3
  44. data/lib/liquid/tags/cycle.rb +35 -16
  45. data/lib/liquid/tags/decrement.rb +6 -3
  46. data/lib/liquid/tags/echo.rb +26 -0
  47. data/lib/liquid/tags/for.rb +79 -47
  48. data/lib/liquid/tags/if.rb +53 -30
  49. data/lib/liquid/tags/ifchanged.rb +11 -10
  50. data/lib/liquid/tags/include.rb +42 -44
  51. data/lib/liquid/tags/increment.rb +7 -3
  52. data/lib/liquid/tags/raw.rb +14 -11
  53. data/lib/liquid/tags/render.rb +84 -0
  54. data/lib/liquid/tags/table_row.rb +32 -20
  55. data/lib/liquid/tags/unless.rb +15 -15
  56. data/lib/liquid/template.rb +60 -71
  57. data/lib/liquid/template_factory.rb +9 -0
  58. data/lib/liquid/tokenizer.rb +17 -9
  59. data/lib/liquid/usage.rb +8 -0
  60. data/lib/liquid/utils.rb +6 -4
  61. data/lib/liquid/variable.rb +55 -38
  62. data/lib/liquid/variable_lookup.rb +14 -6
  63. data/lib/liquid/version.rb +3 -1
  64. data/test/integration/assign_test.rb +74 -5
  65. data/test/integration/blank_test.rb +11 -8
  66. data/test/integration/block_test.rb +58 -0
  67. data/test/integration/capture_test.rb +18 -10
  68. data/test/integration/context_test.rb +608 -5
  69. data/test/integration/document_test.rb +4 -2
  70. data/test/integration/drop_test.rb +67 -83
  71. data/test/integration/error_handling_test.rb +90 -60
  72. data/test/integration/expression_test.rb +46 -0
  73. data/test/integration/filter_test.rb +53 -42
  74. data/test/integration/hash_ordering_test.rb +5 -3
  75. data/test/integration/output_test.rb +26 -24
  76. data/test/integration/parsing_quirks_test.rb +24 -8
  77. data/test/integration/{render_profiling_test.rb → profiler_test.rb} +84 -25
  78. data/test/integration/security_test.rb +41 -18
  79. data/test/integration/standard_filter_test.rb +523 -205
  80. data/test/integration/tag/disableable_test.rb +59 -0
  81. data/test/integration/tag_test.rb +45 -0
  82. data/test/integration/tags/break_tag_test.rb +4 -2
  83. data/test/integration/tags/continue_tag_test.rb +4 -2
  84. data/test/integration/tags/echo_test.rb +13 -0
  85. data/test/integration/tags/for_tag_test.rb +109 -53
  86. data/test/integration/tags/if_else_tag_test.rb +5 -3
  87. data/test/integration/tags/include_tag_test.rb +83 -52
  88. data/test/integration/tags/increment_tag_test.rb +4 -2
  89. data/test/integration/tags/liquid_tag_test.rb +116 -0
  90. data/test/integration/tags/raw_tag_test.rb +14 -11
  91. data/test/integration/tags/render_tag_test.rb +213 -0
  92. data/test/integration/tags/standard_tag_test.rb +38 -31
  93. data/test/integration/tags/statements_test.rb +23 -21
  94. data/test/integration/tags/table_row_test.rb +2 -0
  95. data/test/integration/tags/unless_else_tag_test.rb +4 -2
  96. data/test/integration/template_test.rb +128 -121
  97. data/test/integration/trim_mode_test.rb +82 -44
  98. data/test/integration/variable_test.rb +46 -31
  99. data/test/test_helper.rb +75 -23
  100. data/test/unit/block_unit_test.rb +19 -24
  101. data/test/unit/condition_unit_test.rb +82 -72
  102. data/test/unit/file_system_unit_test.rb +6 -4
  103. data/test/unit/i18n_unit_test.rb +7 -5
  104. data/test/unit/lexer_unit_test.rb +12 -10
  105. data/test/unit/parse_tree_visitor_test.rb +247 -0
  106. data/test/unit/parser_unit_test.rb +37 -35
  107. data/test/unit/partial_cache_unit_test.rb +128 -0
  108. data/test/unit/regexp_unit_test.rb +17 -15
  109. data/test/unit/static_registers_unit_test.rb +156 -0
  110. data/test/unit/strainer_factory_unit_test.rb +100 -0
  111. data/test/unit/strainer_template_unit_test.rb +82 -0
  112. data/test/unit/tag_unit_test.rb +5 -3
  113. data/test/unit/tags/case_tag_unit_test.rb +3 -1
  114. data/test/unit/tags/for_tag_unit_test.rb +4 -2
  115. data/test/unit/tags/if_tag_unit_test.rb +3 -1
  116. data/test/unit/template_factory_unit_test.rb +12 -0
  117. data/test/unit/template_unit_test.rb +19 -10
  118. data/test/unit/tokenizer_unit_test.rb +19 -17
  119. data/test/unit/variable_unit_test.rb +51 -49
  120. metadata +83 -50
  121. data/lib/liquid/strainer.rb +0 -65
  122. data/test/unit/context_unit_test.rb +0 -483
  123. data/test/unit/strainer_unit_test.rb +0 -136
@@ -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
- name.split("::").reject(&:empty?).reduce(Object) { |scope, const| scope.const_get(const) }
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
- attr_writer :error_mode
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
- def file_system
73
- @@file_system
67
+ attr_accessor :default_exception_renderer
68
+ Template.default_exception_renderer = lambda do |exception|
69
+ exception
74
70
  end
75
71
 
76
- def file_system=(obj)
77
- @@file_system = obj
78
- end
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
- Strainer.global_filter(mod)
86
+ StrainerFactory.add_global_filter(mod)
100
87
  end
101
88
 
102
- def default_resource_limits
103
- @default_resource_limits ||= {}
104
- end
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
- template = Template.new
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 = false
117
- @resource_limits = ResourceLimits.new(self.class.default_resource_limits)
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
- @options = options
124
- @profiling = options[:profile]
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 ''.freeze if @root.nil?
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.exception_handler = ->(e) { raise }
152
+ c.exception_renderer = Liquid::RAISE_EXCEPTION_LAMBDA
171
153
  end
172
154
 
173
155
  c
174
156
  when Liquid::Drop
175
- drop = args.shift
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
- registers.merge!(options[:registers]) if options[:registers].is_a?(Hash)
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
- # for performance reasons we get an array back here. join will make a string out of it.
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
- private
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
- def with_profiling(context)
225
- if @profiling && !context.partial
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
- @profiler = Profiler.new
229
- @profiler.start
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
- begin
232
- yield
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 = options[:global_filter] if options[:global_filter]
244
- context.exception_handler = options[:exception_handler] if options[:exception_handler]
245
- context.strict_variables = options[:strict_variables] if options[:strict_variables]
246
- context.strict_filters = options[:strict_filters] if options[: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
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Liquid
4
+ class TemplateFactory
5
+ def for(_template_name)
6
+ Liquid::Template.new
7
+ end
8
+ end
9
+ end
@@ -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 = source
7
- @line_number = line_numbers ? 1 : nil
8
- @tokens = tokenize
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
- @line_number += token.count("\n") if @line_number && token
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] && tokens[0].empty?
34
+ tokens.shift if tokens[0]&.empty?
27
35
 
28
36
  tokens
29
37
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Liquid
4
+ module Usage
5
+ def self.increment(name)
6
+ end
7
+ end
8
+ end
@@ -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 = 0
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.new(obj.to_s)
51
+ BigDecimal(obj.to_s)
50
52
  when Numeric
51
53
  obj
52
54
  when String
53
- (obj.strip =~ /\A-?\d+\.\d+\z/) ? BigDecimal.new(obj) : obj.to_i
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'.freeze, 'today'.freeze
74
+ when 'now', 'today'
73
75
  Time.now
74
76
  when /\A\d+\z/, Integer
75
77
  Time.at(obj.to_i)
@@ -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
- FilterParser = /(?:\s+|#{QuotedFragment}|#{ArgumentSeparator})+/o
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 = markup
21
- @name = nil
28
+ @markup = markup
29
+ @name = nil
22
30
  @parse_context = parse_context
23
- @line_number = parse_context.line_number
31
+ @line_number = parse_context.line_number
24
32
 
25
- parse_with_selected_parser(markup)
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 =~ /(#{QuotedFragment})(.*)/om
46
+ return unless markup =~ MarkupWithQuotedFragment
39
47
 
40
- name_markup = $1
41
- filter_markup = $2
42
- @name = Expression.parse(name_markup)
43
- if filter_markup =~ /#{FilterSeparator}\s*(.*)/om
44
- filters = $1.scan(FilterParser)
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(/(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*((?:\w+\s*\:\s*)?#{QuotedFragment})/o).flatten
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 = @filters.inject(context.evaluate(@name)) do |output, (filter_name, filter_args, filter_kwargs)|
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, output, *filter_args)
90
+ obj = context.invoke(filter_name, obj, *filter_args)
79
91
  end
80
92
 
81
- obj = context.apply_global_filter(obj)
93
+ context.apply_global_filter(obj)
94
+ end
95
+
96
+ def render_to_output_buffer(context, output)
97
+ obj = render(context)
82
98
 
83
- taint_check(context, obj)
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
- obj
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(/\A#{TagAttributes}\z/o)
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 unless keyword_args.empty?
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
- def taint_check(context, obj)
118
- return unless obj.tainted?
119
- return if Template.taint_mode == :lax
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