liquid 3.0.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/History.md +130 -62
- data/README.md +31 -0
- data/lib/liquid/block.rb +31 -124
- data/lib/liquid/block_body.rb +75 -59
- data/lib/liquid/condition.rb +23 -22
- data/lib/liquid/context.rb +51 -60
- data/lib/liquid/document.rb +19 -9
- data/lib/liquid/drop.rb +17 -16
- data/lib/liquid/errors.rb +20 -24
- data/lib/liquid/expression.rb +15 -3
- data/lib/liquid/extensions.rb +13 -7
- data/lib/liquid/file_system.rb +11 -11
- data/lib/liquid/forloop_drop.rb +42 -0
- data/lib/liquid/i18n.rb +5 -5
- data/lib/liquid/interrupts.rb +1 -2
- data/lib/liquid/lexer.rb +6 -4
- data/lib/liquid/locales/en.yml +5 -1
- data/lib/liquid/parse_context.rb +37 -0
- data/lib/liquid/parser.rb +1 -1
- data/lib/liquid/parser_switching.rb +4 -4
- data/lib/liquid/profiler/hooks.rb +7 -7
- data/lib/liquid/profiler.rb +18 -19
- data/lib/liquid/range_lookup.rb +16 -1
- data/lib/liquid/resource_limits.rb +23 -0
- data/lib/liquid/standardfilters.rb +121 -61
- data/lib/liquid/strainer.rb +32 -29
- data/lib/liquid/tablerowloop_drop.rb +62 -0
- data/lib/liquid/tag.rb +9 -8
- data/lib/liquid/tags/assign.rb +17 -4
- data/lib/liquid/tags/break.rb +0 -3
- data/lib/liquid/tags/capture.rb +2 -2
- data/lib/liquid/tags/case.rb +19 -12
- data/lib/liquid/tags/comment.rb +2 -2
- data/lib/liquid/tags/cycle.rb +6 -6
- data/lib/liquid/tags/decrement.rb +1 -4
- data/lib/liquid/tags/for.rb +95 -75
- data/lib/liquid/tags/if.rb +48 -43
- data/lib/liquid/tags/ifchanged.rb +0 -2
- data/lib/liquid/tags/include.rb +61 -52
- data/lib/liquid/tags/raw.rb +32 -4
- data/lib/liquid/tags/table_row.rb +12 -31
- data/lib/liquid/tags/unless.rb +4 -5
- data/lib/liquid/template.rb +42 -54
- data/lib/liquid/tokenizer.rb +31 -0
- data/lib/liquid/utils.rb +52 -8
- data/lib/liquid/variable.rb +46 -45
- data/lib/liquid/variable_lookup.rb +9 -5
- data/lib/liquid/version.rb +1 -1
- data/lib/liquid.rb +9 -7
- data/test/integration/assign_test.rb +18 -8
- data/test/integration/blank_test.rb +14 -14
- data/test/integration/capture_test.rb +10 -0
- data/test/integration/context_test.rb +2 -2
- data/test/integration/document_test.rb +19 -0
- data/test/integration/drop_test.rb +42 -40
- data/test/integration/error_handling_test.rb +99 -46
- data/test/integration/filter_test.rb +72 -19
- data/test/integration/hash_ordering_test.rb +9 -9
- data/test/integration/output_test.rb +34 -27
- data/test/integration/parsing_quirks_test.rb +15 -13
- data/test/integration/render_profiling_test.rb +20 -20
- data/test/integration/security_test.rb +9 -7
- data/test/integration/standard_filter_test.rb +198 -42
- data/test/integration/tags/break_tag_test.rb +1 -2
- data/test/integration/tags/continue_tag_test.rb +0 -1
- data/test/integration/tags/for_tag_test.rb +133 -98
- data/test/integration/tags/if_else_tag_test.rb +96 -77
- data/test/integration/tags/include_tag_test.rb +34 -30
- data/test/integration/tags/increment_tag_test.rb +10 -11
- data/test/integration/tags/raw_tag_test.rb +7 -1
- data/test/integration/tags/standard_tag_test.rb +121 -122
- data/test/integration/tags/statements_test.rb +3 -5
- data/test/integration/tags/table_row_test.rb +20 -19
- data/test/integration/tags/unless_else_tag_test.rb +6 -6
- data/test/integration/template_test.rb +190 -49
- data/test/integration/trim_mode_test.rb +525 -0
- data/test/integration/variable_test.rb +23 -13
- data/test/test_helper.rb +44 -9
- data/test/unit/block_unit_test.rb +8 -5
- data/test/unit/condition_unit_test.rb +86 -77
- data/test/unit/context_unit_test.rb +48 -57
- data/test/unit/file_system_unit_test.rb +3 -3
- data/test/unit/i18n_unit_test.rb +2 -2
- data/test/unit/lexer_unit_test.rb +11 -8
- data/test/unit/parser_unit_test.rb +2 -2
- data/test/unit/regexp_unit_test.rb +1 -1
- data/test/unit/strainer_unit_test.rb +85 -8
- data/test/unit/tag_unit_test.rb +7 -2
- data/test/unit/tags/case_tag_unit_test.rb +1 -1
- data/test/unit/tags/for_tag_unit_test.rb +2 -2
- data/test/unit/tags/if_tag_unit_test.rb +1 -1
- data/test/unit/template_unit_test.rb +14 -5
- data/test/unit/tokenizer_unit_test.rb +24 -7
- data/test/unit/variable_unit_test.rb +66 -43
- metadata +55 -50
- data/lib/liquid/module_ex.rb +0 -62
- data/lib/liquid/token.rb +0 -18
- data/test/unit/module_ex_unit_test.rb +0 -87
- /data/{MIT-LICENSE → LICENSE} +0 -0
data/lib/liquid/errors.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
module Liquid
|
2
2
|
class Error < ::StandardError
|
3
3
|
attr_accessor :line_number
|
4
|
+
attr_accessor :template_name
|
4
5
|
attr_accessor :markup_context
|
5
6
|
|
6
|
-
def to_s(with_prefix=true)
|
7
|
+
def to_s(with_prefix = true)
|
7
8
|
str = ""
|
8
9
|
str << message_prefix if with_prefix
|
9
10
|
str << super()
|
@@ -16,20 +17,6 @@ module Liquid
|
|
16
17
|
str
|
17
18
|
end
|
18
19
|
|
19
|
-
def set_line_number_from_token(token)
|
20
|
-
return unless token.respond_to?(:line_number)
|
21
|
-
return if self.line_number
|
22
|
-
self.line_number = token.line_number
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.render(e)
|
26
|
-
if e.is_a?(Liquid::Error)
|
27
|
-
e.to_s
|
28
|
-
else
|
29
|
-
"Liquid error: #{e.to_s}"
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
20
|
private
|
34
21
|
|
35
22
|
def message_prefix
|
@@ -41,7 +28,9 @@ module Liquid
|
|
41
28
|
end
|
42
29
|
|
43
30
|
if line_number
|
44
|
-
str << " (
|
31
|
+
str << " ("
|
32
|
+
str << template_name << " " if template_name
|
33
|
+
str << "line " << line_number.to_s << ")"
|
45
34
|
end
|
46
35
|
|
47
36
|
str << ": "
|
@@ -49,12 +38,19 @@ module Liquid
|
|
49
38
|
end
|
50
39
|
end
|
51
40
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
41
|
+
ArgumentError = Class.new(Error)
|
42
|
+
ContextError = Class.new(Error)
|
43
|
+
FileSystemError = Class.new(Error)
|
44
|
+
StandardError = Class.new(Error)
|
45
|
+
SyntaxError = Class.new(Error)
|
46
|
+
StackLevelError = Class.new(Error)
|
47
|
+
TaintedError = Class.new(Error)
|
48
|
+
MemoryError = Class.new(Error)
|
49
|
+
ZeroDivisionError = Class.new(Error)
|
50
|
+
FloatDomainError = Class.new(Error)
|
51
|
+
UndefinedVariable = Class.new(Error)
|
52
|
+
UndefinedDropMethod = Class.new(Error)
|
53
|
+
UndefinedFilter = Class.new(Error)
|
54
|
+
MethodOverrideError = Class.new(Error)
|
55
|
+
InternalError = Class.new(Error)
|
60
56
|
end
|
data/lib/liquid/expression.rb
CHANGED
@@ -1,11 +1,24 @@
|
|
1
1
|
module Liquid
|
2
2
|
class Expression
|
3
|
+
class MethodLiteral
|
4
|
+
attr_reader :method_name, :to_s
|
5
|
+
|
6
|
+
def initialize(method_name, to_s)
|
7
|
+
@method_name = method_name
|
8
|
+
@to_s = to_s
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_liquid
|
12
|
+
to_s
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
3
16
|
LITERALS = {
|
4
17
|
nil => nil, 'nil'.freeze => nil, 'null'.freeze => nil, ''.freeze => nil,
|
5
18
|
'true'.freeze => true,
|
6
19
|
'false'.freeze => false,
|
7
|
-
'blank'.freeze => :blank?,
|
8
|
-
'empty'.freeze => :empty
|
20
|
+
'blank'.freeze => MethodLiteral.new(:blank?, '').freeze,
|
21
|
+
'empty'.freeze => MethodLiteral.new(:empty?, '').freeze
|
9
22
|
}
|
10
23
|
|
11
24
|
def self.parse(markup)
|
@@ -28,6 +41,5 @@ module Liquid
|
|
28
41
|
end
|
29
42
|
end
|
30
43
|
end
|
31
|
-
|
32
44
|
end
|
33
45
|
end
|
data/lib/liquid/extensions.rb
CHANGED
@@ -7,44 +7,50 @@ class String # :nodoc:
|
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
-
class Array
|
10
|
+
class Array # :nodoc:
|
11
11
|
def to_liquid
|
12
12
|
self
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
class Hash
|
16
|
+
class Hash # :nodoc:
|
17
17
|
def to_liquid
|
18
18
|
self
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
class Numeric
|
22
|
+
class Numeric # :nodoc:
|
23
23
|
def to_liquid
|
24
24
|
self
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
class
|
28
|
+
class Range # :nodoc:
|
29
29
|
def to_liquid
|
30
30
|
self
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
class
|
34
|
+
class Time # :nodoc:
|
35
35
|
def to_liquid
|
36
36
|
self
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
class Date
|
40
|
+
class DateTime < Date # :nodoc:
|
41
|
+
def to_liquid
|
42
|
+
self
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Date # :nodoc:
|
41
47
|
def to_liquid
|
42
48
|
self
|
43
49
|
end
|
44
50
|
end
|
45
51
|
|
46
52
|
class TrueClass
|
47
|
-
def to_liquid
|
53
|
+
def to_liquid # :nodoc:
|
48
54
|
self
|
49
55
|
end
|
50
56
|
end
|
data/lib/liquid/file_system.rb
CHANGED
@@ -8,13 +8,13 @@ module Liquid
|
|
8
8
|
#
|
9
9
|
# Example:
|
10
10
|
#
|
11
|
-
#
|
12
|
-
#
|
11
|
+
# Liquid::Template.file_system = Liquid::LocalFileSystem.new(template_path)
|
12
|
+
# liquid = Liquid::Template.parse(template)
|
13
13
|
#
|
14
14
|
# This will parse the template with a LocalFileSystem implementation rooted at 'template_path'.
|
15
15
|
class BlankFileSystem
|
16
16
|
# Called by Liquid to retrieve a template file
|
17
|
-
def read_template_file(
|
17
|
+
def read_template_file(_template_path)
|
18
18
|
raise FileSystemError, "This liquid context does not allow includes."
|
19
19
|
end
|
20
20
|
end
|
@@ -26,10 +26,10 @@ module Liquid
|
|
26
26
|
#
|
27
27
|
# Example:
|
28
28
|
#
|
29
|
-
#
|
29
|
+
# file_system = Liquid::LocalFileSystem.new("/some/path")
|
30
30
|
#
|
31
|
-
#
|
32
|
-
#
|
31
|
+
# file_system.full_path("mypartial") # => "/some/path/_mypartial.liquid"
|
32
|
+
# file_system.full_path("dir/mypartial") # => "/some/path/dir/_mypartial.liquid"
|
33
33
|
#
|
34
34
|
# Optionally in the second argument you can specify a custom pattern for template filenames.
|
35
35
|
# The Kernel::sprintf format specification is used.
|
@@ -37,9 +37,9 @@ module Liquid
|
|
37
37
|
#
|
38
38
|
# Example:
|
39
39
|
#
|
40
|
-
#
|
40
|
+
# file_system = Liquid::LocalFileSystem.new("/some/path", "%s.html")
|
41
41
|
#
|
42
|
-
#
|
42
|
+
# file_system.full_path("index") # => "/some/path/index.html"
|
43
43
|
#
|
44
44
|
class LocalFileSystem
|
45
45
|
attr_accessor :root
|
@@ -49,9 +49,9 @@ module Liquid
|
|
49
49
|
@pattern = pattern
|
50
50
|
end
|
51
51
|
|
52
|
-
def read_template_file(template_path
|
52
|
+
def read_template_file(template_path)
|
53
53
|
full_path = full_path(template_path)
|
54
|
-
raise FileSystemError, "No such template '#{template_path}'" unless File.
|
54
|
+
raise FileSystemError, "No such template '#{template_path}'" unless File.exist?(full_path)
|
55
55
|
|
56
56
|
File.read(full_path)
|
57
57
|
end
|
@@ -65,7 +65,7 @@ module Liquid
|
|
65
65
|
File.join(root, @pattern % template_path)
|
66
66
|
end
|
67
67
|
|
68
|
-
raise FileSystemError, "Illegal template path '#{File.expand_path(full_path)}'" unless File.expand_path(full_path)
|
68
|
+
raise FileSystemError, "Illegal template path '#{File.expand_path(full_path)}'" unless File.expand_path(full_path).start_with?(File.expand_path(root))
|
69
69
|
|
70
70
|
full_path
|
71
71
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Liquid
|
2
|
+
class ForloopDrop < Drop
|
3
|
+
def initialize(name, length, parentloop)
|
4
|
+
@name = name
|
5
|
+
@length = length
|
6
|
+
@parentloop = parentloop
|
7
|
+
@index = 0
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :name, :length, :parentloop
|
11
|
+
|
12
|
+
def index
|
13
|
+
@index + 1
|
14
|
+
end
|
15
|
+
|
16
|
+
def index0
|
17
|
+
@index
|
18
|
+
end
|
19
|
+
|
20
|
+
def rindex
|
21
|
+
@length - @index
|
22
|
+
end
|
23
|
+
|
24
|
+
def rindex0
|
25
|
+
@length - @index - 1
|
26
|
+
end
|
27
|
+
|
28
|
+
def first
|
29
|
+
@index == 0
|
30
|
+
end
|
31
|
+
|
32
|
+
def last
|
33
|
+
@index == @length - 1
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
def increment!
|
39
|
+
@index += 1
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/liquid/i18n.rb
CHANGED
@@ -2,10 +2,9 @@ require 'yaml'
|
|
2
2
|
|
3
3
|
module Liquid
|
4
4
|
class I18n
|
5
|
-
DEFAULT_LOCALE = File.join(File.expand_path(
|
5
|
+
DEFAULT_LOCALE = File.join(File.expand_path(__dir__), "locales", "en.yml")
|
6
6
|
|
7
|
-
|
8
|
-
end
|
7
|
+
TranslationError = Class.new(StandardError)
|
9
8
|
|
10
9
|
attr_reader :path
|
11
10
|
|
@@ -23,11 +22,12 @@ module Liquid
|
|
23
22
|
end
|
24
23
|
|
25
24
|
private
|
25
|
+
|
26
26
|
def interpolate(name, vars)
|
27
|
-
name.gsub(/%\{(\w+)\}/)
|
27
|
+
name.gsub(/%\{(\w+)\}/) do
|
28
28
|
# raise TranslationError, "Undefined key #{$1} for interpolation in translation #{name}" unless vars[$1.to_sym]
|
29
29
|
"#{vars[$1.to_sym]}"
|
30
|
-
|
30
|
+
end
|
31
31
|
end
|
32
32
|
|
33
33
|
def deep_fetch_translation(name)
|
data/lib/liquid/interrupts.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
module Liquid
|
2
|
-
|
3
2
|
# An interrupt is any command that breaks processing of a block (ex: a for loop).
|
4
3
|
class Interrupt
|
5
4
|
attr_reader :message
|
6
5
|
|
7
|
-
def initialize(message=nil)
|
6
|
+
def initialize(message = nil)
|
8
7
|
@message = message || "interrupt".freeze
|
9
8
|
end
|
10
9
|
end
|
data/lib/liquid/lexer.rb
CHANGED
@@ -9,9 +9,11 @@ module Liquid
|
|
9
9
|
'['.freeze => :open_square,
|
10
10
|
']'.freeze => :close_square,
|
11
11
|
'('.freeze => :open_round,
|
12
|
-
')'.freeze => :close_round
|
12
|
+
')'.freeze => :close_round,
|
13
|
+
'?'.freeze => :question,
|
14
|
+
'-'.freeze => :dash
|
13
15
|
}
|
14
|
-
IDENTIFIER = /[\w
|
16
|
+
IDENTIFIER = /[a-zA-Z_][\w-]*\??/
|
15
17
|
SINGLE_STRING_LITERAL = /'[^\']*'/
|
16
18
|
DOUBLE_STRING_LITERAL = /"[^\"]*"/
|
17
19
|
NUMBER_LITERAL = /-?\d+(\.\d+)?/
|
@@ -25,7 +27,7 @@ module Liquid
|
|
25
27
|
def tokenize
|
26
28
|
@output = []
|
27
29
|
|
28
|
-
|
30
|
+
until @ss.eos?
|
29
31
|
@ss.skip(/\s*/)
|
30
32
|
tok = case
|
31
33
|
when t = @ss.scan(COMPARISON_OPERATOR) then [:comparison, t]
|
@@ -37,7 +39,7 @@ module Liquid
|
|
37
39
|
else
|
38
40
|
c = @ss.getch
|
39
41
|
if s = SPECIALS[c]
|
40
|
-
[s,c]
|
42
|
+
[s, c]
|
41
43
|
else
|
42
44
|
raise SyntaxError, "Unexpected character #{c}"
|
43
45
|
end
|
data/lib/liquid/locales/en.yml
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
---
|
2
2
|
errors:
|
3
3
|
syntax:
|
4
|
+
tag_unexpected_args: "Syntax Error in '%{tag}' - Valid syntax: %{tag}"
|
4
5
|
assign: "Syntax Error in 'assign' - Valid syntax: assign [var] = [source]"
|
5
6
|
capture: "Syntax Error in 'capture' - Valid syntax: capture [var]"
|
6
7
|
case: "Syntax Error in 'case' - Valid syntax: case [condition]"
|
@@ -14,9 +15,12 @@
|
|
14
15
|
include: "Error in tag 'include' - Valid syntax: include '[template]' (with|for) [object|collection]"
|
15
16
|
unknown_tag: "Unknown tag '%{tag}'"
|
16
17
|
invalid_delimiter: "'end' is not a valid delimiter for %{block_name} tags. use %{block_delimiter}"
|
17
|
-
unexpected_else: "%{block_name} tag does not expect else tag"
|
18
|
+
unexpected_else: "%{block_name} tag does not expect 'else' tag"
|
19
|
+
unexpected_outer_tag: "Unexpected outer '%{tag}' tag"
|
18
20
|
tag_termination: "Tag '%{token}' was not properly terminated with regexp: %{tag_end}"
|
19
21
|
variable_termination: "Variable '%{token}' was not properly terminated with regexp: %{tag_end}"
|
20
22
|
tag_never_closed: "'%{block_name}' tag was never closed"
|
21
23
|
meta_syntax_error: "Liquid syntax error: #{e.message}"
|
22
24
|
table_row: "Syntax Error in 'table_row loop' - Valid syntax: table_row [item] in [collection] cols=3"
|
25
|
+
argument:
|
26
|
+
include: "Argument error in tag 'include' - Illegal template name"
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Liquid
|
2
|
+
class ParseContext
|
3
|
+
attr_accessor :locale, :line_number, :trim_whitespace
|
4
|
+
attr_reader :partial, :warnings, :error_mode
|
5
|
+
|
6
|
+
def initialize(options = {})
|
7
|
+
@template_options = options ? options.dup : {}
|
8
|
+
@locale = @template_options[:locale] ||= I18n.new
|
9
|
+
@warnings = []
|
10
|
+
self.partial = false
|
11
|
+
end
|
12
|
+
|
13
|
+
def [](option_key)
|
14
|
+
@options[option_key]
|
15
|
+
end
|
16
|
+
|
17
|
+
def partial=(value)
|
18
|
+
@partial = value
|
19
|
+
@options = value ? partial_options : @template_options
|
20
|
+
@error_mode = @options[:error_mode] || Template.error_mode
|
21
|
+
value
|
22
|
+
end
|
23
|
+
|
24
|
+
def partial_options
|
25
|
+
@partial_options ||= begin
|
26
|
+
dont_pass = @template_options[:include_options_blacklist]
|
27
|
+
if dont_pass == true
|
28
|
+
{ locale: locale }
|
29
|
+
elsif dont_pass.is_a?(Array)
|
30
|
+
@template_options.reject { |k, v| dont_pass.include?(k) }
|
31
|
+
else
|
32
|
+
@template_options
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/liquid/parser.rb
CHANGED
@@ -1,25 +1,25 @@
|
|
1
1
|
module Liquid
|
2
2
|
module ParserSwitching
|
3
3
|
def parse_with_selected_parser(markup)
|
4
|
-
case
|
4
|
+
case parse_context.error_mode
|
5
5
|
when :strict then strict_parse_with_error_context(markup)
|
6
6
|
when :lax then lax_parse(markup)
|
7
7
|
when :warn
|
8
8
|
begin
|
9
9
|
return strict_parse_with_error_context(markup)
|
10
10
|
rescue SyntaxError => e
|
11
|
-
e
|
12
|
-
@warnings ||= []
|
13
|
-
@warnings << e
|
11
|
+
parse_context.warnings << e
|
14
12
|
return lax_parse(markup)
|
15
13
|
end
|
16
14
|
end
|
17
15
|
end
|
18
16
|
|
19
17
|
private
|
18
|
+
|
20
19
|
def strict_parse_with_error_context(markup)
|
21
20
|
strict_parse(markup)
|
22
21
|
rescue SyntaxError => e
|
22
|
+
e.line_number = line_number
|
23
23
|
e.markup_context = markup_context(markup)
|
24
24
|
raise e
|
25
25
|
end
|
@@ -1,18 +1,18 @@
|
|
1
1
|
module Liquid
|
2
|
-
class
|
3
|
-
def
|
4
|
-
Profiler.
|
5
|
-
|
2
|
+
class BlockBody
|
3
|
+
def render_node_with_profiling(node, context)
|
4
|
+
Profiler.profile_node_render(node) do
|
5
|
+
render_node_without_profiling(node, context)
|
6
6
|
end
|
7
7
|
end
|
8
8
|
|
9
|
-
alias_method :
|
10
|
-
alias_method :
|
9
|
+
alias_method :render_node_without_profiling, :render_node
|
10
|
+
alias_method :render_node, :render_node_with_profiling
|
11
11
|
end
|
12
12
|
|
13
13
|
class Include < Tag
|
14
14
|
def render_with_profiling(context)
|
15
|
-
Profiler.profile_children(@
|
15
|
+
Profiler.profile_children(context.evaluate(@template_name_expr).to_s) do
|
16
16
|
render_without_profiling(context)
|
17
17
|
end
|
18
18
|
end
|
data/lib/liquid/profiler.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
-
|
1
|
+
require 'liquid/profiler/hooks'
|
2
2
|
|
3
|
+
module Liquid
|
3
4
|
# Profiler enables support for profiling template rendering to help track down performance issues.
|
4
5
|
#
|
5
|
-
# To enable profiling,
|
6
|
-
#
|
6
|
+
# To enable profiling, first require 'liquid/profiler'.
|
7
|
+
# Then, to profile a parse/render cycle, pass the <tt>profile: true</tt> option to <tt>Liquid::Template.parse</tt>.
|
8
|
+
# After <tt>Liquid::Template#render</tt> is called, the template object makes available an instance of this
|
7
9
|
# class via the <tt>Liquid::Template#profiler</tt> method.
|
8
10
|
#
|
9
11
|
# template = Liquid::Template.parse(template_content, profile: true)
|
@@ -17,7 +19,7 @@ module Liquid
|
|
17
19
|
# inside of <tt>{% include %}</tt> tags.
|
18
20
|
#
|
19
21
|
# profile.each do |node|
|
20
|
-
# # Access to the
|
22
|
+
# # Access to the node itself
|
21
23
|
# node.code
|
22
24
|
#
|
23
25
|
# # Which template and line number of this node.
|
@@ -44,17 +46,15 @@ module Liquid
|
|
44
46
|
class Timing
|
45
47
|
attr_reader :code, :partial, :line_number, :children
|
46
48
|
|
47
|
-
def initialize(
|
48
|
-
@code =
|
49
|
+
def initialize(node, partial)
|
50
|
+
@code = node.respond_to?(:raw) ? node.raw : node
|
49
51
|
@partial = partial
|
50
|
-
@line_number =
|
52
|
+
@line_number = node.respond_to?(:line_number) ? node.line_number : nil
|
51
53
|
@children = []
|
52
54
|
end
|
53
55
|
|
54
|
-
def self.start(
|
55
|
-
new(
|
56
|
-
t.start
|
57
|
-
end
|
56
|
+
def self.start(node, partial)
|
57
|
+
new(node, partial).tap(&:start)
|
58
58
|
end
|
59
59
|
|
60
60
|
def start
|
@@ -70,11 +70,11 @@ module Liquid
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
-
def self.
|
74
|
-
if Profiler.current_profile &&
|
75
|
-
Profiler.current_profile.
|
73
|
+
def self.profile_node_render(node)
|
74
|
+
if Profiler.current_profile && node.respond_to?(:render)
|
75
|
+
Profiler.current_profile.start_node(node)
|
76
76
|
output = yield
|
77
|
-
Profiler.current_profile.
|
77
|
+
Profiler.current_profile.end_node(node)
|
78
78
|
output
|
79
79
|
else
|
80
80
|
yield
|
@@ -132,11 +132,11 @@ module Liquid
|
|
132
132
|
@root_timing.children.length
|
133
133
|
end
|
134
134
|
|
135
|
-
def
|
136
|
-
@timing_stack.push(Timing.start(
|
135
|
+
def start_node(node)
|
136
|
+
@timing_stack.push(Timing.start(node, current_partial))
|
137
137
|
end
|
138
138
|
|
139
|
-
def
|
139
|
+
def end_node(_node)
|
140
140
|
timing = @timing_stack.pop
|
141
141
|
timing.finish
|
142
142
|
|
@@ -154,6 +154,5 @@ module Liquid
|
|
154
154
|
def pop_partial
|
155
155
|
@partial_stack.pop
|
156
156
|
end
|
157
|
-
|
158
157
|
end
|
159
158
|
end
|
data/lib/liquid/range_lookup.rb
CHANGED
@@ -16,7 +16,22 @@ module Liquid
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def evaluate(context)
|
19
|
-
context.evaluate(@start_obj)
|
19
|
+
start_int = to_integer(context.evaluate(@start_obj))
|
20
|
+
end_int = to_integer(context.evaluate(@end_obj))
|
21
|
+
start_int..end_int
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def to_integer(input)
|
27
|
+
case input
|
28
|
+
when Integer
|
29
|
+
input
|
30
|
+
when NilClass, String
|
31
|
+
input.to_i
|
32
|
+
else
|
33
|
+
Utils.to_integer(input)
|
34
|
+
end
|
20
35
|
end
|
21
36
|
end
|
22
37
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Liquid
|
2
|
+
class ResourceLimits
|
3
|
+
attr_accessor :render_length, :render_score, :assign_score,
|
4
|
+
:render_length_limit, :render_score_limit, :assign_score_limit
|
5
|
+
|
6
|
+
def initialize(limits)
|
7
|
+
@render_length_limit = limits[:render_length_limit]
|
8
|
+
@render_score_limit = limits[:render_score_limit]
|
9
|
+
@assign_score_limit = limits[:assign_score_limit]
|
10
|
+
reset
|
11
|
+
end
|
12
|
+
|
13
|
+
def reached?
|
14
|
+
(@render_length_limit && @render_length > @render_length_limit) ||
|
15
|
+
(@render_score_limit && @render_score > @render_score_limit) ||
|
16
|
+
(@assign_score_limit && @assign_score > @assign_score_limit)
|
17
|
+
end
|
18
|
+
|
19
|
+
def reset
|
20
|
+
@render_length = @render_score = @assign_score = 0
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|