liquid 3.0.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +130 -62
  3. data/README.md +31 -0
  4. data/lib/liquid/block.rb +31 -124
  5. data/lib/liquid/block_body.rb +75 -59
  6. data/lib/liquid/condition.rb +23 -22
  7. data/lib/liquid/context.rb +51 -60
  8. data/lib/liquid/document.rb +19 -9
  9. data/lib/liquid/drop.rb +17 -16
  10. data/lib/liquid/errors.rb +20 -24
  11. data/lib/liquid/expression.rb +15 -3
  12. data/lib/liquid/extensions.rb +13 -7
  13. data/lib/liquid/file_system.rb +11 -11
  14. data/lib/liquid/forloop_drop.rb +42 -0
  15. data/lib/liquid/i18n.rb +5 -5
  16. data/lib/liquid/interrupts.rb +1 -2
  17. data/lib/liquid/lexer.rb +6 -4
  18. data/lib/liquid/locales/en.yml +5 -1
  19. data/lib/liquid/parse_context.rb +37 -0
  20. data/lib/liquid/parser.rb +1 -1
  21. data/lib/liquid/parser_switching.rb +4 -4
  22. data/lib/liquid/profiler/hooks.rb +7 -7
  23. data/lib/liquid/profiler.rb +18 -19
  24. data/lib/liquid/range_lookup.rb +16 -1
  25. data/lib/liquid/resource_limits.rb +23 -0
  26. data/lib/liquid/standardfilters.rb +121 -61
  27. data/lib/liquid/strainer.rb +32 -29
  28. data/lib/liquid/tablerowloop_drop.rb +62 -0
  29. data/lib/liquid/tag.rb +9 -8
  30. data/lib/liquid/tags/assign.rb +17 -4
  31. data/lib/liquid/tags/break.rb +0 -3
  32. data/lib/liquid/tags/capture.rb +2 -2
  33. data/lib/liquid/tags/case.rb +19 -12
  34. data/lib/liquid/tags/comment.rb +2 -2
  35. data/lib/liquid/tags/cycle.rb +6 -6
  36. data/lib/liquid/tags/decrement.rb +1 -4
  37. data/lib/liquid/tags/for.rb +95 -75
  38. data/lib/liquid/tags/if.rb +48 -43
  39. data/lib/liquid/tags/ifchanged.rb +0 -2
  40. data/lib/liquid/tags/include.rb +61 -52
  41. data/lib/liquid/tags/raw.rb +32 -4
  42. data/lib/liquid/tags/table_row.rb +12 -31
  43. data/lib/liquid/tags/unless.rb +4 -5
  44. data/lib/liquid/template.rb +42 -54
  45. data/lib/liquid/tokenizer.rb +31 -0
  46. data/lib/liquid/utils.rb +52 -8
  47. data/lib/liquid/variable.rb +46 -45
  48. data/lib/liquid/variable_lookup.rb +9 -5
  49. data/lib/liquid/version.rb +1 -1
  50. data/lib/liquid.rb +9 -7
  51. data/test/integration/assign_test.rb +18 -8
  52. data/test/integration/blank_test.rb +14 -14
  53. data/test/integration/capture_test.rb +10 -0
  54. data/test/integration/context_test.rb +2 -2
  55. data/test/integration/document_test.rb +19 -0
  56. data/test/integration/drop_test.rb +42 -40
  57. data/test/integration/error_handling_test.rb +99 -46
  58. data/test/integration/filter_test.rb +72 -19
  59. data/test/integration/hash_ordering_test.rb +9 -9
  60. data/test/integration/output_test.rb +34 -27
  61. data/test/integration/parsing_quirks_test.rb +15 -13
  62. data/test/integration/render_profiling_test.rb +20 -20
  63. data/test/integration/security_test.rb +9 -7
  64. data/test/integration/standard_filter_test.rb +198 -42
  65. data/test/integration/tags/break_tag_test.rb +1 -2
  66. data/test/integration/tags/continue_tag_test.rb +0 -1
  67. data/test/integration/tags/for_tag_test.rb +133 -98
  68. data/test/integration/tags/if_else_tag_test.rb +96 -77
  69. data/test/integration/tags/include_tag_test.rb +34 -30
  70. data/test/integration/tags/increment_tag_test.rb +10 -11
  71. data/test/integration/tags/raw_tag_test.rb +7 -1
  72. data/test/integration/tags/standard_tag_test.rb +121 -122
  73. data/test/integration/tags/statements_test.rb +3 -5
  74. data/test/integration/tags/table_row_test.rb +20 -19
  75. data/test/integration/tags/unless_else_tag_test.rb +6 -6
  76. data/test/integration/template_test.rb +190 -49
  77. data/test/integration/trim_mode_test.rb +525 -0
  78. data/test/integration/variable_test.rb +23 -13
  79. data/test/test_helper.rb +44 -9
  80. data/test/unit/block_unit_test.rb +8 -5
  81. data/test/unit/condition_unit_test.rb +86 -77
  82. data/test/unit/context_unit_test.rb +48 -57
  83. data/test/unit/file_system_unit_test.rb +3 -3
  84. data/test/unit/i18n_unit_test.rb +2 -2
  85. data/test/unit/lexer_unit_test.rb +11 -8
  86. data/test/unit/parser_unit_test.rb +2 -2
  87. data/test/unit/regexp_unit_test.rb +1 -1
  88. data/test/unit/strainer_unit_test.rb +85 -8
  89. data/test/unit/tag_unit_test.rb +7 -2
  90. data/test/unit/tags/case_tag_unit_test.rb +1 -1
  91. data/test/unit/tags/for_tag_unit_test.rb +2 -2
  92. data/test/unit/tags/if_tag_unit_test.rb +1 -1
  93. data/test/unit/template_unit_test.rb +14 -5
  94. data/test/unit/tokenizer_unit_test.rb +24 -7
  95. data/test/unit/variable_unit_test.rb +66 -43
  96. metadata +55 -50
  97. data/lib/liquid/module_ex.rb +0 -62
  98. data/lib/liquid/token.rb +0 -18
  99. data/test/unit/module_ex_unit_test.rb +0 -87
  100. /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 << " (line #{line_number})"
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
- class ArgumentError < Error; end
53
- class ContextError < Error; end
54
- class FileSystemError < Error; end
55
- class StandardError < Error; end
56
- class SyntaxError < Error; end
57
- class StackLevelError < Error; end
58
- class TaintedError < Error; end
59
- class MemoryError < Error; end
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
@@ -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
@@ -7,44 +7,50 @@ class String # :nodoc:
7
7
  end
8
8
  end
9
9
 
10
- class Array # :nodoc:
10
+ class Array # :nodoc:
11
11
  def to_liquid
12
12
  self
13
13
  end
14
14
  end
15
15
 
16
- class Hash # :nodoc:
16
+ class Hash # :nodoc:
17
17
  def to_liquid
18
18
  self
19
19
  end
20
20
  end
21
21
 
22
- class Numeric # :nodoc:
22
+ class Numeric # :nodoc:
23
23
  def to_liquid
24
24
  self
25
25
  end
26
26
  end
27
27
 
28
- class Time # :nodoc:
28
+ class Range # :nodoc:
29
29
  def to_liquid
30
30
  self
31
31
  end
32
32
  end
33
33
 
34
- class DateTime < Date # :nodoc:
34
+ class Time # :nodoc:
35
35
  def to_liquid
36
36
  self
37
37
  end
38
38
  end
39
39
 
40
- class Date # :nodoc:
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 # :nodoc:
53
+ def to_liquid # :nodoc:
48
54
  self
49
55
  end
50
56
  end
@@ -8,13 +8,13 @@ module Liquid
8
8
  #
9
9
  # Example:
10
10
  #
11
- # Liquid::Template.file_system = Liquid::LocalFileSystem.new(template_path)
12
- # liquid = Liquid::Template.parse(template)
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(template_path, context)
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
- # file_system = Liquid::LocalFileSystem.new("/some/path")
29
+ # file_system = Liquid::LocalFileSystem.new("/some/path")
30
30
  #
31
- # file_system.full_path("mypartial") # => "/some/path/_mypartial.liquid"
32
- # file_system.full_path("dir/mypartial") # => "/some/path/dir/_mypartial.liquid"
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
- # file_system = Liquid::LocalFileSystem.new("/some/path", "%s.html")
40
+ # file_system = Liquid::LocalFileSystem.new("/some/path", "%s.html")
41
41
  #
42
- # file_system.full_path("index") # => "/some/path/index.html"
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, context)
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.exists?(full_path)
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) =~ /\A#{File.expand_path(root)}/
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(File.dirname(__FILE__)), "locales", "en.yml")
5
+ DEFAULT_LOCALE = File.join(File.expand_path(__dir__), "locales", "en.yml")
6
6
 
7
- class TranslationError < StandardError
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)
@@ -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
- while !@ss.eos?
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
@@ -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
@@ -75,7 +75,7 @@ module Liquid
75
75
 
76
76
  def variable_signature
77
77
  str = consume(:id)
78
- if look(:open_square)
78
+ while look(:open_square)
79
79
  str << consume
80
80
  str << expression
81
81
  str << consume(:close_square)
@@ -1,25 +1,25 @@
1
1
  module Liquid
2
2
  module ParserSwitching
3
3
  def parse_with_selected_parser(markup)
4
- case @options[:error_mode] || Template.error_mode
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.set_line_number_from_token(markup)
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 Block < Tag
3
- def render_token_with_profiling(token, context)
4
- Profiler.profile_token_render(token) do
5
- render_token_without_profiling(token, context)
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 :render_token_without_profiling, :render_token
10
- alias_method :render_token, :render_token_with_profiling
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(@template_name) do
15
+ Profiler.profile_children(context.evaluate(@template_name_expr).to_s) do
16
16
  render_without_profiling(context)
17
17
  end
18
18
  end
@@ -1,9 +1,11 @@
1
- module Liquid
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, pass the <tt>profile: true</tt> option to <tt>Liquid::Template.parse</tt>. Then, after
6
- # <tt>Liquid::Template#render</tt> is called, the template object makes available an instance of this
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 token itself
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(token, partial)
48
- @code = token.respond_to?(:raw) ? token.raw : token
49
+ def initialize(node, partial)
50
+ @code = node.respond_to?(:raw) ? node.raw : node
49
51
  @partial = partial
50
- @line_number = token.respond_to?(:line_number) ? token.line_number : nil
52
+ @line_number = node.respond_to?(:line_number) ? node.line_number : nil
51
53
  @children = []
52
54
  end
53
55
 
54
- def self.start(token, partial)
55
- new(token, partial).tap do |t|
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.profile_token_render(token)
74
- if Profiler.current_profile && token.respond_to?(:render)
75
- Profiler.current_profile.start_token(token)
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.end_token(token)
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 start_token(token)
136
- @timing_stack.push(Timing.start(token, current_partial))
135
+ def start_node(node)
136
+ @timing_stack.push(Timing.start(node, current_partial))
137
137
  end
138
138
 
139
- def end_token(token)
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
@@ -16,7 +16,22 @@ module Liquid
16
16
  end
17
17
 
18
18
  def evaluate(context)
19
- context.evaluate(@start_obj).to_i..context.evaluate(@end_obj).to_i
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