locomotivecms-liquid 2.6.0 → 4.0.0.alpha
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 +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
|
+
[](http://travis-ci.org/Shopify/liquid)
|
|
2
|
+
[](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
|
-
[](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
|