locomotivecms-liquid 2.6.0 → 4.0.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +62 -5
- data/README.md +4 -4
- data/lib/liquid.rb +16 -12
- data/lib/liquid/block.rb +37 -118
- data/lib/liquid/block_body.rb +131 -0
- data/lib/liquid/condition.rb +28 -17
- data/lib/liquid/context.rb +94 -146
- data/lib/liquid/document.rb +16 -10
- data/lib/liquid/drop.rb +8 -5
- data/lib/liquid/drops/inherited_block_drop.rb +24 -0
- data/lib/liquid/errors.rb +44 -5
- data/lib/liquid/expression.rb +33 -0
- data/lib/liquid/file_system.rb +17 -6
- data/lib/liquid/i18n.rb +2 -2
- data/lib/liquid/interrupts.rb +1 -1
- data/lib/liquid/lexer.rb +11 -9
- data/lib/liquid/locales/en.yml +2 -4
- data/lib/liquid/parser.rb +2 -1
- data/lib/liquid/parser_switching.rb +31 -0
- data/lib/liquid/profiler.rb +162 -0
- data/lib/liquid/profiler/hooks.rb +23 -0
- data/lib/liquid/range_lookup.rb +22 -0
- data/lib/liquid/resource_limits.rb +23 -0
- data/lib/liquid/standardfilters.rb +142 -67
- data/lib/liquid/strainer.rb +14 -4
- data/lib/liquid/tag.rb +22 -41
- data/lib/liquid/tags/assign.rb +15 -10
- data/lib/liquid/tags/break.rb +1 -1
- data/lib/liquid/tags/capture.rb +7 -9
- data/lib/liquid/tags/case.rb +28 -19
- data/lib/liquid/tags/comment.rb +2 -2
- data/lib/liquid/tags/continue.rb +1 -4
- data/lib/liquid/tags/cycle.rb +10 -14
- data/lib/liquid/tags/decrement.rb +3 -4
- data/lib/liquid/tags/extends.rb +28 -44
- data/lib/liquid/tags/for.rb +64 -42
- data/lib/liquid/tags/if.rb +30 -19
- data/lib/liquid/tags/ifchanged.rb +4 -4
- data/lib/liquid/tags/include.rb +30 -20
- data/lib/liquid/tags/increment.rb +3 -8
- data/lib/liquid/tags/inherited_block.rb +54 -56
- data/lib/liquid/tags/raw.rb +18 -10
- data/lib/liquid/tags/table_row.rb +72 -0
- data/lib/liquid/tags/unless.rb +5 -7
- data/lib/liquid/template.rb +113 -53
- data/lib/liquid/token.rb +18 -0
- data/lib/liquid/utils.rb +13 -4
- data/lib/liquid/variable.rb +68 -50
- data/lib/liquid/variable_lookup.rb +78 -0
- data/lib/liquid/version.rb +1 -1
- data/test/fixtures/en_locale.yml +9 -0
- data/test/integration/assign_test.rb +48 -0
- data/test/integration/blank_test.rb +106 -0
- data/test/integration/capture_test.rb +50 -0
- data/test/integration/context_test.rb +32 -0
- data/test/integration/document_test.rb +19 -0
- data/test/integration/drop_test.rb +271 -0
- data/test/integration/error_handling_test.rb +207 -0
- data/test/integration/filter_test.rb +125 -0
- data/test/integration/hash_ordering_test.rb +23 -0
- data/test/integration/output_test.rb +116 -0
- data/test/integration/parsing_quirks_test.rb +119 -0
- data/test/integration/render_profiling_test.rb +154 -0
- data/test/integration/security_test.rb +64 -0
- data/test/integration/standard_filter_test.rb +379 -0
- data/test/integration/tags/break_tag_test.rb +16 -0
- data/test/integration/tags/continue_tag_test.rb +16 -0
- data/test/integration/tags/extends_tag_test.rb +104 -0
- data/test/integration/tags/for_tag_test.rb +375 -0
- data/test/integration/tags/if_else_tag_test.rb +169 -0
- data/test/integration/tags/include_tag_test.rb +234 -0
- data/test/integration/tags/increment_tag_test.rb +24 -0
- data/test/integration/tags/raw_tag_test.rb +25 -0
- data/test/integration/tags/standard_tag_test.rb +297 -0
- data/test/integration/tags/statements_test.rb +113 -0
- data/test/integration/tags/table_row_test.rb +63 -0
- data/test/integration/tags/unless_else_tag_test.rb +26 -0
- data/test/integration/template_test.rb +216 -0
- data/test/integration/variable_test.rb +82 -0
- data/test/test_helper.rb +83 -0
- data/test/unit/block_unit_test.rb +55 -0
- data/test/unit/condition_unit_test.rb +149 -0
- data/test/unit/context_unit_test.rb +482 -0
- data/test/unit/file_system_unit_test.rb +35 -0
- data/test/unit/i18n_unit_test.rb +37 -0
- data/test/unit/lexer_unit_test.rb +51 -0
- data/test/unit/module_ex_unit_test.rb +87 -0
- data/test/unit/parser_unit_test.rb +82 -0
- data/test/unit/regexp_unit_test.rb +44 -0
- data/test/unit/strainer_unit_test.rb +71 -0
- data/test/unit/tag_unit_test.rb +16 -0
- data/test/unit/tags/case_tag_unit_test.rb +10 -0
- data/test/unit/tags/for_tag_unit_test.rb +13 -0
- data/test/unit/tags/if_tag_unit_test.rb +8 -0
- data/test/unit/template_unit_test.rb +70 -0
- data/test/unit/tokenizer_unit_test.rb +38 -0
- data/test/unit/variable_unit_test.rb +150 -0
- metadata +144 -15
- data/lib/extras/liquid_view.rb +0 -51
- data/lib/liquid/htmltags.rb +0 -74
- data/lib/liquid/tags/default_content.rb +0 -21
- data/lib/locomotivecms-liquid.rb +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 390ba2f8603e9d8dd6a70219c727e7912f5a0af6
|
4
|
+
data.tar.gz: 3dab20ea5da6160a906c8946b6b8d6e3f96554de
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d64a2bcf781c84c400d6b17d56e047bfc3c4347d67a86bcc5f15ffdbea84b6f0665acaf18b1009ea5aaad6bad71c724f397a329ee8f04bc7d3d48c3dcce2cfad
|
7
|
+
data.tar.gz: 3851c097575f9c31845cb8b396fd795a3a10b8037377b19463516225415a259b7c16d4bc970bbc28e4bf2b6c3e7f47d16b2b8f1bd42a360ec0a73d4781f19d88
|
data/History.md
CHANGED
@@ -1,18 +1,53 @@
|
|
1
1
|
# Liquid Version History
|
2
2
|
|
3
|
-
|
4
|
-
The following releases will only be tested against Ruby 1.9 and Ruby 2.0 and are likely to break on Ruby 1.8.
|
5
|
-
|
6
|
-
## 2.6.0 / Master branch (not yet released)
|
3
|
+
## 3.0.0 / not yet released / branch "master"
|
7
4
|
|
8
5
|
* ...
|
6
|
+
* Block parsing moved to BlockBody class, see #458 [Dylan Thacker-Smith, dylanahsmith]
|
7
|
+
* Removed Block#end_tag. Instead, override parse with `super` followed by your code. See #446 [Dylan Thacker-Smith, dylanahsmith]
|
8
|
+
* Fixed condition with wrong data types, see #423 [Bogdan Gusiev]
|
9
|
+
* Add url_encode to standard filters, see #421 [Derrick Reimer, djreimer]
|
10
|
+
* Add uniq to standard filters [Florian Weingarten, fw42]
|
11
|
+
* Add exception_handler feature, see #397 and #254 [Bogdan Gusiev, bogdan and Florian Weingarten, fw42]
|
12
|
+
* Optimize variable parsing to avoid repeated regex evaluation during template rendering #383 [Jason Hiltz-Laforge, jasonhl]
|
13
|
+
* Optimize checking for block interrupts to reduce object allocation #380 [Jason Hiltz-Laforge, jasonhl]
|
14
|
+
* Properly set context rethrow_errors on render! #349 [Thierry Joyal, tjoyal]
|
15
|
+
* Fix broken rendering of variables which are equal to false, see #345 [Florian Weingarten, fw42]
|
16
|
+
* Remove ActionView template handler [Dylan Thacker-Smith, dylanahsmith]
|
17
|
+
* Freeze lots of string literals for new Ruby 2.1 optimization, see #297 [Florian Weingarten, fw42]
|
18
|
+
* Allow newlines in tags and variables, see #324 [Dylan Thacker-Smith, dylanahsmith]
|
19
|
+
* Tag#parse is called after initialize, which now takes options instead of tokens as the 3rd argument. See #321 [Dylan Thacker-Smith, dylanahsmith]
|
20
|
+
* Raise `Liquid::ArgumentError` instead of `::ArgumentError` when filter has wrong number of arguments #309 [Bogdan Gusiev, bogdan]
|
21
|
+
* Add a to_s default for liquid drops, see #306 [Adam Doeler, releod]
|
22
|
+
* Add strip, lstrip, and rstrip to standard filters [Florian Weingarten, fw42]
|
23
|
+
* Make if, for & case tags return complete and consistent nodelists, see #250 [Nick Jones, dntj]
|
24
|
+
* Prevent arbitrary method invocation on condition objects, see #274 [Dylan Thacker-Smith, dylanahsmith]
|
25
|
+
* Don't call to_sym when creating conditions for security reasons, see #273 [Bouke van der Bijl, bouk]
|
26
|
+
* Fix resource counting bug with respond_to?(:length), see #263 [Florian Weingarten, fw42]
|
27
|
+
* Allow specifying custom patterns for template filenames, see #284 [Andrei Gladkyi, agladkyi]
|
28
|
+
* Allow drops to optimize loading a slice of elements, see #282 [Tom Burns, boourns]
|
29
|
+
* Support for passing variables to snippets in subdirs, see #271 [Joost Hietbrink, joost]
|
30
|
+
* Add a class cache to avoid runtime extend calls, see #249 [James Tucker, raggi]
|
31
|
+
* Remove some legacy Ruby 1.8 compatibility code, see #276 [Florian Weingarten, fw42]
|
32
|
+
* Add default filter to standard filters, see #267 [Derrick Reimer, djreimer]
|
9
33
|
* Add optional strict parsing and warn parsing, see #235 [Tristan Hume, trishume]
|
10
34
|
* Add I18n syntax error translation, see #241 [Simon Hørup Eskildsen, Sirupsen]
|
11
35
|
* Make sort filter work on enumerable drops, see #239 [Florian Weingarten, fw42]
|
12
36
|
* Fix clashing method names in enumerable drops, see #238 [Florian Weingarten, fw42]
|
13
37
|
* Make map filter work on enumerable drops, see #233 [Florian Weingarten, fw42]
|
14
|
-
* Fix security issue with map filter, see #230, #232, #234, #237 [Florian Weingarten, fw42]
|
15
38
|
* Improved whitespace stripping for blank blocks, related to #216 [Florian Weingarten, fw42]
|
39
|
+
|
40
|
+
## 2.6.1 / 2014-01-10 / branch "2-6-stable"
|
41
|
+
|
42
|
+
Security fix, cherry-picked from master (4e14a65):
|
43
|
+
* Don't call to_sym when creating conditions for security reasons, see #273 [Bouke van der Bijl, bouk]
|
44
|
+
* Prevent arbitrary method invocation on condition objects, see #274 [Dylan Thacker-Smith, dylanahsmith]
|
45
|
+
|
46
|
+
## 2.6.0 / 2013-11-25
|
47
|
+
|
48
|
+
IMPORTANT: Liquid 2.6 is going to be the last version of Liquid which maintains explicit Ruby 1.8 compatability.
|
49
|
+
The following releases will only be tested against Ruby 1.9 and Ruby 2.0 and are likely to break on Ruby 1.8.
|
50
|
+
|
16
51
|
* Bugfix for #106: fix example servlet [gnowoel]
|
17
52
|
* Bugfix for #97: strip_html filter supports multi-line tags [Jo Liss, joliss]
|
18
53
|
* Bugfix for #114: strip_html filter supports style tags [James Allardice, jamesallardice]
|
@@ -21,6 +56,7 @@ The following releases will only be tested against Ruby 1.9 and Ruby 2.0 and are
|
|
21
56
|
* Bugfix for #204: 'raw' parsing bug [Florian Weingarten, fw42]
|
22
57
|
* Bugfix for #150: 'for' parsing bug [Peter Schröder, phoet]
|
23
58
|
* Bugfix for #126: Strip CRLF in strip_newline [Peter Schröder, phoet]
|
59
|
+
* Bugfix for #174, "can't convert Fixnum into String" for "replace" [wǒ_is神仙, jsw0528]
|
24
60
|
* Allow a Liquid::Drop to be passed into Template#render [Daniel Huckstep, darkhelmet]
|
25
61
|
* Resource limits [Florian Weingarten, fw42]
|
26
62
|
* Add reverse filter [Jay Strybis, unreal]
|
@@ -31,6 +67,27 @@ The following releases will only be tested against Ruby 1.9 and Ruby 2.0 and are
|
|
31
67
|
* Better documentation for 'include' tag (closes #163) [Peter Schröder, phoet]
|
32
68
|
* Use of BigDecimal on filters to have better precision (closes #155) [Arthur Nogueira Neves, arthurnn]
|
33
69
|
|
70
|
+
## 2.5.5 / 2014-01-10 / branch "2-5-stable"
|
71
|
+
|
72
|
+
Security fix, cherry-picked from master (4e14a65):
|
73
|
+
* Don't call to_sym when creating conditions for security reasons, see #273 [Bouke van der Bijl, bouk]
|
74
|
+
* Prevent arbitrary method invocation on condition objects, see #274 [Dylan Thacker-Smith, dylanahsmith]
|
75
|
+
|
76
|
+
## 2.5.4 / 2013-11-11
|
77
|
+
|
78
|
+
* Fix "can't convert Fixnum into String" for "replace", see #173, [wǒ_is神仙, jsw0528]
|
79
|
+
|
80
|
+
## 2.5.3 / 2013-10-09
|
81
|
+
|
82
|
+
* #232, #234, #237: Fix map filter bugs [Florian Weingarten, fw42]
|
83
|
+
|
84
|
+
## 2.5.2 / 2013-09-03 / deleted
|
85
|
+
|
86
|
+
Yanked from rubygems, as it contained too many changes that broke compatibility. Those changes will be on following major releases.
|
87
|
+
|
88
|
+
## 2.5.1 / 2013-07-24
|
89
|
+
|
90
|
+
* #230: Fix security issue with map filter, Use invoke_drop in map filter [Florian Weingarten, fw42]
|
34
91
|
|
35
92
|
## 2.5.0 / 2013-03-06
|
36
93
|
|
data/README.md
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
[![Build Status](https://api.travis-ci.org/Shopify/liquid.svg?branch=master)](http://travis-ci.org/Shopify/liquid)
|
2
|
+
[![Inline docs](http://inch-ci.org/github/Shopify/liquid.svg?branch=master)](http://inch-ci.org/github/Shopify/liquid)
|
3
|
+
|
1
4
|
# Liquid template engine
|
2
5
|
|
3
6
|
* [Contributing guidelines](CONTRIBUTING.md)
|
4
7
|
* [Version history](History.md)
|
5
8
|
* [Liquid documentation from Shopify](http://docs.shopify.com/themes/liquid-basics)
|
6
|
-
* [Liquid Wiki from Shopify](http://wiki.shopify.com/Liquid)
|
7
9
|
* [Liquid Wiki at GitHub](https://github.com/Shopify/liquid/wiki)
|
8
10
|
* [Website](http://liquidmarkup.org/)
|
9
11
|
|
@@ -52,7 +54,7 @@ For standard use you can just pass it the content of a file and call render with
|
|
52
54
|
|
53
55
|
Setting the error mode of Liquid lets you specify how strictly you want your templates to be interpreted.
|
54
56
|
Normally the parser is very lax and will accept almost anything without error. Unfortunately this can make
|
55
|
-
it very hard to debug and can lead to unexpected behaviour.
|
57
|
+
it very hard to debug and can lead to unexpected behaviour.
|
56
58
|
|
57
59
|
Liquid also comes with a stricter parser that can be used when editing templates to give better error messages
|
58
60
|
when templates are invalid. You can enable this new parser like this:
|
@@ -71,5 +73,3 @@ This is useful for doing things like enabling strict mode only in the theme edit
|
|
71
73
|
|
72
74
|
It is recommended that you enable `:strict` or `:warn` mode on new apps to stop invalid templates from being created.
|
73
75
|
It is also recommended that you use it in the template editors of existing apps to give editors better error messages.
|
74
|
-
|
75
|
-
[![Build Status](https://secure.travis-ci.org/Shopify/liquid.png)](http://travis-ci.org/Shopify/liquid)
|
data/lib/liquid.rb
CHANGED
@@ -21,9 +21,9 @@
|
|
21
21
|
|
22
22
|
module Liquid
|
23
23
|
FilterSeparator = /\|/
|
24
|
-
ArgumentSeparator = ','
|
25
|
-
FilterArgumentSeparator = ':'
|
26
|
-
VariableAttributeSeparator = '.'
|
24
|
+
ArgumentSeparator = ','.freeze
|
25
|
+
FilterArgumentSeparator = ':'.freeze
|
26
|
+
VariableAttributeSeparator = '.'.freeze
|
27
27
|
TagStart = /\{\%/
|
28
28
|
TagEnd = /\%\}/
|
29
29
|
VariableSignature = /\(?[\w\-\.\[\]]\)?/
|
@@ -33,16 +33,14 @@ module Liquid
|
|
33
33
|
VariableIncompleteEnd = /\}\}?/
|
34
34
|
QuotedString = /"[^"]*"|'[^']*'/
|
35
35
|
QuotedFragment = /#{QuotedString}|(?:[^\s,\|'"]|#{QuotedString})+/o
|
36
|
-
StrictQuotedFragment = /"[^"]+"|'[^']+'|[^\s|:,]+/
|
37
|
-
FirstFilterArgument = /#{FilterArgumentSeparator}(?:#{StrictQuotedFragment})/o
|
38
|
-
OtherFilterArgument = /#{ArgumentSeparator}(?:#{StrictQuotedFragment})/o
|
39
|
-
SpacelessFilter = /^(?:'[^']+'|"[^"]+"|[^'"])*#{FilterSeparator}(?:#{StrictQuotedFragment})(?:#{FirstFilterArgument}(?:#{OtherFilterArgument})*)?/o
|
40
|
-
Expression = /(?:#{QuotedFragment}(?:#{SpacelessFilter})*)/o
|
41
36
|
TagAttributes = /(\w+)\s*\:\s*(#{QuotedFragment})/o
|
42
37
|
AnyStartingTag = /\{\{|\{\%/
|
43
|
-
PartialTemplateParser = /#{TagStart}.*?#{TagEnd}|#{VariableStart}.*?#{VariableIncompleteEnd}/
|
44
|
-
TemplateParser = /(#{PartialTemplateParser}|#{AnyStartingTag})/
|
38
|
+
PartialTemplateParser = /#{TagStart}.*?#{TagEnd}|#{VariableStart}.*?#{VariableIncompleteEnd}/om
|
39
|
+
TemplateParser = /(#{PartialTemplateParser}|#{AnyStartingTag})/om
|
45
40
|
VariableParser = /\[[^\]]+\]|#{VariableSegment}+\??/o
|
41
|
+
|
42
|
+
singleton_class.send(:attr_accessor, :cache_classes)
|
43
|
+
self.cache_classes = true
|
46
44
|
end
|
47
45
|
|
48
46
|
require "liquid/version"
|
@@ -54,19 +52,25 @@ require 'liquid/extensions'
|
|
54
52
|
require 'liquid/errors'
|
55
53
|
require 'liquid/interrupts'
|
56
54
|
require 'liquid/strainer'
|
55
|
+
require 'liquid/expression'
|
57
56
|
require 'liquid/context'
|
57
|
+
require 'liquid/parser_switching'
|
58
58
|
require 'liquid/tag'
|
59
59
|
require 'liquid/block'
|
60
|
+
require 'liquid/block_body'
|
60
61
|
require 'liquid/document'
|
61
62
|
require 'liquid/variable'
|
63
|
+
require 'liquid/variable_lookup'
|
64
|
+
require 'liquid/range_lookup'
|
62
65
|
require 'liquid/file_system'
|
66
|
+
require 'liquid/resource_limits'
|
63
67
|
require 'liquid/template'
|
64
|
-
require 'liquid/htmltags'
|
65
68
|
require 'liquid/standardfilters'
|
66
69
|
require 'liquid/condition'
|
67
70
|
require 'liquid/module_ex'
|
68
71
|
require 'liquid/utils'
|
72
|
+
require 'liquid/token'
|
69
73
|
|
70
74
|
# Load all the tags of the standard library
|
71
75
|
#
|
72
|
-
Dir[File.dirname(__FILE__) + '/liquid/tags/*.rb'].each { |f| require f }
|
76
|
+
Dir[File.dirname(__FILE__) + '/liquid/{tags,drops}/*.rb'].each { |f| require f }
|
data/lib/liquid/block.rb
CHANGED
@@ -1,69 +1,26 @@
|
|
1
1
|
module Liquid
|
2
2
|
class Block < Tag
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
ContentOfVariable = /^#{VariableStart}(.*)#{VariableEnd}$/o
|
7
|
-
|
8
|
-
def blank?
|
9
|
-
@blank || false
|
3
|
+
def initialize(tag_name, markup, options)
|
4
|
+
super
|
5
|
+
@blank = true
|
10
6
|
end
|
11
7
|
|
12
8
|
def parse(tokens)
|
13
|
-
|
14
|
-
|
15
|
-
@nodelist ||= []
|
16
|
-
@nodelist.clear
|
17
|
-
|
18
|
-
# All child tags of the current block.
|
19
|
-
@children = []
|
20
|
-
|
21
|
-
while token = tokens.shift
|
22
|
-
case token
|
23
|
-
when IsTag
|
24
|
-
if token =~ FullToken
|
25
|
-
|
26
|
-
# if we found the proper block delimiter just end parsing here and let the outer block
|
27
|
-
# proceed
|
28
|
-
if block_delimiter == $1
|
29
|
-
end_tag
|
30
|
-
return
|
31
|
-
end
|
32
|
-
|
33
|
-
# fetch the tag from registered blocks
|
34
|
-
if tag = Template.tags[$1]
|
35
|
-
new_tag = tag.new_with_options($1, $2, tokens, @options.merge(line: line))
|
36
|
-
@blank &&= new_tag.blank?
|
37
|
-
@nodelist << new_tag
|
38
|
-
@children << new_tag
|
39
|
-
else
|
40
|
-
# this tag is not registered with the system
|
41
|
-
# pass it to the current block for special handling or error reporting
|
42
|
-
unknown_tag($1, $2, tokens)
|
43
|
-
end
|
44
|
-
else
|
45
|
-
raise SyntaxError.new(options[:locale].t("errors.syntax.tag_termination", :token => token, :tag_end => TagEnd.inspect), line)
|
46
|
-
end
|
47
|
-
when IsVariable
|
48
|
-
new_var = create_variable(token)
|
49
|
-
@nodelist << new_var
|
50
|
-
@children << new_var
|
51
|
-
@blank = false
|
52
|
-
when ''
|
53
|
-
# pass
|
54
|
-
else
|
55
|
-
self.line += token.count("\n") if @options[:count_lines] || Template.count_lines
|
56
|
-
@nodelist << token
|
57
|
-
@blank &&= (token =~ /\A\s*\z/)
|
58
|
-
end
|
9
|
+
@body = BlockBody.new
|
10
|
+
while more = parse_body(@body, tokens)
|
59
11
|
end
|
12
|
+
end
|
60
13
|
|
61
|
-
|
14
|
+
def render(context)
|
15
|
+
@body.render(context)
|
16
|
+
end
|
17
|
+
|
18
|
+
def blank?
|
19
|
+
@blank
|
20
|
+
end
|
62
21
|
|
63
|
-
|
64
|
-
|
65
|
-
# of type Document
|
66
|
-
assert_missing_delimitation!
|
22
|
+
def nodelist
|
23
|
+
@body.nodelist
|
67
24
|
end
|
68
25
|
|
69
26
|
# warnings of this block and all sub-tags
|
@@ -71,90 +28,52 @@ module Liquid
|
|
71
28
|
all_warnings = []
|
72
29
|
all_warnings.concat(@warnings) if @warnings
|
73
30
|
|
74
|
-
(
|
75
|
-
all_warnings.concat(node.warnings || [])
|
31
|
+
(nodelist || []).each do |node|
|
32
|
+
all_warnings.concat(node.warnings || []) if node.respond_to?(:warnings)
|
76
33
|
end
|
77
34
|
|
78
35
|
all_warnings
|
79
36
|
end
|
80
37
|
|
81
|
-
def end_tag
|
82
|
-
end
|
83
|
-
|
84
38
|
def unknown_tag(tag, params, tokens)
|
85
39
|
case tag
|
86
|
-
when 'else'
|
87
|
-
raise SyntaxError.new(options[:locale].t("errors.syntax.unexpected_else",
|
88
|
-
:block_name => block_name)
|
89
|
-
when 'end'
|
90
|
-
raise SyntaxError.new(options[:locale].t("errors.syntax.invalid_delimiter",
|
40
|
+
when 'else'.freeze
|
41
|
+
raise SyntaxError.new(options[:locale].t("errors.syntax.unexpected_else".freeze,
|
42
|
+
:block_name => block_name))
|
43
|
+
when 'end'.freeze
|
44
|
+
raise SyntaxError.new(options[:locale].t("errors.syntax.invalid_delimiter".freeze,
|
91
45
|
:block_name => block_name,
|
92
|
-
:block_delimiter => block_delimiter)
|
46
|
+
:block_delimiter => block_delimiter))
|
93
47
|
else
|
94
|
-
raise SyntaxError.new(options[:locale].t("errors.syntax.unknown_tag", :tag => tag)
|
48
|
+
raise SyntaxError.new(options[:locale].t("errors.syntax.unknown_tag".freeze, :tag => tag))
|
95
49
|
end
|
96
50
|
end
|
97
51
|
|
98
|
-
def block_delimiter
|
99
|
-
"end#{block_name}"
|
100
|
-
end
|
101
|
-
|
102
52
|
def block_name
|
103
53
|
@tag_name
|
104
54
|
end
|
105
55
|
|
106
|
-
def
|
107
|
-
|
108
|
-
return Variable.new(content.first, @options)
|
109
|
-
end
|
110
|
-
raise SyntaxError.new(options[:locale].t("errors.syntax.variable_termination", :token => token, :tag_end => VariableEnd.inspect), line)
|
111
|
-
end
|
112
|
-
|
113
|
-
def render(context)
|
114
|
-
render_all(@nodelist, context)
|
56
|
+
def block_delimiter
|
57
|
+
@block_delimiter ||= "end#{block_name}"
|
115
58
|
end
|
116
59
|
|
117
60
|
protected
|
118
61
|
|
119
|
-
def
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
def render_all(list, context)
|
124
|
-
output = []
|
125
|
-
context.resource_limits[:render_length_current] = 0
|
126
|
-
context.resource_limits[:render_score_current] += list.length
|
62
|
+
def parse_body(body, tokens)
|
63
|
+
body.parse(tokens, options) do |end_tag_name, end_tag_params|
|
64
|
+
@blank &&= body.blank?
|
127
65
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
begin
|
133
|
-
# If we get an Interrupt that means the block must stop processing. An
|
134
|
-
# Interrupt is any command that stops block execution such as {% break %}
|
135
|
-
# or {% continue %}
|
136
|
-
if token.is_a? Continue or token.is_a? Break
|
137
|
-
context.push_interrupt(token.interrupt)
|
138
|
-
break
|
139
|
-
end
|
140
|
-
|
141
|
-
token_output = (token.respond_to?(:render) ? token.render(context) : token)
|
142
|
-
context.resource_limits[:render_length_current] += (token_output.respond_to?(:length) ? token_output.length : 1)
|
143
|
-
if context.resource_limits_reached?
|
144
|
-
context.resource_limits[:reached] = true
|
145
|
-
raise MemoryError.new("Memory limits exceeded", token.respond_to?(:line) ? token.line : nil)
|
146
|
-
end
|
147
|
-
unless token.is_a?(Block) && token.blank?
|
148
|
-
output << token_output
|
149
|
-
end
|
150
|
-
rescue MemoryError => e
|
151
|
-
raise e
|
152
|
-
rescue ::StandardError => e
|
153
|
-
output << (context.handle_error(e))
|
66
|
+
return false if end_tag_name == block_delimiter
|
67
|
+
unless end_tag_name
|
68
|
+
raise SyntaxError.new(@options[:locale].t("errors.syntax.tag_never_closed".freeze, :block_name => block_name))
|
154
69
|
end
|
70
|
+
|
71
|
+
# this tag is not registered with the system
|
72
|
+
# pass it to the current block for special handling or error reporting
|
73
|
+
unknown_tag(end_tag_name, end_tag_params, tokens)
|
155
74
|
end
|
156
75
|
|
157
|
-
|
76
|
+
true
|
158
77
|
end
|
159
78
|
end
|
160
79
|
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
module Liquid
|
2
|
+
class BlockBody
|
3
|
+
FullToken = /\A#{TagStart}\s*(\w+)\s*(.*)?#{TagEnd}\z/om
|
4
|
+
ContentOfVariable = /\A#{VariableStart}(.*)#{VariableEnd}\z/om
|
5
|
+
TAGSTART = "{%".freeze
|
6
|
+
VARSTART = "{{".freeze
|
7
|
+
|
8
|
+
attr_reader :nodelist
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@nodelist = []
|
12
|
+
@blank = true
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse(tokens, options)
|
16
|
+
while token = tokens.shift
|
17
|
+
begin
|
18
|
+
unless token.empty?
|
19
|
+
case
|
20
|
+
when token.start_with?(TAGSTART)
|
21
|
+
if token =~ FullToken
|
22
|
+
tag_name = $1
|
23
|
+
markup = $2
|
24
|
+
# fetch the tag from registered blocks
|
25
|
+
if tag = Template.tags[tag_name]
|
26
|
+
markup = token.child(markup) if token.is_a?(Token)
|
27
|
+
new_tag = tag.parse(tag_name, markup, tokens, options)
|
28
|
+
new_tag.line_number = token.line_number if token.is_a?(Token)
|
29
|
+
@blank &&= new_tag.blank?
|
30
|
+
@nodelist << new_tag
|
31
|
+
else
|
32
|
+
# end parsing if we reach an unknown tag and let the caller decide
|
33
|
+
# determine how to proceed
|
34
|
+
return yield tag_name, markup
|
35
|
+
end
|
36
|
+
else
|
37
|
+
raise_missing_tag_terminator(token, options)
|
38
|
+
end
|
39
|
+
when token.start_with?(VARSTART)
|
40
|
+
new_var = create_variable(token, options)
|
41
|
+
new_var.line_number = token.line_number if token.is_a?(Token)
|
42
|
+
@nodelist << new_var
|
43
|
+
@blank = false
|
44
|
+
else
|
45
|
+
@nodelist << token
|
46
|
+
@blank &&= !!(token =~ /\A\s*\z/)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
rescue SyntaxError => e
|
50
|
+
e.set_line_number_from_token(token)
|
51
|
+
raise
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
yield nil, nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def blank?
|
59
|
+
@blank
|
60
|
+
end
|
61
|
+
|
62
|
+
def warnings
|
63
|
+
all_warnings = []
|
64
|
+
nodelist.each do |node|
|
65
|
+
all_warnings.concat(node.warnings || []) if node.respond_to?(:warnings)
|
66
|
+
end
|
67
|
+
all_warnings
|
68
|
+
end
|
69
|
+
|
70
|
+
def render(context)
|
71
|
+
output = []
|
72
|
+
context.resource_limits.render_score += @nodelist.length
|
73
|
+
|
74
|
+
@nodelist.each do |token|
|
75
|
+
# Break out if we have any unhanded interrupts.
|
76
|
+
break if context.has_interrupt?
|
77
|
+
|
78
|
+
begin
|
79
|
+
# If we get an Interrupt that means the block must stop processing. An
|
80
|
+
# Interrupt is any command that stops block execution such as {% break %}
|
81
|
+
# or {% continue %}
|
82
|
+
if token.is_a?(Continue) or token.is_a?(Break)
|
83
|
+
context.push_interrupt(token.interrupt)
|
84
|
+
break
|
85
|
+
end
|
86
|
+
|
87
|
+
token_output = render_token(token, context)
|
88
|
+
|
89
|
+
unless token.is_a?(Block) && token.blank?
|
90
|
+
output << token_output
|
91
|
+
end
|
92
|
+
rescue MemoryError => e
|
93
|
+
raise e
|
94
|
+
rescue ::StandardError => e
|
95
|
+
output << context.handle_error(e, token)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
output.join
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def render_token(token, context)
|
105
|
+
token_output = (token.respond_to?(:render) ? token.render(context) : token)
|
106
|
+
token_str = token_output.is_a?(Array) ? token_output.join : token_output.to_s
|
107
|
+
|
108
|
+
context.resource_limits.render_length += token_str.length
|
109
|
+
if context.resource_limits.reached?
|
110
|
+
raise MemoryError.new("Memory limits exceeded".freeze)
|
111
|
+
end
|
112
|
+
token_str
|
113
|
+
end
|
114
|
+
|
115
|
+
def create_variable(token, options)
|
116
|
+
token.scan(ContentOfVariable) do |content|
|
117
|
+
markup = token.is_a?(Token) ? token.child(content.first) : content.first
|
118
|
+
return Variable.new(markup, options)
|
119
|
+
end
|
120
|
+
raise_missing_variable_terminator(token, options)
|
121
|
+
end
|
122
|
+
|
123
|
+
def raise_missing_tag_terminator(token, options)
|
124
|
+
raise SyntaxError.new(options[:locale].t("errors.syntax.tag_termination".freeze, :token => token, :tag_end => TagEnd.inspect))
|
125
|
+
end
|
126
|
+
|
127
|
+
def raise_missing_variable_terminator(token, options)
|
128
|
+
raise SyntaxError.new(options[:locale].t("errors.syntax.variable_termination".freeze, :token => token, :tag_end => VariableEnd.inspect))
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|