mirror of
https://github.com/kemko/liquid.git
synced 2026-01-02 00:05:42 +03:00
Compare commits
18 Commits
v4.0.2
...
range-opti
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd5e3e87c7 | ||
|
|
b3b63a683f | ||
|
|
1c577c5b62 | ||
|
|
755d2821f3 | ||
|
|
495b3d312f | ||
|
|
453f6348c2 | ||
|
|
70ed1fc86d | ||
|
|
c2ef247be5 | ||
|
|
1518d3f6f9 | ||
|
|
c67b77709d | ||
|
|
c89ce9c2ed | ||
|
|
b0629f17f7 | ||
|
|
274f078806 | ||
|
|
d7171aa084 | ||
|
|
06c4789dc5 | ||
|
|
f2f467bdbc | ||
|
|
ff99d92c18 | ||
|
|
39fecd06db |
17
.rubocop.yml
17
.rubocop.yml
@@ -1,4 +1,6 @@
|
|||||||
inherit_from: ./.rubocop_todo.yml
|
inherit_from:
|
||||||
|
- .rubocop_todo.yml
|
||||||
|
- ./.rubocop_todo.yml
|
||||||
|
|
||||||
AllCops:
|
AllCops:
|
||||||
Exclude:
|
Exclude:
|
||||||
@@ -29,7 +31,7 @@ Lint/ParenthesesAsGroupedExpression:
|
|||||||
Lint/UnusedBlockArgument:
|
Lint/UnusedBlockArgument:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Lint/EndAlignment:
|
Layout/EndAlignment:
|
||||||
EnforcedStyleAlignWith: variable
|
EnforcedStyleAlignWith: variable
|
||||||
|
|
||||||
Lint/UnusedMethodArgument:
|
Lint/UnusedMethodArgument:
|
||||||
@@ -59,7 +61,7 @@ Style/BracesAroundHashParameters:
|
|||||||
Style/NumericLiterals:
|
Style/NumericLiterals:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Layout/SpaceInsideBrackets:
|
Layout/SpaceInsideArrayLiteralBrackets:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Layout/SpaceBeforeBlockBraces:
|
Layout/SpaceBeforeBlockBraces:
|
||||||
@@ -71,7 +73,10 @@ Style/Documentation:
|
|||||||
Style/ClassAndModuleChildren:
|
Style/ClassAndModuleChildren:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Style/TrailingCommaInLiteral:
|
Style/TrailingCommaInArrayLiteral:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/TrailingCommaInHashLiteral:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Layout/IndentHash:
|
Layout/IndentHash:
|
||||||
@@ -104,7 +109,7 @@ Style/SymbolLiteral:
|
|||||||
Performance/Count:
|
Performance/Count:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Style/ConstantName:
|
Naming/ConstantName:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Layout/CaseIndentation:
|
Layout/CaseIndentation:
|
||||||
@@ -122,6 +127,6 @@ Style/TrivialAccessors:
|
|||||||
Style/WordArray:
|
Style/WordArray:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Style/MethodName:
|
Naming/MethodName:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'example/server/liquid_servlet.rb'
|
- 'example/server/liquid_servlet.rb'
|
||||||
|
|||||||
@@ -1,14 +1,22 @@
|
|||||||
# This configuration was generated by
|
# This configuration was generated by
|
||||||
# `rubocop --auto-gen-config`
|
# `rubocop --auto-gen-config`
|
||||||
# on 2019-02-03 21:12:39 +0530 using RuboCop version 0.49.1.
|
# on 2019-03-19 11:04:37 -0400 using RuboCop version 0.53.0.
|
||||||
# The point is for the user to remove these configuration records
|
# The point is for the user to remove these configuration records
|
||||||
# one by one as the offenses are removed from the code base.
|
# one by one as the offenses are removed from the code base.
|
||||||
# Note that changes in the inspected code, or installation of new
|
# Note that changes in the inspected code, or installation of new
|
||||||
# versions of RuboCop, may require this file to be generated again.
|
# versions of RuboCop, may require this file to be generated again.
|
||||||
|
|
||||||
|
# Offense count: 1
|
||||||
|
# Cop supports --auto-correct.
|
||||||
|
# Configuration parameters: Include, TreatCommentsAsGroupSeparators.
|
||||||
|
# Include: **/*.gemspec
|
||||||
|
Gemspec/OrderedDependencies:
|
||||||
|
Exclude:
|
||||||
|
- 'liquid.gemspec'
|
||||||
|
|
||||||
# Offense count: 5
|
# Offense count: 5
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
# Configuration parameters: EnforcedStyle.
|
||||||
# SupportedStyles: auto_detection, squiggly, active_support, powerpack, unindent
|
# SupportedStyles: auto_detection, squiggly, active_support, powerpack, unindent
|
||||||
Layout/IndentHeredoc:
|
Layout/IndentHeredoc:
|
||||||
Exclude:
|
Exclude:
|
||||||
@@ -17,7 +25,7 @@ Layout/IndentHeredoc:
|
|||||||
|
|
||||||
# Offense count: 6
|
# Offense count: 6
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
# Configuration parameters: EnforcedStyle.
|
||||||
# SupportedStyles: symmetrical, new_line, same_line
|
# SupportedStyles: symmetrical, new_line, same_line
|
||||||
Layout/MultilineMethodCallBraceLayout:
|
Layout/MultilineMethodCallBraceLayout:
|
||||||
Exclude:
|
Exclude:
|
||||||
@@ -26,38 +34,65 @@ Layout/MultilineMethodCallBraceLayout:
|
|||||||
|
|
||||||
# Offense count: 2
|
# Offense count: 2
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
# Configuration parameters: EnforcedStyle.
|
||||||
# SupportedStyles: runtime_error, standard_error
|
# SupportedStyles: runtime_error, standard_error
|
||||||
Lint/InheritException:
|
Lint/InheritException:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'lib/liquid/interrupts.rb'
|
- 'lib/liquid/interrupts.rb'
|
||||||
|
|
||||||
# Offense count: 51
|
# Offense count: 1
|
||||||
|
# Configuration parameters: CheckForMethodsWithNoSideEffects.
|
||||||
|
Lint/Void:
|
||||||
|
Exclude:
|
||||||
|
- 'lib/liquid/parse_context.rb'
|
||||||
|
|
||||||
|
# Offense count: 54
|
||||||
Metrics/AbcSize:
|
Metrics/AbcSize:
|
||||||
Max: 56
|
Max: 56
|
||||||
|
|
||||||
# Offense count: 11
|
# Offense count: 12
|
||||||
Metrics/CyclomaticComplexity:
|
Metrics/CyclomaticComplexity:
|
||||||
Max: 12
|
Max: 12
|
||||||
|
|
||||||
# Offense count: 639
|
# Offense count: 112
|
||||||
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
|
|
||||||
# URISchemes: http, https
|
|
||||||
Metrics/LineLength:
|
|
||||||
Max: 294
|
|
||||||
|
|
||||||
# Offense count: 108
|
|
||||||
# Configuration parameters: CountComments.
|
# Configuration parameters: CountComments.
|
||||||
Metrics/MethodLength:
|
Metrics/MethodLength:
|
||||||
Max: 37
|
Max: 37
|
||||||
|
|
||||||
# Offense count: 7
|
# Offense count: 8
|
||||||
Metrics/PerceivedComplexity:
|
Metrics/PerceivedComplexity:
|
||||||
Max: 11
|
Max: 11
|
||||||
|
|
||||||
|
# Offense count: 52
|
||||||
|
# Configuration parameters: Blacklist.
|
||||||
|
# Blacklist: END, (?-mix:EO[A-Z]{1})
|
||||||
|
Naming/HeredocDelimiterNaming:
|
||||||
|
Exclude:
|
||||||
|
- 'test/integration/assign_test.rb'
|
||||||
|
- 'test/integration/capture_test.rb'
|
||||||
|
- 'test/integration/trim_mode_test.rb'
|
||||||
|
|
||||||
|
# Offense count: 23
|
||||||
|
# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
|
||||||
|
# AllowedNames: io, id
|
||||||
|
Naming/UncommunicativeMethodParamName:
|
||||||
|
Exclude:
|
||||||
|
- 'example/server/example_servlet.rb'
|
||||||
|
- 'lib/liquid/condition.rb'
|
||||||
|
- 'lib/liquid/context.rb'
|
||||||
|
- 'lib/liquid/standardfilters.rb'
|
||||||
|
- 'lib/liquid/tags/if.rb'
|
||||||
|
- 'lib/liquid/utils.rb'
|
||||||
|
- 'lib/liquid/variable.rb'
|
||||||
|
- 'test/integration/filter_test.rb'
|
||||||
|
- 'test/integration/standard_filter_test.rb'
|
||||||
|
- 'test/integration/tags/for_tag_test.rb'
|
||||||
|
- 'test/integration/template_test.rb'
|
||||||
|
- 'test/unit/condition_unit_test.rb'
|
||||||
|
|
||||||
# Offense count: 10
|
# Offense count: 10
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
# Configuration parameters: EnforcedStyle.
|
||||||
# SupportedStyles: prefer_alias, prefer_alias_method
|
# SupportedStyles: prefer_alias, prefer_alias_method
|
||||||
Style/Alias:
|
Style/Alias:
|
||||||
Exclude:
|
Exclude:
|
||||||
@@ -69,14 +104,23 @@ Style/Alias:
|
|||||||
- 'lib/liquid/tags/include.rb'
|
- 'lib/liquid/tags/include.rb'
|
||||||
- 'lib/liquid/variable.rb'
|
- 'lib/liquid/variable.rb'
|
||||||
|
|
||||||
|
# Offense count: 22
|
||||||
|
Style/CommentedKeyword:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 1
|
# Offense count: 1
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, SupportedStyles, SingleLineConditionsOnly, IncludeTernaryExpressions.
|
# Configuration parameters: EnforcedStyle, SingleLineConditionsOnly, IncludeTernaryExpressions.
|
||||||
# SupportedStyles: assign_to_condition, assign_inside_condition
|
# SupportedStyles: assign_to_condition, assign_inside_condition
|
||||||
Style/ConditionalAssignment:
|
Style/ConditionalAssignment:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'lib/liquid/errors.rb'
|
- 'lib/liquid/errors.rb'
|
||||||
|
|
||||||
|
# Offense count: 1
|
||||||
|
Style/DateTime:
|
||||||
|
Exclude:
|
||||||
|
- 'test/unit/context_unit_test.rb'
|
||||||
|
|
||||||
# Offense count: 2
|
# Offense count: 2
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
Style/EmptyCaseCondition:
|
Style/EmptyCaseCondition:
|
||||||
@@ -86,7 +130,7 @@ Style/EmptyCaseCondition:
|
|||||||
|
|
||||||
# Offense count: 5
|
# Offense count: 5
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
# Configuration parameters: EnforcedStyle.
|
||||||
# SupportedStyles: compact, expanded
|
# SupportedStyles: compact, expanded
|
||||||
Style/EmptyMethod:
|
Style/EmptyMethod:
|
||||||
Exclude:
|
Exclude:
|
||||||
@@ -96,11 +140,28 @@ Style/EmptyMethod:
|
|||||||
- 'test/integration/tags/include_tag_test.rb'
|
- 'test/integration/tags/include_tag_test.rb'
|
||||||
- 'test/unit/context_unit_test.rb'
|
- 'test/unit/context_unit_test.rb'
|
||||||
|
|
||||||
|
# Offense count: 3
|
||||||
|
# Cop supports --auto-correct.
|
||||||
|
Style/Encoding:
|
||||||
|
Exclude:
|
||||||
|
- 'lib/liquid/version.rb'
|
||||||
|
- 'liquid.gemspec'
|
||||||
|
- 'test/integration/standard_filter_test.rb'
|
||||||
|
|
||||||
# Offense count: 2
|
# Offense count: 2
|
||||||
# Configuration parameters: SupportedStyles.
|
# Cop supports --auto-correct.
|
||||||
# SupportedStyles: annotated, template
|
Style/ExpandPathArguments:
|
||||||
|
Exclude:
|
||||||
|
- 'Rakefile'
|
||||||
|
- 'liquid.gemspec'
|
||||||
|
|
||||||
|
# Offense count: 7
|
||||||
|
# Configuration parameters: EnforcedStyle.
|
||||||
|
# SupportedStyles: annotated, template, unannotated
|
||||||
Style/FormatStringToken:
|
Style/FormatStringToken:
|
||||||
EnforcedStyle: template
|
Exclude:
|
||||||
|
- 'test/integration/filter_test.rb'
|
||||||
|
- 'test/integration/hash_ordering_test.rb'
|
||||||
|
|
||||||
# Offense count: 14
|
# Offense count: 14
|
||||||
# Configuration parameters: MinBodyLength.
|
# Configuration parameters: MinBodyLength.
|
||||||
@@ -121,7 +182,7 @@ Style/GuardClause:
|
|||||||
|
|
||||||
# Offense count: 1
|
# Offense count: 1
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
|
# Configuration parameters: EnforcedStyle, MinBodyLength.
|
||||||
# SupportedStyles: skip_modifier_ifs, always
|
# SupportedStyles: skip_modifier_ifs, always
|
||||||
Style/Next:
|
Style/Next:
|
||||||
Exclude:
|
Exclude:
|
||||||
@@ -129,7 +190,7 @@ Style/Next:
|
|||||||
|
|
||||||
# Offense count: 4
|
# Offense count: 4
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: AutoCorrect, EnforcedStyle, SupportedStyles.
|
# Configuration parameters: AutoCorrect, EnforcedStyle.
|
||||||
# SupportedStyles: predicate, comparison
|
# SupportedStyles: predicate, comparison
|
||||||
Style/NumericPredicate:
|
Style/NumericPredicate:
|
||||||
Exclude:
|
Exclude:
|
||||||
@@ -166,14 +227,14 @@ Style/Semicolon:
|
|||||||
|
|
||||||
# Offense count: 7
|
# Offense count: 7
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: MinSize, SupportedStyles.
|
# Configuration parameters: MinSize.
|
||||||
# SupportedStyles: percent, brackets
|
# SupportedStyles: percent, brackets
|
||||||
Style/SymbolArray:
|
Style/SymbolArray:
|
||||||
EnforcedStyle: brackets
|
EnforcedStyle: brackets
|
||||||
|
|
||||||
# Offense count: 2
|
# Offense count: 2
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowSafeAssignment.
|
# Configuration parameters: EnforcedStyle, AllowSafeAssignment.
|
||||||
# SupportedStyles: require_parentheses, require_no_parentheses, require_parentheses_when_complex
|
# SupportedStyles: require_parentheses, require_no_parentheses, require_parentheses_when_complex
|
||||||
Style/TernaryParentheses:
|
Style/TernaryParentheses:
|
||||||
Exclude:
|
Exclude:
|
||||||
@@ -188,7 +249,12 @@ Style/UnneededPercentQ:
|
|||||||
|
|
||||||
# Offense count: 1
|
# Offense count: 1
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: MaxLineLength.
|
|
||||||
Style/WhileUntilModifier:
|
Style/WhileUntilModifier:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'lib/liquid/tags/case.rb'
|
- 'lib/liquid/tags/case.rb'
|
||||||
|
|
||||||
|
# Offense count: 640
|
||||||
|
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
|
||||||
|
# URISchemes: http, https
|
||||||
|
Metrics/LineLength:
|
||||||
|
Max: 294
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ matrix:
|
|||||||
- rvm: jruby-head
|
- rvm: jruby-head
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- gem install rainbow -v 2.2.1
|
|
||||||
- bundle install
|
- bundle install
|
||||||
|
|
||||||
script: bundle exec rake
|
script: bundle exec rake
|
||||||
|
|||||||
11
Gemfile
11
Gemfile
@@ -5,16 +5,19 @@ end
|
|||||||
|
|
||||||
gemspec
|
gemspec
|
||||||
|
|
||||||
gem 'stackprof', platforms: :mri
|
|
||||||
|
|
||||||
group :benchmark, :test do
|
group :benchmark, :test do
|
||||||
gem 'benchmark-ips'
|
gem 'benchmark-ips'
|
||||||
|
gem 'memory_profiler'
|
||||||
|
|
||||||
|
install_if -> { RUBY_PLATFORM !~ /mingw|mswin|java/ } do
|
||||||
|
gem 'stackprof'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
group :test do
|
group :test do
|
||||||
gem 'rubocop', '~> 0.49.0'
|
gem 'rubocop', '~> 0.53.0'
|
||||||
|
|
||||||
platform :mri do
|
platform :mri do
|
||||||
gem 'liquid-c', github: 'Shopify/liquid-c', ref: '9168659de45d6d576fce30c735f857e597fa26f6'
|
gem 'liquid-c', github: 'Shopify/liquid-c', ref: 'reversable-range'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
# Liquid Change Log
|
# Liquid Change Log
|
||||||
|
|
||||||
|
## 4.0.3 / 2019-03-12
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
* Fix break and continue tags inside included templates in loops (#1072) [Justin Li]
|
||||||
|
|
||||||
## 4.0.2 / 2019-03-08
|
## 4.0.2 / 2019-03-08
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|||||||
7
Rakefile
7
Rakefile
@@ -85,6 +85,13 @@ namespace :profile do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
namespace :memory_profile do
|
||||||
|
desc "Run memory profiler"
|
||||||
|
task :run do
|
||||||
|
ruby "./performance/memory_profile.rb"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
desc "Run example"
|
desc "Run example"
|
||||||
task :example do
|
task :example do
|
||||||
ruby "-w -d -Ilib example/server/server.rb"
|
ruby "-w -d -Ilib example/server/server.rb"
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ require 'liquid/condition'
|
|||||||
require 'liquid/utils'
|
require 'liquid/utils'
|
||||||
require 'liquid/tokenizer'
|
require 'liquid/tokenizer'
|
||||||
require 'liquid/parse_context'
|
require 'liquid/parse_context'
|
||||||
|
require 'liquid/reversable_range'
|
||||||
|
|
||||||
# Load all the tags of the standard library
|
# Load all the tags of the standard library
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ module Liquid
|
|||||||
break
|
break
|
||||||
else # Other non-Block tags
|
else # Other non-Block tags
|
||||||
render_node_to_output(node, output, context)
|
render_node_to_output(node, output, context)
|
||||||
|
break if context.interrupt? # might have happened through an include
|
||||||
end
|
end
|
||||||
idx += 1
|
idx += 1
|
||||||
end
|
end
|
||||||
@@ -114,7 +115,7 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def check_resources(context, node_output)
|
def check_resources(context, node_output)
|
||||||
context.resource_limits.render_length += node_output.length
|
context.resource_limits.render_length += node_output.bytesize
|
||||||
return unless context.resource_limits.reached?
|
return unless context.resource_limits.reached?
|
||||||
raise MemoryError.new("Memory limits exceeded".freeze)
|
raise MemoryError.new("Memory limits exceeded".freeze)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ module Liquid
|
|||||||
if start_obj.respond_to?(:evaluate) || end_obj.respond_to?(:evaluate)
|
if start_obj.respond_to?(:evaluate) || end_obj.respond_to?(:evaluate)
|
||||||
new(start_obj, end_obj)
|
new(start_obj, end_obj)
|
||||||
else
|
else
|
||||||
start_obj.to_i..end_obj.to_i
|
ReversableRange.new(start_obj.to_i, end_obj.to_i)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ module Liquid
|
|||||||
def evaluate(context)
|
def evaluate(context)
|
||||||
start_int = to_integer(context.evaluate(@start_obj))
|
start_int = to_integer(context.evaluate(@start_obj))
|
||||||
end_int = to_integer(context.evaluate(@end_obj))
|
end_int = to_integer(context.evaluate(@end_obj))
|
||||||
start_int..end_int
|
ReversableRange.new(start_int, end_int)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
77
lib/liquid/reversable_range.rb
Normal file
77
lib/liquid/reversable_range.rb
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
module Liquid
|
||||||
|
class ReversableRange
|
||||||
|
include Enumerable
|
||||||
|
|
||||||
|
def initialize(min, max)
|
||||||
|
@min = min
|
||||||
|
@max = max
|
||||||
|
@reversed = false
|
||||||
|
end
|
||||||
|
|
||||||
|
def each
|
||||||
|
if reversed
|
||||||
|
index = max
|
||||||
|
while index >= min
|
||||||
|
yield index
|
||||||
|
index -= 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
index = min
|
||||||
|
while index <= max
|
||||||
|
yield index
|
||||||
|
index += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def reverse!
|
||||||
|
@reversed = !reversed
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def empty?
|
||||||
|
max < min
|
||||||
|
end
|
||||||
|
|
||||||
|
def size
|
||||||
|
difference = max - min
|
||||||
|
if difference > 0
|
||||||
|
difference + 1
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_slice(from, to = nil)
|
||||||
|
to ||= max
|
||||||
|
slice_max = [max, to].min
|
||||||
|
slice_min = [min, from].max
|
||||||
|
range = ReversableRange.new(slice_min, slice_max)
|
||||||
|
range.reverse! if reversed
|
||||||
|
range
|
||||||
|
end
|
||||||
|
|
||||||
|
def ==(other)
|
||||||
|
other.is_a?(self.class) &&
|
||||||
|
other.min == min &&
|
||||||
|
other.max == max &&
|
||||||
|
other.reversed == reversed
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
if reversed
|
||||||
|
"#{max}..#{min}"
|
||||||
|
else
|
||||||
|
"#{min}..#{max}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_liquid
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
attr_reader :min, :max, :reversed
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -37,7 +37,7 @@ module Liquid
|
|||||||
|
|
||||||
def assign_score_of(val)
|
def assign_score_of(val)
|
||||||
if val.instance_of?(String)
|
if val.instance_of?(String)
|
||||||
val.length
|
val.bytesize
|
||||||
elsif val.instance_of?(Array) || val.instance_of?(Hash)
|
elsif val.instance_of?(Array) || val.instance_of?(Hash)
|
||||||
sum = 1
|
sum = 1
|
||||||
# Uses #each to avoid extra allocations.
|
# Uses #each to avoid extra allocations.
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ module Liquid
|
|||||||
def render(context)
|
def render(context)
|
||||||
output = super
|
output = super
|
||||||
context.scopes.last[@to] = output
|
context.scopes.last[@to] = output
|
||||||
context.resource_limits.assign_score += output.length
|
context.resource_limits.assign_score += output.bytesize
|
||||||
''.freeze
|
''.freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -124,26 +124,34 @@ module Liquid
|
|||||||
from = if @from == :continue
|
from = if @from == :continue
|
||||||
offsets[@name].to_i
|
offsets[@name].to_i
|
||||||
else
|
else
|
||||||
context.evaluate(@from).to_i
|
from_value = context.evaluate(@from)
|
||||||
|
if from_value.nil?
|
||||||
|
0
|
||||||
|
else
|
||||||
|
Utils.to_integer(from_value)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
collection = context.evaluate(@collection_name)
|
collection = context.evaluate(@collection_name)
|
||||||
collection = collection.to_a if collection.is_a?(Range)
|
|
||||||
|
|
||||||
limit = context.evaluate(@limit)
|
limit_value = context.evaluate(@limit)
|
||||||
to = limit ? limit.to_i + from : nil
|
to = if limit_value.nil?
|
||||||
|
nil
|
||||||
|
else
|
||||||
|
Utils.to_integer(limit_value) + from
|
||||||
|
end
|
||||||
|
|
||||||
segment = Utils.slice_collection(collection, from, to)
|
segment = Utils.slice_collection(collection, from, to)
|
||||||
segment.reverse! if @reversed
|
segment.reverse! if @reversed
|
||||||
|
|
||||||
offsets[@name] = from + segment.length
|
offsets[@name] = from + segment.size
|
||||||
|
|
||||||
segment
|
segment
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_segment(context, segment)
|
def render_segment(context, segment)
|
||||||
for_stack = context.registers[:for_stack] ||= []
|
for_stack = context.registers[:for_stack] ||= []
|
||||||
length = segment.length
|
length = segment.size
|
||||||
|
|
||||||
result = ''
|
result = ''
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
module Liquid
|
module Liquid
|
||||||
module Utils
|
module Utils
|
||||||
def self.slice_collection(collection, from, to)
|
def self.slice_collection(collection, from, to)
|
||||||
|
return collection.load_slice(from, to) if collection.is_a?(ReversableRange)
|
||||||
|
|
||||||
if (from != 0 || !to.nil?) && collection.respond_to?(:load_slice)
|
if (from != 0 || !to.nil?) && collection.respond_to?(:load_slice)
|
||||||
collection.load_slice(from, to)
|
collection.load_slice(from, to)
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -95,16 +95,17 @@ module Liquid
|
|||||||
|
|
||||||
def parse_filter_expressions(filter_name, unparsed_args)
|
def parse_filter_expressions(filter_name, unparsed_args)
|
||||||
filter_args = []
|
filter_args = []
|
||||||
keyword_args = {}
|
keyword_args = nil
|
||||||
unparsed_args.each do |a|
|
unparsed_args.each do |a|
|
||||||
if matches = a.match(JustTagAttributes)
|
if matches = a.match(JustTagAttributes)
|
||||||
|
keyword_args ||= {}
|
||||||
keyword_args[matches[1]] = Expression.parse(matches[2])
|
keyword_args[matches[1]] = Expression.parse(matches[2])
|
||||||
else
|
else
|
||||||
filter_args << Expression.parse(a)
|
filter_args << Expression.parse(a)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
result = [filter_name, filter_args]
|
result = [filter_name, filter_args]
|
||||||
result << keyword_args unless keyword_args.empty?
|
result << keyword_args if keyword_args
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
VERSION = "4.0.2".freeze
|
VERSION = "4.0.3".freeze
|
||||||
end
|
end
|
||||||
|
|||||||
26
performance/memory_profile.rb
Normal file
26
performance/memory_profile.rb
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'benchmark/ips'
|
||||||
|
require 'memory_profiler'
|
||||||
|
require_relative 'theme_runner'
|
||||||
|
|
||||||
|
def profile(phase, &block)
|
||||||
|
puts
|
||||||
|
puts "#{phase}:"
|
||||||
|
puts
|
||||||
|
|
||||||
|
report = MemoryProfiler.report(&block)
|
||||||
|
|
||||||
|
report.pretty_print(
|
||||||
|
color_output: true,
|
||||||
|
scale_bytes: true,
|
||||||
|
detailed_report: true
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
Liquid::Template.error_mode = ARGV.first.to_sym if ARGV.first
|
||||||
|
|
||||||
|
profiler = ThemeRunner.new
|
||||||
|
|
||||||
|
profile("Parsing") { profiler.compile }
|
||||||
|
profile("Rendering") { profiler.render }
|
||||||
@@ -36,6 +36,10 @@ HERE
|
|||||||
assert_template_result('321', '{%for item in array reversed %}{{item}}{%endfor%}', assigns)
|
assert_template_result('321', '{%for item in array reversed %}{{item}}{%endfor%}', assigns)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_for_range_reversed
|
||||||
|
assert_template_result('321', '{%for item in (1..3) reversed %}{{item}}{%endfor%}', {})
|
||||||
|
end
|
||||||
|
|
||||||
def test_for_with_range
|
def test_for_with_range
|
||||||
assert_template_result(' 1 2 3 ', '{%for item in (1..3) %} {{item}} {%endfor%}')
|
assert_template_result(' 1 2 3 ', '{%for item in (1..3) %} {{item}} {%endfor%}')
|
||||||
|
|
||||||
@@ -103,6 +107,34 @@ HERE
|
|||||||
assert_template_result('3456', '{%for i in array limit: 4 offset: 2 %}{{ i }}{%endfor%}', assigns)
|
assert_template_result('3456', '{%for i in array limit: 4 offset: 2 %}{{ i }}{%endfor%}', assigns)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_limiting_with_invalid_limit
|
||||||
|
assigns = { 'array' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] }
|
||||||
|
template = <<-MKUP
|
||||||
|
{% for i in array limit: true offset: 1 %}
|
||||||
|
{{ i }}
|
||||||
|
{% endfor %}
|
||||||
|
MKUP
|
||||||
|
|
||||||
|
exception = assert_raises(Liquid::ArgumentError) do
|
||||||
|
Template.parse(template).render!(assigns)
|
||||||
|
end
|
||||||
|
assert_equal("Liquid error: invalid integer", exception.message)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_limiting_with_invalid_offset
|
||||||
|
assigns = { 'array' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] }
|
||||||
|
template = <<-MKUP
|
||||||
|
{% for i in array limit: 1 offset: true %}
|
||||||
|
{{ i }}
|
||||||
|
{% endfor %}
|
||||||
|
MKUP
|
||||||
|
|
||||||
|
exception = assert_raises(Liquid::ArgumentError) do
|
||||||
|
Template.parse(template).render!(assigns)
|
||||||
|
end
|
||||||
|
assert_equal("Liquid error: invalid integer", exception.message)
|
||||||
|
end
|
||||||
|
|
||||||
def test_dynamic_variable_limiting
|
def test_dynamic_variable_limiting
|
||||||
assigns = { 'array' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] }
|
assigns = { 'array' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] }
|
||||||
assigns['limit'] = 2
|
assigns['limit'] = 2
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ class TestFileSystem
|
|||||||
when 'assignments'
|
when 'assignments'
|
||||||
"{% assign foo = 'bar' %}"
|
"{% assign foo = 'bar' %}"
|
||||||
|
|
||||||
|
when 'break'
|
||||||
|
"{% break %}"
|
||||||
|
|
||||||
else
|
else
|
||||||
template_path
|
template_path
|
||||||
end
|
end
|
||||||
@@ -242,4 +245,9 @@ class IncludeTagTest < Minitest::Test
|
|||||||
|
|
||||||
assert_equal [], template.errors
|
assert_equal [], template.errors
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_break_through_include
|
||||||
|
assert_template_result "1", "{% for i in (1..3) %}{{ i }}{% break %}{{ i }}{% endfor %}"
|
||||||
|
assert_template_result "1", "{% for i in (1..3) %}{{ i }}{% include 'break' %}{{ i }}{% endfor %}"
|
||||||
|
end
|
||||||
end # IncludeTagTest
|
end # IncludeTagTest
|
||||||
|
|||||||
@@ -139,6 +139,16 @@ class TemplateTest < Minitest::Test
|
|||||||
refute_nil t.resource_limits.assign_score
|
refute_nil t.resource_limits.assign_score
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_resource_limits_assign_score_counts_bytes_not_characters
|
||||||
|
t = Template.parse("{% assign foo = 'すごい' %}")
|
||||||
|
t.render
|
||||||
|
assert_equal 9, t.resource_limits.assign_score
|
||||||
|
|
||||||
|
t = Template.parse("{% capture foo %}すごい{% endcapture %}")
|
||||||
|
t.render
|
||||||
|
assert_equal 9, t.resource_limits.assign_score
|
||||||
|
end
|
||||||
|
|
||||||
def test_resource_limits_assign_score_nested
|
def test_resource_limits_assign_score_nested
|
||||||
t = Template.parse("{% assign foo = 'aaaa' | reverse %}")
|
t = Template.parse("{% assign foo = 'aaaa' | reverse %}")
|
||||||
|
|
||||||
@@ -187,6 +197,14 @@ class TemplateTest < Minitest::Test
|
|||||||
assert_equal "ababab", t.render
|
assert_equal "ababab", t.render
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_render_length_uses_number_of_bytes_not_characters
|
||||||
|
t = Template.parse("{% if true %}すごい{% endif %}")
|
||||||
|
t.resource_limits.render_length_limit = 10
|
||||||
|
assert_equal "Liquid error: Memory limits exceeded", t.render
|
||||||
|
t.resource_limits.render_length_limit = 18
|
||||||
|
assert_equal "すごい", t.render
|
||||||
|
end
|
||||||
|
|
||||||
def test_default_resource_limits_unaffected_by_render_with_context
|
def test_default_resource_limits_unaffected_by_render_with_context
|
||||||
context = Context.new
|
context = Context.new
|
||||||
t = Template.parse("{% for a in (1..100) %} {% assign foo = 1 %} {% endfor %}")
|
t = Template.parse("{% for a in (1..100) %} {% assign foo = 1 %} {% endfor %}")
|
||||||
|
|||||||
@@ -349,9 +349,9 @@ class ContextUnitTest < Minitest::Test
|
|||||||
|
|
||||||
def test_ranges
|
def test_ranges
|
||||||
@context.merge("test" => '5')
|
@context.merge("test" => '5')
|
||||||
assert_equal (1..5), @context['(1..5)']
|
assert_equal ReversableRange.new(1, 5), @context['(1..5)']
|
||||||
assert_equal (1..5), @context['(1..test)']
|
assert_equal ReversableRange.new(1, 5), @context['(1..test)']
|
||||||
assert_equal (5..5), @context['(test..test)']
|
assert_equal ReversableRange.new(5, 5), @context['(test..test)']
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_cents_through_drop_nestedly
|
def test_cents_through_drop_nestedly
|
||||||
|
|||||||
116
test/unit/reversable_range_unit_test.rb
Normal file
116
test/unit/reversable_range_unit_test.rb
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class ReversableRangeTest < Minitest::Test
|
||||||
|
include Liquid
|
||||||
|
|
||||||
|
def test_each_iterates_through_items_in_the_range
|
||||||
|
actual_items = []
|
||||||
|
ReversableRange.new(1, 10).each { |item| actual_items << item }
|
||||||
|
|
||||||
|
expected_items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||||
|
assert_equal expected_items, actual_items
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_implements_enumerable
|
||||||
|
actual_items = ReversableRange.new(1, 10).select(&:even?)
|
||||||
|
|
||||||
|
expected_items = [2, 4, 6, 8, 10]
|
||||||
|
assert_equal expected_items, actual_items
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_is_not_empty_max_greater_than_min
|
||||||
|
range = ReversableRange.new(9, 10)
|
||||||
|
|
||||||
|
refute_predicate range, :empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_is_not_empty_max_equal_to_min
|
||||||
|
range = ReversableRange.new(10, 10)
|
||||||
|
|
||||||
|
refute_predicate range, :empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_is_empty_if_not_reversed_and_max_less_than_min
|
||||||
|
range = ReversableRange.new(10, 9)
|
||||||
|
|
||||||
|
assert_predicate range, :empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_ranges_with_the_same_max_and_min_have_one_element
|
||||||
|
actual_items = ReversableRange.new(1337, 1337).to_a
|
||||||
|
expected_items = [1337]
|
||||||
|
assert_equal expected_items, actual_items
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_load_slice_returns_a_sub_range
|
||||||
|
actual_items = ReversableRange.new(1, 10).load_slice(5, 8).to_a
|
||||||
|
|
||||||
|
expected_items = [5, 6, 7, 8]
|
||||||
|
assert_equal expected_items, actual_items
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_load_slice_returns_a_reversed_sub_range_if_reversed
|
||||||
|
range = ReversableRange.new(1, 10)
|
||||||
|
range.reverse!
|
||||||
|
actual_items = range.load_slice(5, 8).to_a
|
||||||
|
|
||||||
|
expected_items = [8, 7, 6, 5]
|
||||||
|
assert_equal expected_items, actual_items
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_is_equal_to_other_if_also_a_reversable_range_and_has_same_properties
|
||||||
|
one = ReversableRange.new(1, 10)
|
||||||
|
one.reverse!
|
||||||
|
|
||||||
|
two = ReversableRange.new(1, 10)
|
||||||
|
two.reverse!
|
||||||
|
|
||||||
|
assert_equal one, two
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_is_not_equal_to_a_non_reversable_range
|
||||||
|
range = ReversableRange.new(1, 10)
|
||||||
|
range.reverse!
|
||||||
|
|
||||||
|
refute_equal range, :something_else
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_is_not_equal_if_ranges_have_different_mins
|
||||||
|
one = ReversableRange.new(1, 10)
|
||||||
|
two = ReversableRange.new(2, 10)
|
||||||
|
|
||||||
|
refute_equal one, two
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_is_not_equal_if_ranges_have_different_maxes
|
||||||
|
one = ReversableRange.new(1, 10)
|
||||||
|
two = ReversableRange.new(1, 11)
|
||||||
|
|
||||||
|
refute_equal one, two
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_is_not_equal_if_only_one_is_reversed
|
||||||
|
one = ReversableRange.new(1, 10)
|
||||||
|
|
||||||
|
two = ReversableRange.new(1, 10)
|
||||||
|
two.reverse!
|
||||||
|
|
||||||
|
refute_equal one, two
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_to_s_mirrors_rubys_range_syntax
|
||||||
|
range = ReversableRange.new(1, 10)
|
||||||
|
assert_equal '1..10', range.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_to_s_reverses_when_reversed
|
||||||
|
range = ReversableRange.new(1, 10)
|
||||||
|
range.reverse!
|
||||||
|
assert_equal '10..1', range.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_size
|
||||||
|
range = ReversableRange.new(1, 10)
|
||||||
|
assert_equal 10, range.size
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user