liquid 4.0.0.rc3 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
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,26 +1,64 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Liquid
2
- class Document < BlockBody
4
+ class Document
3
5
  def self.parse(tokens, parse_context)
4
- doc = new
6
+ doc = new(parse_context)
5
7
  doc.parse(tokens, parse_context)
6
8
  doc
7
9
  end
8
10
 
9
- def parse(tokens, parse_context)
10
- super do |end_tag_name, end_tag_params|
11
- unknown_tag(end_tag_name, parse_context) if end_tag_name
11
+ attr_reader :parse_context, :body
12
+
13
+ def initialize(parse_context)
14
+ @parse_context = parse_context
15
+ @body = new_body
16
+ end
17
+
18
+ def nodelist
19
+ @body.nodelist
20
+ end
21
+
22
+ def parse(tokenizer, parse_context)
23
+ while parse_body(tokenizer)
12
24
  end
25
+ @body.freeze
13
26
  rescue SyntaxError => e
14
27
  e.line_number ||= parse_context.line_number
15
28
  raise
16
29
  end
17
30
 
18
- def unknown_tag(tag, parse_context)
31
+ def unknown_tag(tag, _markup, _tokenizer)
19
32
  case tag
20
- when 'else'.freeze, 'end'.freeze
21
- raise SyntaxError.new(parse_context.locale.t("errors.syntax.unexpected_outer_tag".freeze, tag: tag))
33
+ when 'else', 'end'
34
+ raise SyntaxError, parse_context.locale.t("errors.syntax.unexpected_outer_tag", tag: tag)
22
35
  else
23
- raise SyntaxError.new(parse_context.locale.t("errors.syntax.unknown_tag".freeze, tag: tag))
36
+ raise SyntaxError, parse_context.locale.t("errors.syntax.unknown_tag", tag: tag)
37
+ end
38
+ end
39
+
40
+ def render_to_output_buffer(context, output)
41
+ @body.render_to_output_buffer(context, output)
42
+ end
43
+
44
+ def render(context)
45
+ render_to_output_buffer(context, +'')
46
+ end
47
+
48
+ private
49
+
50
+ def new_body
51
+ parse_context.new_block_body
52
+ end
53
+
54
+ def parse_body(tokenizer)
55
+ @body.parse(tokenizer, parse_context) do |unknown_tag_name, unknown_tag_markup|
56
+ if unknown_tag_name
57
+ unknown_tag(unknown_tag_name, unknown_tag_markup, tokenizer)
58
+ true
59
+ else
60
+ false
61
+ end
24
62
  end
25
63
  end
26
64
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'set'
2
4
 
3
5
  module Liquid
@@ -25,7 +27,7 @@ module Liquid
25
27
 
26
28
  # Catch all for the method
27
29
  def liquid_method_missing(method)
28
- return nil unless @context && @context.strict_variables
30
+ return nil unless @context&.strict_variables
29
31
  raise Liquid::UndefinedDropMethod, "undefined method #{method}"
30
32
  end
31
33
 
@@ -67,7 +69,7 @@ module Liquid
67
69
 
68
70
  if include?(Enumerable)
69
71
  blacklist += Enumerable.public_instance_methods
70
- blacklist -= [:sort, :count, :first, :min, :max, :include?]
72
+ blacklist -= [:sort, :count, :first, :min, :max]
71
73
  end
72
74
 
73
75
  whitelist = [:to_liquid] + (public_instance_methods - blacklist)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Liquid
2
4
  class Error < ::StandardError
3
5
  attr_accessor :line_number
@@ -5,7 +7,7 @@ module Liquid
5
7
  attr_accessor :markup_context
6
8
 
7
9
  def to_s(with_prefix = true)
8
- str = ""
10
+ str = +""
9
11
  str << message_prefix if with_prefix
10
12
  str << super()
11
13
 
@@ -17,22 +19,14 @@ module Liquid
17
19
  str
18
20
  end
19
21
 
20
- def self.render(e)
21
- if e.is_a?(Liquid::Error)
22
- e.to_s
23
- else
24
- "Liquid error: #{e}"
25
- end
26
- end
27
-
28
22
  private
29
23
 
30
24
  def message_prefix
31
- str = ""
32
- if is_a?(SyntaxError)
33
- str << "Liquid syntax error"
25
+ str = +""
26
+ str << if is_a?(SyntaxError)
27
+ "Liquid syntax error"
34
28
  else
35
- str << "Liquid error"
29
+ "Liquid error"
36
30
  end
37
31
 
38
32
  if line_number
@@ -46,18 +40,19 @@ module Liquid
46
40
  end
47
41
  end
48
42
 
49
- ArgumentError = Class.new(Error)
50
- ContextError = Class.new(Error)
51
- FileSystemError = Class.new(Error)
52
- StandardError = Class.new(Error)
53
- SyntaxError = Class.new(Error)
54
- StackLevelError = Class.new(Error)
55
- TaintedError = Class.new(Error)
56
- MemoryError = Class.new(Error)
57
- ZeroDivisionError = Class.new(Error)
58
- FloatDomainError = Class.new(Error)
59
- UndefinedVariable = Class.new(Error)
43
+ ArgumentError = Class.new(Error)
44
+ ContextError = Class.new(Error)
45
+ FileSystemError = Class.new(Error)
46
+ StandardError = Class.new(Error)
47
+ SyntaxError = Class.new(Error)
48
+ StackLevelError = Class.new(Error)
49
+ MemoryError = Class.new(Error)
50
+ ZeroDivisionError = Class.new(Error)
51
+ FloatDomainError = Class.new(Error)
52
+ UndefinedVariable = Class.new(Error)
60
53
  UndefinedDropMethod = Class.new(Error)
61
- UndefinedFilter = Class.new(Error)
54
+ UndefinedFilter = Class.new(Error)
62
55
  MethodOverrideError = Class.new(Error)
56
+ DisabledError = Class.new(Error)
57
+ InternalError = Class.new(Error)
63
58
  end
@@ -1,41 +1,40 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Liquid
2
4
  class Expression
3
- class MethodLiteral
4
- attr_reader :method_name, :to_s
5
+ LITERALS = {
6
+ nil => nil, 'nil' => nil, 'null' => nil, '' => nil,
7
+ 'true' => true,
8
+ 'false' => false,
9
+ 'blank' => '',
10
+ 'empty' => ''
11
+ }.freeze
5
12
 
6
- def initialize(method_name, to_s)
7
- @method_name = method_name
8
- @to_s = to_s
9
- end
13
+ SINGLE_QUOTED_STRING = /\A\s*'(.*)'\s*\z/m
14
+ DOUBLE_QUOTED_STRING = /\A\s*"(.*)"\s*\z/m
15
+ INTEGERS_REGEX = /\A\s*(-?\d+)\s*\z/
16
+ FLOATS_REGEX = /\A\s*(-?\d[\d\.]+)\s*\z/
10
17
 
11
- def to_liquid
12
- to_s
13
- end
14
- end
15
-
16
- LITERALS = {
17
- nil => nil, 'nil'.freeze => nil, 'null'.freeze => nil, ''.freeze => nil,
18
- 'true'.freeze => true,
19
- 'false'.freeze => false,
20
- 'blank'.freeze => MethodLiteral.new(:blank?, '').freeze,
21
- 'empty'.freeze => MethodLiteral.new(:empty?, '').freeze
22
- }
18
+ # Use an atomic group (?>...) to avoid pathological backtracing from
19
+ # malicious input as described in https://github.com/Shopify/liquid/issues/1357
20
+ RANGES_REGEX = /\A\s*\(\s*(?>(\S+)\s*\.\.)\s*(\S+)\s*\)\s*\z/
23
21
 
24
22
  def self.parse(markup)
25
- if LITERALS.key?(markup)
26
- LITERALS[markup]
23
+ case markup
24
+ when nil
25
+ nil
26
+ when SINGLE_QUOTED_STRING, DOUBLE_QUOTED_STRING
27
+ Regexp.last_match(1)
28
+ when INTEGERS_REGEX
29
+ Regexp.last_match(1).to_i
30
+ when RANGES_REGEX
31
+ RangeLookup.parse(Regexp.last_match(1), Regexp.last_match(2))
32
+ when FLOATS_REGEX
33
+ Regexp.last_match(1).to_f
27
34
  else
28
- case markup
29
- when /\A'(.*)'\z/m # Single quoted strings
30
- $1
31
- when /\A"(.*)"\z/m # Double quoted strings
32
- $1
33
- when /\A(-?\d+)\z/ # Integer and floats
34
- $1.to_i
35
- when /\A\((\S+)\.\.(\S+)\)\z/ # Ranges
36
- RangeLookup.parse($1, $2)
37
- when /\A(-?\d[\d\.]+)\z/ # Floats
38
- $1.to_f
35
+ markup = markup.strip
36
+ if LITERALS.key?(markup)
37
+ LITERALS[markup]
39
38
  else
40
39
  VariableLookup.parse(markup)
41
40
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'time'
2
4
  require 'date'
3
5
 
@@ -7,6 +9,12 @@ class String # :nodoc:
7
9
  end
8
10
  end
9
11
 
12
+ class Symbol # :nodoc:
13
+ def to_liquid
14
+ to_s
15
+ end
16
+ end
17
+
10
18
  class Array # :nodoc:
11
19
  def to_liquid
12
20
  self
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Liquid
2
4
  # A Liquid file system is a way to let your templates retrieve other templates for use with the include tag.
3
5
  #
@@ -44,8 +46,8 @@ module Liquid
44
46
  class LocalFileSystem
45
47
  attr_accessor :root
46
48
 
47
- def initialize(root, pattern = "_%s.liquid".freeze)
48
- @root = root
49
+ def initialize(root, pattern = "_%s.liquid")
50
+ @root = root
49
51
  @pattern = pattern
50
52
  end
51
53
 
@@ -57,9 +59,9 @@ module Liquid
57
59
  end
58
60
 
59
61
  def full_path(template_path)
60
- raise FileSystemError, "Illegal template name '#{template_path}'" unless template_path =~ /\A[^.\/][a-zA-Z0-9_\/]+\z/
62
+ raise FileSystemError, "Illegal template name '#{template_path}'" unless %r{\A[^./][a-zA-Z0-9_/]+\z}.match?(template_path)
61
63
 
62
- full_path = if template_path.include?('/'.freeze)
64
+ full_path = if template_path.include?('/')
63
65
  File.join(root, File.dirname(template_path), @pattern % File.basename(template_path))
64
66
  else
65
67
  File.join(root, @pattern % template_path)
@@ -1,13 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Liquid
2
4
  class ForloopDrop < Drop
3
5
  def initialize(name, length, parentloop)
4
- @name = name
5
- @length = length
6
+ @name = name
7
+ @length = length
6
8
  @parentloop = parentloop
7
- @index = 0
9
+ @index = 0
8
10
  end
9
11
 
10
- attr_reader :name, :length, :parentloop
12
+ attr_reader :length, :parentloop
13
+
14
+ def name
15
+ Usage.increment('forloop_drop_name')
16
+ @name
17
+ end
11
18
 
12
19
  def index
13
20
  @index + 1
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'yaml'
2
4
 
3
5
  module Liquid
@@ -26,13 +28,13 @@ module Liquid
26
28
  def interpolate(name, vars)
27
29
  name.gsub(/%\{(\w+)\}/) do
28
30
  # raise TranslationError, "Undefined key #{$1} for interpolation in translation #{name}" unless vars[$1.to_sym]
29
- "#{vars[$1.to_sym]}"
31
+ (vars[Regexp.last_match(1).to_sym]).to_s
30
32
  end
31
33
  end
32
34
 
33
35
  def deep_fetch_translation(name)
34
- name.split('.'.freeze).reduce(locale) do |level, cur|
35
- level[cur] or raise TranslationError, "Translation for #{name} does not exist in locale #{path}"
36
+ name.split('.').reduce(locale) do |level, cur|
37
+ level[cur] || raise(TranslationError, "Translation for #{name} does not exist in locale #{path}")
36
38
  end
37
39
  end
38
40
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Liquid
2
4
  # An interrupt is any command that breaks processing of a block (ex: a for loop).
3
5
  class Interrupt
4
6
  attr_reader :message
5
7
 
6
8
  def initialize(message = nil)
7
- @message = message || "interrupt".freeze
9
+ @message = message || "interrupt"
8
10
  end
9
11
  end
10
12
 
@@ -1,44 +1,53 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "strscan"
2
4
  module Liquid
3
5
  class Lexer
4
6
  SPECIALS = {
5
- '|'.freeze => :pipe,
6
- '.'.freeze => :dot,
7
- ':'.freeze => :colon,
8
- ','.freeze => :comma,
9
- '['.freeze => :open_square,
10
- ']'.freeze => :close_square,
11
- '('.freeze => :open_round,
12
- ')'.freeze => :close_round,
13
- '?'.freeze => :question,
14
- '-'.freeze => :dash
15
- }
16
- IDENTIFIER = /[a-zA-Z_][\w-]*\??/
7
+ '|' => :pipe,
8
+ '.' => :dot,
9
+ ':' => :colon,
10
+ ',' => :comma,
11
+ '[' => :open_square,
12
+ ']' => :close_square,
13
+ '(' => :open_round,
14
+ ')' => :close_round,
15
+ '?' => :question,
16
+ '-' => :dash,
17
+ }.freeze
18
+ IDENTIFIER = /[a-zA-Z_][\w-]*\??/
17
19
  SINGLE_STRING_LITERAL = /'[^\']*'/
18
20
  DOUBLE_STRING_LITERAL = /"[^\"]*"/
19
- NUMBER_LITERAL = /-?\d+(\.\d+)?/
20
- DOTDOT = /\.\./
21
- COMPARISON_OPERATOR = /==|!=|<>|<=?|>=?|contains/
21
+ NUMBER_LITERAL = /-?\d+(\.\d+)?/
22
+ DOTDOT = /\.\./
23
+ COMPARISON_OPERATOR = /==|!=|<>|<=?|>=?|contains(?=\s)/
24
+ WHITESPACE_OR_NOTHING = /\s*/
22
25
 
23
26
  def initialize(input)
24
- @ss = StringScanner.new(input.rstrip)
27
+ @ss = StringScanner.new(input)
25
28
  end
26
29
 
27
30
  def tokenize
28
31
  @output = []
29
32
 
30
33
  until @ss.eos?
31
- @ss.skip(/\s*/)
32
- tok = case
33
- when t = @ss.scan(COMPARISON_OPERATOR) then [:comparison, t]
34
- when t = @ss.scan(SINGLE_STRING_LITERAL) then [:string, t]
35
- when t = @ss.scan(DOUBLE_STRING_LITERAL) then [:string, t]
36
- when t = @ss.scan(NUMBER_LITERAL) then [:number, t]
37
- when t = @ss.scan(IDENTIFIER) then [:id, t]
38
- when t = @ss.scan(DOTDOT) then [:dotdot, t]
34
+ @ss.skip(WHITESPACE_OR_NOTHING)
35
+ break if @ss.eos?
36
+ tok = if (t = @ss.scan(COMPARISON_OPERATOR))
37
+ [:comparison, t]
38
+ elsif (t = @ss.scan(SINGLE_STRING_LITERAL))
39
+ [:string, t]
40
+ elsif (t = @ss.scan(DOUBLE_STRING_LITERAL))
41
+ [:string, t]
42
+ elsif (t = @ss.scan(NUMBER_LITERAL))
43
+ [:number, t]
44
+ elsif (t = @ss.scan(IDENTIFIER))
45
+ [:id, t]
46
+ elsif (t = @ss.scan(DOTDOT))
47
+ [:dotdot, t]
39
48
  else
40
- c = @ss.getch
41
- if s = SPECIALS[c]
49
+ c = @ss.getch
50
+ if (s = SPECIALS[c])
42
51
  [s, c]
43
52
  else
44
53
  raise SyntaxError, "Unexpected character #{c}"
@@ -14,13 +14,15 @@
14
14
  if: "Syntax Error in tag 'if' - Valid syntax: if [expression]"
15
15
  include: "Error in tag 'include' - Valid syntax: include '[template]' (with|for) [object|collection]"
16
16
  unknown_tag: "Unknown tag '%{tag}'"
17
- invalid_delimiter: "'end' is not a valid delimiter for %{block_name} tags. use %{block_delimiter}"
17
+ invalid_delimiter: "'%{tag}' is not a valid delimiter for %{block_name} tags. use %{block_delimiter}"
18
18
  unexpected_else: "%{block_name} tag does not expect 'else' tag"
19
19
  unexpected_outer_tag: "Unexpected outer '%{tag}' tag"
20
20
  tag_termination: "Tag '%{token}' was not properly terminated with regexp: %{tag_end}"
21
21
  variable_termination: "Variable '%{token}' was not properly terminated with regexp: %{tag_end}"
22
22
  tag_never_closed: "'%{block_name}' tag was never closed"
23
- meta_syntax_error: "Liquid syntax error: #{e.message}"
24
23
  table_row: "Syntax Error in 'table_row loop' - Valid syntax: table_row [item] in [collection] cols=3"
24
+ render: "Syntax error in tag 'render' - Template name must be a quoted string"
25
25
  argument:
26
26
  include: "Argument error in tag 'include' - Illegal template name"
27
+ disabled:
28
+ tag: "usage is not allowed in this context"