mirror of
https://github.com/kemko/liquid.git
synced 2026-01-03 16:55:40 +03:00
Compare commits
5 Commits
rubocop-up
...
implicit-v
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b3e50f7ae | ||
|
|
3ef7eead27 | ||
|
|
250048717c | ||
|
|
78d2a437ff | ||
|
|
af614f3a2e |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -4,8 +4,6 @@
|
|||||||
pkg
|
pkg
|
||||||
*.rbc
|
*.rbc
|
||||||
.rvmrc
|
.rvmrc
|
||||||
.idea
|
|
||||||
.ruby-version
|
.ruby-version
|
||||||
Gemfile.lock
|
Gemfile.lock
|
||||||
.bundle
|
.bundle
|
||||||
.byebug_history
|
|
||||||
|
|||||||
1027
.rubocop.shopify.yml
1027
.rubocop.shopify.yml
File diff suppressed because it is too large
Load Diff
134
.rubocop.yml
134
.rubocop.yml
@@ -1,10 +1,132 @@
|
|||||||
inherit_from:
|
inherit_from:
|
||||||
- .rubocop.shopify.yml
|
- .rubocop_todo.yml
|
||||||
|
- ./.rubocop_todo.yml
|
||||||
|
|
||||||
require: rubocop-performance
|
AllCops:
|
||||||
|
Exclude:
|
||||||
|
- 'performance/shopify/*'
|
||||||
|
- 'pkg/**'
|
||||||
|
|
||||||
Performance:
|
Metrics/BlockNesting:
|
||||||
Enabled: true
|
Max: 3
|
||||||
|
|
||||||
Metrics/LineLength:
|
Metrics/ModuleLength:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
Metrics/ClassLength:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Lint/AssignmentInCondition:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Lint/AmbiguousOperator:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Lint/AmbiguousRegexpLiteral:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Lint/ParenthesesAsGroupedExpression:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Lint/UnusedBlockArgument:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Layout/EndAlignment:
|
||||||
|
EnforcedStyleAlignWith: variable
|
||||||
|
|
||||||
|
Lint/UnusedMethodArgument:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/SingleLineBlockParams:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/DoubleNegation:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/StringLiteralsInInterpolation:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/AndOr:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/SignalException:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/StringLiterals:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/BracesAroundHashParameters:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/NumericLiterals:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Layout/SpaceInsideArrayLiteralBrackets:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Layout/SpaceBeforeBlockBraces:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/Documentation:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/ClassAndModuleChildren:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/TrailingCommaInArrayLiteral:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/TrailingCommaInHashLiteral:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Layout/IndentHash:
|
||||||
|
EnforcedStyle: consistent
|
||||||
|
|
||||||
|
Style/FormatString:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Layout/AlignParameters:
|
||||||
|
EnforcedStyle: with_fixed_indentation
|
||||||
|
|
||||||
|
Layout/MultilineOperationIndentation:
|
||||||
|
EnforcedStyle: indented
|
||||||
|
|
||||||
|
Style/IfUnlessModifier:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/RaiseArgs:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/PreferredHashMethods:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/RegexpLiteral:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/SymbolLiteral:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Performance/Count:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Naming/ConstantName:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Layout/CaseIndentation:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/ClassVars:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/PerlBackrefs:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/TrivialAccessors:
|
||||||
|
AllowPredicates: true
|
||||||
|
|
||||||
|
Style/WordArray:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Naming/MethodName:
|
||||||
|
Exclude:
|
||||||
|
- 'example/server/liquid_servlet.rb'
|
||||||
|
|||||||
260
.rubocop_todo.yml
Normal file
260
.rubocop_todo.yml
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
# This configuration was generated by
|
||||||
|
# `rubocop --auto-gen-config`
|
||||||
|
# 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
|
||||||
|
# one by one as the offenses are removed from the code base.
|
||||||
|
# Note that changes in the inspected code, or installation of new
|
||||||
|
# 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
|
||||||
|
# Cop supports --auto-correct.
|
||||||
|
# Configuration parameters: EnforcedStyle.
|
||||||
|
# SupportedStyles: auto_detection, squiggly, active_support, powerpack, unindent
|
||||||
|
Layout/IndentHeredoc:
|
||||||
|
Exclude:
|
||||||
|
- 'test/integration/tags/for_tag_test.rb'
|
||||||
|
- 'test/integration/trim_mode_test.rb'
|
||||||
|
|
||||||
|
# Offense count: 6
|
||||||
|
# Cop supports --auto-correct.
|
||||||
|
# Configuration parameters: EnforcedStyle.
|
||||||
|
# SupportedStyles: symmetrical, new_line, same_line
|
||||||
|
Layout/MultilineMethodCallBraceLayout:
|
||||||
|
Exclude:
|
||||||
|
- 'test/integration/error_handling_test.rb'
|
||||||
|
- 'test/unit/strainer_unit_test.rb'
|
||||||
|
|
||||||
|
# Offense count: 2
|
||||||
|
# Cop supports --auto-correct.
|
||||||
|
# Configuration parameters: EnforcedStyle.
|
||||||
|
# SupportedStyles: runtime_error, standard_error
|
||||||
|
Lint/InheritException:
|
||||||
|
Exclude:
|
||||||
|
- 'lib/liquid/interrupts.rb'
|
||||||
|
|
||||||
|
# Offense count: 1
|
||||||
|
# Configuration parameters: CheckForMethodsWithNoSideEffects.
|
||||||
|
Lint/Void:
|
||||||
|
Exclude:
|
||||||
|
- 'lib/liquid/parse_context.rb'
|
||||||
|
|
||||||
|
# Offense count: 54
|
||||||
|
Metrics/AbcSize:
|
||||||
|
Max: 56
|
||||||
|
|
||||||
|
# Offense count: 12
|
||||||
|
Metrics/CyclomaticComplexity:
|
||||||
|
Max: 12
|
||||||
|
|
||||||
|
# Offense count: 112
|
||||||
|
# Configuration parameters: CountComments.
|
||||||
|
Metrics/MethodLength:
|
||||||
|
Max: 37
|
||||||
|
|
||||||
|
# Offense count: 8
|
||||||
|
Metrics/PerceivedComplexity:
|
||||||
|
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
|
||||||
|
# Cop supports --auto-correct.
|
||||||
|
# Configuration parameters: EnforcedStyle.
|
||||||
|
# SupportedStyles: prefer_alias, prefer_alias_method
|
||||||
|
Style/Alias:
|
||||||
|
Exclude:
|
||||||
|
- 'lib/liquid/drop.rb'
|
||||||
|
- 'lib/liquid/i18n.rb'
|
||||||
|
- 'lib/liquid/profiler/hooks.rb'
|
||||||
|
- 'lib/liquid/standardfilters.rb'
|
||||||
|
- 'lib/liquid/tag.rb'
|
||||||
|
- 'lib/liquid/tags/include.rb'
|
||||||
|
- 'lib/liquid/variable.rb'
|
||||||
|
|
||||||
|
# Offense count: 22
|
||||||
|
Style/CommentedKeyword:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
# Offense count: 1
|
||||||
|
# Cop supports --auto-correct.
|
||||||
|
# Configuration parameters: EnforcedStyle, SingleLineConditionsOnly, IncludeTernaryExpressions.
|
||||||
|
# SupportedStyles: assign_to_condition, assign_inside_condition
|
||||||
|
Style/ConditionalAssignment:
|
||||||
|
Exclude:
|
||||||
|
- 'lib/liquid/errors.rb'
|
||||||
|
|
||||||
|
# Offense count: 1
|
||||||
|
Style/DateTime:
|
||||||
|
Exclude:
|
||||||
|
- 'test/unit/context_unit_test.rb'
|
||||||
|
|
||||||
|
# Offense count: 2
|
||||||
|
# Cop supports --auto-correct.
|
||||||
|
Style/EmptyCaseCondition:
|
||||||
|
Exclude:
|
||||||
|
- 'lib/liquid/block_body.rb'
|
||||||
|
- 'lib/liquid/lexer.rb'
|
||||||
|
|
||||||
|
# Offense count: 5
|
||||||
|
# Cop supports --auto-correct.
|
||||||
|
# Configuration parameters: EnforcedStyle.
|
||||||
|
# SupportedStyles: compact, expanded
|
||||||
|
Style/EmptyMethod:
|
||||||
|
Exclude:
|
||||||
|
- 'lib/liquid/tag.rb'
|
||||||
|
- 'lib/liquid/tags/comment.rb'
|
||||||
|
- 'lib/liquid/tags/include.rb'
|
||||||
|
- 'test/integration/tags/include_tag_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
|
||||||
|
# Cop supports --auto-correct.
|
||||||
|
Style/ExpandPathArguments:
|
||||||
|
Exclude:
|
||||||
|
- 'Rakefile'
|
||||||
|
- 'liquid.gemspec'
|
||||||
|
|
||||||
|
# Offense count: 7
|
||||||
|
# Configuration parameters: EnforcedStyle.
|
||||||
|
# SupportedStyles: annotated, template, unannotated
|
||||||
|
Style/FormatStringToken:
|
||||||
|
Exclude:
|
||||||
|
- 'test/integration/filter_test.rb'
|
||||||
|
- 'test/integration/hash_ordering_test.rb'
|
||||||
|
|
||||||
|
# Offense count: 14
|
||||||
|
# Configuration parameters: MinBodyLength.
|
||||||
|
Style/GuardClause:
|
||||||
|
Exclude:
|
||||||
|
- 'lib/liquid/condition.rb'
|
||||||
|
- 'lib/liquid/lexer.rb'
|
||||||
|
- 'lib/liquid/strainer.rb'
|
||||||
|
- 'lib/liquid/tags/assign.rb'
|
||||||
|
- 'lib/liquid/tags/capture.rb'
|
||||||
|
- 'lib/liquid/tags/case.rb'
|
||||||
|
- 'lib/liquid/tags/for.rb'
|
||||||
|
- 'lib/liquid/tags/include.rb'
|
||||||
|
- 'lib/liquid/tags/raw.rb'
|
||||||
|
- 'lib/liquid/tags/table_row.rb'
|
||||||
|
- 'lib/liquid/variable.rb'
|
||||||
|
- 'test/unit/tokenizer_unit_test.rb'
|
||||||
|
|
||||||
|
# Offense count: 1
|
||||||
|
# Cop supports --auto-correct.
|
||||||
|
# Configuration parameters: EnforcedStyle, MinBodyLength.
|
||||||
|
# SupportedStyles: skip_modifier_ifs, always
|
||||||
|
Style/Next:
|
||||||
|
Exclude:
|
||||||
|
- 'lib/liquid/tags/for.rb'
|
||||||
|
|
||||||
|
# Offense count: 4
|
||||||
|
# Cop supports --auto-correct.
|
||||||
|
# Configuration parameters: AutoCorrect, EnforcedStyle.
|
||||||
|
# SupportedStyles: predicate, comparison
|
||||||
|
Style/NumericPredicate:
|
||||||
|
Exclude:
|
||||||
|
- 'spec/**/*'
|
||||||
|
- 'lib/liquid/context.rb'
|
||||||
|
- 'lib/liquid/forloop_drop.rb'
|
||||||
|
- 'lib/liquid/standardfilters.rb'
|
||||||
|
- 'lib/liquid/tablerowloop_drop.rb'
|
||||||
|
|
||||||
|
# Offense count: 14
|
||||||
|
# Cop supports --auto-correct.
|
||||||
|
# Configuration parameters: PreferredDelimiters.
|
||||||
|
Style/PercentLiteralDelimiters:
|
||||||
|
Exclude:
|
||||||
|
- 'lib/liquid/tags/if.rb'
|
||||||
|
- 'liquid.gemspec'
|
||||||
|
- 'test/integration/assign_test.rb'
|
||||||
|
- 'test/integration/standard_filter_test.rb'
|
||||||
|
|
||||||
|
# Offense count: 1
|
||||||
|
# Cop supports --auto-correct.
|
||||||
|
Style/RedundantSelf:
|
||||||
|
Exclude:
|
||||||
|
- 'lib/liquid/strainer.rb'
|
||||||
|
|
||||||
|
# Offense count: 9
|
||||||
|
# Cop supports --auto-correct.
|
||||||
|
# Configuration parameters: AllowAsExpressionSeparator.
|
||||||
|
Style/Semicolon:
|
||||||
|
Exclude:
|
||||||
|
- 'test/integration/error_handling_test.rb'
|
||||||
|
- 'test/integration/template_test.rb'
|
||||||
|
- 'test/unit/context_unit_test.rb'
|
||||||
|
|
||||||
|
# Offense count: 7
|
||||||
|
# Cop supports --auto-correct.
|
||||||
|
# Configuration parameters: MinSize.
|
||||||
|
# SupportedStyles: percent, brackets
|
||||||
|
Style/SymbolArray:
|
||||||
|
EnforcedStyle: brackets
|
||||||
|
|
||||||
|
# Offense count: 2
|
||||||
|
# Cop supports --auto-correct.
|
||||||
|
# Configuration parameters: EnforcedStyle, AllowSafeAssignment.
|
||||||
|
# SupportedStyles: require_parentheses, require_no_parentheses, require_parentheses_when_complex
|
||||||
|
Style/TernaryParentheses:
|
||||||
|
Exclude:
|
||||||
|
- 'lib/liquid/context.rb'
|
||||||
|
- 'lib/liquid/utils.rb'
|
||||||
|
|
||||||
|
# Offense count: 2
|
||||||
|
# Cop supports --auto-correct.
|
||||||
|
Style/UnneededPercentQ:
|
||||||
|
Exclude:
|
||||||
|
- 'test/integration/error_handling_test.rb'
|
||||||
|
|
||||||
|
# Offense count: 1
|
||||||
|
# Cop supports --auto-correct.
|
||||||
|
Style/WhileUntilModifier:
|
||||||
|
Exclude:
|
||||||
|
- 'lib/liquid/tags/case.rb'
|
||||||
|
|
||||||
|
# Offense count: 640
|
||||||
|
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
|
||||||
|
# URISchemes: http, https
|
||||||
|
Metrics/LineLength:
|
||||||
|
Max: 294
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
language: ruby
|
language: ruby
|
||||||
|
|
||||||
rvm:
|
rvm:
|
||||||
|
- 2.1
|
||||||
|
- 2.2
|
||||||
|
- 2.3
|
||||||
- 2.4
|
- 2.4
|
||||||
- 2.5
|
- 2.5
|
||||||
- 2.6
|
|
||||||
- 2.7
|
|
||||||
- ruby-head
|
- ruby-head
|
||||||
- jruby-head
|
- jruby-head
|
||||||
- truffleruby
|
# - rbx-2
|
||||||
|
|
||||||
sudo: false
|
sudo: false
|
||||||
|
|
||||||
|
|||||||
11
Gemfile
11
Gemfile
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
git_source(:github) do |repo_name|
|
git_source(:github) do |repo_name|
|
||||||
"https://github.com/#{repo_name}.git"
|
"https://github.com/#{repo_name}.git"
|
||||||
@@ -11,16 +9,15 @@ group :benchmark, :test do
|
|||||||
gem 'benchmark-ips'
|
gem 'benchmark-ips'
|
||||||
gem 'memory_profiler'
|
gem 'memory_profiler'
|
||||||
|
|
||||||
install_if -> { RUBY_PLATFORM !~ /mingw|mswin|java/ && RUBY_ENGINE != 'truffleruby' } do
|
install_if -> { RUBY_PLATFORM !~ /mingw|mswin|java/ } do
|
||||||
gem 'stackprof'
|
gem 'stackprof'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
group :test do
|
group :test do
|
||||||
gem 'rubocop', '~> 0.74.0', require: false
|
gem 'rubocop', '~> 0.53.0'
|
||||||
gem 'rubocop-performance', require: false
|
|
||||||
|
|
||||||
platform :mri, :truffleruby do
|
platform :mri do
|
||||||
gem 'liquid-c', github: 'Shopify/liquid-c', ref: '7ba926791ef8411984d0f3e41c6353fd716041c6'
|
gem 'liquid-c', github: 'Shopify/liquid-c', ref: '9168659de45d6d576fce30c735f857e597fa26f6'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -274,7 +274,7 @@ Yanked from rubygems, as it contained too many changes that broke compatibility.
|
|||||||
* Fixed bad error reporting when a filter called a method which doesn't exist. Liquid told you that it couldn't find the filter which was obviously misleading [Tobias Luetke]
|
* Fixed bad error reporting when a filter called a method which doesn't exist. Liquid told you that it couldn't find the filter which was obviously misleading [Tobias Luetke]
|
||||||
* Removed count helper from standard lib. use size [Tobias Luetke]
|
* Removed count helper from standard lib. use size [Tobias Luetke]
|
||||||
* Fixed bug with string filter parameters failing to tolerate commas in strings. [Paul Hammond]
|
* Fixed bug with string filter parameters failing to tolerate commas in strings. [Paul Hammond]
|
||||||
* Improved filter parameters. Filter parameters are now context sensitive; Types are resolved according to the rules of the context. Multiple parameters are now separated by the Liquid::ARGUMENT_SEPARATOR: , by default [Paul Hammond]
|
* Improved filter parameters. Filter parameters are now context sensitive; Types are resolved according to the rules of the context. Multiple parameters are now separated by the Liquid::ArgumentSeparator: , by default [Paul Hammond]
|
||||||
{{ 'Typo' | link_to: 'http://typo.leetsoft.com', 'Typo - a modern weblog engine' }}
|
{{ 'Typo' | link_to: 'http://typo.leetsoft.com', 'Typo - a modern weblog engine' }}
|
||||||
* Added Liquid::Drop. A base class which you can use for exporting proxy objects to liquid which can acquire more data when used in liquid. [Tobias Luetke]
|
* Added Liquid::Drop. A base class which you can use for exporting proxy objects to liquid which can acquire more data when used in liquid. [Tobias Luetke]
|
||||||
|
|
||||||
|
|||||||
55
Rakefile
55
Rakefile
@@ -1,33 +1,29 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'rake'
|
require 'rake'
|
||||||
require 'rake/testtask'
|
require 'rake/testtask'
|
||||||
$LOAD_PATH.unshift(File.expand_path('lib', __dir__))
|
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
||||||
require 'liquid/version'
|
require "liquid/version"
|
||||||
|
|
||||||
task(default: %i[test rubocop])
|
task default: [:test, :rubocop]
|
||||||
|
|
||||||
desc('run test suite with default parser')
|
desc 'run test suite with default parser'
|
||||||
Rake::TestTask.new(:base_test) do |t|
|
Rake::TestTask.new(:base_test) do |t|
|
||||||
t.libs << '.' << 'lib' << 'test'
|
t.libs << '.' << 'lib' << 'test'
|
||||||
t.test_files = FileList['test/{integration,unit}/**/*_test.rb']
|
t.test_files = FileList['test/{integration,unit}/**/*_test.rb']
|
||||||
t.verbose = false
|
t.verbose = false
|
||||||
end
|
end
|
||||||
|
|
||||||
desc('run test suite with warn error mode')
|
desc 'run test suite with warn error mode'
|
||||||
task :warn_test do
|
task :warn_test do
|
||||||
ENV['LIQUID_PARSER_MODE'] = 'warn'
|
ENV['LIQUID_PARSER_MODE'] = 'warn'
|
||||||
Rake::Task['base_test'].invoke
|
Rake::Task['base_test'].invoke
|
||||||
end
|
end
|
||||||
|
|
||||||
task :rubocop do
|
task :rubocop do
|
||||||
if RUBY_ENGINE == 'ruby'
|
require 'rubocop/rake_task'
|
||||||
require 'rubocop/rake_task'
|
RuboCop::RakeTask.new
|
||||||
RuboCop::RakeTask.new
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
desc('runs test suite with both strict and lax parsers')
|
desc 'runs test suite with both strict and lax parsers'
|
||||||
task :test do
|
task :test do
|
||||||
ENV['LIQUID_PARSER_MODE'] = 'lax'
|
ENV['LIQUID_PARSER_MODE'] = 'lax'
|
||||||
Rake::Task['base_test'].invoke
|
Rake::Task['base_test'].invoke
|
||||||
@@ -36,9 +32,8 @@ task :test do
|
|||||||
Rake::Task['base_test'].reenable
|
Rake::Task['base_test'].reenable
|
||||||
Rake::Task['base_test'].invoke
|
Rake::Task['base_test'].invoke
|
||||||
|
|
||||||
if RUBY_ENGINE == 'ruby' || RUBY_ENGINE == 'truffleruby'
|
if RUBY_ENGINE == 'ruby'
|
||||||
|
ENV['LIQUID-C'] = '1'
|
||||||
ENV['LIQUID_C'] = '1'
|
|
||||||
|
|
||||||
ENV['LIQUID_PARSER_MODE'] = 'lax'
|
ENV['LIQUID_PARSER_MODE'] = 'lax'
|
||||||
Rake::Task['base_test'].reenable
|
Rake::Task['base_test'].reenable
|
||||||
@@ -50,9 +45,9 @@ task :test do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
task(gem: :build)
|
task gem: :build
|
||||||
task :build do
|
task :build do
|
||||||
system 'gem build liquid.gemspec'
|
system "gem build liquid.gemspec"
|
||||||
end
|
end
|
||||||
|
|
||||||
task install: :build do
|
task install: :build do
|
||||||
@@ -61,45 +56,45 @@ end
|
|||||||
|
|
||||||
task release: :build do
|
task release: :build do
|
||||||
system "git tag -a v#{Liquid::VERSION} -m 'Tagging #{Liquid::VERSION}'"
|
system "git tag -a v#{Liquid::VERSION} -m 'Tagging #{Liquid::VERSION}'"
|
||||||
system 'git push --tags'
|
system "git push --tags"
|
||||||
system "gem push liquid-#{Liquid::VERSION}.gem"
|
system "gem push liquid-#{Liquid::VERSION}.gem"
|
||||||
system "rm liquid-#{Liquid::VERSION}.gem"
|
system "rm liquid-#{Liquid::VERSION}.gem"
|
||||||
end
|
end
|
||||||
|
|
||||||
namespace :benchmark do
|
namespace :benchmark do
|
||||||
desc 'Run the liquid benchmark with lax parsing'
|
desc "Run the liquid benchmark with lax parsing"
|
||||||
task :run do
|
task :run do
|
||||||
ruby './performance/benchmark.rb lax'
|
ruby "./performance/benchmark.rb lax"
|
||||||
end
|
end
|
||||||
|
|
||||||
desc 'Run the liquid benchmark with strict parsing'
|
desc "Run the liquid benchmark with strict parsing"
|
||||||
task :strict do
|
task :strict do
|
||||||
ruby './performance/benchmark.rb strict'
|
ruby "./performance/benchmark.rb strict"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
namespace :profile do
|
namespace :profile do
|
||||||
desc 'Run the liquid profile/performance coverage'
|
desc "Run the liquid profile/performance coverage"
|
||||||
task :run do
|
task :run do
|
||||||
ruby './performance/profile.rb'
|
ruby "./performance/profile.rb"
|
||||||
end
|
end
|
||||||
|
|
||||||
desc 'Run the liquid profile/performance coverage with strict parsing'
|
desc "Run the liquid profile/performance coverage with strict parsing"
|
||||||
task :strict do
|
task :strict do
|
||||||
ruby './performance/profile.rb strict'
|
ruby "./performance/profile.rb strict"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
namespace :memory_profile do
|
namespace :memory_profile do
|
||||||
desc 'Run memory profiler'
|
desc "Run memory profiler"
|
||||||
task :run do
|
task :run do
|
||||||
ruby './performance/memory_profile.rb'
|
ruby "./performance/memory_profile.rb"
|
||||||
end
|
end
|
||||||
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"
|
||||||
end
|
end
|
||||||
|
|
||||||
task :console do
|
task :console do
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module ProductsFilter
|
module ProductsFilter
|
||||||
def price(integer)
|
def price(integer)
|
||||||
format('$%.2d USD', integer / 100.0)
|
sprintf("$%.2d USD", integer / 100.0)
|
||||||
end
|
end
|
||||||
|
|
||||||
def prettyprint(text)
|
def prettyprint(text)
|
||||||
@@ -30,17 +28,17 @@ class Servlet < LiquidServlet
|
|||||||
private
|
private
|
||||||
|
|
||||||
def products_list
|
def products_list
|
||||||
[{ 'name' => 'Arbor Draft', 'price' => 39_900, 'description' => 'the *arbor draft* is a excellent product' },
|
[{ 'name' => 'Arbor Draft', 'price' => 39900, 'description' => 'the *arbor draft* is a excellent product' },
|
||||||
{ 'name' => 'Arbor Element', 'price' => 40_000, 'description' => 'the *arbor element* rocks for freestyling' },
|
{ 'name' => 'Arbor Element', 'price' => 40000, 'description' => 'the *arbor element* rocks for freestyling' },
|
||||||
{ 'name' => 'Arbor Diamond', 'price' => 59_900, 'description' => 'the *arbor diamond* is a made up product because im obsessed with arbor and have no creativity' }]
|
{ 'name' => 'Arbor Diamond', 'price' => 59900, 'description' => 'the *arbor diamond* is a made up product because im obsessed with arbor and have no creativity' }]
|
||||||
end
|
end
|
||||||
|
|
||||||
def more_products_list
|
def more_products_list
|
||||||
[{ 'name' => 'Arbor Catalyst', 'price' => 39_900, 'description' => 'the *arbor catalyst* is an advanced drop-through for freestyle and flatground performance and versatility' },
|
[{ 'name' => 'Arbor Catalyst', 'price' => 39900, 'description' => 'the *arbor catalyst* is an advanced drop-through for freestyle and flatground performance and versatility' },
|
||||||
{ 'name' => 'Arbor Fish', 'price' => 40_000, 'description' => 'the *arbor fish* is a compact pin that features an extended wheelbase and time-honored teardrop shape' }]
|
{ 'name' => 'Arbor Fish', 'price' => 40000, 'description' => 'the *arbor fish* is a compact pin that features an extended wheelbase and time-honored teardrop shape' }]
|
||||||
end
|
end
|
||||||
|
|
||||||
def description
|
def description
|
||||||
'List of Products ~ This is a list of products with price and description.'
|
"List of Products ~ This is a list of products with price and description."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,28 +1,23 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class LiquidServlet < WEBrick::HTTPServlet::AbstractServlet
|
class LiquidServlet < WEBrick::HTTPServlet::AbstractServlet
|
||||||
def get(req, res)
|
def do_GET(req, res)
|
||||||
handle(:get, req, res)
|
handle(:get, req, res)
|
||||||
end
|
end
|
||||||
|
|
||||||
def post(req, res)
|
def do_POST(req, res)
|
||||||
handle(:post, req, res)
|
handle(:post, req, res)
|
||||||
end
|
end
|
||||||
|
|
||||||
alias_method :do_GET, :get
|
|
||||||
alias_method :do_POST, :post
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def handle(_type, req, res)
|
def handle(type, req, res)
|
||||||
@request = req
|
@request = req
|
||||||
@response = res
|
@response = res
|
||||||
|
|
||||||
@request.path_info =~ /(\w+)\z/
|
@request.path_info =~ /(\w+)\z/
|
||||||
@action = Regexp.last_match(1) || 'index'
|
@action = $1 || 'index'
|
||||||
@assigns = send(@action) if respond_to?(@action)
|
@assigns = send(@action) if respond_to?(@action)
|
||||||
|
|
||||||
@response['Content-Type'] = 'text/html'
|
@response['Content-Type'] = "text/html"
|
||||||
@response.status = 200
|
@response.status = 200
|
||||||
@response.body = Liquid::Template.parse(read_template).render(@assigns, filters: [ProductsFilter])
|
@response.body = Liquid::Template.parse(read_template).render(@assigns, filters: [ProductsFilter])
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'webrick'
|
require 'webrick'
|
||||||
require 'rexml/document'
|
require 'rexml/document'
|
||||||
|
|
||||||
@@ -10,5 +8,5 @@ require_relative 'example_servlet'
|
|||||||
# Setup webrick
|
# Setup webrick
|
||||||
server = WEBrick::HTTPServer.new(Port: ARGV[1] || 3000)
|
server = WEBrick::HTTPServer.new(Port: ARGV[1] || 3000)
|
||||||
server.mount('/', Servlet)
|
server.mount('/', Servlet)
|
||||||
trap('INT') { server.shutdown }
|
trap("INT"){ server.shutdown }
|
||||||
server.start
|
server.start
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
# Copyright (c) 2005 Tobias Luetke
|
# Copyright (c) 2005 Tobias Luetke
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
@@ -22,31 +20,31 @@
|
|||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
FILTER_SEPARATOR = /\|/.freeze
|
FilterSeparator = /\|/
|
||||||
ARGUMENT_SEPARATOR = ','
|
ArgumentSeparator = ','.freeze
|
||||||
FILTER_ARGUMENT_SEPARATOR = ':'
|
FilterArgumentSeparator = ':'.freeze
|
||||||
VARIABLE_ATTRIBUTE_SEPARATOR = '.'
|
VariableAttributeSeparator = '.'.freeze
|
||||||
WHITESPACE_CONTROL = '-'
|
WhitespaceControl = '-'.freeze
|
||||||
TAG_START = /\{\%/.freeze
|
TagStart = /\{\%/
|
||||||
TAG_END = /\%\}/.freeze
|
TagEnd = /\%\}/
|
||||||
VARIABLE_SIGNATURE = /\(?[\w\-\.\[\]]\)?/.freeze
|
VariableSignature = /\(?[\w\-\.\[\]]\)?/
|
||||||
VARIABLE_SEGMENT = /[\w\-]/.freeze
|
VariableSegment = /[\w\-]/
|
||||||
VARIABLE_START = /\{\{/.freeze
|
VariableStart = /\{\{/
|
||||||
VARIABLE_END = /\}\}/.freeze
|
VariableEnd = /\}\}/
|
||||||
VARIABLE_INCOMPLETE_END = /\}\}?/.freeze
|
VariableIncompleteEnd = /\}\}?/
|
||||||
QUOTED_STRING = /"[^"]*"|'[^']*'/.freeze
|
QuotedString = /"[^"]*"|'[^']*'/
|
||||||
QUOTED_FRAGMENT = /#{QUOTED_STRING}|(?:[^\s,\|'"]|#{QUOTED_STRING})+/o.freeze
|
QuotedFragment = /#{QuotedString}|(?:[^\s,\|'"]|#{QuotedString})+/o
|
||||||
TAG_ATTRIBUTES = /(\w+)\s*\:\s*(#{QUOTED_FRAGMENT})/o.freeze
|
TagAttributes = /(\w+)\s*\:\s*(#{QuotedFragment})/o
|
||||||
ANY_STARTING_TAG = /#{TAG_START}|#{VARIABLE_START}/o.freeze
|
AnyStartingTag = /#{TagStart}|#{VariableStart}/o
|
||||||
PARTIAL_TEMPLATE_PARSER = /#{TAG_START}.*?#{TAG_END}|#{VARIABLE_START}.*?#{VARIABLE_INCOMPLETE_END}/om.freeze
|
PartialTemplateParser = /#{TagStart}.*?#{TagEnd}|#{VariableStart}.*?#{VariableIncompleteEnd}/om
|
||||||
TEMPLATE_PARSER = /(#{PARTIAL_TEMPLATE_PARSER}|#{ANY_STARTING_TAG})/om.freeze
|
TemplateParser = /(#{PartialTemplateParser}|#{AnyStartingTag})/om
|
||||||
VARIABLE_PARSER = /\[[^\]]+\]|#{VARIABLE_SEGMENT}+\??/o.freeze
|
VariableParser = /\[[^\]]+\]|#{VariableSegment}+\??/o
|
||||||
|
|
||||||
singleton_class.send(:attr_accessor, :cache_classes)
|
singleton_class.send(:attr_accessor, :cache_classes)
|
||||||
self.cache_classes = true
|
self.cache_classes = true
|
||||||
end
|
end
|
||||||
|
|
||||||
require 'liquid/version'
|
require "liquid/version"
|
||||||
require 'liquid/parse_tree_visitor'
|
require 'liquid/parse_tree_visitor'
|
||||||
require 'liquid/lexer'
|
require 'liquid/lexer'
|
||||||
require 'liquid/parser'
|
require 'liquid/parser'
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class Block < Tag
|
class Block < Tag
|
||||||
MAX_DEPTH = 100
|
MAX_DEPTH = 100
|
||||||
@@ -15,7 +13,6 @@ module Liquid
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# For backwards compatibility
|
|
||||||
def render(context)
|
def render(context)
|
||||||
@body.render(context)
|
@body.render(context)
|
||||||
end
|
end
|
||||||
@@ -29,16 +26,16 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def unknown_tag(tag, _params, _tokens)
|
def unknown_tag(tag, _params, _tokens)
|
||||||
if tag == 'else'
|
if tag == 'else'.freeze
|
||||||
raise SyntaxError, parse_context.locale.t('errors.syntax.unexpected_else',
|
raise SyntaxError.new(parse_context.locale.t("errors.syntax.unexpected_else".freeze,
|
||||||
block_name: block_name)
|
block_name: block_name))
|
||||||
elsif tag.start_with?('end')
|
elsif tag.start_with?('end'.freeze)
|
||||||
raise SyntaxError, parse_context.locale.t('errors.syntax.invalid_delimiter',
|
raise SyntaxError.new(parse_context.locale.t("errors.syntax.invalid_delimiter".freeze,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
block_name: block_name,
|
block_name: block_name,
|
||||||
block_delimiter: block_delimiter)
|
block_delimiter: block_delimiter))
|
||||||
else
|
else
|
||||||
raise SyntaxError, parse_context.locale.t('errors.syntax.unknown_tag', tag: tag)
|
raise SyntaxError.new(parse_context.locale.t("errors.syntax.unknown_tag".freeze, tag: tag))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -53,15 +50,18 @@ module Liquid
|
|||||||
protected
|
protected
|
||||||
|
|
||||||
def parse_body(body, tokens)
|
def parse_body(body, tokens)
|
||||||
raise StackLevelError, 'Nesting too deep' if parse_context.depth >= MAX_DEPTH
|
if parse_context.depth >= MAX_DEPTH
|
||||||
|
raise StackLevelError, "Nesting too deep".freeze
|
||||||
|
end
|
||||||
parse_context.depth += 1
|
parse_context.depth += 1
|
||||||
begin
|
begin
|
||||||
body.parse(tokens, parse_context) do |end_tag_name, end_tag_params|
|
body.parse(tokens, parse_context) do |end_tag_name, end_tag_params|
|
||||||
@blank &&= body.blank?
|
@blank &&= body.blank?
|
||||||
|
|
||||||
return false if end_tag_name == block_delimiter
|
return false if end_tag_name == block_delimiter
|
||||||
raise SyntaxError, parse_context.locale.t('errors.syntax.tag_never_closed', block_name: block_name) unless end_tag_name
|
unless end_tag_name
|
||||||
|
raise SyntaxError.new(parse_context.locale.t("errors.syntax.tag_never_closed".freeze, block_name: block_name))
|
||||||
|
end
|
||||||
|
|
||||||
# this tag is not registered with the system
|
# this tag is not registered with the system
|
||||||
# pass it to the current block for special handling or error reporting
|
# pass it to the current block for special handling or error reporting
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class BlockBody
|
class BlockBody
|
||||||
FULL_TOKEN = /\A#{TAG_START}#{WHITESPACE_CONTROL}?\s*(\w+)\s*(.*?)#{WHITESPACE_CONTROL}?#{TAG_END}\z/om.freeze
|
FullToken = /\A#{TagStart}#{WhitespaceControl}?\s*(\w+)\s*(.*?)#{WhitespaceControl}?#{TagEnd}\z/om
|
||||||
CONTENT_OF_VARIABLE = /\A#{VARIABLE_START}#{WHITESPACE_CONTROL}?(.*?)#{WHITESPACE_CONTROL}?#{VARIABLE_END}\z/om.freeze
|
ContentOfVariable = /\A#{VariableStart}#{WhitespaceControl}?(.*?)#{WhitespaceControl}?#{VariableEnd}\z/om
|
||||||
WHITESPACE_OR_NOTHING = /\A\s*\z/.freeze
|
WhitespaceOrNothing = /\A\s*\z/
|
||||||
TAG_START = '{%'
|
TAGSTART = "{%".freeze
|
||||||
VAR_START = '{{'
|
VARSTART = "{{".freeze
|
||||||
|
|
||||||
attr_reader :nodelist
|
attr_reader :nodelist
|
||||||
|
|
||||||
@@ -17,34 +15,36 @@ module Liquid
|
|||||||
|
|
||||||
def parse(tokenizer, parse_context)
|
def parse(tokenizer, parse_context)
|
||||||
parse_context.line_number = tokenizer.line_number
|
parse_context.line_number = tokenizer.line_number
|
||||||
while (token = tokenizer.shift)
|
while token = tokenizer.shift
|
||||||
next if token.empty?
|
next if token.empty?
|
||||||
|
|
||||||
case
|
case
|
||||||
when token.start_with?(TAG_START)
|
when token.start_with?(TAGSTART)
|
||||||
whitespace_handler(token, parse_context)
|
whitespace_handler(token, parse_context)
|
||||||
raise_missing_tag_terminator(token, parse_context) unless token =~ FULL_TOKEN
|
unless token =~ FullToken
|
||||||
tag_name = Regexp.last_match(1)
|
raise_missing_tag_terminator(token, parse_context)
|
||||||
markup = Regexp.last_match(2)
|
end
|
||||||
|
tag_name = $1
|
||||||
|
markup = $2
|
||||||
# fetch the tag from registered blocks
|
# fetch the tag from registered blocks
|
||||||
unless (tag = registered_tags[tag_name])
|
unless tag = registered_tags[tag_name]
|
||||||
# end parsing if we reach an unknown tag and let the caller decide
|
# end parsing if we reach an unknown tag and let the caller decide
|
||||||
# determine how to proceed
|
# determine how to proceed
|
||||||
return yield tag_name, markup
|
return yield tag_name, markup
|
||||||
end
|
end
|
||||||
|
|
||||||
new_tag = tag.parse(tag_name, markup, tokenizer, parse_context)
|
new_tag = tag.parse(tag_name, markup, tokenizer, parse_context)
|
||||||
@blank &&= new_tag.blank?
|
@blank &&= new_tag.blank?
|
||||||
@nodelist << new_tag
|
@nodelist << new_tag
|
||||||
when token.start_with?(VAR_START)
|
when token.start_with?(VARSTART)
|
||||||
whitespace_handler(token, parse_context)
|
whitespace_handler(token, parse_context)
|
||||||
@nodelist << create_variable(token, parse_context)
|
@nodelist << create_variable(token, parse_context)
|
||||||
@blank = false
|
@blank = false
|
||||||
else
|
else
|
||||||
token.lstrip! if parse_context.trim_whitespace
|
if parse_context.trim_whitespace
|
||||||
|
token.lstrip!
|
||||||
|
end
|
||||||
parse_context.trim_whitespace = false
|
parse_context.trim_whitespace = false
|
||||||
@nodelist << token
|
@nodelist << token
|
||||||
@blank &&= token.match?(WHITESPACE_OR_NOTHING)
|
@blank &&= !!(token =~ WhitespaceOrNothing)
|
||||||
end
|
end
|
||||||
parse_context.line_number = tokenizer.line_number
|
parse_context.line_number = tokenizer.line_number
|
||||||
end
|
end
|
||||||
@@ -53,11 +53,13 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def whitespace_handler(token, parse_context)
|
def whitespace_handler(token, parse_context)
|
||||||
if token[2] == WHITESPACE_CONTROL
|
if token[2] == WhitespaceControl
|
||||||
previous_token = @nodelist.last
|
previous_token = @nodelist.last
|
||||||
previous_token.rstrip! if previous_token.is_a?(String)
|
if previous_token.is_a? String
|
||||||
|
previous_token.rstrip!
|
||||||
|
end
|
||||||
end
|
end
|
||||||
parse_context.trim_whitespace = (token[-3] == WHITESPACE_CONTROL)
|
parse_context.trim_whitespace = (token[-3] == WhitespaceControl)
|
||||||
end
|
end
|
||||||
|
|
||||||
def blank?
|
def blank?
|
||||||
@@ -65,23 +67,19 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def render(context)
|
def render(context)
|
||||||
render_to_output_buffer(context, +'')
|
output = []
|
||||||
end
|
|
||||||
|
|
||||||
def render_to_output_buffer(context, output)
|
|
||||||
context.resource_limits.render_score += @nodelist.length
|
context.resource_limits.render_score += @nodelist.length
|
||||||
|
|
||||||
idx = 0
|
idx = 0
|
||||||
while (node = @nodelist[idx])
|
while node = @nodelist[idx]
|
||||||
previous_output_size = output.bytesize
|
|
||||||
|
|
||||||
case node
|
case node
|
||||||
when String
|
when String
|
||||||
|
check_resources(context, node)
|
||||||
output << node
|
output << node
|
||||||
when Variable
|
when Variable
|
||||||
render_node(context, output, node)
|
render_node_to_output(node, output, context)
|
||||||
when Block
|
when Block
|
||||||
render_node(context, node.blank? ? +'' : output, node)
|
render_node_to_output(node, output, context, node.blank?)
|
||||||
break if context.interrupt? # might have happened in a for-block
|
break if context.interrupt? # might have happened in a for-block
|
||||||
when Continue, Break
|
when Continue, Break
|
||||||
# If we get an Interrupt that means the block must stop processing. An
|
# If we get an Interrupt that means the block must stop processing. An
|
||||||
@@ -90,37 +88,40 @@ module Liquid
|
|||||||
context.push_interrupt(node.interrupt)
|
context.push_interrupt(node.interrupt)
|
||||||
break
|
break
|
||||||
else # Other non-Block tags
|
else # Other non-Block tags
|
||||||
render_node(context, output, node)
|
render_node_to_output(node, output, context)
|
||||||
break if context.interrupt? # might have happened through an include
|
break if context.interrupt? # might have happened through an include
|
||||||
end
|
end
|
||||||
idx += 1
|
idx += 1
|
||||||
|
|
||||||
raise_if_resource_limits_reached(context, output.bytesize - previous_output_size)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
output
|
output.join
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def render_node(context, output, node)
|
def render_node_to_output(node, output, context, skip_output = false)
|
||||||
node.render_to_output_buffer(context, output)
|
node_output = node.render(context)
|
||||||
|
node_output = node_output.is_a?(Array) ? node_output.join : node_output.to_s
|
||||||
|
check_resources(context, node_output)
|
||||||
|
output << node_output unless skip_output
|
||||||
|
rescue MemoryError => e
|
||||||
|
raise e
|
||||||
rescue UndefinedVariable, UndefinedDropMethod, UndefinedFilter => e
|
rescue UndefinedVariable, UndefinedDropMethod, UndefinedFilter => e
|
||||||
context.handle_error(e, node.line_number)
|
context.handle_error(e, node.line_number)
|
||||||
|
output << nil
|
||||||
rescue ::StandardError => e
|
rescue ::StandardError => e
|
||||||
line_number = node.is_a?(String) ? nil : node.line_number
|
line_number = node.is_a?(String) ? nil : node.line_number
|
||||||
output << context.handle_error(e, line_number)
|
output << context.handle_error(e, line_number)
|
||||||
end
|
end
|
||||||
|
|
||||||
def raise_if_resource_limits_reached(context, length)
|
def check_resources(context, node_output)
|
||||||
context.resource_limits.render_length += 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, 'Memory limits exceeded'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_variable(token, parse_context)
|
def create_variable(token, parse_context)
|
||||||
token.scan(CONTENT_OF_VARIABLE) do |content|
|
token.scan(ContentOfVariable) do |content|
|
||||||
markup = content.first
|
markup = content.first
|
||||||
return Variable.new(markup, parse_context)
|
return Variable.new(markup, parse_context)
|
||||||
end
|
end
|
||||||
@@ -128,11 +129,11 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def raise_missing_tag_terminator(token, parse_context)
|
def raise_missing_tag_terminator(token, parse_context)
|
||||||
raise SyntaxError, parse_context.locale.t('errors.syntax.tag_termination', token: token, tag_end: TAG_END.inspect)
|
raise SyntaxError.new(parse_context.locale.t("errors.syntax.tag_termination".freeze, token: token, tag_end: TagEnd.inspect))
|
||||||
end
|
end
|
||||||
|
|
||||||
def raise_missing_variable_terminator(token, parse_context)
|
def raise_missing_variable_terminator(token, parse_context)
|
||||||
raise SyntaxError, parse_context.locale.t('errors.syntax.variable_termination', token: token, tag_end: VARIABLE_END.inspect)
|
raise SyntaxError.new(parse_context.locale.t("errors.syntax.variable_termination".freeze, token: token, tag_end: VariableEnd.inspect))
|
||||||
end
|
end
|
||||||
|
|
||||||
def registered_tags
|
def registered_tags
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
# Container for liquid nodes which conveniently wraps decision making logic
|
# Container for liquid nodes which conveniently wraps decision making logic
|
||||||
#
|
#
|
||||||
@@ -9,26 +7,26 @@ module Liquid
|
|||||||
# c.evaluate #=> true
|
# c.evaluate #=> true
|
||||||
#
|
#
|
||||||
class Condition #:nodoc:
|
class Condition #:nodoc:
|
||||||
@operators = {
|
@@operators = {
|
||||||
'==' => ->(cond, left, right) { cond.send(:equal_variables, left, right) },
|
'=='.freeze => ->(cond, left, right) { cond.send(:equal_variables, left, right) },
|
||||||
'!=' => ->(cond, left, right) { !cond.send(:equal_variables, left, right) },
|
'!='.freeze => ->(cond, left, right) { !cond.send(:equal_variables, left, right) },
|
||||||
'<>' => ->(cond, left, right) { !cond.send(:equal_variables, left, right) },
|
'<>'.freeze => ->(cond, left, right) { !cond.send(:equal_variables, left, right) },
|
||||||
'<' => :<,
|
'<'.freeze => :<,
|
||||||
'>' => :>,
|
'>'.freeze => :>,
|
||||||
'>=' => :>=,
|
'>='.freeze => :>=,
|
||||||
'<=' => :<=,
|
'<='.freeze => :<=,
|
||||||
'contains' => lambda do |_cond, left, right|
|
'contains'.freeze => lambda do |cond, left, right|
|
||||||
if left && right && left.respond_to?(:include?)
|
if left && right && left.respond_to?(:include?)
|
||||||
right = right.to_s if left.is_a?(String)
|
right = right.to_s if left.is_a?(String)
|
||||||
left.include?(right)
|
left.include?(right)
|
||||||
else
|
else
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
end,
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
class << self
|
def self.operators
|
||||||
attr_accessor :operators
|
@@operators
|
||||||
end
|
end
|
||||||
|
|
||||||
attr_reader :attachment, :child_condition
|
attr_reader :attachment, :child_condition
|
||||||
@@ -38,7 +36,7 @@ module Liquid
|
|||||||
@left = left
|
@left = left
|
||||||
@operator = operator
|
@operator = operator
|
||||||
@right = right
|
@right = right
|
||||||
@child_relation = nil
|
@child_relation = nil
|
||||||
@child_condition = nil
|
@child_condition = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -80,7 +78,7 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def inspect
|
def inspect
|
||||||
"#<Condition #{[@left, @operator, @right].compact.join(' ')}>"
|
"#<Condition #{[@left, @operator, @right].compact.join(' '.freeze)}>"
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
@@ -118,7 +116,7 @@ module Liquid
|
|||||||
left = context.evaluate(left)
|
left = context.evaluate(left)
|
||||||
right = context.evaluate(right)
|
right = context.evaluate(right)
|
||||||
|
|
||||||
operation = self.class.operators[op] || raise(Liquid::ArgumentError, "Unknown operator #{op}")
|
operation = self.class.operators[op] || raise(Liquid::ArgumentError.new("Unknown operator #{op}"))
|
||||||
|
|
||||||
if operation.respond_to?(:call)
|
if operation.respond_to?(:call)
|
||||||
operation.call(self, left, right)
|
operation.call(self, left, right)
|
||||||
@@ -126,7 +124,7 @@ module Liquid
|
|||||||
begin
|
begin
|
||||||
left.send(operation, right)
|
left.send(operation, right)
|
||||||
rescue ::ArgumentError => e
|
rescue ::ArgumentError => e
|
||||||
raise Liquid::ArgumentError, e.message
|
raise Liquid::ArgumentError.new(e.message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
# Context keeps the variable stack and resolves variables, as well as keywords
|
# Context keeps the variable stack and resolves variables, as well as keywords
|
||||||
#
|
#
|
||||||
@@ -14,12 +12,12 @@ module Liquid
|
|||||||
#
|
#
|
||||||
# context['bob'] #=> nil class Context
|
# context['bob'] #=> nil class Context
|
||||||
class Context
|
class Context
|
||||||
attr_reader :scopes, :errors, :registers, :environments, :resource_limits
|
attr_reader :scope, :errors, :registers, :environments, :resource_limits
|
||||||
attr_accessor :exception_renderer, :template_name, :partial, :global_filter, :strict_variables, :strict_filters
|
attr_accessor :exception_renderer, :template_name, :partial, :global_filter, :strict_variables, :strict_filters
|
||||||
|
|
||||||
def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = nil)
|
def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = nil)
|
||||||
@environments = [environments].flatten
|
@environments = [environments].flatten
|
||||||
@scopes = [(outer_scope || {})]
|
@scope = outer_scope || {}
|
||||||
@registers = registers
|
@registers = registers
|
||||||
@errors = []
|
@errors = []
|
||||||
@partial = false
|
@partial = false
|
||||||
@@ -27,14 +25,16 @@ module Liquid
|
|||||||
@resource_limits = resource_limits || ResourceLimits.new(Template.default_resource_limits)
|
@resource_limits = resource_limits || ResourceLimits.new(Template.default_resource_limits)
|
||||||
squash_instance_assigns_with_environments
|
squash_instance_assigns_with_environments
|
||||||
|
|
||||||
@this_stack_used = false
|
|
||||||
|
|
||||||
self.exception_renderer = Template.default_exception_renderer
|
self.exception_renderer = Template.default_exception_renderer
|
||||||
self.exception_renderer = ->(_e) { raise } if rethrow_errors
|
if rethrow_errors
|
||||||
|
self.exception_renderer = ->(e) { raise }
|
||||||
|
end
|
||||||
|
|
||||||
@interrupts = []
|
@interrupts = []
|
||||||
@filters = []
|
@filters = []
|
||||||
@global_filter = nil
|
@global_filter = nil
|
||||||
|
|
||||||
|
@stack_level = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
def warnings
|
def warnings
|
||||||
@@ -86,22 +86,9 @@ module Liquid
|
|||||||
strainer.invoke(method, *args).to_liquid
|
strainer.invoke(method, *args).to_liquid
|
||||||
end
|
end
|
||||||
|
|
||||||
# Push new local scope on the stack. use <tt>Context#stack</tt> instead
|
|
||||||
def push(new_scope = {})
|
|
||||||
@scopes.unshift(new_scope)
|
|
||||||
raise StackLevelError, 'Nesting too deep' if @scopes.length > Block::MAX_DEPTH
|
|
||||||
end
|
|
||||||
|
|
||||||
# Merge a hash of variables in the current local scope
|
# Merge a hash of variables in the current local scope
|
||||||
def merge(new_scopes)
|
def merge(new_scopes)
|
||||||
@scopes[0].merge!(new_scopes)
|
new_scopes.each { |k, v| self[k] = v }
|
||||||
end
|
|
||||||
|
|
||||||
# Pop from the stack. use <tt>Context#stack</tt> instead
|
|
||||||
def pop
|
|
||||||
raise ContextError if @scopes.size == 1
|
|
||||||
|
|
||||||
@scopes.shift
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Pushes a new local scope on the stack, pops it at the end of the block
|
# Pushes a new local scope on the stack, pops it at the end of the block
|
||||||
@@ -112,32 +99,20 @@ module Liquid
|
|||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# context['var] #=> nil
|
# context['var] #=> nil
|
||||||
def stack(new_scope = nil)
|
def stack(*variable_names)
|
||||||
old_stack_used = @this_stack_used
|
@stack_level += 1
|
||||||
if new_scope
|
raise StackLevelError, "Nesting too deep".freeze if @stack_level > Block::MAX_DEPTH
|
||||||
push(new_scope)
|
|
||||||
@this_stack_used = true
|
begin
|
||||||
else
|
yield
|
||||||
@this_stack_used = false
|
ensure
|
||||||
|
@stack_level -= 1
|
||||||
end
|
end
|
||||||
|
|
||||||
yield
|
|
||||||
ensure
|
|
||||||
pop if @this_stack_used
|
|
||||||
@this_stack_used = old_stack_used
|
|
||||||
end
|
|
||||||
|
|
||||||
def clear_instance_assigns
|
|
||||||
@scopes[0] = {}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Only allow String, Numeric, Hash, Array, Proc, Boolean or <tt>Liquid::Drop</tt>
|
# Only allow String, Numeric, Hash, Array, Proc, Boolean or <tt>Liquid::Drop</tt>
|
||||||
def []=(key, value)
|
def []=(key, value)
|
||||||
unless @this_stack_used
|
(@scope[key] ||= [nil]) << value
|
||||||
@this_stack_used = true
|
|
||||||
push({})
|
|
||||||
end
|
|
||||||
@scopes[0][key] = value
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Look up variable, either resolve directly after considering the name. We can directly handle
|
# Look up variable, either resolve directly after considering the name. We can directly handle
|
||||||
@@ -152,6 +127,29 @@ module Liquid
|
|||||||
evaluate(Expression.parse(expression))
|
evaluate(Expression.parse(expression))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def unset(key)
|
||||||
|
if @scope[key].size <= 1
|
||||||
|
@scope.delete(key)
|
||||||
|
else
|
||||||
|
@scope[key].pop
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_root(key, val)
|
||||||
|
@scope[key] ||= []
|
||||||
|
@scope[key][0] = val
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_level(key, val, int)
|
||||||
|
@scope[key] ||= []
|
||||||
|
@scope[key][int] = val
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_level(key)
|
||||||
|
(@scope[key] ||= [nil]) << nil
|
||||||
|
@scope[key].size - 1
|
||||||
|
end
|
||||||
|
|
||||||
def key?(key)
|
def key?(key)
|
||||||
self[key] != nil
|
self[key] != nil
|
||||||
end
|
end
|
||||||
@@ -162,27 +160,23 @@ module Liquid
|
|||||||
|
|
||||||
# Fetches an object starting at the local scope and then moving up the hierachy
|
# Fetches an object starting at the local scope and then moving up the hierachy
|
||||||
def find_variable(key, raise_on_not_found: true)
|
def find_variable(key, raise_on_not_found: true)
|
||||||
# This was changed from find() to find_index() because this is a very hot
|
trigger = false
|
||||||
# path and find_index() is optimized in MRI to reduce object allocation
|
value = @scope[key]
|
||||||
index = @scopes.find_index { |s| s.key?(key) }
|
scope = @scope unless value.nil?
|
||||||
scope = @scopes[index] if index
|
trigger = true unless value.nil?
|
||||||
|
|
||||||
variable = nil
|
|
||||||
|
|
||||||
if scope.nil?
|
if scope.nil?
|
||||||
@environments.each do |e|
|
index = @environments.find_index do |e|
|
||||||
variable = lookup_and_evaluate(e, key, raise_on_not_found: raise_on_not_found)
|
variable = lookup_and_evaluate(e, key, raise_on_not_found: raise_on_not_found)
|
||||||
# When lookup returned a value OR there is no value but the lookup also did not raise
|
# When lookup returned a value OR there is no value but the lookup also did not raise
|
||||||
# then it is the value we are looking for.
|
# then it is the value we are looking for.
|
||||||
if !variable.nil? || @strict_variables && raise_on_not_found
|
!variable.nil? || @strict_variables && raise_on_not_found
|
||||||
scope = e
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scope = @environments[index || -1]
|
||||||
end
|
end
|
||||||
|
|
||||||
scope ||= @environments.last || @scopes.last
|
variable ||= lookup_and_evaluate(scope, key, trigger, raise_on_not_found: raise_on_not_found)
|
||||||
variable ||= lookup_and_evaluate(scope, key, raise_on_not_found: raise_on_not_found)
|
|
||||||
|
|
||||||
variable = variable.to_liquid
|
variable = variable.to_liquid
|
||||||
variable.context = self if variable.respond_to?(:context=)
|
variable.context = self if variable.respond_to?(:context=)
|
||||||
@@ -190,13 +184,19 @@ module Liquid
|
|||||||
variable
|
variable
|
||||||
end
|
end
|
||||||
|
|
||||||
def lookup_and_evaluate(obj, key, raise_on_not_found: true)
|
def lookup_and_evaluate(obj, key, trigger = false, raise_on_not_found: true)
|
||||||
raise Liquid::UndefinedVariable, "undefined variable #{key}" if @strict_variables && raise_on_not_found && obj.respond_to?(:key?) && !obj.key?(key)
|
if @strict_variables && raise_on_not_found && obj.respond_to?(:key?) && !obj.key?(key)
|
||||||
|
raise Liquid::UndefinedVariable, "undefined variable #{key}"
|
||||||
|
end
|
||||||
|
|
||||||
value = obj[key]
|
value = if trigger == true
|
||||||
|
obj[key][-1]
|
||||||
|
else
|
||||||
|
obj[key]
|
||||||
|
end
|
||||||
|
|
||||||
if value.is_a?(Proc) && obj.respond_to?(:[]=)
|
if value.is_a?(Proc) && obj.respond_to?(:[]=)
|
||||||
obj[key] = value.arity == 0 ? value.call : value.call(self)
|
obj[key] = (value.arity == 0) ? value.call : value.call(self)
|
||||||
else
|
else
|
||||||
value
|
value
|
||||||
end
|
end
|
||||||
@@ -207,15 +207,15 @@ module Liquid
|
|||||||
def internal_error
|
def internal_error
|
||||||
# raise and catch to set backtrace and cause on exception
|
# raise and catch to set backtrace and cause on exception
|
||||||
raise Liquid::InternalError, 'internal'
|
raise Liquid::InternalError, 'internal'
|
||||||
rescue Liquid::InternalError => e
|
rescue Liquid::InternalError => exc
|
||||||
e
|
exc
|
||||||
end
|
end
|
||||||
|
|
||||||
def squash_instance_assigns_with_environments
|
def squash_instance_assigns_with_environments
|
||||||
@scopes.last.each_key do |k|
|
@scope.each_key do |k|
|
||||||
@environments.each do |env|
|
@environments.each do |env|
|
||||||
if env.key?(k)
|
if env.key?(k)
|
||||||
scopes.last[k] = lookup_and_evaluate(env, k)
|
@scope[k] = [lookup_and_evaluate(env, k)]
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class Document < BlockBody
|
class Document < BlockBody
|
||||||
def self.parse(tokens, parse_context)
|
def self.parse(tokens, parse_context)
|
||||||
@@ -9,7 +7,7 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def parse(tokens, parse_context)
|
def parse(tokens, parse_context)
|
||||||
super do |end_tag_name, _end_tag_params|
|
super do |end_tag_name, end_tag_params|
|
||||||
unknown_tag(end_tag_name, parse_context) if end_tag_name
|
unknown_tag(end_tag_name, parse_context) if end_tag_name
|
||||||
end
|
end
|
||||||
rescue SyntaxError => e
|
rescue SyntaxError => e
|
||||||
@@ -19,10 +17,10 @@ module Liquid
|
|||||||
|
|
||||||
def unknown_tag(tag, parse_context)
|
def unknown_tag(tag, parse_context)
|
||||||
case tag
|
case tag
|
||||||
when 'else', 'end'
|
when 'else'.freeze, 'end'.freeze
|
||||||
raise SyntaxError, parse_context.locale.t('errors.syntax.unexpected_outer_tag', tag: tag)
|
raise SyntaxError.new(parse_context.locale.t("errors.syntax.unexpected_outer_tag".freeze, tag: tag))
|
||||||
else
|
else
|
||||||
raise SyntaxError, parse_context.locale.t('errors.syntax.unknown_tag', tag: tag)
|
raise SyntaxError.new(parse_context.locale.t("errors.syntax.unknown_tag".freeze, tag: tag))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'set'
|
require 'set'
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
@@ -27,8 +25,7 @@ module Liquid
|
|||||||
|
|
||||||
# Catch all for the method
|
# Catch all for the method
|
||||||
def liquid_method_missing(method)
|
def liquid_method_missing(method)
|
||||||
return nil unless @context&.strict_variables
|
return nil unless @context && @context.strict_variables
|
||||||
|
|
||||||
raise Liquid::UndefinedDropMethod, "undefined method #{method}"
|
raise Liquid::UndefinedDropMethod, "undefined method #{method}"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -70,7 +67,7 @@ module Liquid
|
|||||||
|
|
||||||
if include?(Enumerable)
|
if include?(Enumerable)
|
||||||
blacklist += Enumerable.public_instance_methods
|
blacklist += Enumerable.public_instance_methods
|
||||||
blacklist -= %i[sort count first min max include?]
|
blacklist -= [:sort, :count, :first, :min, :max, :include?]
|
||||||
end
|
end
|
||||||
|
|
||||||
whitelist = [:to_liquid] + (public_instance_methods - blacklist)
|
whitelist = [:to_liquid] + (public_instance_methods - blacklist)
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class Error < ::StandardError
|
class Error < ::StandardError
|
||||||
attr_accessor :line_number
|
attr_accessor :line_number
|
||||||
@@ -7,12 +5,12 @@ module Liquid
|
|||||||
attr_accessor :markup_context
|
attr_accessor :markup_context
|
||||||
|
|
||||||
def to_s(with_prefix = true)
|
def to_s(with_prefix = true)
|
||||||
str = +''
|
str = ""
|
||||||
str << message_prefix if with_prefix
|
str << message_prefix if with_prefix
|
||||||
str << super()
|
str << super()
|
||||||
|
|
||||||
if markup_context
|
if markup_context
|
||||||
str << ' '
|
str << " "
|
||||||
str << markup_context
|
str << markup_context
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -22,20 +20,20 @@ module Liquid
|
|||||||
private
|
private
|
||||||
|
|
||||||
def message_prefix
|
def message_prefix
|
||||||
str = +''
|
str = ""
|
||||||
str << if is_a?(SyntaxError)
|
if is_a?(SyntaxError)
|
||||||
'Liquid syntax error'
|
str << "Liquid syntax error"
|
||||||
else
|
else
|
||||||
'Liquid error'
|
str << "Liquid error"
|
||||||
end
|
end
|
||||||
|
|
||||||
if line_number
|
if line_number
|
||||||
str << ' ('
|
str << " ("
|
||||||
str << template_name << ' ' if template_name
|
str << template_name << " " if template_name
|
||||||
str << 'line ' << line_number.to_s << ')'
|
str << "line " << line_number.to_s << ")"
|
||||||
end
|
end
|
||||||
|
|
||||||
str << ': '
|
str << ": "
|
||||||
str
|
str
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class Expression
|
class Expression
|
||||||
class MethodLiteral
|
class MethodLiteral
|
||||||
@@ -16,18 +14,18 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
LITERALS = {
|
LITERALS = {
|
||||||
nil => nil, 'nil' => nil, 'null' => nil, '' => nil,
|
nil => nil, 'nil'.freeze => nil, 'null'.freeze => nil, ''.freeze => nil,
|
||||||
'true' => true,
|
'true'.freeze => true,
|
||||||
'false' => false,
|
'false'.freeze => false,
|
||||||
'blank' => MethodLiteral.new(:blank?, '').freeze,
|
'blank'.freeze => MethodLiteral.new(:blank?, '').freeze,
|
||||||
'empty' => MethodLiteral.new(:empty?, '').freeze
|
'empty'.freeze => MethodLiteral.new(:empty?, '').freeze
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
SINGLE_QUOTED_STRING = /\A'(.*)'\z/m.freeze
|
SINGLE_QUOTED_STRING = /\A'(.*)'\z/m
|
||||||
DOUBLE_QUOTED_STRING = /\A"(.*)"\z/m.freeze
|
DOUBLE_QUOTED_STRING = /\A"(.*)"\z/m
|
||||||
INTEGERS_REGEX = /\A(-?\d+)\z/.freeze
|
INTEGERS_REGEX = /\A(-?\d+)\z/
|
||||||
FLOATS_REGEX = /\A(-?\d[\d\.]+)\z/.freeze
|
FLOATS_REGEX = /\A(-?\d[\d\.]+)\z/
|
||||||
RANGES_REGEX = /\A\((\S+)\.\.(\S+)\)\z/.freeze
|
RANGES_REGEX = /\A\((\S+)\.\.(\S+)\)\z/
|
||||||
|
|
||||||
def self.parse(markup)
|
def self.parse(markup)
|
||||||
if LITERALS.key?(markup)
|
if LITERALS.key?(markup)
|
||||||
@@ -35,13 +33,13 @@ module Liquid
|
|||||||
else
|
else
|
||||||
case markup
|
case markup
|
||||||
when SINGLE_QUOTED_STRING, DOUBLE_QUOTED_STRING
|
when SINGLE_QUOTED_STRING, DOUBLE_QUOTED_STRING
|
||||||
Regexp.last_match(1)
|
$1
|
||||||
when INTEGERS_REGEX
|
when INTEGERS_REGEX
|
||||||
Regexp.last_match(1).to_i
|
$1.to_i
|
||||||
when RANGES_REGEX
|
when RANGES_REGEX
|
||||||
RangeLookup.parse(Regexp.last_match(1), Regexp.last_match(2))
|
RangeLookup.parse($1, $2)
|
||||||
when FLOATS_REGEX
|
when FLOATS_REGEX
|
||||||
Regexp.last_match(1).to_f
|
$1.to_f
|
||||||
else
|
else
|
||||||
VariableLookup.parse(markup)
|
VariableLookup.parse(markup)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'time'
|
require 'time'
|
||||||
require 'date'
|
require 'date'
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
# A Liquid file system is a way to let your templates retrieve other templates for use with the include tag.
|
# A Liquid file system is a way to let your templates retrieve other templates for use with the include tag.
|
||||||
#
|
#
|
||||||
@@ -17,7 +15,7 @@ module Liquid
|
|||||||
class BlankFileSystem
|
class BlankFileSystem
|
||||||
# Called by Liquid to retrieve a template file
|
# Called by Liquid to retrieve a template file
|
||||||
def read_template_file(_template_path)
|
def read_template_file(_template_path)
|
||||||
raise FileSystemError, 'This liquid context does not allow includes.'
|
raise FileSystemError, "This liquid context does not allow includes."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -46,7 +44,7 @@ module Liquid
|
|||||||
class LocalFileSystem
|
class LocalFileSystem
|
||||||
attr_accessor :root
|
attr_accessor :root
|
||||||
|
|
||||||
def initialize(root, pattern = '_%s.liquid')
|
def initialize(root, pattern = "_%s.liquid".freeze)
|
||||||
@root = root
|
@root = root
|
||||||
@pattern = pattern
|
@pattern = pattern
|
||||||
end
|
end
|
||||||
@@ -59,9 +57,9 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def full_path(template_path)
|
def full_path(template_path)
|
||||||
raise FileSystemError, "Illegal template name '#{template_path}'" unless template_path =~ %r{\A[^./][a-zA-Z0-9_/]+\z}
|
raise FileSystemError, "Illegal template name '#{template_path}'" unless template_path =~ /\A[^.\/][a-zA-Z0-9_\/]+\z/
|
||||||
|
|
||||||
full_path = if template_path.include?('/')
|
full_path = if template_path.include?('/'.freeze)
|
||||||
File.join(root, File.dirname(template_path), @pattern % File.basename(template_path))
|
File.join(root, File.dirname(template_path), @pattern % File.basename(template_path))
|
||||||
else
|
else
|
||||||
File.join(root, @pattern % template_path)
|
File.join(root, @pattern % template_path)
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class ForloopDrop < Drop
|
class ForloopDrop < Drop
|
||||||
def initialize(name, length, parentloop)
|
def initialize(name, length, parentloop)
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'yaml'
|
require 'yaml'
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class I18n
|
class I18n
|
||||||
DEFAULT_LOCALE = File.join(File.expand_path(__dir__), 'locales', 'en.yml')
|
DEFAULT_LOCALE = File.join(File.expand_path(__dir__), "locales", "en.yml")
|
||||||
|
|
||||||
TranslationError = Class.new(StandardError)
|
TranslationError = Class.new(StandardError)
|
||||||
|
|
||||||
@@ -28,13 +26,13 @@ module Liquid
|
|||||||
def interpolate(name, vars)
|
def interpolate(name, vars)
|
||||||
name.gsub(/%\{(\w+)\}/) do
|
name.gsub(/%\{(\w+)\}/) do
|
||||||
# raise TranslationError, "Undefined key #{$1} for interpolation in translation #{name}" unless vars[$1.to_sym]
|
# raise TranslationError, "Undefined key #{$1} for interpolation in translation #{name}" unless vars[$1.to_sym]
|
||||||
(vars[Regexp.last_match(1).to_sym]).to_s
|
(vars[$1.to_sym]).to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def deep_fetch_translation(name)
|
def deep_fetch_translation(name)
|
||||||
name.split('.').reduce(locale) do |level, cur|
|
name.split('.'.freeze).reduce(locale) do |level, cur|
|
||||||
level[cur] || raise(TranslationError, "Translation for #{name} does not exist in locale #{path}")
|
level[cur] or raise TranslationError, "Translation for #{name} does not exist in locale #{path}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
# An interrupt is any command that breaks processing of a block (ex: a for loop).
|
# An interrupt is any command that breaks processing of a block (ex: a for loop).
|
||||||
class Interrupt
|
class Interrupt
|
||||||
attr_reader :message
|
attr_reader :message
|
||||||
|
|
||||||
def initialize(message = nil)
|
def initialize(message = nil)
|
||||||
@message = message || 'interrupt'
|
@message = message || "interrupt".freeze
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Interrupt that is thrown whenever a {% break %} is called.
|
# Interrupt that is thrown whenever a {% break %} is called.
|
||||||
class BreakInterrupt < RuntimeError; end
|
class BreakInterrupt < Interrupt; end
|
||||||
|
|
||||||
# Interrupt that is thrown whenever a {% continue %} is called.
|
# Interrupt that is thrown whenever a {% continue %} is called.
|
||||||
class ContinueInterrupt < RuntimeError; end
|
class ContinueInterrupt < Interrupt; end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,79 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
|
||||||
FilterSeparator = FILTER_SEPARATOR
|
|
||||||
ArgumentSeparator = ARGUMENT_SEPARATOR
|
|
||||||
FilterArgumentSeparator = FILTER_ARGUMENT_SEPARATOR
|
|
||||||
VariableAttributeSeparator = VARIABLE_ATTRIBUTE_SEPARATOR
|
|
||||||
WhitespaceControl = WHITESPACE_CONTROL
|
|
||||||
TagStart = TAG_START
|
|
||||||
TagEnd = TAG_END
|
|
||||||
VariableSignature = VARIABLE_SIGNATURE
|
|
||||||
VariableSegment = VARIABLE_SEGMENT
|
|
||||||
VariableStart = VARIABLE_START
|
|
||||||
VariableEnd = VARIABLE_END
|
|
||||||
VariableIncompleteEnd = VARIABLE_INCOMPLETE_END
|
|
||||||
QuotedString = QUOTED_STRING
|
|
||||||
QuotedFragment = QUOTED_FRAGMENT
|
|
||||||
TagAttributes = TAG_ATTRIBUTES
|
|
||||||
AnyStartingTag = ANY_STARTING_TAG
|
|
||||||
PartialTemplateParser = PARTIAL_TEMPLATE_PARSER
|
|
||||||
TemplateParser = TEMPLATE_PARSER
|
|
||||||
VariableParser = VARIABLE_PARSER
|
|
||||||
|
|
||||||
class BlockBody
|
|
||||||
FullToken = FULL_TOKEN
|
|
||||||
ContentOfVariable = CONTENT_OF_VARIABLE
|
|
||||||
WhitespaceOrNothing = WHITESPACE_OR_NOTHING
|
|
||||||
TAGSTART = TAG_START
|
|
||||||
VARSTART = VAR_START
|
|
||||||
end
|
|
||||||
|
|
||||||
class Assign < Tag
|
|
||||||
Syntax = SYNTAX
|
|
||||||
end
|
|
||||||
|
|
||||||
class Capture < Block
|
|
||||||
Syntax = SYNTAX
|
|
||||||
end
|
|
||||||
|
|
||||||
class Case < Block
|
|
||||||
Syntax = SYNTAX
|
|
||||||
WhenSyntax = WHEN_SYNTAX
|
|
||||||
end
|
|
||||||
|
|
||||||
class Cycle < Tag
|
|
||||||
SimpleSyntax = SIMPLE_SYNTAX
|
|
||||||
NamedSyntax = NAMED_SYNTAX
|
|
||||||
end
|
|
||||||
|
|
||||||
class For < Block
|
|
||||||
Syntax = SYNTAX
|
|
||||||
end
|
|
||||||
|
|
||||||
class If < Block
|
|
||||||
Syntax = SYNTAX
|
|
||||||
ExpressionsAndOperators = EXPRESSIONS_AND_OPERATORS
|
|
||||||
end
|
|
||||||
|
|
||||||
class Include < Tag
|
|
||||||
Syntax = SYNTAX
|
|
||||||
end
|
|
||||||
|
|
||||||
class Raw < Block
|
|
||||||
Syntax = SYNTAX
|
|
||||||
FullTokenPossiblyInvalid = FULL_TOKEN_POSSIBLY_INVALID
|
|
||||||
end
|
|
||||||
|
|
||||||
class TableRow < Block
|
|
||||||
Syntax = SYNTAX
|
|
||||||
end
|
|
||||||
|
|
||||||
class Variable
|
|
||||||
FilterMarkupRegex = FILTER_MARKUP_REGEX
|
|
||||||
FilterParser = FILTER_PARSER
|
|
||||||
FilterArgsRegex = FILTER_ARGS_REGEX
|
|
||||||
JustTagAttributes = JUST_TAG_ATTRIBUTES
|
|
||||||
MarkupWithQuotedFragment = MARKUP_WITH_QUOTED_FRAGMENT
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,27 +1,25 @@
|
|||||||
# frozen_string_literal: true
|
require "strscan"
|
||||||
|
|
||||||
require 'strscan'
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class Lexer
|
class Lexer
|
||||||
SPECIALS = {
|
SPECIALS = {
|
||||||
'|' => :pipe,
|
'|'.freeze => :pipe,
|
||||||
'.' => :dot,
|
'.'.freeze => :dot,
|
||||||
':' => :colon,
|
':'.freeze => :colon,
|
||||||
',' => :comma,
|
','.freeze => :comma,
|
||||||
'[' => :open_square,
|
'['.freeze => :open_square,
|
||||||
']' => :close_square,
|
']'.freeze => :close_square,
|
||||||
'(' => :open_round,
|
'('.freeze => :open_round,
|
||||||
')' => :close_round,
|
')'.freeze => :close_round,
|
||||||
'?' => :question,
|
'?'.freeze => :question,
|
||||||
'-' => :dash,
|
'-'.freeze => :dash
|
||||||
}.freeze
|
}.freeze
|
||||||
IDENTIFIER = /[a-zA-Z_][\w-]*\??/.freeze
|
IDENTIFIER = /[a-zA-Z_][\w-]*\??/
|
||||||
SINGLE_STRING_LITERAL = /'[^\']*'/.freeze
|
SINGLE_STRING_LITERAL = /'[^\']*'/
|
||||||
DOUBLE_STRING_LITERAL = /"[^\"]*"/.freeze
|
DOUBLE_STRING_LITERAL = /"[^\"]*"/
|
||||||
NUMBER_LITERAL = /-?\d+(\.\d+)?/.freeze
|
NUMBER_LITERAL = /-?\d+(\.\d+)?/
|
||||||
DOTDOT = /\.\./.freeze
|
DOTDOT = /\.\./
|
||||||
COMPARISON_OPERATOR = /==|!=|<>|<=?|>=?|contains(?=\s)/.freeze
|
COMPARISON_OPERATOR = /==|!=|<>|<=?|>=?|contains(?=\s)/
|
||||||
WHITESPACE_OR_NOTHING = /\s*/.freeze
|
WHITESPACE_OR_NOTHING = /\s*/
|
||||||
|
|
||||||
def initialize(input)
|
def initialize(input)
|
||||||
@ss = StringScanner.new(input)
|
@ss = StringScanner.new(input)
|
||||||
@@ -33,16 +31,16 @@ module Liquid
|
|||||||
until @ss.eos?
|
until @ss.eos?
|
||||||
@ss.skip(WHITESPACE_OR_NOTHING)
|
@ss.skip(WHITESPACE_OR_NOTHING)
|
||||||
break if @ss.eos?
|
break if @ss.eos?
|
||||||
|
tok = case
|
||||||
tok = if (t = @ss.scan(COMPARISON_OPERATOR)) then [:comparison, t]
|
when t = @ss.scan(COMPARISON_OPERATOR) then [:comparison, t]
|
||||||
elsif (t = @ss.scan(SINGLE_STRING_LITERAL)) then [:string, t]
|
when t = @ss.scan(SINGLE_STRING_LITERAL) then [:string, t]
|
||||||
elsif (t = @ss.scan(DOUBLE_STRING_LITERAL)) then [:string, t]
|
when t = @ss.scan(DOUBLE_STRING_LITERAL) then [:string, t]
|
||||||
elsif (t = @ss.scan(NUMBER_LITERAL)) then [:number, t]
|
when t = @ss.scan(NUMBER_LITERAL) then [:number, t]
|
||||||
elsif (t = @ss.scan(IDENTIFIER)) then [:id, t]
|
when t = @ss.scan(IDENTIFIER) then [:id, t]
|
||||||
elsif (t = @ss.scan(DOTDOT)) then [:dotdot, t]
|
when t = @ss.scan(DOTDOT) then [:dotdot, t]
|
||||||
else
|
else
|
||||||
c = @ss.getch
|
c = @ss.getch
|
||||||
if (s = SPECIALS[c])
|
if s = SPECIALS[c]
|
||||||
[s, c]
|
[s, c]
|
||||||
else
|
else
|
||||||
raise SyntaxError, "Unexpected character #{c}"
|
raise SyntaxError, "Unexpected character #{c}"
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class ParseContext
|
class ParseContext
|
||||||
attr_accessor :locale, :line_number, :trim_whitespace, :depth
|
attr_accessor :locale, :line_number, :trim_whitespace, :depth
|
||||||
@@ -21,6 +19,7 @@ module Liquid
|
|||||||
@partial = value
|
@partial = value
|
||||||
@options = value ? partial_options : @template_options
|
@options = value ? partial_options : @template_options
|
||||||
@error_mode = @options[:error_mode] || Template.error_mode
|
@error_mode = @options[:error_mode] || Template.error_mode
|
||||||
|
value
|
||||||
end
|
end
|
||||||
|
|
||||||
def partial_options
|
def partial_options
|
||||||
@@ -29,7 +28,7 @@ module Liquid
|
|||||||
if dont_pass == true
|
if dont_pass == true
|
||||||
{ locale: locale }
|
{ locale: locale }
|
||||||
elsif dont_pass.is_a?(Array)
|
elsif dont_pass.is_a?(Array)
|
||||||
@template_options.reject { |k, _v| dont_pass.include?(k) }
|
@template_options.reject { |k, v| dont_pass.include?(k) }
|
||||||
else
|
else
|
||||||
@template_options
|
@template_options
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ module Liquid
|
|||||||
item, new_context = @callbacks[node.class].call(node, context)
|
item, new_context = @callbacks[node.class].call(node, context)
|
||||||
[
|
[
|
||||||
item,
|
item,
|
||||||
ParseTreeVisitor.for(node, @callbacks).visit(new_context || context),
|
ParseTreeVisitor.for(node, @callbacks).visit(new_context || context)
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class Parser
|
class Parser
|
||||||
def initialize(input)
|
def initialize(input)
|
||||||
@@ -14,8 +12,9 @@ module Liquid
|
|||||||
|
|
||||||
def consume(type = nil)
|
def consume(type = nil)
|
||||||
token = @tokens[@p]
|
token = @tokens[@p]
|
||||||
raise SyntaxError, "Expected #{type} but found #{@tokens[@p].first}" if type && token[0] != type
|
if type && token[0] != type
|
||||||
|
raise SyntaxError, "Expected #{type} but found #{@tokens[@p].first}"
|
||||||
|
end
|
||||||
@p += 1
|
@p += 1
|
||||||
token[1]
|
token[1]
|
||||||
end
|
end
|
||||||
@@ -26,7 +25,6 @@ module Liquid
|
|||||||
def consume?(type)
|
def consume?(type)
|
||||||
token = @tokens[@p]
|
token = @tokens[@p]
|
||||||
return false unless token && token[0] == type
|
return false unless token && token[0] == type
|
||||||
|
|
||||||
@p += 1
|
@p += 1
|
||||||
token[1]
|
token[1]
|
||||||
end
|
end
|
||||||
@@ -36,7 +34,6 @@ module Liquid
|
|||||||
token = @tokens[@p]
|
token = @tokens[@p]
|
||||||
return false unless token && token[0] == :id
|
return false unless token && token[0] == :id
|
||||||
return false unless token[1] == str
|
return false unless token[1] == str
|
||||||
|
|
||||||
@p += 1
|
@p += 1
|
||||||
token[1]
|
token[1]
|
||||||
end
|
end
|
||||||
@@ -44,18 +41,14 @@ module Liquid
|
|||||||
def look(type, ahead = 0)
|
def look(type, ahead = 0)
|
||||||
tok = @tokens[@p + ahead]
|
tok = @tokens[@p + ahead]
|
||||||
return false unless tok
|
return false unless tok
|
||||||
|
|
||||||
tok[0] == type
|
tok[0] == type
|
||||||
end
|
end
|
||||||
|
|
||||||
SINGLE_TOKEN_EXPRESSION_TYPES = %i[string number].freeze
|
|
||||||
private_constant :SINGLE_TOKEN_EXPRESSION_TYPES
|
|
||||||
|
|
||||||
def expression
|
def expression
|
||||||
token = @tokens[@p]
|
token = @tokens[@p]
|
||||||
if token[0] == :id
|
if token[0] == :id
|
||||||
variable_signature
|
variable_signature
|
||||||
elsif SINGLE_TOKEN_EXPRESSION_TYPES.include?(token[0])
|
elsif [:string, :number].include? token[0]
|
||||||
consume
|
consume
|
||||||
elsif token.first == :open_round
|
elsif token.first == :open_round
|
||||||
consume
|
consume
|
||||||
@@ -70,9 +63,11 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def argument
|
def argument
|
||||||
str = +''
|
str = ""
|
||||||
# might be a keyword argument (identifier: expression)
|
# might be a keyword argument (identifier: expression)
|
||||||
str << consume << consume << ' ' if look(:id) && look(:colon, 1)
|
if look(:id) && look(:colon, 1)
|
||||||
|
str << consume << consume << ' '.freeze
|
||||||
|
end
|
||||||
|
|
||||||
str << expression
|
str << expression
|
||||||
str
|
str
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
module ParserSwitching
|
module ParserSwitching
|
||||||
def parse_with_selected_parser(markup)
|
def parse_with_selected_parser(markup)
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'liquid/profiler/hooks'
|
require 'liquid/profiler/hooks'
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
@@ -99,9 +97,9 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@partial_stack = ['<root>']
|
@partial_stack = ["<root>"]
|
||||||
|
|
||||||
@root_timing = Timing.new('', current_partial)
|
@root_timing = Timing.new("", current_partial)
|
||||||
@timing_stack = [@root_timing]
|
@timing_stack = [@root_timing]
|
||||||
|
|
||||||
@render_start_at = Time.now
|
@render_start_at = Time.now
|
||||||
|
|||||||
@@ -1,25 +1,23 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class BlockBody
|
class BlockBody
|
||||||
def render_node_with_profiling(context, output, node)
|
def render_node_with_profiling(node, output, context, skip_output = false)
|
||||||
Profiler.profile_node_render(node) do
|
Profiler.profile_node_render(node) do
|
||||||
render_node_without_profiling(context, output, node)
|
render_node_without_profiling(node, output, context, skip_output)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
alias_method :render_node_without_profiling, :render_node
|
alias_method :render_node_without_profiling, :render_node_to_output
|
||||||
alias_method :render_node, :render_node_with_profiling
|
alias_method :render_node_to_output, :render_node_with_profiling
|
||||||
end
|
end
|
||||||
|
|
||||||
class Include < Tag
|
class Include < Tag
|
||||||
def render_to_output_buffer_with_profiling(context, output)
|
def render_with_profiling(context)
|
||||||
Profiler.profile_children(context.evaluate(@template_name_expr).to_s) do
|
Profiler.profile_children(context.evaluate(@template_name_expr).to_s) do
|
||||||
render_to_output_buffer_without_profiling(context, output)
|
render_without_profiling(context)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
alias_method :render_to_output_buffer_without_profiling, :render_to_output_buffer
|
alias_method :render_without_profiling, :render
|
||||||
alias_method :render_to_output_buffer, :render_to_output_buffer_with_profiling
|
alias_method :render, :render_with_profiling
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class RangeLookup
|
class RangeLookup
|
||||||
def self.parse(start_markup, end_markup)
|
def self.parse(start_markup, end_markup)
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class ResourceLimits
|
class ResourceLimits
|
||||||
attr_accessor :render_length, :render_score, :assign_score,
|
attr_accessor :render_length, :render_score, :assign_score,
|
||||||
:render_length_limit, :render_score_limit, :assign_score_limit
|
:render_length_limit, :render_score_limit, :assign_score_limit
|
||||||
|
|
||||||
def initialize(limits)
|
def initialize(limits)
|
||||||
@render_length_limit = limits[:render_length_limit]
|
@render_length_limit = limits[:render_length_limit]
|
||||||
|
|||||||
@@ -1,24 +1,22 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'cgi'
|
require 'cgi'
|
||||||
require 'bigdecimal'
|
require 'bigdecimal'
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
module StandardFilters
|
module StandardFilters
|
||||||
HTML_ESCAPE = {
|
HTML_ESCAPE = {
|
||||||
'&' => '&',
|
'&'.freeze => '&'.freeze,
|
||||||
'>' => '>',
|
'>'.freeze => '>'.freeze,
|
||||||
'<' => '<',
|
'<'.freeze => '<'.freeze,
|
||||||
'"' => '"',
|
'"'.freeze => '"'.freeze,
|
||||||
"'" => ''',
|
"'".freeze => '''.freeze
|
||||||
}.freeze
|
}.freeze
|
||||||
HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/.freeze
|
HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/
|
||||||
STRIP_HTML_BLOCKS = Regexp.union(
|
STRIP_HTML_BLOCKS = Regexp.union(
|
||||||
%r{<script.*?</script>}m,
|
/<script.*?<\/script>/m,
|
||||||
/<!--.*?-->/m,
|
/<!--.*?-->/m,
|
||||||
%r{<style.*?</style>}m
|
/<style.*?<\/style>/m
|
||||||
)
|
)
|
||||||
STRIP_HTML_TAGS = /<.*?>/m.freeze
|
STRIP_HTML_TAGS = /<.*?>/m
|
||||||
|
|
||||||
# Return the size of an array or of an string
|
# Return the size of an array or of an string
|
||||||
def size(input)
|
def size(input)
|
||||||
@@ -74,25 +72,23 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Truncate a string down to x characters
|
# Truncate a string down to x characters
|
||||||
def truncate(input, length = 50, truncate_string = '...')
|
def truncate(input, length = 50, truncate_string = "...".freeze)
|
||||||
return if input.nil?
|
return if input.nil?
|
||||||
|
|
||||||
input_str = input.to_s
|
input_str = input.to_s
|
||||||
length = Utils.to_integer(length)
|
length = Utils.to_integer(length)
|
||||||
truncate_string_str = truncate_string.to_s
|
truncate_string_str = truncate_string.to_s
|
||||||
l = length - truncate_string_str.length
|
l = length - truncate_string_str.length
|
||||||
l = 0 if l < 0
|
l = 0 if l < 0
|
||||||
input_str.length > length ? input_str[0...l].concat(truncate_string_str) : input_str
|
input_str.length > length ? input_str[0...l] + truncate_string_str : input_str
|
||||||
end
|
end
|
||||||
|
|
||||||
def truncatewords(input, words = 15, truncate_string = '...')
|
def truncatewords(input, words = 15, truncate_string = "...".freeze)
|
||||||
return if input.nil?
|
return if input.nil?
|
||||||
|
|
||||||
wordlist = input.to_s.split
|
wordlist = input.to_s.split
|
||||||
words = Utils.to_integer(words)
|
words = Utils.to_integer(words)
|
||||||
l = words - 1
|
l = words - 1
|
||||||
l = 0 if l < 0
|
l = 0 if l < 0
|
||||||
wordlist.length > l ? wordlist[0..l].join(' ').concat(truncate_string.to_s) : input
|
wordlist.length > l ? wordlist[0..l].join(" ".freeze) + truncate_string.to_s : input
|
||||||
end
|
end
|
||||||
|
|
||||||
# Split input string into an array of substrings separated by given pattern.
|
# Split input string into an array of substrings separated by given pattern.
|
||||||
@@ -117,7 +113,7 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def strip_html(input)
|
def strip_html(input)
|
||||||
empty = ''
|
empty = ''.freeze
|
||||||
result = input.to_s.gsub(STRIP_HTML_BLOCKS, empty)
|
result = input.to_s.gsub(STRIP_HTML_BLOCKS, empty)
|
||||||
result.gsub!(STRIP_HTML_TAGS, empty)
|
result.gsub!(STRIP_HTML_TAGS, empty)
|
||||||
result
|
result
|
||||||
@@ -125,11 +121,11 @@ module Liquid
|
|||||||
|
|
||||||
# Remove all newlines from the string
|
# Remove all newlines from the string
|
||||||
def strip_newlines(input)
|
def strip_newlines(input)
|
||||||
input.to_s.gsub(/\r?\n/, '')
|
input.to_s.gsub(/\r?\n/, ''.freeze)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Join elements of the array with certain character between them
|
# Join elements of the array with certain character between them
|
||||||
def join(input, glue = ' ')
|
def join(input, glue = ' '.freeze)
|
||||||
InputIterator.new(input).join(glue)
|
InputIterator.new(input).join(glue)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -224,7 +220,7 @@ module Liquid
|
|||||||
InputIterator.new(input).map do |e|
|
InputIterator.new(input).map do |e|
|
||||||
e = e.call if e.is_a?(Proc)
|
e = e.call if e.is_a?(Proc)
|
||||||
|
|
||||||
if property == 'to_liquid'
|
if property == "to_liquid".freeze
|
||||||
e
|
e
|
||||||
elsif e.respond_to?(:[])
|
elsif e.respond_to?(:[])
|
||||||
r = e[property]
|
r = e[property]
|
||||||
@@ -254,23 +250,23 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Replace occurrences of a string with another
|
# Replace occurrences of a string with another
|
||||||
def replace(input, string, replacement = '')
|
def replace(input, string, replacement = ''.freeze)
|
||||||
input.to_s.gsub(string.to_s, replacement.to_s)
|
input.to_s.gsub(string.to_s, replacement.to_s)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Replace the first occurrences of a string with another
|
# Replace the first occurrences of a string with another
|
||||||
def replace_first(input, string, replacement = '')
|
def replace_first(input, string, replacement = ''.freeze)
|
||||||
input.to_s.sub(string.to_s, replacement.to_s)
|
input.to_s.sub(string.to_s, replacement.to_s)
|
||||||
end
|
end
|
||||||
|
|
||||||
# remove a substring
|
# remove a substring
|
||||||
def remove(input, string)
|
def remove(input, string)
|
||||||
input.to_s.gsub(string.to_s, '')
|
input.to_s.gsub(string.to_s, ''.freeze)
|
||||||
end
|
end
|
||||||
|
|
||||||
# remove the first occurrences of a substring
|
# remove the first occurrences of a substring
|
||||||
def remove_first(input, string)
|
def remove_first(input, string)
|
||||||
input.to_s.sub(string.to_s, '')
|
input.to_s.sub(string.to_s, ''.freeze)
|
||||||
end
|
end
|
||||||
|
|
||||||
# add one string to another
|
# add one string to another
|
||||||
@@ -279,8 +275,9 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def concat(input, array)
|
def concat(input, array)
|
||||||
raise ArgumentError, 'concat filter requires an array argument' unless array.respond_to?(:to_ary)
|
unless array.respond_to?(:to_ary)
|
||||||
|
raise ArgumentError.new("concat filter requires an array argument")
|
||||||
|
end
|
||||||
InputIterator.new(input).concat(array)
|
InputIterator.new(input).concat(array)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -291,7 +288,7 @@ module Liquid
|
|||||||
|
|
||||||
# Add <br /> tags in front of all newlines in input string
|
# Add <br /> tags in front of all newlines in input string
|
||||||
def newline_to_br(input)
|
def newline_to_br(input)
|
||||||
input.to_s.gsub(/\n/, "<br />\n")
|
input.to_s.gsub(/\n/, "<br />\n".freeze)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Reformat a date using Ruby's core Time#strftime( string ) -> string
|
# Reformat a date using Ruby's core Time#strftime( string ) -> string
|
||||||
@@ -328,7 +325,7 @@ module Liquid
|
|||||||
def date(input, format)
|
def date(input, format)
|
||||||
return input if format.to_s.empty?
|
return input if format.to_s.empty?
|
||||||
|
|
||||||
return input unless (date = Utils.to_date(input))
|
return input unless date = Utils.to_date(input)
|
||||||
|
|
||||||
date.strftime(format.to_s)
|
date.strftime(format.to_s)
|
||||||
end
|
end
|
||||||
@@ -422,7 +419,7 @@ module Liquid
|
|||||||
result.is_a?(BigDecimal) ? result.to_f : result
|
result.is_a?(BigDecimal) ? result.to_f : result
|
||||||
end
|
end
|
||||||
|
|
||||||
def default(input, default_value = '')
|
def default(input, default_value = ''.freeze)
|
||||||
if !input || input.respond_to?(:empty?) && input.empty?
|
if !input || input.respond_to?(:empty?) && input.empty?
|
||||||
default_value
|
default_value
|
||||||
else
|
else
|
||||||
@@ -433,7 +430,7 @@ module Liquid
|
|||||||
private
|
private
|
||||||
|
|
||||||
def raise_property_error(property)
|
def raise_property_error(property)
|
||||||
raise Liquid::ArgumentError, "cannot select the property '#{property}'"
|
raise Liquid::ArgumentError.new("cannot select the property '#{property}'")
|
||||||
end
|
end
|
||||||
|
|
||||||
def apply_operation(input, operand, operation)
|
def apply_operation(input, operand, operation)
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'set'
|
require 'set'
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
@@ -9,12 +7,12 @@ module Liquid
|
|||||||
# The Strainer only allows method calls defined in filters given to it via Strainer.global_filter,
|
# The Strainer only allows method calls defined in filters given to it via Strainer.global_filter,
|
||||||
# Context#add_filters or Template.register_filter
|
# Context#add_filters or Template.register_filter
|
||||||
class Strainer #:nodoc:
|
class Strainer #:nodoc:
|
||||||
@global_strainer = Class.new(Strainer) do
|
@@global_strainer = Class.new(Strainer) do
|
||||||
@filter_methods = Set.new
|
@filter_methods = Set.new
|
||||||
end
|
end
|
||||||
@strainer_class_cache = Hash.new do |hash, filters|
|
@@strainer_class_cache = Hash.new do |hash, filters|
|
||||||
hash[filters] = Class.new(@global_strainer) do
|
hash[filters] = Class.new(@@global_strainer) do
|
||||||
@filter_methods = Strainer.global_strainer.filter_methods.dup
|
@filter_methods = @@global_strainer.filter_methods.dup
|
||||||
filters.each { |f| add_filter(f) }
|
filters.each { |f| add_filter(f) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -24,14 +22,12 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
attr_accessor :strainer_class_cache, :global_strainer
|
|
||||||
attr_reader :filter_methods
|
attr_reader :filter_methods
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.add_filter(filter)
|
def self.add_filter(filter)
|
||||||
raise ArgumentError, "Expected module but got: #{filter.class}" unless filter.is_a?(Module)
|
raise ArgumentError, "Expected module but got: #{filter.class}" unless filter.is_a?(Module)
|
||||||
|
unless self.include?(filter)
|
||||||
unless include?(filter)
|
|
||||||
invokable_non_public_methods = (filter.private_instance_methods + filter.protected_instance_methods).select { |m| invokable?(m) }
|
invokable_non_public_methods = (filter.private_instance_methods + filter.protected_instance_methods).select { |m| invokable?(m) }
|
||||||
if invokable_non_public_methods.any?
|
if invokable_non_public_methods.any?
|
||||||
raise MethodOverrideError, "Filter overrides registered public methods as non public: #{invokable_non_public_methods.join(', ')}"
|
raise MethodOverrideError, "Filter overrides registered public methods as non public: #{invokable_non_public_methods.join(', ')}"
|
||||||
@@ -43,8 +39,8 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.global_filter(filter)
|
def self.global_filter(filter)
|
||||||
@strainer_class_cache.clear
|
@@strainer_class_cache.clear
|
||||||
@global_strainer.add_filter(filter)
|
@@global_strainer.add_filter(filter)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.invokable?(method)
|
def self.invokable?(method)
|
||||||
@@ -52,13 +48,13 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.create(context, filters = [])
|
def self.create(context, filters = [])
|
||||||
@strainer_class_cache[filters].new(context)
|
@@strainer_class_cache[filters].new(context)
|
||||||
end
|
end
|
||||||
|
|
||||||
def invoke(method, *args)
|
def invoke(method, *args)
|
||||||
if self.class.invokable?(method)
|
if self.class.invokable?(method)
|
||||||
send(method, *args)
|
send(method, *args)
|
||||||
elsif @context&.strict_filters
|
elsif @context && @context.strict_filters
|
||||||
raise Liquid::UndefinedFilter, "undefined filter #{method}"
|
raise Liquid::UndefinedFilter, "undefined filter #{method}"
|
||||||
else
|
else
|
||||||
args.first
|
args.first
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class TablerowloopDrop < Drop
|
class TablerowloopDrop < Drop
|
||||||
def initialize(length, cols)
|
def initialize(length, cols)
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class Tag
|
class Tag
|
||||||
attr_reader :nodelist, :tag_name, :line_number, :parse_context
|
attr_reader :nodelist, :tag_name, :line_number, :parse_context
|
||||||
@@ -23,7 +21,8 @@ module Liquid
|
|||||||
@line_number = parse_context.line_number
|
@line_number = parse_context.line_number
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse(_tokens); end
|
def parse(_tokens)
|
||||||
|
end
|
||||||
|
|
||||||
def raw
|
def raw
|
||||||
"#{@tag_name} #{@markup}"
|
"#{@tag_name} #{@markup}"
|
||||||
@@ -34,15 +33,7 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def render(_context)
|
def render(_context)
|
||||||
''
|
''.freeze
|
||||||
end
|
|
||||||
|
|
||||||
# For backwards compatibility with custom tags. In a future release, the semantics
|
|
||||||
# of the `render_to_output_buffer` method will become the default and the `render`
|
|
||||||
# method will be removed.
|
|
||||||
def render_to_output_buffer(context, output)
|
|
||||||
output << render(context)
|
|
||||||
output
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def blank?
|
def blank?
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
# Assign sets a variable in your template.
|
# Assign sets a variable in your template.
|
||||||
#
|
#
|
||||||
@@ -10,25 +8,25 @@ module Liquid
|
|||||||
# {{ foo }}
|
# {{ foo }}
|
||||||
#
|
#
|
||||||
class Assign < Tag
|
class Assign < Tag
|
||||||
SYNTAX = /(#{VARIABLE_SIGNATURE}+)\s*=\s*(.*)\s*/om.freeze
|
Syntax = /(#{VariableSignature}+)\s*=\s*(.*)\s*/om
|
||||||
|
|
||||||
attr_reader :to, :from
|
attr_reader :to, :from
|
||||||
|
|
||||||
def initialize(tag_name, markup, options)
|
def initialize(tag_name, markup, options)
|
||||||
super
|
super
|
||||||
if markup =~ SYNTAX
|
if markup =~ Syntax
|
||||||
@to = Regexp.last_match(1)
|
@to = $1
|
||||||
@from = Variable.new(Regexp.last_match(2), options)
|
@from = Variable.new($2, options)
|
||||||
else
|
else
|
||||||
raise SyntaxError, options[:locale].t('errors.syntax.assign')
|
raise SyntaxError.new options[:locale].t("errors.syntax.assign".freeze)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_to_output_buffer(context, output)
|
def render(context)
|
||||||
val = @from.render(context)
|
val = @from.render(context)
|
||||||
context.scopes.last[@to] = val
|
context.set_root(@to, val)
|
||||||
context.resource_limits.assign_score += assign_score_of(val)
|
context.resource_limits.assign_score += assign_score_of(val)
|
||||||
output
|
''.freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
def blank?
|
def blank?
|
||||||
@@ -57,5 +55,5 @@ module Liquid
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Template.register_tag('assign', Assign)
|
Template.register_tag('assign'.freeze, Assign)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
# Break tag to be used to break out of a for loop.
|
# Break tag to be used to break out of a for loop.
|
||||||
#
|
#
|
||||||
@@ -16,5 +14,5 @@ module Liquid
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Template.register_tag('break', Break)
|
Template.register_tag('break'.freeze, Break)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
# Capture stores the result of a block into a variable without rendering it inplace.
|
# Capture stores the result of a block into a variable without rendering it inplace.
|
||||||
#
|
#
|
||||||
@@ -13,23 +11,22 @@ module Liquid
|
|||||||
# in a sidebar or footer.
|
# in a sidebar or footer.
|
||||||
#
|
#
|
||||||
class Capture < Block
|
class Capture < Block
|
||||||
SYNTAX = /(#{VARIABLE_SIGNATURE}+)/o.freeze
|
Syntax = /(#{VariableSignature}+)/o
|
||||||
|
|
||||||
def initialize(tag_name, markup, options)
|
def initialize(tag_name, markup, options)
|
||||||
super
|
super
|
||||||
if markup =~ SYNTAX
|
if markup =~ Syntax
|
||||||
@to = Regexp.last_match(1)
|
@to = $1
|
||||||
else
|
else
|
||||||
raise SyntaxError, options[:locale].t('errors.syntax.capture')
|
raise SyntaxError.new(options[:locale].t("errors.syntax.capture"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_to_output_buffer(context, output)
|
def render(context)
|
||||||
previous_output_size = output.bytesize
|
output = super
|
||||||
super
|
context.set_root(@to, output)
|
||||||
context.scopes.last[@to] = output
|
context.resource_limits.assign_score += output.bytesize
|
||||||
context.resource_limits.assign_score += (output.bytesize - previous_output_size)
|
''.freeze
|
||||||
output
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def blank?
|
def blank?
|
||||||
@@ -37,5 +34,5 @@ module Liquid
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Template.register_tag('capture', Capture)
|
Template.register_tag('capture'.freeze, Capture)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class Case < Block
|
class Case < Block
|
||||||
SYNTAX = /(#{QUOTED_FRAGMENT})/o.freeze
|
Syntax = /(#{QuotedFragment})/o
|
||||||
WHEN_SYNTAX = /(#{QUOTED_FRAGMENT})(?:(?:\s+or\s+|\s*\,\s*)(#{QUOTED_FRAGMENT}.*))?/om.freeze
|
WhenSyntax = /(#{QuotedFragment})(?:(?:\s+or\s+|\s*\,\s*)(#{QuotedFragment}.*))?/om
|
||||||
|
|
||||||
attr_reader :blocks, :left
|
attr_reader :blocks, :left
|
||||||
|
|
||||||
@@ -11,16 +9,18 @@ module Liquid
|
|||||||
super
|
super
|
||||||
@blocks = []
|
@blocks = []
|
||||||
|
|
||||||
if markup =~ SYNTAX
|
if markup =~ Syntax
|
||||||
@left = Expression.parse(Regexp.last_match(1))
|
@left = Expression.parse($1)
|
||||||
else
|
else
|
||||||
raise SyntaxError, options[:locale].t('errors.syntax.case')
|
raise SyntaxError.new(options[:locale].t("errors.syntax.case".freeze))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse(tokens)
|
def parse(tokens)
|
||||||
body = BlockBody.new
|
body = BlockBody.new
|
||||||
body = @blocks.last.attachment while parse_body(body, tokens)
|
while parse_body(body, tokens)
|
||||||
|
body = @blocks.last.attachment
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def nodelist
|
def nodelist
|
||||||
@@ -29,26 +29,25 @@ module Liquid
|
|||||||
|
|
||||||
def unknown_tag(tag, markup, tokens)
|
def unknown_tag(tag, markup, tokens)
|
||||||
case tag
|
case tag
|
||||||
when 'when'
|
when 'when'.freeze
|
||||||
record_when_condition(markup)
|
record_when_condition(markup)
|
||||||
when 'else'
|
when 'else'.freeze
|
||||||
record_else_condition(markup)
|
record_else_condition(markup)
|
||||||
else
|
else
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_to_output_buffer(context, output)
|
def render(context)
|
||||||
context.stack do
|
execute_else_block = true
|
||||||
execute_else_block = true
|
|
||||||
|
|
||||||
@blocks.each do |block|
|
output = ''
|
||||||
if block.else?
|
@blocks.each do |block|
|
||||||
block.attachment.render_to_output_buffer(context, output) if execute_else_block
|
if block.else?
|
||||||
elsif block.evaluate(context)
|
return block.attachment.render(context) if execute_else_block
|
||||||
execute_else_block = false
|
elsif block.evaluate(context)
|
||||||
block.attachment.render_to_output_buffer(context, output)
|
execute_else_block = false
|
||||||
end
|
output << block.attachment.render(context)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -61,18 +60,22 @@ module Liquid
|
|||||||
body = BlockBody.new
|
body = BlockBody.new
|
||||||
|
|
||||||
while markup
|
while markup
|
||||||
raise SyntaxError, options[:locale].t('errors.syntax.case_invalid_when') unless markup =~ WHEN_SYNTAX
|
unless markup =~ WhenSyntax
|
||||||
|
raise SyntaxError.new(options[:locale].t("errors.syntax.case_invalid_when".freeze))
|
||||||
|
end
|
||||||
|
|
||||||
markup = Regexp.last_match(2)
|
markup = $2
|
||||||
|
|
||||||
block = Condition.new(@left, '==', Expression.parse(Regexp.last_match(1)))
|
block = Condition.new(@left, '=='.freeze, Expression.parse($1))
|
||||||
block.attach(body)
|
block.attach(body)
|
||||||
@blocks << block
|
@blocks << block
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def record_else_condition(markup)
|
def record_else_condition(markup)
|
||||||
raise SyntaxError, options[:locale].t('errors.syntax.case_invalid_else') unless markup.strip.empty?
|
unless markup.strip.empty?
|
||||||
|
raise SyntaxError.new(options[:locale].t("errors.syntax.case_invalid_else".freeze))
|
||||||
|
end
|
||||||
|
|
||||||
block = ElseCondition.new
|
block = ElseCondition.new
|
||||||
block.attach(BlockBody.new)
|
block.attach(BlockBody.new)
|
||||||
@@ -86,5 +89,5 @@ module Liquid
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Template.register_tag('case', Case)
|
Template.register_tag('case'.freeze, Case)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class Comment < Block
|
class Comment < Block
|
||||||
def render_to_output_buffer(_context, output)
|
def render(_context)
|
||||||
output
|
''.freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
def unknown_tag(_tag, _markup, _tokens); end
|
def unknown_tag(_tag, _markup, _tokens)
|
||||||
|
end
|
||||||
|
|
||||||
def blank?
|
def blank?
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Template.register_tag('comment', Comment)
|
Template.register_tag('comment'.freeze, Comment)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
# Continue tag to be used to break out of a for loop.
|
# Continue tag to be used to break out of a for loop.
|
||||||
#
|
#
|
||||||
@@ -16,5 +14,5 @@ module Liquid
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Template.register_tag('continue', Continue)
|
Template.register_tag('continue'.freeze, Continue)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
# Cycle is usually used within a loop to alternate between values, like colors or DOM classes.
|
# Cycle is usually used within a loop to alternate between values, like colors or DOM classes.
|
||||||
#
|
#
|
||||||
@@ -14,56 +12,43 @@ module Liquid
|
|||||||
# <div class="green"> Item five</div>
|
# <div class="green"> Item five</div>
|
||||||
#
|
#
|
||||||
class Cycle < Tag
|
class Cycle < Tag
|
||||||
SIMPLE_SYNTAX = /\A#{QUOTED_FRAGMENT}+/o.freeze
|
SimpleSyntax = /\A#{QuotedFragment}+/o
|
||||||
NAMED_SYNTAX = /\A(#{QUOTED_FRAGMENT})\s*\:\s*(.*)/om.freeze
|
NamedSyntax = /\A(#{QuotedFragment})\s*\:\s*(.*)/om
|
||||||
|
|
||||||
attr_reader :variables
|
attr_reader :variables
|
||||||
|
|
||||||
def initialize(tag_name, markup, options)
|
def initialize(tag_name, markup, options)
|
||||||
super
|
super
|
||||||
case markup
|
case markup
|
||||||
when NAMED_SYNTAX
|
when NamedSyntax
|
||||||
@variables = variables_from_string(Regexp.last_match(2))
|
@variables = variables_from_string($2)
|
||||||
@name = Expression.parse(Regexp.last_match(1))
|
@name = Expression.parse($1)
|
||||||
when SIMPLE_SYNTAX
|
when SimpleSyntax
|
||||||
@variables = variables_from_string(markup)
|
@variables = variables_from_string(markup)
|
||||||
@name = @variables.to_s
|
@name = @variables.to_s
|
||||||
else
|
else
|
||||||
raise SyntaxError, options[:locale].t('errors.syntax.cycle')
|
raise SyntaxError.new(options[:locale].t("errors.syntax.cycle".freeze))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_to_output_buffer(context, output)
|
def render(context)
|
||||||
context.registers[:cycle] ||= {}
|
context.registers[:cycle] ||= {}
|
||||||
|
|
||||||
context.stack do
|
key = context.evaluate(@name)
|
||||||
key = context.evaluate(@name)
|
iteration = context.registers[:cycle][key].to_i
|
||||||
iteration = context.registers[:cycle][key].to_i
|
result = context.evaluate(@variables[iteration])
|
||||||
|
iteration += 1
|
||||||
val = context.evaluate(@variables[iteration])
|
iteration = 0 if iteration >= @variables.size
|
||||||
|
context.registers[:cycle][key] = iteration
|
||||||
if val.is_a?(Array)
|
result
|
||||||
val = val.join
|
|
||||||
elsif !val.is_a?(String)
|
|
||||||
val = val.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
output << val
|
|
||||||
|
|
||||||
iteration += 1
|
|
||||||
iteration = 0 if iteration >= @variables.size
|
|
||||||
context.registers[:cycle][key] = iteration
|
|
||||||
end
|
|
||||||
|
|
||||||
output
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def variables_from_string(markup)
|
def variables_from_string(markup)
|
||||||
markup.split(',').collect do |var|
|
markup.split(',').collect do |var|
|
||||||
var =~ /\s*(#{QUOTED_FRAGMENT})\s*/o
|
var =~ /\s*(#{QuotedFragment})\s*/o
|
||||||
Regexp.last_match(1) ? Expression.parse(Regexp.last_match(1)) : nil
|
$1 ? Expression.parse($1) : nil
|
||||||
end.compact
|
end.compact
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
# decrement is used in a place where one needs to insert a counter
|
# decrement is used in a place where one needs to insert a counter
|
||||||
# into a template, and needs the counter to survive across
|
# into a template, and needs the counter to survive across
|
||||||
@@ -25,14 +23,13 @@ module Liquid
|
|||||||
@variable = markup.strip
|
@variable = markup.strip
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_to_output_buffer(context, output)
|
def render(context)
|
||||||
value = context.environments.first[@variable] ||= 0
|
value = context.environments.first[@variable] ||= 0
|
||||||
value -= 1
|
value -= 1
|
||||||
context.environments.first[@variable] = value
|
context.environments.first[@variable] = value
|
||||||
output << value.to_s
|
value.to_s
|
||||||
output
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Template.register_tag('decrement', Decrement)
|
Template.register_tag('decrement'.freeze, Decrement)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
# "For" iterates over an array or collection.
|
# "For" iterates over an array or collection.
|
||||||
# Several useful variables are available to you within the loop.
|
# Several useful variables are available to you within the loop.
|
||||||
@@ -46,7 +44,7 @@ module Liquid
|
|||||||
# forloop.parentloop:: Provides access to the parent loop, if present.
|
# forloop.parentloop:: Provides access to the parent loop, if present.
|
||||||
#
|
#
|
||||||
class For < Block
|
class For < Block
|
||||||
SYNTAX = /\A(#{VARIABLE_SEGMENT}+)\s+in\s+(#{QUOTED_FRAGMENT}+)\s*(reversed)?/o.freeze
|
Syntax = /\A(#{VariableSegment}+)\s+in\s+(#{QuotedFragment}+)\s*(reversed)?/o
|
||||||
|
|
||||||
attr_reader :collection_name, :variable_name, :limit, :from
|
attr_reader :collection_name, :variable_name, :limit, :from
|
||||||
|
|
||||||
@@ -60,7 +58,6 @@ module Liquid
|
|||||||
|
|
||||||
def parse(tokens)
|
def parse(tokens)
|
||||||
return unless parse_body(@for_block, tokens)
|
return unless parse_body(@for_block, tokens)
|
||||||
|
|
||||||
parse_body(@else_block, tokens)
|
parse_body(@else_block, tokens)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -69,55 +66,50 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def unknown_tag(tag, markup, tokens)
|
def unknown_tag(tag, markup, tokens)
|
||||||
return super unless tag == 'else'
|
return super unless tag == 'else'.freeze
|
||||||
|
|
||||||
@else_block = BlockBody.new
|
@else_block = BlockBody.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_to_output_buffer(context, output)
|
def render(context)
|
||||||
segment = collection_segment(context)
|
segment = collection_segment(context)
|
||||||
|
|
||||||
if segment.empty?
|
if segment.empty?
|
||||||
render_else(context, output)
|
render_else(context)
|
||||||
else
|
else
|
||||||
render_segment(context, output, segment)
|
render_segment(context, segment)
|
||||||
end
|
end
|
||||||
|
|
||||||
output
|
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def lax_parse(markup)
|
def lax_parse(markup)
|
||||||
if markup =~ SYNTAX
|
if markup =~ Syntax
|
||||||
@variable_name = Regexp.last_match(1)
|
@variable_name = $1
|
||||||
collection_name = Regexp.last_match(2)
|
collection_name = $2
|
||||||
@reversed = !!Regexp.last_match(3)
|
@reversed = !!$3
|
||||||
@name = "#{@variable_name}-#{collection_name}"
|
@name = "#{@variable_name}-#{collection_name}"
|
||||||
@collection_name = Expression.parse(collection_name)
|
@collection_name = Expression.parse(collection_name)
|
||||||
markup.scan(TAG_ATTRIBUTES) do |key, value|
|
markup.scan(TagAttributes) do |key, value|
|
||||||
set_attribute(key, value)
|
set_attribute(key, value)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
raise SyntaxError, options[:locale].t('errors.syntax.for')
|
raise SyntaxError.new(options[:locale].t("errors.syntax.for".freeze))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def strict_parse(markup)
|
def strict_parse(markup)
|
||||||
p = Parser.new(markup)
|
p = Parser.new(markup)
|
||||||
@variable_name = p.consume(:id)
|
@variable_name = p.consume(:id)
|
||||||
raise SyntaxError, options[:locale].t('errors.syntax.for_invalid_in') unless p.id?('in')
|
raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_in".freeze)) unless p.id?('in'.freeze)
|
||||||
|
|
||||||
collection_name = p.expression
|
collection_name = p.expression
|
||||||
@name = "#{@variable_name}-#{collection_name}"
|
@name = "#{@variable_name}-#{collection_name}"
|
||||||
@collection_name = Expression.parse(collection_name)
|
@collection_name = Expression.parse(collection_name)
|
||||||
@reversed = p.id?('reversed')
|
@reversed = p.id?('reversed'.freeze)
|
||||||
|
|
||||||
while p.look(:id) && p.look(:colon, 1)
|
while p.look(:id) && p.look(:colon, 1)
|
||||||
unless (attribute = p.id?('limit') || p.id?('offset'))
|
unless attribute = p.id?('limit'.freeze) || p.id?('offset'.freeze)
|
||||||
raise SyntaxError, options[:locale].t('errors.syntax.for_invalid_attribute')
|
raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_attribute".freeze))
|
||||||
end
|
end
|
||||||
|
|
||||||
p.consume
|
p.consume
|
||||||
set_attribute(attribute, p.expression)
|
set_attribute(attribute, p.expression)
|
||||||
end
|
end
|
||||||
@@ -158,57 +150,58 @@ module Liquid
|
|||||||
segment
|
segment
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_segment(context, output, segment)
|
def render_segment(context, segment)
|
||||||
for_stack = context.registers[:for_stack] ||= []
|
for_stack = context.registers[:for_stack] ||= []
|
||||||
length = segment.length
|
length = segment.length
|
||||||
|
|
||||||
context.stack do
|
result = ''
|
||||||
|
|
||||||
|
context.stack('forloop', @variable_name) do
|
||||||
loop_vars = Liquid::ForloopDrop.new(@name, length, for_stack[-1])
|
loop_vars = Liquid::ForloopDrop.new(@name, length, for_stack[-1])
|
||||||
|
|
||||||
for_stack.push(loop_vars)
|
for_stack.push(loop_vars)
|
||||||
|
|
||||||
begin
|
begin
|
||||||
context['forloop'] = loop_vars
|
context['forloop'.freeze] = loop_vars
|
||||||
|
level = context.create_level(@variable_name)
|
||||||
|
|
||||||
segment.each do |item|
|
segment.each do |item|
|
||||||
context[@variable_name] = item
|
context.set_level(@variable_name, item, level)
|
||||||
@for_block.render_to_output_buffer(context, output)
|
result << @for_block.render(context)
|
||||||
loop_vars.send(:increment!)
|
loop_vars.send(:increment!)
|
||||||
|
|
||||||
# Handle any interrupts if they exist.
|
# Handle any interrupts if they exist.
|
||||||
next unless context.interrupt?
|
if context.interrupt?
|
||||||
|
interrupt = context.pop_interrupt
|
||||||
interrupt = context.pop_interrupt
|
break if interrupt.is_a? BreakInterrupt
|
||||||
break if interrupt.is_a?(BreakInterrupt)
|
next if interrupt.is_a? ContinueInterrupt
|
||||||
next if interrupt.is_a?(ContinueInterrupt)
|
end
|
||||||
end
|
end
|
||||||
|
context.unset(@variable_name)
|
||||||
|
context.unset('forloop'.freeze)
|
||||||
ensure
|
ensure
|
||||||
|
|
||||||
for_stack.pop
|
for_stack.pop
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
output
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_attribute(key, expr)
|
def set_attribute(key, expr)
|
||||||
case key
|
case key
|
||||||
when 'offset'
|
when 'offset'.freeze
|
||||||
@from = if expr == 'continue'
|
@from = if expr == 'continue'.freeze
|
||||||
:continue
|
:continue
|
||||||
else
|
else
|
||||||
Expression.parse(expr)
|
Expression.parse(expr)
|
||||||
end
|
end
|
||||||
when 'limit'
|
when 'limit'.freeze
|
||||||
@limit = Expression.parse(expr)
|
@limit = Expression.parse(expr)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_else(context, output)
|
def render_else(context)
|
||||||
if @else_block
|
@else_block ? @else_block.render(context) : ''.freeze
|
||||||
@else_block.render_to_output_buffer(context, output)
|
|
||||||
else
|
|
||||||
output
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
||||||
@@ -218,5 +211,5 @@ module Liquid
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Template.register_tag('for', For)
|
Template.register_tag('for'.freeze, For)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
# If is the conditional block
|
# If is the conditional block
|
||||||
#
|
#
|
||||||
@@ -12,16 +10,16 @@ module Liquid
|
|||||||
# There are {% if count < 5 %} less {% else %} more {% endif %} items than you need.
|
# There are {% if count < 5 %} less {% else %} more {% endif %} items than you need.
|
||||||
#
|
#
|
||||||
class If < Block
|
class If < Block
|
||||||
SYNTAX = /(#{QUOTED_FRAGMENT})\s*([=!<>a-z_]+)?\s*(#{QUOTED_FRAGMENT})?/o.freeze
|
Syntax = /(#{QuotedFragment})\s*([=!<>a-z_]+)?\s*(#{QuotedFragment})?/o
|
||||||
EXPRESSIONS_AND_OPERATORS = /(?:\b(?:\s?and\s?|\s?or\s?)\b|(?:\s*(?!\b(?:\s?and\s?|\s?or\s?)\b)(?:#{QUOTED_FRAGMENT}|\S+)\s*)+)/o.freeze
|
ExpressionsAndOperators = /(?:\b(?:\s?and\s?|\s?or\s?)\b|(?:\s*(?!\b(?:\s?and\s?|\s?or\s?)\b)(?:#{QuotedFragment}|\S+)\s*)+)/o
|
||||||
BOOLEAN_OPERATORS = %w[and or].freeze
|
BOOLEAN_OPERATORS = %w(and or).freeze
|
||||||
|
|
||||||
attr_reader :blocks
|
attr_reader :blocks
|
||||||
|
|
||||||
def initialize(tag_name, markup, options)
|
def initialize(tag_name, markup, options)
|
||||||
super
|
super
|
||||||
@blocks = []
|
@blocks = []
|
||||||
push_block('if', markup)
|
push_block('if'.freeze, markup)
|
||||||
end
|
end
|
||||||
|
|
||||||
def nodelist
|
def nodelist
|
||||||
@@ -34,27 +32,26 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def unknown_tag(tag, markup, tokens)
|
def unknown_tag(tag, markup, tokens)
|
||||||
if %w[elsif else].include?(tag)
|
if ['elsif'.freeze, 'else'.freeze].include?(tag)
|
||||||
push_block(tag, markup)
|
push_block(tag, markup)
|
||||||
else
|
else
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_to_output_buffer(context, output)
|
def render(context)
|
||||||
context.stack do
|
@blocks.each do |block|
|
||||||
@blocks.each do |block|
|
if block.evaluate(context)
|
||||||
return block.attachment.render_to_output_buffer(context, output) if block.evaluate(context)
|
return block.attachment.render(context)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
''.freeze
|
||||||
output
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def push_block(tag, markup)
|
def push_block(tag, markup)
|
||||||
block = if tag == 'else'
|
block = if tag == 'else'.freeze
|
||||||
ElseCondition.new
|
ElseCondition.new
|
||||||
else
|
else
|
||||||
parse_with_selected_parser(markup)
|
parse_with_selected_parser(markup)
|
||||||
@@ -65,19 +62,18 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def lax_parse(markup)
|
def lax_parse(markup)
|
||||||
expressions = markup.scan(EXPRESSIONS_AND_OPERATORS)
|
expressions = markup.scan(ExpressionsAndOperators)
|
||||||
raise SyntaxError, options[:locale].t('errors.syntax.if') unless expressions.pop =~ SYNTAX
|
raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.pop =~ Syntax
|
||||||
|
|
||||||
condition = Condition.new(Expression.parse(Regexp.last_match(1)), Regexp.last_match(2), Expression.parse(Regexp.last_match(3)))
|
condition = Condition.new(Expression.parse($1), $2, Expression.parse($3))
|
||||||
|
|
||||||
until expressions.empty?
|
until expressions.empty?
|
||||||
operator = expressions.pop.to_s.strip
|
operator = expressions.pop.to_s.strip
|
||||||
|
|
||||||
raise SyntaxError, options[:locale].t('errors.syntax.if') unless expressions.pop.to_s =~ SYNTAX
|
raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.pop.to_s =~ Syntax
|
||||||
|
|
||||||
new_condition = Condition.new(Expression.parse(Regexp.last_match(1)), Regexp.last_match(2), Expression.parse(Regexp.last_match(3)))
|
|
||||||
raise SyntaxError, options[:locale].t('errors.syntax.if') unless BOOLEAN_OPERATORS.include?(operator)
|
|
||||||
|
|
||||||
|
new_condition = Condition.new(Expression.parse($1), $2, Expression.parse($3))
|
||||||
|
raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless BOOLEAN_OPERATORS.include?(operator)
|
||||||
new_condition.send(operator, condition)
|
new_condition.send(operator, condition)
|
||||||
condition = new_condition
|
condition = new_condition
|
||||||
end
|
end
|
||||||
@@ -95,7 +91,7 @@ module Liquid
|
|||||||
def parse_binary_comparisons(p)
|
def parse_binary_comparisons(p)
|
||||||
condition = parse_comparison(p)
|
condition = parse_comparison(p)
|
||||||
first_condition = condition
|
first_condition = condition
|
||||||
while (op = (p.id?('and') || p.id?('or')))
|
while op = (p.id?('and'.freeze) || p.id?('or'.freeze))
|
||||||
child_condition = parse_comparison(p)
|
child_condition = parse_comparison(p)
|
||||||
condition.send(op, child_condition)
|
condition.send(op, child_condition)
|
||||||
condition = child_condition
|
condition = child_condition
|
||||||
@@ -105,7 +101,7 @@ module Liquid
|
|||||||
|
|
||||||
def parse_comparison(p)
|
def parse_comparison(p)
|
||||||
a = Expression.parse(p.expression)
|
a = Expression.parse(p.expression)
|
||||||
if (op = p.consume?(:comparison))
|
if op = p.consume?(:comparison)
|
||||||
b = Expression.parse(p.expression)
|
b = Expression.parse(p.expression)
|
||||||
Condition.new(a, op, b)
|
Condition.new(a, op, b)
|
||||||
else
|
else
|
||||||
@@ -120,5 +116,5 @@ module Liquid
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Template.register_tag('if', If)
|
Template.register_tag('if'.freeze, If)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,21 +1,16 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class Ifchanged < Block
|
class Ifchanged < Block
|
||||||
def render_to_output_buffer(context, output)
|
def render(context)
|
||||||
context.stack do
|
output = super
|
||||||
block_output = +''
|
|
||||||
super(context, block_output)
|
|
||||||
|
|
||||||
if block_output != context.registers[:ifchanged]
|
if output != context.registers[:ifchanged]
|
||||||
context.registers[:ifchanged] = block_output
|
context.registers[:ifchanged] = output
|
||||||
output << block_output
|
output
|
||||||
end
|
else
|
||||||
|
''.freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
output
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Template.register_tag('ifchanged', Ifchanged)
|
Template.register_tag('ifchanged'.freeze, Ifchanged)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
# Include allows templates to relate with other templates
|
# Include allows templates to relate with other templates
|
||||||
#
|
#
|
||||||
@@ -16,39 +14,40 @@ module Liquid
|
|||||||
# {% include 'product' for products %}
|
# {% include 'product' for products %}
|
||||||
#
|
#
|
||||||
class Include < Tag
|
class Include < Tag
|
||||||
SYNTAX = /(#{QUOTED_FRAGMENT}+)(\s+(?:with|for)\s+(#{QUOTED_FRAGMENT}+))?/o.freeze
|
Syntax = /(#{QuotedFragment}+)(\s+(?:with|for)\s+(#{QuotedFragment}+))?/o
|
||||||
|
|
||||||
attr_reader :template_name_expr, :variable_name_expr, :attributes
|
attr_reader :template_name_expr, :variable_name_expr, :attributes
|
||||||
|
|
||||||
def initialize(tag_name, markup, options)
|
def initialize(tag_name, markup, options)
|
||||||
super
|
super
|
||||||
|
|
||||||
if markup =~ SYNTAX
|
if markup =~ Syntax
|
||||||
|
|
||||||
template_name = Regexp.last_match(1)
|
template_name = $1
|
||||||
variable_name = Regexp.last_match(3)
|
variable_name = $3
|
||||||
|
|
||||||
@variable_name_expr = variable_name ? Expression.parse(variable_name) : nil
|
@variable_name_expr = variable_name ? Expression.parse(variable_name) : nil
|
||||||
@template_name_expr = Expression.parse(template_name)
|
@template_name_expr = Expression.parse(template_name)
|
||||||
@attributes = {}
|
@attributes = {}
|
||||||
|
|
||||||
markup.scan(TAG_ATTRIBUTES) do |key, value|
|
markup.scan(TagAttributes) do |key, value|
|
||||||
@attributes[key] = Expression.parse(value)
|
@attributes[key] = Expression.parse(value)
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
raise SyntaxError, options[:locale].t('errors.syntax.include')
|
raise SyntaxError.new(options[:locale].t("errors.syntax.include".freeze))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse(_tokens); end
|
def parse(_tokens)
|
||||||
|
end
|
||||||
|
|
||||||
def render_to_output_buffer(context, output)
|
def render(context)
|
||||||
template_name = context.evaluate(@template_name_expr)
|
template_name = context.evaluate(@template_name_expr)
|
||||||
raise ArgumentError, options[:locale].t('errors.argument.include') unless template_name
|
raise ArgumentError.new(options[:locale].t("errors.argument.include")) unless template_name
|
||||||
|
|
||||||
partial = load_cached_partial(template_name, context)
|
partial = load_cached_partial(template_name, context)
|
||||||
context_variable_name = template_name.split('/').last
|
context_variable_name = template_name.split('/'.freeze).last
|
||||||
|
|
||||||
variable = if @variable_name_expr
|
variable = if @variable_name_expr
|
||||||
context.evaluate(@variable_name_expr)
|
context.evaluate(@variable_name_expr)
|
||||||
@@ -61,27 +60,25 @@ module Liquid
|
|||||||
begin
|
begin
|
||||||
context.template_name = template_name
|
context.template_name = template_name
|
||||||
context.partial = true
|
context.partial = true
|
||||||
context.stack do
|
context.stack(context_variable_name, *@attributes.keys) do
|
||||||
@attributes.each do |key, value|
|
@attributes.each do |key, value|
|
||||||
context[key] = context.evaluate(value)
|
context[key] = context.evaluate(value)
|
||||||
end
|
end
|
||||||
|
|
||||||
if variable.is_a?(Array)
|
if variable.is_a?(Array)
|
||||||
variable.each do |var|
|
variable.collect do |var|
|
||||||
context[context_variable_name] = var
|
context[context_variable_name] = var
|
||||||
partial.render_to_output_buffer(context, output)
|
partial.render(context)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
context[context_variable_name] = variable
|
context[context_variable_name] = variable
|
||||||
partial.render_to_output_buffer(context, output)
|
partial.render(context)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
ensure
|
ensure
|
||||||
context.template_name = old_template_name
|
context.template_name = old_template_name
|
||||||
context.partial = old_partial
|
context.partial = old_partial
|
||||||
end
|
end
|
||||||
|
|
||||||
output
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@@ -92,10 +89,9 @@ module Liquid
|
|||||||
def load_cached_partial(template_name, context)
|
def load_cached_partial(template_name, context)
|
||||||
cached_partials = context.registers[:cached_partials] || {}
|
cached_partials = context.registers[:cached_partials] || {}
|
||||||
|
|
||||||
if (cached = cached_partials[template_name])
|
if cached = cached_partials[template_name]
|
||||||
return cached
|
return cached
|
||||||
end
|
end
|
||||||
|
|
||||||
source = read_template_from_file_system(context)
|
source = read_template_from_file_system(context)
|
||||||
begin
|
begin
|
||||||
parse_context.partial = true
|
parse_context.partial = true
|
||||||
@@ -118,11 +114,11 @@ module Liquid
|
|||||||
def children
|
def children
|
||||||
[
|
[
|
||||||
@node.template_name_expr,
|
@node.template_name_expr,
|
||||||
@node.variable_name_expr,
|
@node.variable_name_expr
|
||||||
] + @node.attributes.values
|
] + @node.attributes.values
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Template.register_tag('include', Include)
|
Template.register_tag('include'.freeze, Include)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
# increment is used in a place where one needs to insert a counter
|
# increment is used in a place where one needs to insert a counter
|
||||||
# into a template, and needs the counter to survive across
|
# into a template, and needs the counter to survive across
|
||||||
@@ -22,13 +20,12 @@ module Liquid
|
|||||||
@variable = markup.strip
|
@variable = markup.strip
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_to_output_buffer(context, output)
|
def render(context)
|
||||||
value = context.environments.first[@variable] ||= 0
|
value = context.environments.first[@variable] ||= 0
|
||||||
context.environments.first[@variable] = value + 1
|
context.environments.first[@variable] = value + 1
|
||||||
output << value.to_s
|
value.to_s
|
||||||
output
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Template.register_tag('increment', Increment)
|
Template.register_tag('increment'.freeze, Increment)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class Raw < Block
|
class Raw < Block
|
||||||
SYNTAX = /\A\s*\z/.freeze
|
Syntax = /\A\s*\z/
|
||||||
FULL_TOKEN_POSSIBLY_INVALID = /\A(.*)#{TAG_START}\s*(\w+)\s*(.*)?#{TAG_END}\z/om.freeze
|
FullTokenPossiblyInvalid = /\A(.*)#{TagStart}\s*(\w+)\s*(.*)?#{TagEnd}\z/om
|
||||||
|
|
||||||
def initialize(tag_name, markup, parse_context)
|
def initialize(tag_name, markup, parse_context)
|
||||||
super
|
super
|
||||||
@@ -12,21 +10,20 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def parse(tokens)
|
def parse(tokens)
|
||||||
@body = +''
|
@body = ''
|
||||||
while (token = tokens.shift)
|
while token = tokens.shift
|
||||||
if token =~ FULL_TOKEN_POSSIBLY_INVALID
|
if token =~ FullTokenPossiblyInvalid
|
||||||
@body << Regexp.last_match(1) if Regexp.last_match(1) != ''
|
@body << $1 if $1 != "".freeze
|
||||||
return if block_delimiter == Regexp.last_match(2)
|
return if block_delimiter == $2
|
||||||
end
|
end
|
||||||
@body << token unless token.empty?
|
@body << token unless token.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
raise SyntaxError, parse_context.locale.t('errors.syntax.tag_never_closed', block_name: block_name)
|
raise SyntaxError.new(parse_context.locale.t("errors.syntax.tag_never_closed".freeze, block_name: block_name))
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_to_output_buffer(_context, output)
|
def render(_context)
|
||||||
output << @body
|
@body
|
||||||
output
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def nodelist
|
def nodelist
|
||||||
@@ -40,9 +37,11 @@ module Liquid
|
|||||||
protected
|
protected
|
||||||
|
|
||||||
def ensure_valid_markup(tag_name, markup, parse_context)
|
def ensure_valid_markup(tag_name, markup, parse_context)
|
||||||
raise SyntaxError, parse_context.locale.t('errors.syntax.tag_unexpected_args', tag: tag_name) unless markup =~ SYNTAX
|
unless markup =~ Syntax
|
||||||
|
raise SyntaxError.new(parse_context.locale.t("errors.syntax.tag_unexpected_args".freeze, tag: tag_name))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Template.register_tag('raw', Raw)
|
Template.register_tag('raw'.freeze, Raw)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,57 +1,54 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class TableRow < Block
|
class TableRow < Block
|
||||||
SYNTAX = /(\w+)\s+in\s+(#{QUOTED_FRAGMENT}+)/o.freeze
|
Syntax = /(\w+)\s+in\s+(#{QuotedFragment}+)/o
|
||||||
|
|
||||||
attr_reader :variable_name, :collection_name, :attributes
|
attr_reader :variable_name, :collection_name, :attributes
|
||||||
|
|
||||||
def initialize(tag_name, markup, options)
|
def initialize(tag_name, markup, options)
|
||||||
super
|
super
|
||||||
if markup =~ SYNTAX
|
if markup =~ Syntax
|
||||||
@variable_name = Regexp.last_match(1)
|
@variable_name = $1
|
||||||
@collection_name = Expression.parse(Regexp.last_match(2))
|
@collection_name = Expression.parse($2)
|
||||||
@attributes = {}
|
@attributes = {}
|
||||||
markup.scan(TAG_ATTRIBUTES) do |key, value|
|
markup.scan(TagAttributes) do |key, value|
|
||||||
@attributes[key] = Expression.parse(value)
|
@attributes[key] = Expression.parse(value)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
raise SyntaxError, options[:locale].t('errors.syntax.table_row')
|
raise SyntaxError.new(options[:locale].t("errors.syntax.table_row".freeze))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_to_output_buffer(context, output)
|
def render(context)
|
||||||
(collection = context.evaluate(@collection_name)) || (return '')
|
collection = context.evaluate(@collection_name) or return ''.freeze
|
||||||
|
|
||||||
from = @attributes.key?('offset') ? context.evaluate(@attributes['offset']).to_i : 0
|
from = @attributes.key?('offset'.freeze) ? context.evaluate(@attributes['offset'.freeze]).to_i : 0
|
||||||
to = @attributes.key?('limit') ? from + context.evaluate(@attributes['limit']).to_i : nil
|
to = @attributes.key?('limit'.freeze) ? from + context.evaluate(@attributes['limit'.freeze]).to_i : nil
|
||||||
|
|
||||||
collection = Utils.slice_collection(collection, from, to)
|
collection = Utils.slice_collection(collection, from, to)
|
||||||
|
|
||||||
length = collection.length
|
length = collection.length
|
||||||
|
|
||||||
cols = context.evaluate(@attributes['cols']).to_i
|
cols = context.evaluate(@attributes['cols'.freeze]).to_i
|
||||||
|
|
||||||
output << "<tr class=\"row1\">\n"
|
result = "<tr class=\"row1\">\n"
|
||||||
context.stack do
|
context.stack('tablerowloop', @variable_name) do
|
||||||
tablerowloop = Liquid::TablerowloopDrop.new(length, cols)
|
tablerowloop = Liquid::TablerowloopDrop.new(length, cols)
|
||||||
context['tablerowloop'] = tablerowloop
|
context['tablerowloop'.freeze] = tablerowloop
|
||||||
|
|
||||||
collection.each do |item|
|
collection.each do |item|
|
||||||
context[@variable_name] = item
|
context[@variable_name] = item
|
||||||
|
|
||||||
output << "<td class=\"col#{tablerowloop.col}\">"
|
result << "<td class=\"col#{tablerowloop.col}\">" << super << '</td>'
|
||||||
super
|
|
||||||
output << '</td>'
|
|
||||||
|
|
||||||
output << "</tr>\n<tr class=\"row#{tablerowloop.row + 1}\">" if tablerowloop.col_last && !tablerowloop.last
|
if tablerowloop.col_last && !tablerowloop.last
|
||||||
|
result << "</tr>\n<tr class=\"row#{tablerowloop.row + 1}\">"
|
||||||
|
end
|
||||||
|
|
||||||
tablerowloop.send(:increment!)
|
tablerowloop.send(:increment!)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
result << "</tr>\n"
|
||||||
output << "</tr>\n"
|
result
|
||||||
output
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
||||||
@@ -61,5 +58,5 @@ module Liquid
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Template.register_tag('tablerow', TableRow)
|
Template.register_tag('tablerow'.freeze, TableRow)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require_relative 'if'
|
require_relative 'if'
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
@@ -8,21 +6,23 @@ module Liquid
|
|||||||
# {% unless x < 0 %} x is greater than zero {% endunless %}
|
# {% unless x < 0 %} x is greater than zero {% endunless %}
|
||||||
#
|
#
|
||||||
class Unless < If
|
class Unless < If
|
||||||
def render_to_output_buffer(context, output)
|
def render(context)
|
||||||
context.stack do
|
# First condition is interpreted backwards ( if not )
|
||||||
# First condition is interpreted backwards ( if not )
|
first_block = @blocks.first
|
||||||
first_block = @blocks.first
|
unless first_block.evaluate(context)
|
||||||
return first_block.attachment.render_to_output_buffer(context, output) unless first_block.evaluate(context)
|
return first_block.attachment.render(context)
|
||||||
|
end
|
||||||
|
|
||||||
# After the first condition unless works just like if
|
# After the first condition unless works just like if
|
||||||
@blocks[1..-1].each do |block|
|
@blocks[1..-1].each do |block|
|
||||||
return block.attachment.render_to_output_buffer(context, output) if block.evaluate(context)
|
if block.evaluate(context)
|
||||||
|
return block.attachment.render(context)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
output
|
''.freeze
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Template.register_tag('unless', Unless)
|
Template.register_tag('unless'.freeze, Unless)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
# Templates are central to liquid.
|
# Templates are central to liquid.
|
||||||
# Interpretating templates is a two step process. First you compile the
|
# Interpretating templates is a two step process. First you compile the
|
||||||
@@ -18,11 +16,7 @@ module Liquid
|
|||||||
attr_accessor :root
|
attr_accessor :root
|
||||||
attr_reader :resource_limits, :warnings
|
attr_reader :resource_limits, :warnings
|
||||||
|
|
||||||
@file_system = BlankFileSystem.new
|
@@file_system = BlankFileSystem.new
|
||||||
|
|
||||||
class << self
|
|
||||||
attr_accessor :file_system
|
|
||||||
end
|
|
||||||
|
|
||||||
class TagRegistry
|
class TagRegistry
|
||||||
include Enumerable
|
include Enumerable
|
||||||
@@ -56,7 +50,7 @@ module Liquid
|
|||||||
private
|
private
|
||||||
|
|
||||||
def lookup_class(name)
|
def lookup_class(name)
|
||||||
Object.const_get(name)
|
name.split("::").reject(&:empty?).reduce(Object) { |scope, const| scope.const_get(const) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -80,6 +74,14 @@ module Liquid
|
|||||||
exception
|
exception
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def file_system
|
||||||
|
@@file_system
|
||||||
|
end
|
||||||
|
|
||||||
|
def file_system=(obj)
|
||||||
|
@@file_system = obj
|
||||||
|
end
|
||||||
|
|
||||||
def register_tag(name, klass)
|
def register_tag(name, klass)
|
||||||
tags[name.to_s] = klass
|
tags[name.to_s] = klass
|
||||||
end
|
end
|
||||||
@@ -163,13 +165,15 @@ module Liquid
|
|||||||
# filters and tags and might be useful to integrate liquid more with its host application
|
# filters and tags and might be useful to integrate liquid more with its host application
|
||||||
#
|
#
|
||||||
def render(*args)
|
def render(*args)
|
||||||
return '' if @root.nil?
|
return ''.freeze if @root.nil?
|
||||||
|
|
||||||
context = case args.first
|
context = case args.first
|
||||||
when Liquid::Context
|
when Liquid::Context
|
||||||
c = args.shift
|
c = args.shift
|
||||||
|
|
||||||
c.exception_renderer = ->(_e) { raise } if @rethrow_errors
|
if @rethrow_errors
|
||||||
|
c.exception_renderer = ->(e) { raise }
|
||||||
|
end
|
||||||
|
|
||||||
c
|
c
|
||||||
when Liquid::Drop
|
when Liquid::Drop
|
||||||
@@ -180,15 +184,12 @@ module Liquid
|
|||||||
when nil
|
when nil
|
||||||
Context.new(assigns, instance_assigns, registers, @rethrow_errors, @resource_limits)
|
Context.new(assigns, instance_assigns, registers, @rethrow_errors, @resource_limits)
|
||||||
else
|
else
|
||||||
raise ArgumentError, 'Expected Hash or Liquid::Context as parameter'
|
raise ArgumentError, "Expected Hash or Liquid::Context as parameter"
|
||||||
end
|
end
|
||||||
|
|
||||||
output = nil
|
|
||||||
|
|
||||||
case args.last
|
case args.last
|
||||||
when Hash
|
when Hash
|
||||||
options = args.pop
|
options = args.pop
|
||||||
output = options[:output] if options[:output]
|
|
||||||
|
|
||||||
registers.merge!(options[:registers]) if options[:registers].is_a?(Hash)
|
registers.merge!(options[:registers]) if options[:registers].is_a?(Hash)
|
||||||
|
|
||||||
@@ -203,9 +204,10 @@ module Liquid
|
|||||||
begin
|
begin
|
||||||
# render the nodelist.
|
# render the nodelist.
|
||||||
# for performance reasons we get an array back here. join will make a string out of it.
|
# for performance reasons we get an array back here. join will make a string out of it.
|
||||||
with_profiling(context) do
|
result = with_profiling(context) do
|
||||||
@root.render_to_output_buffer(context, output || +'')
|
@root.render(context)
|
||||||
end
|
end
|
||||||
|
result.respond_to?(:join) ? result.join : result
|
||||||
rescue Liquid::MemoryError => e
|
rescue Liquid::MemoryError => e
|
||||||
context.handle_error(e)
|
context.handle_error(e)
|
||||||
ensure
|
ensure
|
||||||
@@ -218,10 +220,6 @@ module Liquid
|
|||||||
render(*args)
|
render(*args)
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_to_output_buffer(context, output)
|
|
||||||
render(context, output: output)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def tokenize(source)
|
def tokenize(source)
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class Tokenizer
|
class Tokenizer
|
||||||
attr_reader :line_number
|
attr_reader :line_number
|
||||||
@@ -22,10 +20,10 @@ module Liquid
|
|||||||
@source = @source.source if @source.respond_to?(:source)
|
@source = @source.source if @source.respond_to?(:source)
|
||||||
return [] if @source.to_s.empty?
|
return [] if @source.to_s.empty?
|
||||||
|
|
||||||
tokens = @source.split(TEMPLATE_PARSER)
|
tokens = @source.split(TemplateParser)
|
||||||
|
|
||||||
# removes the rogue empty element at the beginning of the array
|
# removes the rogue empty element at the beginning of the array
|
||||||
tokens.shift if tokens[0]&.empty?
|
tokens.shift if tokens[0] && tokens[0].empty?
|
||||||
|
|
||||||
tokens
|
tokens
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
module Utils
|
module Utils
|
||||||
def self.slice_collection(collection, from, to)
|
def self.slice_collection(collection, from, to)
|
||||||
@@ -21,9 +19,13 @@ module Liquid
|
|||||||
return [] unless collection.respond_to?(:each)
|
return [] unless collection.respond_to?(:each)
|
||||||
|
|
||||||
collection.each do |item|
|
collection.each do |item|
|
||||||
break if to && to <= index
|
if to && to <= index
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
segments << item if from <= index
|
if from <= index
|
||||||
|
segments << item
|
||||||
|
end
|
||||||
|
|
||||||
index += 1
|
index += 1
|
||||||
end
|
end
|
||||||
@@ -33,12 +35,11 @@ module Liquid
|
|||||||
|
|
||||||
def self.to_integer(num)
|
def self.to_integer(num)
|
||||||
return num if num.is_a?(Integer)
|
return num if num.is_a?(Integer)
|
||||||
|
|
||||||
num = num.to_s
|
num = num.to_s
|
||||||
begin
|
begin
|
||||||
Integer(num)
|
Integer(num)
|
||||||
rescue ::ArgumentError
|
rescue ::ArgumentError
|
||||||
raise Liquid::ArgumentError, 'invalid integer'
|
raise Liquid::ArgumentError, "invalid integer"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ module Liquid
|
|||||||
when Numeric
|
when Numeric
|
||||||
obj
|
obj
|
||||||
when String
|
when String
|
||||||
obj.strip =~ /\A-?\d+\.\d+\z/ ? BigDecimal(obj) : obj.to_i
|
(obj.strip =~ /\A-?\d+\.\d+\z/) ? BigDecimal(obj) : obj.to_i
|
||||||
else
|
else
|
||||||
if obj.respond_to?(:to_number)
|
if obj.respond_to?(:to_number)
|
||||||
obj.to_number
|
obj.to_number
|
||||||
@@ -64,12 +65,11 @@ module Liquid
|
|||||||
|
|
||||||
if obj.is_a?(String)
|
if obj.is_a?(String)
|
||||||
return nil if obj.empty?
|
return nil if obj.empty?
|
||||||
|
|
||||||
obj = obj.downcase
|
obj = obj.downcase
|
||||||
end
|
end
|
||||||
|
|
||||||
case obj
|
case obj
|
||||||
when 'now', 'today'
|
when 'now'.freeze, 'today'.freeze
|
||||||
Time.now
|
Time.now
|
||||||
when /\A\d+\z/, Integer
|
when /\A\d+\z/, Integer
|
||||||
Time.at(obj.to_i)
|
Time.at(obj.to_i)
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
# Holds variables. Variables are only loaded "just in time"
|
# Holds variables. Variables are only loaded "just in time"
|
||||||
# and are not evaluated as part of the render stage
|
# and are not evaluated as part of the render stage
|
||||||
@@ -12,11 +10,11 @@ module Liquid
|
|||||||
# {{ user | link }}
|
# {{ user | link }}
|
||||||
#
|
#
|
||||||
class Variable
|
class Variable
|
||||||
FILTER_MARKUP_REGEX = /#{FILTER_SEPARATOR}\s*(.*)/om.freeze
|
FilterMarkupRegex = /#{FilterSeparator}\s*(.*)/om
|
||||||
FILTER_PARSER = /(?:\s+|#{QUOTED_FRAGMENT}|#{ARGUMENT_SEPARATOR})+/o.freeze
|
FilterParser = /(?:\s+|#{QuotedFragment}|#{ArgumentSeparator})+/o
|
||||||
FILTER_ARGS_REGEX = /(?:#{FILTER_ARGUMENT_SEPARATOR}|#{ARGUMENT_SEPARATOR})\s*((?:\w+\s*\:\s*)?#{QUOTED_FRAGMENT})/o.freeze
|
FilterArgsRegex = /(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*((?:\w+\s*\:\s*)?#{QuotedFragment})/o
|
||||||
JUST_TAG_ATTRIBUTES = /\A#{TAG_ATTRIBUTES}\z/o.freeze
|
JustTagAttributes = /\A#{TagAttributes}\z/o
|
||||||
MARKUP_WITH_QUOTED_FRAGMENT = /(#{QUOTED_FRAGMENT})(.*)/om.freeze
|
MarkupWithQuotedFragment = /(#{QuotedFragment})(.*)/om
|
||||||
|
|
||||||
attr_accessor :filters, :name, :line_number
|
attr_accessor :filters, :name, :line_number
|
||||||
attr_reader :parse_context
|
attr_reader :parse_context
|
||||||
@@ -43,18 +41,17 @@ module Liquid
|
|||||||
|
|
||||||
def lax_parse(markup)
|
def lax_parse(markup)
|
||||||
@filters = []
|
@filters = []
|
||||||
return unless markup =~ MARKUP_WITH_QUOTED_FRAGMENT
|
return unless markup =~ MarkupWithQuotedFragment
|
||||||
|
|
||||||
name_markup = Regexp.last_match(1)
|
name_markup = $1
|
||||||
filter_markup = Regexp.last_match(2)
|
filter_markup = $2
|
||||||
@name = Expression.parse(name_markup)
|
@name = Expression.parse(name_markup)
|
||||||
if filter_markup =~ FILTER_MARKUP_REGEX
|
if filter_markup =~ FilterMarkupRegex
|
||||||
filters = Regexp.last_match(1).scan(FILTER_PARSER)
|
filters = $1.scan(FilterParser)
|
||||||
filters.each do |f|
|
filters.each do |f|
|
||||||
next unless f =~ /\w+/
|
next unless f =~ /\w+/
|
||||||
|
|
||||||
filtername = Regexp.last_match(0)
|
filtername = Regexp.last_match(0)
|
||||||
filterargs = f.scan(FILTER_ARGS_REGEX).flatten
|
filterargs = f.scan(FilterArgsRegex).flatten
|
||||||
@filters << parse_filter_expressions(filtername, filterargs)
|
@filters << parse_filter_expressions(filtername, filterargs)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -88,30 +85,19 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
obj = context.apply_global_filter(obj)
|
obj = context.apply_global_filter(obj)
|
||||||
|
|
||||||
taint_check(context, obj)
|
taint_check(context, obj)
|
||||||
|
|
||||||
obj
|
obj
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_to_output_buffer(context, output)
|
|
||||||
obj = render(context)
|
|
||||||
|
|
||||||
if obj.is_a?(Array)
|
|
||||||
output << obj.join
|
|
||||||
elsif obj.nil?
|
|
||||||
else
|
|
||||||
output << obj.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
output
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def parse_filter_expressions(filter_name, unparsed_args)
|
def parse_filter_expressions(filter_name, unparsed_args)
|
||||||
filter_args = []
|
filter_args = []
|
||||||
keyword_args = nil
|
keyword_args = nil
|
||||||
unparsed_args.each do |a|
|
unparsed_args.each do |a|
|
||||||
if (matches = a.match(JUST_TAG_ATTRIBUTES))
|
if matches = a.match(JustTagAttributes)
|
||||||
keyword_args ||= {}
|
keyword_args ||= {}
|
||||||
keyword_args[matches[1]] = Expression.parse(matches[2])
|
keyword_args[matches[1]] = Expression.parse(matches[2])
|
||||||
else
|
else
|
||||||
@@ -124,7 +110,7 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def evaluate_filter_expressions(context, filter_args, filter_kwargs)
|
def evaluate_filter_expressions(context, filter_args, filter_kwargs)
|
||||||
parsed_args = filter_args.map { |expr| context.evaluate(expr) }
|
parsed_args = filter_args.map{ |expr| context.evaluate(expr) }
|
||||||
if filter_kwargs
|
if filter_kwargs
|
||||||
parsed_kwargs = {}
|
parsed_kwargs = {}
|
||||||
filter_kwargs.each do |key, expr|
|
filter_kwargs.each do |key, expr|
|
||||||
@@ -139,7 +125,7 @@ module Liquid
|
|||||||
return unless obj.tainted?
|
return unless obj.tainted?
|
||||||
return if Template.taint_mode == :lax
|
return if Template.taint_mode == :lax
|
||||||
|
|
||||||
@markup =~ QUOTED_FRAGMENT
|
@markup =~ QuotedFragment
|
||||||
name = Regexp.last_match(0)
|
name = Regexp.last_match(0)
|
||||||
|
|
||||||
error = TaintedError.new("variable '#{name}' is tainted and was not escaped")
|
error = TaintedError.new("variable '#{name}' is tainted and was not escaped")
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class VariableLookup
|
class VariableLookup
|
||||||
SQUARE_BRACKETED = /\A\[(.*)\]\z/m.freeze
|
SQUARE_BRACKETED = /\A\[(.*)\]\z/m
|
||||||
COMMAND_METHODS = %w[size first last].freeze
|
COMMAND_METHODS = ['size'.freeze, 'first'.freeze, 'last'.freeze].freeze
|
||||||
|
|
||||||
attr_reader :name, :lookups
|
attr_reader :name, :lookups
|
||||||
|
|
||||||
@@ -12,10 +10,12 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def initialize(markup)
|
def initialize(markup)
|
||||||
lookups = markup.scan(VARIABLE_PARSER)
|
lookups = markup.scan(VariableParser)
|
||||||
|
|
||||||
name = lookups.shift
|
name = lookups.shift
|
||||||
name = Expression.parse(Regexp.last_match(1)) if name =~ SQUARE_BRACKETED
|
if name =~ SQUARE_BRACKETED
|
||||||
|
name = Expression.parse($1)
|
||||||
|
end
|
||||||
@name = name
|
@name = name
|
||||||
|
|
||||||
@lookups = lookups
|
@lookups = lookups
|
||||||
@@ -24,7 +24,7 @@ module Liquid
|
|||||||
@lookups.each_index do |i|
|
@lookups.each_index do |i|
|
||||||
lookup = lookups[i]
|
lookup = lookups[i]
|
||||||
if lookup =~ SQUARE_BRACKETED
|
if lookup =~ SQUARE_BRACKETED
|
||||||
lookups[i] = Expression.parse(Regexp.last_match(1))
|
lookups[i] = Expression.parse($1)
|
||||||
elsif COMMAND_METHODS.include?(lookup)
|
elsif COMMAND_METHODS.include?(lookup)
|
||||||
@command_flags |= 1 << i
|
@command_flags |= 1 << i
|
||||||
end
|
end
|
||||||
@@ -41,8 +41,8 @@ module Liquid
|
|||||||
# If object is a hash- or array-like object we look for the
|
# If object is a hash- or array-like object we look for the
|
||||||
# presence of the key and if its available we return it
|
# presence of the key and if its available we return it
|
||||||
if object.respond_to?(:[]) &&
|
if object.respond_to?(:[]) &&
|
||||||
((object.respond_to?(:key?) && object.key?(key)) ||
|
((object.respond_to?(:key?) && object.key?(key)) ||
|
||||||
(object.respond_to?(:fetch) && key.is_a?(Integer)))
|
(object.respond_to?(:fetch) && key.is_a?(Integer)))
|
||||||
|
|
||||||
# if its a proc we will replace the entry with the proc
|
# if its a proc we will replace the entry with the proc
|
||||||
res = context.lookup_and_evaluate(object, key)
|
res = context.lookup_and_evaluate(object, key)
|
||||||
@@ -59,7 +59,6 @@ module Liquid
|
|||||||
# raise an exception if `strict_variables` option is set to true
|
# raise an exception if `strict_variables` option is set to true
|
||||||
else
|
else
|
||||||
return nil unless context.strict_variables
|
return nil unless context.strict_variables
|
||||||
|
|
||||||
raise Liquid::UndefinedVariable, "undefined variable #{key}"
|
raise Liquid::UndefinedVariable, "undefined variable #{key}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# frozen_string_literal: true
|
# encoding: utf-8
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
VERSION = '4.0.3'
|
VERSION = "4.0.3".freeze
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,31 +1,31 @@
|
|||||||
# frozen_string_literal: true
|
# encoding: utf-8
|
||||||
|
|
||||||
lib = File.expand_path('lib', __dir__)
|
lib = File.expand_path('../lib/', __FILE__)
|
||||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
$LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib)
|
||||||
|
|
||||||
require 'liquid/version'
|
require "liquid/version"
|
||||||
|
|
||||||
Gem::Specification.new do |s|
|
Gem::Specification.new do |s|
|
||||||
s.name = 'liquid'
|
s.name = "liquid"
|
||||||
s.version = Liquid::VERSION
|
s.version = Liquid::VERSION
|
||||||
s.platform = Gem::Platform::RUBY
|
s.platform = Gem::Platform::RUBY
|
||||||
s.summary = 'A secure, non-evaling end user template engine with aesthetic markup.'
|
s.summary = "A secure, non-evaling end user template engine with aesthetic markup."
|
||||||
s.authors = ['Tobias Lütke']
|
s.authors = ["Tobias Lütke"]
|
||||||
s.email = ['tobi@leetsoft.com']
|
s.email = ["tobi@leetsoft.com"]
|
||||||
s.homepage = 'http://www.liquidmarkup.org'
|
s.homepage = "http://www.liquidmarkup.org"
|
||||||
s.license = 'MIT'
|
s.license = "MIT"
|
||||||
# s.description = "A secure, non-evaling end user template engine with aesthetic markup."
|
# s.description = "A secure, non-evaling end user template engine with aesthetic markup."
|
||||||
|
|
||||||
s.required_ruby_version = '>= 2.4.0'
|
s.required_ruby_version = ">= 2.1.0"
|
||||||
s.required_rubygems_version = '>= 1.3.7'
|
s.required_rubygems_version = ">= 1.3.7"
|
||||||
|
|
||||||
s.test_files = Dir.glob('{test}/**/*')
|
s.test_files = Dir.glob("{test}/**/*")
|
||||||
s.files = Dir.glob('{lib}/**/*') + %w[LICENSE README.md]
|
s.files = Dir.glob("{lib}/**/*") + %w(LICENSE README.md)
|
||||||
|
|
||||||
s.extra_rdoc_files = ['History.md', 'README.md']
|
s.extra_rdoc_files = ["History.md", "README.md"]
|
||||||
|
|
||||||
s.require_path = 'lib'
|
s.require_path = "lib"
|
||||||
|
|
||||||
s.add_development_dependency('minitest')
|
s.add_development_dependency 'rake', '~> 11.3'
|
||||||
s.add_development_dependency('rake', '~> 11.3')
|
s.add_development_dependency 'minitest'
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'benchmark/ips'
|
require 'benchmark/ips'
|
||||||
require_relative 'theme_runner'
|
require_relative 'theme_runner'
|
||||||
|
|
||||||
@@ -14,7 +12,7 @@ Benchmark.ips do |x|
|
|||||||
puts "Running benchmark for #{x.time} seconds (with #{x.warmup} seconds warmup)."
|
puts "Running benchmark for #{x.time} seconds (with #{x.warmup} seconds warmup)."
|
||||||
puts
|
puts
|
||||||
|
|
||||||
x.report('parse:') { profiler.compile }
|
x.report("parse:") { profiler.compile }
|
||||||
x.report('render:') { profiler.render }
|
x.report("render:") { profiler.render }
|
||||||
x.report('parse & render:') { profiler.run }
|
x.report("parse & render:") { profiler.run }
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -22,5 +22,5 @@ Liquid::Template.error_mode = ARGV.first.to_sym if ARGV.first
|
|||||||
|
|
||||||
profiler = ThemeRunner.new
|
profiler = ThemeRunner.new
|
||||||
|
|
||||||
profile('Parsing') { profiler.compile }
|
profile("Parsing") { profiler.compile }
|
||||||
profile('Rendering') { profiler.render }
|
profile("Rendering") { profiler.render }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'stackprof'
|
require 'stackprof'
|
||||||
require_relative 'theme_runner'
|
require_relative 'theme_runner'
|
||||||
|
|
||||||
@@ -7,7 +5,7 @@ Liquid::Template.error_mode = ARGV.first.to_sym if ARGV.first
|
|||||||
profiler = ThemeRunner.new
|
profiler = ThemeRunner.new
|
||||||
profiler.run
|
profiler.run
|
||||||
|
|
||||||
%i[cpu object].each do |profile_type|
|
[:cpu, :object].each do |profile_type|
|
||||||
puts "Profiling in #{profile_type} mode..."
|
puts "Profiling in #{profile_type} mode..."
|
||||||
results = StackProf.run(mode: profile_type) do
|
results = StackProf.run(mode: profile_type) do
|
||||||
200.times do
|
200.times do
|
||||||
@@ -15,12 +13,12 @@ profiler.run
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if profile_type == :cpu && (graph_filename = ENV['GRAPH_FILENAME'])
|
if profile_type == :cpu && graph_filename = ENV['GRAPH_FILENAME']
|
||||||
File.open(graph_filename, 'w') do |f|
|
File.open(graph_filename, 'w') do |f|
|
||||||
StackProf::Report.new(results).print_graphviz(nil, f)
|
StackProf::Report.new(results).print_graphviz(nil, f)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
StackProf::Report.new(results).print_text(false, 20)
|
StackProf::Report.new(results).print_text(false, 20)
|
||||||
File.write(ENV['FILENAME'] + '.' + profile_type.to_s, Marshal.dump(results)) if ENV['FILENAME']
|
File.write(ENV['FILENAME'] + "." + profile_type.to_s, Marshal.dump(results)) if ENV['FILENAME']
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,33 +1,29 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class CommentForm < Liquid::Block
|
class CommentForm < Liquid::Block
|
||||||
SYNTAX = /(#{Liquid::VARIABLE_SIGNATURE}+)/.freeze
|
Syntax = /(#{Liquid::VariableSignature}+)/
|
||||||
|
|
||||||
def initialize(tag_name, markup, options)
|
def initialize(tag_name, markup, options)
|
||||||
super
|
super
|
||||||
|
|
||||||
if markup =~ SYNTAX
|
if markup =~ Syntax
|
||||||
@variable_name = Regexp.last_match(1)
|
@variable_name = $1
|
||||||
@attributes = {}
|
@attributes = {}
|
||||||
else
|
else
|
||||||
raise SyntaxError, "Syntax Error in 'comment_form' - Valid syntax: comment_form [article]"
|
raise SyntaxError.new("Syntax Error in 'comment_form' - Valid syntax: comment_form [article]")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_to_output_buffer(context, output)
|
def render(context)
|
||||||
article = context[@variable_name]
|
article = context[@variable_name]
|
||||||
|
|
||||||
context.stack do
|
context.stack('form') do
|
||||||
context['form'] = {
|
context['form'] = {
|
||||||
'posted_successfully?' => context.registers[:posted_successfully],
|
'posted_successfully?' => context.registers[:posted_successfully],
|
||||||
'errors' => context['comment.errors'],
|
'errors' => context['comment.errors'],
|
||||||
'author' => context['comment.author'],
|
'author' => context['comment.author'],
|
||||||
'email' => context['comment.email'],
|
'email' => context['comment.email'],
|
||||||
'body' => context['comment.body'],
|
'body' => context['comment.body']
|
||||||
}
|
}
|
||||||
|
wrap_in_form(article, render_all(@nodelist, context))
|
||||||
output << wrap_in_form(article, render_all(@nodelist, context, output))
|
|
||||||
output
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'yaml'
|
require 'yaml'
|
||||||
|
|
||||||
module Database
|
module Database
|
||||||
@@ -18,11 +16,8 @@ module Database
|
|||||||
end
|
end
|
||||||
|
|
||||||
# key the tables by handles, as this is how liquid expects it.
|
# key the tables by handles, as this is how liquid expects it.
|
||||||
db = db.each_with_object({}) do |(key, values), assigns|
|
db = db.inject({}) do |assigns, (key, values)|
|
||||||
assigns[key] = values.each_with_object({}) do |v, h|
|
assigns[key] = values.inject({}) { |h, v| h[v['handle']] = v; h; }
|
||||||
h[v['handle']] = v
|
|
||||||
h
|
|
||||||
end
|
|
||||||
assigns
|
assigns
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -34,9 +29,9 @@ module Database
|
|||||||
db['article'] = db['blog']['articles'].first
|
db['article'] = db['blog']['articles'].first
|
||||||
|
|
||||||
db['cart'] = {
|
db['cart'] = {
|
||||||
'total_price' => db['line_items'].values.inject(0) { |sum, item| sum + item['line_price'] * item['quantity'] },
|
'total_price' => db['line_items'].values.inject(0) { |sum, item| sum += item['line_price'] * item['quantity'] },
|
||||||
'item_count' => db['line_items'].values.inject(0) { |sum, item| sum + item['quantity'] },
|
'item_count' => db['line_items'].values.inject(0) { |sum, item| sum += item['quantity'] },
|
||||||
'items' => db['line_items'].values,
|
'items' => db['line_items'].values
|
||||||
}
|
}
|
||||||
|
|
||||||
db
|
db
|
||||||
@@ -45,6 +40,6 @@ module Database
|
|||||||
end
|
end
|
||||||
|
|
||||||
if __FILE__ == $PROGRAM_NAME
|
if __FILE__ == $PROGRAM_NAME
|
||||||
p(Database.tables['collections']['frontpage'].keys)
|
p Database.tables['collections']['frontpage'].keys
|
||||||
# p Database.tables['blog']['articles']
|
# p Database.tables['blog']['articles']
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'json'
|
require 'json'
|
||||||
|
|
||||||
module JsonFilter
|
module JsonFilter
|
||||||
def json(object)
|
def json(object)
|
||||||
JSON.dump(object.reject { |k, _v| k == 'collections' })
|
JSON.dump(object.reject { |k, v| k == "collections" })
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
# frozen_string_literal: true
|
$:.unshift __dir__ + '/../../lib'
|
||||||
|
|
||||||
$LOAD_PATH.unshift(__dir__ + '/../../lib')
|
|
||||||
require_relative '../../lib/liquid'
|
require_relative '../../lib/liquid'
|
||||||
|
|
||||||
require_relative 'comment_form'
|
require_relative 'comment_form'
|
||||||
@@ -11,11 +9,11 @@ require_relative 'shop_filter'
|
|||||||
require_relative 'tag_filter'
|
require_relative 'tag_filter'
|
||||||
require_relative 'weight_filter'
|
require_relative 'weight_filter'
|
||||||
|
|
||||||
Liquid::Template.register_tag('paginate', Paginate)
|
Liquid::Template.register_tag 'paginate', Paginate
|
||||||
Liquid::Template.register_tag('form', CommentForm)
|
Liquid::Template.register_tag 'form', CommentForm
|
||||||
|
|
||||||
Liquid::Template.register_filter(JsonFilter)
|
Liquid::Template.register_filter JsonFilter
|
||||||
Liquid::Template.register_filter(MoneyFilter)
|
Liquid::Template.register_filter MoneyFilter
|
||||||
Liquid::Template.register_filter(WeightFilter)
|
Liquid::Template.register_filter WeightFilter
|
||||||
Liquid::Template.register_filter(ShopFilter)
|
Liquid::Template.register_filter ShopFilter
|
||||||
Liquid::Template.register_filter(TagFilter)
|
Liquid::Template.register_filter TagFilter
|
||||||
|
|||||||
@@ -1,16 +1,12 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module MoneyFilter
|
module MoneyFilter
|
||||||
def money_with_currency(money)
|
def money_with_currency(money)
|
||||||
return '' if money.nil?
|
return '' if money.nil?
|
||||||
|
sprintf("$ %.2f USD", money / 100.0)
|
||||||
format('$ %.2f USD', money / 100.0)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def money(money)
|
def money(money)
|
||||||
return '' if money.nil?
|
return '' if money.nil?
|
||||||
|
sprintf("$ %.2f", money / 100.0)
|
||||||
format('$ %.2f', money / 100.0)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -1,51 +1,49 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class Paginate < Liquid::Block
|
class Paginate < Liquid::Block
|
||||||
SYNTAX = /(#{Liquid::QUOTED_FRAGMENT})\s*(by\s*(\d+))?/.freeze
|
Syntax = /(#{Liquid::QuotedFragment})\s*(by\s*(\d+))?/
|
||||||
|
|
||||||
def initialize(tag_name, markup, options)
|
def initialize(tag_name, markup, options)
|
||||||
super
|
super
|
||||||
|
|
||||||
if markup =~ SYNTAX
|
if markup =~ Syntax
|
||||||
@collection_name = Regexp.last_match(1)
|
@collection_name = $1
|
||||||
@page_size = if Regexp.last_match(2)
|
@page_size = if $2
|
||||||
Regexp.last_match(3).to_i
|
$3.to_i
|
||||||
else
|
else
|
||||||
20
|
20
|
||||||
end
|
end
|
||||||
|
|
||||||
@attributes = { 'window_size' => 3 }
|
@attributes = { 'window_size' => 3 }
|
||||||
markup.scan(Liquid::TAG_ATTRIBUTES) do |key, value|
|
markup.scan(Liquid::TagAttributes) do |key, value|
|
||||||
@attributes[key] = value
|
@attributes[key] = value
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
raise SyntaxError, "Syntax Error in tag 'paginate' - Valid syntax: paginate [collection] by number"
|
raise SyntaxError.new("Syntax Error in tag 'paginate' - Valid syntax: paginate [collection] by number")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_to_output_buffer(context, output)
|
def render(context)
|
||||||
@context = context
|
@context = context
|
||||||
|
|
||||||
context.stack do
|
context.stack('paginate') do
|
||||||
current_page = context['current_page'].to_i
|
current_page = context['current_page'].to_i
|
||||||
|
|
||||||
pagination = {
|
pagination = {
|
||||||
'page_size' => @page_size,
|
'page_size' => @page_size,
|
||||||
'current_page' => 5,
|
'current_page' => 5,
|
||||||
'current_offset' => @page_size * 5,
|
'current_offset' => @page_size * 5
|
||||||
}
|
}
|
||||||
|
|
||||||
context['paginate'] = pagination
|
context['paginate'] = pagination
|
||||||
|
|
||||||
collection_size = context[@collection_name].size
|
collection_size = context[@collection_name].size
|
||||||
|
|
||||||
raise ArgumentError, "Cannot paginate array '#{@collection_name}'. Not found." if collection_size.nil?
|
raise ArgumentError.new("Cannot paginate array '#{@collection_name}'. Not found.") if collection_size.nil?
|
||||||
|
|
||||||
page_count = (collection_size.to_f / @page_size.to_f).to_f.ceil + 1
|
page_count = (collection_size.to_f / @page_size.to_f).to_f.ceil + 1
|
||||||
|
|
||||||
pagination['items'] = collection_size
|
pagination['items'] = collection_size
|
||||||
pagination['pages'] = page_count - 1
|
pagination['pages'] = page_count - 1
|
||||||
pagination['previous'] = link('« Previous', current_page - 1) unless current_page <= 1
|
pagination['previous'] = link('« Previous', current_page - 1) unless 1 >= current_page
|
||||||
pagination['next'] = link('Next »', current_page + 1) unless page_count <= current_page + 1
|
pagination['next'] = link('Next »', current_page + 1) unless page_count <= current_page + 1
|
||||||
pagination['parts'] = []
|
pagination['parts'] = []
|
||||||
|
|
||||||
@@ -61,7 +59,6 @@ class Paginate < Liquid::Block
|
|||||||
pagination['parts'] << link(page, page)
|
pagination['parts'] << link(page, page)
|
||||||
elsif page <= current_page - @attributes['window_size'] || page >= current_page + @attributes['window_size']
|
elsif page <= current_page - @attributes['window_size'] || page >= current_page + @attributes['window_size']
|
||||||
next if hellip_break
|
next if hellip_break
|
||||||
|
|
||||||
pagination['parts'] << no_link('…')
|
pagination['parts'] << no_link('…')
|
||||||
hellip_break = true
|
hellip_break = true
|
||||||
next
|
next
|
||||||
@@ -88,6 +85,6 @@ class Paginate < Liquid::Block
|
|||||||
end
|
end
|
||||||
|
|
||||||
def current_url
|
def current_url
|
||||||
'/collections/frontpage'
|
"/collections/frontpage"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module ShopFilter
|
module ShopFilter
|
||||||
def asset_url(input)
|
def asset_url(input)
|
||||||
"/files/1/[shop_id]/[shop_id]/assets/#{input}"
|
"/files/1/[shop_id]/[shop_id]/assets/#{input}"
|
||||||
@@ -17,15 +15,15 @@ module ShopFilter
|
|||||||
%(<script src="#{url}" type="text/javascript"></script>)
|
%(<script src="#{url}" type="text/javascript"></script>)
|
||||||
end
|
end
|
||||||
|
|
||||||
def stylesheet_tag(url, media = 'all')
|
def stylesheet_tag(url, media = "all")
|
||||||
%(<link href="#{url}" rel="stylesheet" type="text/css" media="#{media}" />)
|
%(<link href="#{url}" rel="stylesheet" type="text/css" media="#{media}" />)
|
||||||
end
|
end
|
||||||
|
|
||||||
def link_to(link, url, title = '')
|
def link_to(link, url, title = "")
|
||||||
%(<a href="#{url}" title="#{title}">#{link}</a>)
|
%(<a href="#{url}" title="#{title}">#{link}</a>)
|
||||||
end
|
end
|
||||||
|
|
||||||
def img_tag(url, alt = '')
|
def img_tag(url, alt = "")
|
||||||
%(<img src="#{url}" alt="#{alt}" />)
|
%(<img src="#{url}" alt="#{alt}" />)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -54,13 +52,15 @@ module ShopFilter
|
|||||||
end
|
end
|
||||||
|
|
||||||
def product_img_url(url, style = 'small')
|
def product_img_url(url, style = 'small')
|
||||||
raise ArgumentError, 'filter "size" can only be called on product images' unless url =~ %r{\Aproducts/([\w\-\_]+)\.(\w{2,4})}
|
unless url =~ /\Aproducts\/([\w\-\_]+)\.(\w{2,4})/
|
||||||
|
raise ArgumentError, 'filter "size" can only be called on product images'
|
||||||
|
end
|
||||||
|
|
||||||
case style
|
case style
|
||||||
when 'original'
|
when 'original'
|
||||||
return '/files/shops/random_number/' + url
|
return '/files/shops/random_number/' + url
|
||||||
when 'grande', 'large', 'medium', 'compact', 'small', 'thumb', 'icon'
|
when 'grande', 'large', 'medium', 'compact', 'small', 'thumb', 'icon'
|
||||||
"/files/shops/random_number/products/#{Regexp.last_match(1)}_#{style}.#{Regexp.last_match(2)}"
|
"/files/shops/random_number/products/#{$1}_#{style}.#{$2}"
|
||||||
else
|
else
|
||||||
raise ArgumentError, 'valid parameters for filter "size" are: original, grande, large, medium, compact, small, thumb and icon '
|
raise ArgumentError, 'valid parameters for filter "size" are: original, grande, large, medium, compact, small, thumb and icon '
|
||||||
end
|
end
|
||||||
@@ -70,14 +70,16 @@ module ShopFilter
|
|||||||
html = []
|
html = []
|
||||||
html << %(<span class="prev">#{link_to(paginate['previous']['title'], paginate['previous']['url'])}</span>) if paginate['previous']
|
html << %(<span class="prev">#{link_to(paginate['previous']['title'], paginate['previous']['url'])}</span>) if paginate['previous']
|
||||||
|
|
||||||
paginate['parts'].each do |part|
|
for part in paginate['parts']
|
||||||
html << if part['is_link']
|
|
||||||
%(<span class="page">#{link_to(part['title'], part['url'])}</span>)
|
if part['is_link']
|
||||||
|
html << %(<span class="page">#{link_to(part['title'], part['url'])}</span>)
|
||||||
elsif part['title'].to_i == paginate['current_page'].to_i
|
elsif part['title'].to_i == paginate['current_page'].to_i
|
||||||
%(<span class="page current">#{part['title']}</span>)
|
html << %(<span class="page current">#{part['title']}</span>)
|
||||||
else
|
else
|
||||||
%(<span class="deco">#{part['title']}</span>)
|
html << %(<span class="deco">#{part['title']}</span>)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
html << %(<span class="next">#{link_to(paginate['next']['title'], paginate['next']['url'])}</span>) if paginate['next']
|
html << %(<span class="next">#{link_to(paginate['next']['title'], paginate['next']['url'])}</span>) if paginate['next']
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module TagFilter
|
module TagFilter
|
||||||
def link_to_tag(label, tag)
|
def link_to_tag(label, tag)
|
||||||
"<a title=\"Show tag #{tag}\" href=\"/collections/#{@context['handle']}/#{tag}\">#{label}</a>"
|
"<a title=\"Show tag #{tag}\" href=\"/collections/#{@context['handle']}/#{tag}\">#{label}</a>"
|
||||||
@@ -15,11 +13,11 @@ module TagFilter
|
|||||||
|
|
||||||
def link_to_add_tag(label, tag)
|
def link_to_add_tag(label, tag)
|
||||||
tags = (@context['current_tags'] + [tag]).uniq
|
tags = (@context['current_tags'] + [tag]).uniq
|
||||||
"<a title=\"Show tag #{tag}\" href=\"/collections/#{@context['handle']}/#{tags.join('+')}\">#{label}</a>"
|
"<a title=\"Show tag #{tag}\" href=\"/collections/#{@context['handle']}/#{tags.join("+")}\">#{label}</a>"
|
||||||
end
|
end
|
||||||
|
|
||||||
def link_to_remove_tag(label, tag)
|
def link_to_remove_tag(label, tag)
|
||||||
tags = (@context['current_tags'] - [tag]).uniq
|
tags = (@context['current_tags'] - [tag]).uniq
|
||||||
"<a title=\"Show tag #{tag}\" href=\"/collections/#{@context['handle']}/#{tags.join('+')}\">#{label}</a>"
|
"<a title=\"Show tag #{tag}\" href=\"/collections/#{@context['handle']}/#{tags.join("+")}\">#{label}</a>"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module WeightFilter
|
module WeightFilter
|
||||||
def weight(grams)
|
def weight(grams)
|
||||||
format('%.2f', grams / 1000)
|
sprintf("%.2f", grams / 1000)
|
||||||
end
|
end
|
||||||
|
|
||||||
def weight_with_unit(grams)
|
def weight_with_unit(grams)
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
# This profiler run simulates Shopify.
|
# This profiler run simulates Shopify.
|
||||||
# We are looking in the tests directory for liquid files and render them within the designated layout file.
|
# We are looking in the tests directory for liquid files and render them within the designated layout file.
|
||||||
# We will also export a substantial database to liquid which the templates can render values of.
|
# We will also export a substantial database to liquid which the templates can render values of.
|
||||||
@@ -33,7 +31,7 @@ class ThemeRunner
|
|||||||
{
|
{
|
||||||
liquid: File.read(test),
|
liquid: File.read(test),
|
||||||
layout: (File.file?(theme_path) ? File.read(theme_path) : nil),
|
layout: (File.file?(theme_path) ? File.read(theme_path) : nil),
|
||||||
template_name: test,
|
template_name: test
|
||||||
}
|
}
|
||||||
end.compact
|
end.compact
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class AssignTest < Minitest::Test
|
class AssignTest < Minitest::Test
|
||||||
@@ -12,29 +10,29 @@ class AssignTest < Minitest::Test
|
|||||||
END_TEMPLATE
|
END_TEMPLATE
|
||||||
template = Template.parse(template_source)
|
template = Template.parse(template_source)
|
||||||
rendered = template.render!
|
rendered = template.render!
|
||||||
assert_equal 'Print this-thing', rendered.strip
|
assert_equal "Print this-thing", rendered.strip
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_assigned_variable
|
def test_assigned_variable
|
||||||
assert_template_result('.foo.',
|
assert_template_result('.foo.',
|
||||||
'{% assign foo = values %}.{{ foo[0] }}.',
|
'{% assign foo = values %}.{{ foo[0] }}.',
|
||||||
'values' => %w[foo bar baz])
|
'values' => %w(foo bar baz))
|
||||||
|
|
||||||
assert_template_result('.bar.',
|
assert_template_result('.bar.',
|
||||||
'{% assign foo = values %}.{{ foo[1] }}.',
|
'{% assign foo = values %}.{{ foo[1] }}.',
|
||||||
'values' => %w[foo bar baz])
|
'values' => %w(foo bar baz))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_assign_with_filter
|
def test_assign_with_filter
|
||||||
assert_template_result('.bar.',
|
assert_template_result('.bar.',
|
||||||
'{% assign foo = values | split: "," %}.{{ foo[1] }}.',
|
'{% assign foo = values | split: "," %}.{{ foo[1] }}.',
|
||||||
'values' => 'foo,bar,baz')
|
'values' => "foo,bar,baz")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_assign_syntax_error
|
def test_assign_syntax_error
|
||||||
assert_match_syntax_error(/assign/,
|
assert_match_syntax_error(/assign/,
|
||||||
'{% assign foo not values %}.',
|
'{% assign foo not values %}.',
|
||||||
'values' => 'foo,bar,baz')
|
'values' => "foo,bar,baz")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_assign_uses_error_mode
|
def test_assign_uses_error_mode
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class FoobarTag < Liquid::Tag
|
class FoobarTag < Liquid::Tag
|
||||||
def render_to_output_buffer(_context, output)
|
def render(*args)
|
||||||
output << ' '
|
" "
|
||||||
output
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Liquid::Template.register_tag('foobar', FoobarTag)
|
||||||
end
|
end
|
||||||
|
|
||||||
class BlankTestFileSystem
|
class BlankTestFileSystem
|
||||||
@@ -32,78 +31,76 @@ class BlankTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_new_tags_are_not_blank_by_default
|
def test_new_tags_are_not_blank_by_default
|
||||||
with_custom_tag('foobar', FoobarTag) do
|
assert_template_result(" " * N, wrap_in_for("{% foobar %}"))
|
||||||
assert_template_result(' ' * N, wrap_in_for('{% foobar %}'))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_loops_are_blank
|
def test_loops_are_blank
|
||||||
assert_template_result('', wrap_in_for(' '))
|
assert_template_result("", wrap_in_for(" "))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_if_else_are_blank
|
def test_if_else_are_blank
|
||||||
assert_template_result('', '{% if true %} {% elsif false %} {% else %} {% endif %}')
|
assert_template_result("", "{% if true %} {% elsif false %} {% else %} {% endif %}")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_unless_is_blank
|
def test_unless_is_blank
|
||||||
assert_template_result('', wrap('{% unless true %} {% endunless %}'))
|
assert_template_result("", wrap("{% unless true %} {% endunless %}"))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_mark_as_blank_only_during_parsing
|
def test_mark_as_blank_only_during_parsing
|
||||||
assert_template_result(' ' * (N + 1), wrap(' {% if false %} this never happens, but still, this block is not blank {% endif %}'))
|
assert_template_result(" " * (N + 1), wrap(" {% if false %} this never happens, but still, this block is not blank {% endif %}"))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_comments_are_blank
|
def test_comments_are_blank
|
||||||
assert_template_result('', wrap(' {% comment %} whatever {% endcomment %} '))
|
assert_template_result("", wrap(" {% comment %} whatever {% endcomment %} "))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_captures_are_blank
|
def test_captures_are_blank
|
||||||
assert_template_result('', wrap(' {% capture foo %} whatever {% endcapture %} '))
|
assert_template_result("", wrap(" {% capture foo %} whatever {% endcapture %} "))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_nested_blocks_are_blank_but_only_if_all_children_are
|
def test_nested_blocks_are_blank_but_only_if_all_children_are
|
||||||
assert_template_result('', wrap(wrap(' ')))
|
assert_template_result("", wrap(wrap(" ")))
|
||||||
assert_template_result("\n but this is not " * (N + 1),
|
assert_template_result("\n but this is not " * (N + 1),
|
||||||
wrap('{% if true %} {% comment %} this is blank {% endcomment %} {% endif %}
|
wrap('{% if true %} {% comment %} this is blank {% endcomment %} {% endif %}
|
||||||
{% if true %} but this is not {% endif %}'))
|
{% if true %} but this is not {% endif %}'))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_assigns_are_blank
|
def test_assigns_are_blank
|
||||||
assert_template_result('', wrap(' {% assign foo = "bar" %} '))
|
assert_template_result("", wrap(' {% assign foo = "bar" %} '))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_whitespace_is_blank
|
def test_whitespace_is_blank
|
||||||
assert_template_result('', wrap(' '))
|
assert_template_result("", wrap(" "))
|
||||||
assert_template_result('', wrap("\t"))
|
assert_template_result("", wrap("\t"))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_whitespace_is_not_blank_if_other_stuff_is_present
|
def test_whitespace_is_not_blank_if_other_stuff_is_present
|
||||||
body = ' x '
|
body = " x "
|
||||||
assert_template_result(body * (N + 1), wrap(body))
|
assert_template_result(body * (N + 1), wrap(body))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_increment_is_not_blank
|
def test_increment_is_not_blank
|
||||||
assert_template_result(' 0' * 2 * (N + 1), wrap('{% assign foo = 0 %} {% increment foo %} {% decrement foo %}'))
|
assert_template_result(" 0" * 2 * (N + 1), wrap("{% assign foo = 0 %} {% increment foo %} {% decrement foo %}"))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_cycle_is_not_blank
|
def test_cycle_is_not_blank
|
||||||
assert_template_result(' ' * ((N + 1) / 2) + ' ', wrap("{% cycle ' ', ' ' %}"))
|
assert_template_result(" " * ((N + 1) / 2) + " ", wrap("{% cycle ' ', ' ' %}"))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_raw_is_not_blank
|
def test_raw_is_not_blank
|
||||||
assert_template_result(' ' * (N + 1), wrap(' {% raw %} {% endraw %}'))
|
assert_template_result(" " * (N + 1), wrap(" {% raw %} {% endraw %}"))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_include_is_blank
|
def test_include_is_blank
|
||||||
Liquid::Template.file_system = BlankTestFileSystem.new
|
Liquid::Template.file_system = BlankTestFileSystem.new
|
||||||
assert_template_result 'foobar' * (N + 1), wrap("{% include 'foobar' %}")
|
assert_template_result "foobar" * (N + 1), wrap("{% include 'foobar' %}")
|
||||||
assert_template_result ' foobar ' * (N + 1), wrap("{% include ' foobar ' %}")
|
assert_template_result " foobar " * (N + 1), wrap("{% include ' foobar ' %}")
|
||||||
assert_template_result ' ' * (N + 1), wrap(" {% include ' ' %} ")
|
assert_template_result " " * (N + 1), wrap(" {% include ' ' %} ")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_case_is_blank
|
def test_case_is_blank
|
||||||
assert_template_result('', wrap(" {% assign foo = 'bar' %} {% case foo %} {% when 'bar' %} {% when 'whatever' %} {% else %} {% endcase %} "))
|
assert_template_result("", wrap(" {% assign foo = 'bar' %} {% case foo %} {% when 'bar' %} {% when 'whatever' %} {% else %} {% endcase %} "))
|
||||||
assert_template_result('', wrap(" {% assign foo = 'else' %} {% case foo %} {% when 'bar' %} {% when 'whatever' %} {% else %} {% endcase %} "))
|
assert_template_result("", wrap(" {% assign foo = 'else' %} {% case foo %} {% when 'bar' %} {% when 'whatever' %} {% else %} {% endcase %} "))
|
||||||
assert_template_result(' x ' * (N + 1), wrap(" {% assign foo = 'else' %} {% case foo %} {% when 'bar' %} {% when 'whatever' %} {% else %} x {% endcase %} "))
|
assert_template_result(" x " * (N + 1), wrap(" {% assign foo = 'else' %} {% case foo %} {% when 'bar' %} {% when 'whatever' %} {% else %} x {% endcase %} "))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class BlockTest < Minitest::Test
|
class BlockTest < Minitest::Test
|
||||||
@@ -7,7 +5,7 @@ class BlockTest < Minitest::Test
|
|||||||
|
|
||||||
def test_unexpected_end_tag
|
def test_unexpected_end_tag
|
||||||
exc = assert_raises(SyntaxError) do
|
exc = assert_raises(SyntaxError) do
|
||||||
Template.parse('{% if true %}{% endunless %}')
|
Template.parse("{% if true %}{% endunless %}")
|
||||||
end
|
end
|
||||||
assert_equal exc.message, "Liquid syntax error: 'endunless' is not a valid delimiter for if tags. use endif"
|
assert_equal exc.message, "Liquid syntax error: 'endunless' is not a valid delimiter for if tags. use endif"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class CaptureTest < Minitest::Test
|
class CaptureTest < Minitest::Test
|
||||||
include Liquid
|
include Liquid
|
||||||
|
|
||||||
def test_captures_block_content_in_variable
|
def test_captures_block_content_in_variable
|
||||||
assert_template_result('test string', "{% capture 'var' %}test string{% endcapture %}{{var}}", {})
|
assert_template_result("test string", "{% capture 'var' %}test string{% endcapture %}{{var}}", {})
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_capture_with_hyphen_in_variable_name
|
def test_capture_with_hyphen_in_variable_name
|
||||||
@@ -16,7 +14,7 @@ class CaptureTest < Minitest::Test
|
|||||||
END_TEMPLATE
|
END_TEMPLATE
|
||||||
template = Template.parse(template_source)
|
template = Template.parse(template_source)
|
||||||
rendered = template.render!
|
rendered = template.render!
|
||||||
assert_equal 'Print this-thing', rendered.strip
|
assert_equal "Print this-thing", rendered.strip
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_capture_to_variable_from_outer_scope_if_existing
|
def test_capture_to_variable_from_outer_scope_if_existing
|
||||||
@@ -32,7 +30,7 @@ class CaptureTest < Minitest::Test
|
|||||||
END_TEMPLATE
|
END_TEMPLATE
|
||||||
template = Template.parse(template_source)
|
template = Template.parse(template_source)
|
||||||
rendered = template.render!
|
rendered = template.render!
|
||||||
assert_equal 'test-string', rendered.gsub(/\s/, '')
|
assert_equal "test-string", rendered.gsub(/\s/, '')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_assigning_from_capture
|
def test_assigning_from_capture
|
||||||
@@ -47,6 +45,6 @@ class CaptureTest < Minitest::Test
|
|||||||
END_TEMPLATE
|
END_TEMPLATE
|
||||||
template = Template.parse(template_source)
|
template = Template.parse(template_source)
|
||||||
rendered = template.render!
|
rendered = template.render!
|
||||||
assert_equal '3-3', rendered.gsub(/\s/, '')
|
assert_equal "3-3", rendered.gsub(/\s/, '')
|
||||||
end
|
end
|
||||||
end # CaptureTest
|
end # CaptureTest
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class ContextTest < Minitest::Test
|
class ContextTest < Minitest::Test
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class DocumentTest < Minitest::Test
|
class DocumentTest < Minitest::Test
|
||||||
@@ -7,14 +5,14 @@ class DocumentTest < Minitest::Test
|
|||||||
|
|
||||||
def test_unexpected_outer_tag
|
def test_unexpected_outer_tag
|
||||||
exc = assert_raises(SyntaxError) do
|
exc = assert_raises(SyntaxError) do
|
||||||
Template.parse('{% else %}')
|
Template.parse("{% else %}")
|
||||||
end
|
end
|
||||||
assert_equal exc.message, "Liquid syntax error: Unexpected outer 'else' tag"
|
assert_equal exc.message, "Liquid syntax error: Unexpected outer 'else' tag"
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_unknown_tag
|
def test_unknown_tag
|
||||||
exc = assert_raises(SyntaxError) do
|
exc = assert_raises(SyntaxError) do
|
||||||
Template.parse('{% foo %}')
|
Template.parse("{% foo %}")
|
||||||
end
|
end
|
||||||
assert_equal exc.message, "Liquid syntax error: Unknown tag 'foo'"
|
assert_equal exc.message, "Liquid syntax error: Unknown tag 'foo'"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,16 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class ContextDrop < Liquid::Drop
|
class ContextDrop < Liquid::Drop
|
||||||
def scopes
|
|
||||||
@context.scopes.size
|
|
||||||
end
|
|
||||||
|
|
||||||
def scopes_as_array
|
|
||||||
(1..@context.scopes.size).to_a
|
|
||||||
end
|
|
||||||
|
|
||||||
def loop_pos
|
def loop_pos
|
||||||
@context['forloop.index']
|
@context['forloop.index']
|
||||||
end
|
end
|
||||||
@@ -23,7 +13,7 @@ end
|
|||||||
class ProductDrop < Liquid::Drop
|
class ProductDrop < Liquid::Drop
|
||||||
class TextDrop < Liquid::Drop
|
class TextDrop < Liquid::Drop
|
||||||
def array
|
def array
|
||||||
%w[text1 text2]
|
['text1', 'text2']
|
||||||
end
|
end
|
||||||
|
|
||||||
def text
|
def text
|
||||||
@@ -33,7 +23,7 @@ class ProductDrop < Liquid::Drop
|
|||||||
|
|
||||||
class CatchallDrop < Liquid::Drop
|
class CatchallDrop < Liquid::Drop
|
||||||
def liquid_method_missing(method)
|
def liquid_method_missing(method)
|
||||||
+'catchall_method: ' << method.to_s
|
'catchall_method: ' << method.to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -50,13 +40,13 @@ class ProductDrop < Liquid::Drop
|
|||||||
end
|
end
|
||||||
|
|
||||||
def user_input
|
def user_input
|
||||||
(+'foo').taint
|
"foo".taint
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def callmenot
|
def callmenot
|
||||||
'protected'
|
"protected"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -141,17 +131,17 @@ class DropsTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_drop_does_only_respond_to_whitelisted_methods
|
def test_drop_does_only_respond_to_whitelisted_methods
|
||||||
assert_equal '', Liquid::Template.parse('{{ product.inspect }}').render!('product' => ProductDrop.new)
|
assert_equal "", Liquid::Template.parse("{{ product.inspect }}").render!('product' => ProductDrop.new)
|
||||||
assert_equal '', Liquid::Template.parse('{{ product.pretty_inspect }}').render!('product' => ProductDrop.new)
|
assert_equal "", Liquid::Template.parse("{{ product.pretty_inspect }}").render!('product' => ProductDrop.new)
|
||||||
assert_equal '', Liquid::Template.parse('{{ product.whatever }}').render!('product' => ProductDrop.new)
|
assert_equal "", Liquid::Template.parse("{{ product.whatever }}").render!('product' => ProductDrop.new)
|
||||||
assert_equal '', Liquid::Template.parse('{{ product | map: "inspect" }}').render!('product' => ProductDrop.new)
|
assert_equal "", Liquid::Template.parse('{{ product | map: "inspect" }}').render!('product' => ProductDrop.new)
|
||||||
assert_equal '', Liquid::Template.parse('{{ product | map: "pretty_inspect" }}').render!('product' => ProductDrop.new)
|
assert_equal "", Liquid::Template.parse('{{ product | map: "pretty_inspect" }}').render!('product' => ProductDrop.new)
|
||||||
assert_equal '', Liquid::Template.parse('{{ product | map: "whatever" }}').render!('product' => ProductDrop.new)
|
assert_equal "", Liquid::Template.parse('{{ product | map: "whatever" }}').render!('product' => ProductDrop.new)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_drops_respond_to_to_liquid
|
def test_drops_respond_to_to_liquid
|
||||||
assert_equal 'text1', Liquid::Template.parse('{{ product.to_liquid.texts.text }}').render!('product' => ProductDrop.new)
|
assert_equal "text1", Liquid::Template.parse("{{ product.to_liquid.texts.text }}").render!('product' => ProductDrop.new)
|
||||||
assert_equal 'text1', Liquid::Template.parse('{{ product | map: "to_liquid" | map: "texts" | map: "text" }}').render!('product' => ProductDrop.new)
|
assert_equal "text1", Liquid::Template.parse('{{ product | map: "to_liquid" | map: "texts" | map: "text" }}').render!('product' => ProductDrop.new)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_text_drop
|
def test_text_drop
|
||||||
@@ -175,12 +165,12 @@ class DropsTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_context_drop
|
def test_context_drop
|
||||||
output = Liquid::Template.parse(' {{ context.bar }} ').render!('context' => ContextDrop.new, 'bar' => 'carrot')
|
output = Liquid::Template.parse(' {{ context.bar }} ').render!('context' => ContextDrop.new, 'bar' => "carrot")
|
||||||
assert_equal ' carrot ', output
|
assert_equal ' carrot ', output
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_nested_context_drop
|
def test_nested_context_drop
|
||||||
output = Liquid::Template.parse(' {{ product.context.foo }} ').render!('product' => ProductDrop.new, 'foo' => 'monkey')
|
output = Liquid::Template.parse(' {{ product.context.foo }} ').render!('product' => ProductDrop.new, 'foo' => "monkey")
|
||||||
assert_equal ' monkey ', output
|
assert_equal ' monkey ', output
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -190,37 +180,12 @@ class DropsTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_object_methods_not_allowed
|
def test_object_methods_not_allowed
|
||||||
%i[dup clone singleton_class eval class_eval inspect].each do |method|
|
[:dup, :clone, :singleton_class, :eval, :class_eval, :inspect].each do |method|
|
||||||
output = Liquid::Template.parse(" {{ product.#{method} }} ").render!('product' => ProductDrop.new)
|
output = Liquid::Template.parse(" {{ product.#{method} }} ").render!('product' => ProductDrop.new)
|
||||||
assert_equal ' ', output
|
assert_equal ' ', output
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_scope
|
|
||||||
assert_equal '1', Liquid::Template.parse('{{ context.scopes }}').render!('context' => ContextDrop.new)
|
|
||||||
assert_equal '2', Liquid::Template.parse('{%for i in dummy%}{{ context.scopes }}{%endfor%}').render!('context' => ContextDrop.new, 'dummy' => [1])
|
|
||||||
assert_equal '3', Liquid::Template.parse('{%for i in dummy%}{%for i in dummy%}{{ context.scopes }}{%endfor%}{%endfor%}').render!('context' => ContextDrop.new, 'dummy' => [1])
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_scope_though_proc
|
|
||||||
assert_equal '1', Liquid::Template.parse('{{ s }}').render!('context' => ContextDrop.new, 's' => proc { |c| c['context.scopes'] })
|
|
||||||
assert_equal '2', Liquid::Template.parse('{%for i in dummy%}{{ s }}{%endfor%}').render!('context' => ContextDrop.new, 's' => proc { |c| c['context.scopes'] }, 'dummy' => [1])
|
|
||||||
assert_equal '3', Liquid::Template.parse('{%for i in dummy%}{%for i in dummy%}{{ s }}{%endfor%}{%endfor%}').render!('context' => ContextDrop.new, 's' => proc { |c| c['context.scopes'] }, 'dummy' => [1])
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_scope_with_assigns
|
|
||||||
assert_equal 'variable', Liquid::Template.parse('{% assign a = "variable"%}{{a}}').render!('context' => ContextDrop.new)
|
|
||||||
assert_equal 'variable', Liquid::Template.parse('{% assign a = "variable"%}{%for i in dummy%}{{a}}{%endfor%}').render!('context' => ContextDrop.new, 'dummy' => [1])
|
|
||||||
assert_equal 'test', Liquid::Template.parse('{% assign header_gif = "test"%}{{header_gif}}').render!('context' => ContextDrop.new)
|
|
||||||
assert_equal 'test', Liquid::Template.parse("{% assign header_gif = 'test'%}{{header_gif}}").render!('context' => ContextDrop.new)
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_scope_from_tags
|
|
||||||
assert_equal '1', Liquid::Template.parse('{% for i in context.scopes_as_array %}{{i}}{% endfor %}').render!('context' => ContextDrop.new, 'dummy' => [1])
|
|
||||||
assert_equal '12', Liquid::Template.parse('{%for a in dummy%}{% for i in context.scopes_as_array %}{{i}}{% endfor %}{% endfor %}').render!('context' => ContextDrop.new, 'dummy' => [1])
|
|
||||||
assert_equal '123', Liquid::Template.parse('{%for a in dummy%}{%for a in dummy%}{% for i in context.scopes_as_array %}{{i}}{% endfor %}{% endfor %}{% endfor %}').render!('context' => ContextDrop.new, 'dummy' => [1])
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_access_context_from_drop
|
def test_access_context_from_drop
|
||||||
assert_equal '123', Liquid::Template.parse('{%for a in dummy%}{{ context.loop_pos }}{% endfor %}').render!('context' => ContextDrop.new, 'dummy' => [1, 2, 3])
|
assert_equal '123', Liquid::Template.parse('{%for a in dummy%}{{ context.loop_pos }}{% endfor %}').render!('context' => ContextDrop.new, 'dummy' => [1, 2, 3])
|
||||||
end
|
end
|
||||||
@@ -234,7 +199,7 @@ class DropsTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_enumerable_drop_will_invoke_liquid_method_missing_for_clashing_method_names
|
def test_enumerable_drop_will_invoke_liquid_method_missing_for_clashing_method_names
|
||||||
%w[select each map cycle].each do |method|
|
["select", "each", "map", "cycle"].each do |method|
|
||||||
assert_equal method.to_s, Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new)
|
assert_equal method.to_s, Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new)
|
||||||
assert_equal method.to_s, Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => EnumerableDrop.new)
|
assert_equal method.to_s, Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => EnumerableDrop.new)
|
||||||
assert_equal method.to_s, Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new)
|
assert_equal method.to_s, Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new)
|
||||||
@@ -243,20 +208,20 @@ class DropsTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_some_enumerable_methods_still_get_invoked
|
def test_some_enumerable_methods_still_get_invoked
|
||||||
%i[count max].each do |method|
|
[ :count, :max ].each do |method|
|
||||||
assert_equal '3', Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new)
|
assert_equal "3", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new)
|
||||||
assert_equal '3', Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => RealEnumerableDrop.new)
|
assert_equal "3", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => RealEnumerableDrop.new)
|
||||||
assert_equal '3', Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new)
|
assert_equal "3", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new)
|
||||||
assert_equal '3', Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => EnumerableDrop.new)
|
assert_equal "3", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => EnumerableDrop.new)
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal 'yes', Liquid::Template.parse('{% if collection contains 3 %}yes{% endif %}').render!('collection' => RealEnumerableDrop.new)
|
assert_equal "yes", Liquid::Template.parse("{% if collection contains 3 %}yes{% endif %}").render!('collection' => RealEnumerableDrop.new)
|
||||||
|
|
||||||
%i[min first].each do |method|
|
[ :min, :first ].each do |method|
|
||||||
assert_equal '1', Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new)
|
assert_equal "1", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new)
|
||||||
assert_equal '1', Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => RealEnumerableDrop.new)
|
assert_equal "1", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => RealEnumerableDrop.new)
|
||||||
assert_equal '1', Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new)
|
assert_equal "1", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new)
|
||||||
assert_equal '1', Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => EnumerableDrop.new)
|
assert_equal "1", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => EnumerableDrop.new)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -269,7 +234,7 @@ class DropsTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_default_to_s_on_drops
|
def test_default_to_s_on_drops
|
||||||
assert_equal 'ProductDrop', Liquid::Template.parse('{{ product }}').render!('product' => ProductDrop.new)
|
assert_equal 'ProductDrop', Liquid::Template.parse("{{ product }}").render!('product' => ProductDrop.new)
|
||||||
assert_equal 'EnumerableDrop', Liquid::Template.parse('{{ collection }}').render!('collection' => EnumerableDrop.new)
|
assert_equal 'EnumerableDrop', Liquid::Template.parse('{{ collection }}').render!('collection' => EnumerableDrop.new)
|
||||||
end
|
end
|
||||||
end # DropsTest
|
end # DropsTest
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class ErrorHandlingTest < Minitest::Test
|
class ErrorHandlingTest < Minitest::Test
|
||||||
@@ -85,14 +83,15 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
|
|
||||||
def test_with_line_numbers_adds_numbers_to_parser_errors
|
def test_with_line_numbers_adds_numbers_to_parser_errors
|
||||||
err = assert_raises(SyntaxError) do
|
err = assert_raises(SyntaxError) do
|
||||||
Liquid::Template.parse('
|
Liquid::Template.parse(%q(
|
||||||
foobar
|
foobar
|
||||||
|
|
||||||
{% "cat" | foobar %}
|
{% "cat" | foobar %}
|
||||||
|
|
||||||
bla
|
bla
|
||||||
',
|
),
|
||||||
line_numbers: true)
|
line_numbers: true
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_match(/Liquid syntax error \(line 4\)/, err.message)
|
assert_match(/Liquid syntax error \(line 4\)/, err.message)
|
||||||
@@ -100,14 +99,15 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
|
|
||||||
def test_with_line_numbers_adds_numbers_to_parser_errors_with_whitespace_trim
|
def test_with_line_numbers_adds_numbers_to_parser_errors_with_whitespace_trim
|
||||||
err = assert_raises(SyntaxError) do
|
err = assert_raises(SyntaxError) do
|
||||||
Liquid::Template.parse('
|
Liquid::Template.parse(%q(
|
||||||
foobar
|
foobar
|
||||||
|
|
||||||
{%- "cat" | foobar -%}
|
{%- "cat" | foobar -%}
|
||||||
|
|
||||||
bla
|
bla
|
||||||
',
|
),
|
||||||
line_numbers: true)
|
line_numbers: true
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_match(/Liquid syntax error \(line 4\)/, err.message)
|
assert_match(/Liquid syntax error \(line 4\)/, err.message)
|
||||||
@@ -121,11 +121,12 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
|
|
||||||
bla
|
bla
|
||||||
',
|
',
|
||||||
error_mode: :warn,
|
error_mode: :warn,
|
||||||
line_numbers: true)
|
line_numbers: true
|
||||||
|
)
|
||||||
|
|
||||||
assert_equal ['Liquid syntax error (line 4): Unexpected character = in "1 =! 2"'],
|
assert_equal ['Liquid syntax error (line 4): Unexpected character = in "1 =! 2"'],
|
||||||
template.warnings.map(&:message)
|
template.warnings.map(&:message)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_parsing_strict_with_line_numbers_adds_numbers_to_lexer_errors
|
def test_parsing_strict_with_line_numbers_adds_numbers_to_lexer_errors
|
||||||
@@ -137,8 +138,9 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
|
|
||||||
bla
|
bla
|
||||||
',
|
',
|
||||||
error_mode: :strict,
|
error_mode: :strict,
|
||||||
line_numbers: true)
|
line_numbers: true
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal 'Liquid syntax error (line 4): Unexpected character = in "1 =! 2"', err.message
|
assert_equal 'Liquid syntax error (line 4): Unexpected character = in "1 =! 2"', err.message
|
||||||
@@ -155,7 +157,8 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
|
|
||||||
bla
|
bla
|
||||||
',
|
',
|
||||||
line_numbers: true)
|
line_numbers: true
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal "Liquid syntax error (line 5): Unknown tag 'foo'", err.message
|
assert_equal "Liquid syntax error (line 5): Unknown tag 'foo'", err.message
|
||||||
@@ -202,7 +205,7 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
def test_default_exception_renderer_with_internal_error
|
def test_default_exception_renderer_with_internal_error
|
||||||
template = Liquid::Template.parse('This is a runtime error: {{ errors.runtime_error }}', line_numbers: true)
|
template = Liquid::Template.parse('This is a runtime error: {{ errors.runtime_error }}', line_numbers: true)
|
||||||
|
|
||||||
output = template.render('errors' => ErrorDrop.new)
|
output = template.render({ 'errors' => ErrorDrop.new })
|
||||||
|
|
||||||
assert_equal 'This is a runtime error: Liquid error (line 1): internal', output
|
assert_equal 'This is a runtime error: Liquid error (line 1): internal', output
|
||||||
assert_equal [Liquid::InternalError], template.errors.map(&:class)
|
assert_equal [Liquid::InternalError], template.errors.map(&:class)
|
||||||
@@ -211,13 +214,10 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
def test_setting_default_exception_renderer
|
def test_setting_default_exception_renderer
|
||||||
old_exception_renderer = Liquid::Template.default_exception_renderer
|
old_exception_renderer = Liquid::Template.default_exception_renderer
|
||||||
exceptions = []
|
exceptions = []
|
||||||
Liquid::Template.default_exception_renderer = lambda { |e|
|
Liquid::Template.default_exception_renderer = ->(e) { exceptions << e; '' }
|
||||||
exceptions << e
|
|
||||||
''
|
|
||||||
}
|
|
||||||
template = Liquid::Template.parse('This is a runtime error: {{ errors.argument_error }}')
|
template = Liquid::Template.parse('This is a runtime error: {{ errors.argument_error }}')
|
||||||
|
|
||||||
output = template.render('errors' => ErrorDrop.new)
|
output = template.render({ 'errors' => ErrorDrop.new })
|
||||||
|
|
||||||
assert_equal 'This is a runtime error: ', output
|
assert_equal 'This is a runtime error: ', output
|
||||||
assert_equal [Liquid::ArgumentError], template.errors.map(&:class)
|
assert_equal [Liquid::ArgumentError], template.errors.map(&:class)
|
||||||
@@ -228,10 +228,7 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
def test_exception_renderer_exposing_non_liquid_error
|
def test_exception_renderer_exposing_non_liquid_error
|
||||||
template = Liquid::Template.parse('This is a runtime error: {{ errors.runtime_error }}', line_numbers: true)
|
template = Liquid::Template.parse('This is a runtime error: {{ errors.runtime_error }}', line_numbers: true)
|
||||||
exceptions = []
|
exceptions = []
|
||||||
handler = lambda { |e|
|
handler = ->(e) { exceptions << e; e.cause }
|
||||||
exceptions << e
|
|
||||||
e.cause
|
|
||||||
}
|
|
||||||
|
|
||||||
output = template.render({ 'errors' => ErrorDrop.new }, exception_renderer: handler)
|
output = template.render({ 'errors' => ErrorDrop.new }, exception_renderer: handler)
|
||||||
|
|
||||||
@@ -242,8 +239,8 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
class TestFileSystem
|
class TestFileSystem
|
||||||
def read_template_file(_template_path)
|
def read_template_file(template_path)
|
||||||
'{{ errors.argument_error }}'
|
"{{ errors.argument_error }}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -258,6 +255,6 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
Liquid::Template.file_system = old_file_system
|
Liquid::Template.file_system = old_file_system
|
||||||
end
|
end
|
||||||
assert_equal "Argument error:\nLiquid error (product line 1): argument error", page
|
assert_equal "Argument error:\nLiquid error (product line 1): argument error", page
|
||||||
assert_equal 'product', template.errors.first.template_name
|
assert_equal "product", template.errors.first.template_name
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,26 +1,24 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
module MoneyFilter
|
module MoneyFilter
|
||||||
def money(input)
|
def money(input)
|
||||||
format(' %d$ ', input)
|
sprintf(' %d$ ', input)
|
||||||
end
|
end
|
||||||
|
|
||||||
def money_with_underscore(input)
|
def money_with_underscore(input)
|
||||||
format(' %d$ ', input)
|
sprintf(' %d$ ', input)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
module CanadianMoneyFilter
|
module CanadianMoneyFilter
|
||||||
def money(input)
|
def money(input)
|
||||||
format(' %d$ CAD ', input)
|
sprintf(' %d$ CAD ', input)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
module SubstituteFilter
|
module SubstituteFilter
|
||||||
def substitute(input, params = {})
|
def substitute(input, params = {})
|
||||||
input.gsub(/%\{(\w+)\}/) { |_match| params[Regexp.last_match(1)] }
|
input.gsub(/%\{(\w+)\}/) { |match| params[$1] }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -28,8 +26,8 @@ class FiltersTest < Minitest::Test
|
|||||||
include Liquid
|
include Liquid
|
||||||
|
|
||||||
module OverrideObjectMethodFilter
|
module OverrideObjectMethodFilter
|
||||||
def tap(_input)
|
def tap(input)
|
||||||
'tap overridden'
|
"tap overridden"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -41,13 +39,13 @@ class FiltersTest < Minitest::Test
|
|||||||
@context['var'] = 1000
|
@context['var'] = 1000
|
||||||
@context.add_filters(MoneyFilter)
|
@context.add_filters(MoneyFilter)
|
||||||
|
|
||||||
assert_equal ' 1000$ ', Template.parse('{{var | money}}').render(@context)
|
assert_equal ' 1000$ ', Template.parse("{{var | money}}").render(@context)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_underscore_in_filter_name
|
def test_underscore_in_filter_name
|
||||||
@context['var'] = 1000
|
@context['var'] = 1000
|
||||||
@context.add_filters(MoneyFilter)
|
@context.add_filters(MoneyFilter)
|
||||||
assert_equal ' 1000$ ', Template.parse('{{var | money_with_underscore}}').render(@context)
|
assert_equal ' 1000$ ', Template.parse("{{var | money_with_underscore}}").render(@context)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_second_filter_overwrites_first
|
def test_second_filter_overwrites_first
|
||||||
@@ -55,43 +53,43 @@ class FiltersTest < Minitest::Test
|
|||||||
@context.add_filters(MoneyFilter)
|
@context.add_filters(MoneyFilter)
|
||||||
@context.add_filters(CanadianMoneyFilter)
|
@context.add_filters(CanadianMoneyFilter)
|
||||||
|
|
||||||
assert_equal ' 1000$ CAD ', Template.parse('{{var | money}}').render(@context)
|
assert_equal ' 1000$ CAD ', Template.parse("{{var | money}}").render(@context)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_size
|
def test_size
|
||||||
@context['var'] = 'abcd'
|
@context['var'] = 'abcd'
|
||||||
@context.add_filters(MoneyFilter)
|
@context.add_filters(MoneyFilter)
|
||||||
|
|
||||||
assert_equal '4', Template.parse('{{var | size}}').render(@context)
|
assert_equal '4', Template.parse("{{var | size}}").render(@context)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_join
|
def test_join
|
||||||
@context['var'] = [1, 2, 3, 4]
|
@context['var'] = [1, 2, 3, 4]
|
||||||
|
|
||||||
assert_equal '1 2 3 4', Template.parse('{{var | join}}').render(@context)
|
assert_equal "1 2 3 4", Template.parse("{{var | join}}").render(@context)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_sort
|
def test_sort
|
||||||
@context['value'] = 3
|
@context['value'] = 3
|
||||||
@context['numbers'] = [2, 1, 4, 3]
|
@context['numbers'] = [2, 1, 4, 3]
|
||||||
@context['words'] = %w[expected as alphabetic]
|
@context['words'] = ['expected', 'as', 'alphabetic']
|
||||||
@context['arrays'] = %w[flower are]
|
@context['arrays'] = ['flower', 'are']
|
||||||
@context['case_sensitive'] = %w[sensitive Expected case]
|
@context['case_sensitive'] = ['sensitive', 'Expected', 'case']
|
||||||
|
|
||||||
assert_equal '1 2 3 4', Template.parse('{{numbers | sort | join}}').render(@context)
|
assert_equal '1 2 3 4', Template.parse("{{numbers | sort | join}}").render(@context)
|
||||||
assert_equal 'alphabetic as expected', Template.parse('{{words | sort | join}}').render(@context)
|
assert_equal 'alphabetic as expected', Template.parse("{{words | sort | join}}").render(@context)
|
||||||
assert_equal '3', Template.parse('{{value | sort}}').render(@context)
|
assert_equal '3', Template.parse("{{value | sort}}").render(@context)
|
||||||
assert_equal 'are flower', Template.parse('{{arrays | sort | join}}').render(@context)
|
assert_equal 'are flower', Template.parse("{{arrays | sort | join}}").render(@context)
|
||||||
assert_equal 'Expected case sensitive', Template.parse('{{case_sensitive | sort | join}}').render(@context)
|
assert_equal 'Expected case sensitive', Template.parse("{{case_sensitive | sort | join}}").render(@context)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_sort_natural
|
def test_sort_natural
|
||||||
@context['words'] = %w[case Assert Insensitive]
|
@context['words'] = ['case', 'Assert', 'Insensitive']
|
||||||
@context['hashes'] = [{ 'a' => 'A' }, { 'a' => 'b' }, { 'a' => 'C' }]
|
@context['hashes'] = [{ 'a' => 'A' }, { 'a' => 'b' }, { 'a' => 'C' }]
|
||||||
@context['objects'] = [TestObject.new('A'), TestObject.new('b'), TestObject.new('C')]
|
@context['objects'] = [TestObject.new('A'), TestObject.new('b'), TestObject.new('C')]
|
||||||
|
|
||||||
# Test strings
|
# Test strings
|
||||||
assert_equal 'Assert case Insensitive', Template.parse('{{words | sort_natural | join}}').render(@context)
|
assert_equal 'Assert case Insensitive', Template.parse("{{words | sort_natural | join}}").render(@context)
|
||||||
|
|
||||||
# Test hashes
|
# Test hashes
|
||||||
assert_equal 'A b C', Template.parse("{{hashes | sort_natural: 'a' | map: 'a' | join}}").render(@context)
|
assert_equal 'A b C', Template.parse("{{hashes | sort_natural: 'a' | map: 'a' | join}}").render(@context)
|
||||||
@@ -106,7 +104,7 @@ class FiltersTest < Minitest::Test
|
|||||||
@context['objects'] = [TestObject.new('A'), TestObject.new(nil), TestObject.new('C')]
|
@context['objects'] = [TestObject.new('A'), TestObject.new(nil), TestObject.new('C')]
|
||||||
|
|
||||||
# Test strings
|
# Test strings
|
||||||
assert_equal 'a b c', Template.parse('{{words | compact | join}}').render(@context)
|
assert_equal 'a b c', Template.parse("{{words | compact | join}}").render(@context)
|
||||||
|
|
||||||
# Test hashes
|
# Test hashes
|
||||||
assert_equal 'A C', Template.parse("{{hashes | compact: 'a' | map: 'a' | join}}").render(@context)
|
assert_equal 'A C', Template.parse("{{hashes | compact: 'a' | map: 'a' | join}}").render(@context)
|
||||||
@@ -116,27 +114,27 @@ class FiltersTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_strip_html
|
def test_strip_html
|
||||||
@context['var'] = '<b>bla blub</a>'
|
@context['var'] = "<b>bla blub</a>"
|
||||||
|
|
||||||
assert_equal 'bla blub', Template.parse('{{ var | strip_html }}').render(@context)
|
assert_equal "bla blub", Template.parse("{{ var | strip_html }}").render(@context)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_strip_html_ignore_comments_with_html
|
def test_strip_html_ignore_comments_with_html
|
||||||
@context['var'] = '<!-- split and some <ul> tag --><b>bla blub</a>'
|
@context['var'] = "<!-- split and some <ul> tag --><b>bla blub</a>"
|
||||||
|
|
||||||
assert_equal 'bla blub', Template.parse('{{ var | strip_html }}').render(@context)
|
assert_equal "bla blub", Template.parse("{{ var | strip_html }}").render(@context)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_capitalize
|
def test_capitalize
|
||||||
@context['var'] = 'blub'
|
@context['var'] = "blub"
|
||||||
|
|
||||||
assert_equal 'Blub', Template.parse('{{ var | capitalize }}').render(@context)
|
assert_equal "Blub", Template.parse("{{ var | capitalize }}").render(@context)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_nonexistent_filter_is_ignored
|
def test_nonexistent_filter_is_ignored
|
||||||
@context['var'] = 1000
|
@context['var'] = 1000
|
||||||
|
|
||||||
assert_equal '1000', Template.parse('{{ var | xyzzy }}').render(@context)
|
assert_equal '1000', Template.parse("{{ var | xyzzy }}").render(@context)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_filter_with_keyword_arguments
|
def test_filter_with_keyword_arguments
|
||||||
@@ -148,10 +146,10 @@ class FiltersTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_override_object_method_in_filter
|
def test_override_object_method_in_filter
|
||||||
assert_equal 'tap overridden', Template.parse('{{var | tap}}').render!({ 'var' => 1000 }, filters: [OverrideObjectMethodFilter])
|
assert_equal "tap overridden", Template.parse("{{var | tap}}").render!({ 'var' => 1000 }, filters: [OverrideObjectMethodFilter])
|
||||||
|
|
||||||
# tap still treated as a non-existent filter
|
# tap still treated as a non-existent filter
|
||||||
assert_equal '1000', Template.parse('{{var | tap}}').render!('var' => 1000)
|
assert_equal "1000", Template.parse("{{var | tap}}").render!({ 'var' => 1000 })
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -160,15 +158,15 @@ class FiltersInTemplate < Minitest::Test
|
|||||||
|
|
||||||
def test_local_global
|
def test_local_global
|
||||||
with_global_filter(MoneyFilter) do
|
with_global_filter(MoneyFilter) do
|
||||||
assert_equal ' 1000$ ', Template.parse('{{1000 | money}}').render!(nil, nil)
|
assert_equal " 1000$ ", Template.parse("{{1000 | money}}").render!(nil, nil)
|
||||||
assert_equal ' 1000$ CAD ', Template.parse('{{1000 | money}}').render!(nil, filters: CanadianMoneyFilter)
|
assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, filters: CanadianMoneyFilter)
|
||||||
assert_equal ' 1000$ CAD ', Template.parse('{{1000 | money}}').render!(nil, filters: [CanadianMoneyFilter])
|
assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, filters: [CanadianMoneyFilter])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_local_filter_with_deprecated_syntax
|
def test_local_filter_with_deprecated_syntax
|
||||||
assert_equal ' 1000$ CAD ', Template.parse('{{1000 | money}}').render!(nil, CanadianMoneyFilter)
|
assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, CanadianMoneyFilter)
|
||||||
assert_equal ' 1000$ CAD ', Template.parse('{{1000 | money}}').render!(nil, [CanadianMoneyFilter])
|
assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, [CanadianMoneyFilter])
|
||||||
end
|
end
|
||||||
end # FiltersTest
|
end # FiltersTest
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class HashOrderingTest < Minitest::Test
|
class HashOrderingTest < Minitest::Test
|
||||||
module MoneyFilter
|
module MoneyFilter
|
||||||
def money(input)
|
def money(input)
|
||||||
format(' %d$ ', input)
|
sprintf(' %d$ ', input)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
module CanadianMoneyFilter
|
module CanadianMoneyFilter
|
||||||
def money(input)
|
def money(input)
|
||||||
format(' %d$ CAD ', input)
|
sprintf(' %d$ CAD ', input)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -19,7 +17,7 @@ class HashOrderingTest < Minitest::Test
|
|||||||
|
|
||||||
def test_global_register_order
|
def test_global_register_order
|
||||||
with_global_filter(MoneyFilter, CanadianMoneyFilter) do
|
with_global_filter(MoneyFilter, CanadianMoneyFilter) do
|
||||||
assert_equal ' 1000$ CAD ', Template.parse('{{1000 | money}}').render(nil, nil)
|
assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render(nil, nil)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
|
||||||
require 'liquid/legacy'
|
|
||||||
|
|
||||||
class FiltersTest < Minitest::Test
|
|
||||||
include Liquid
|
|
||||||
|
|
||||||
def test_constants
|
|
||||||
assert_equal Liquid::FilterSeparator, Liquid::FILTER_SEPARATOR
|
|
||||||
assert_equal Liquid::BlockBody::ContentOfVariable, Liquid::BlockBody::CONTENT_OF_VARIABLE
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
module FunnyFilter
|
module FunnyFilter
|
||||||
def make_funny(_input)
|
def make_funny(input)
|
||||||
'LOL'
|
'LOL'
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -11,11 +9,11 @@ module FunnyFilter
|
|||||||
"LOL: #{input}"
|
"LOL: #{input}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_smiley(input, smiley = ':-)')
|
def add_smiley(input, smiley = ":-)")
|
||||||
"#{input} #{smiley}"
|
"#{input} #{smiley}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_tag(input, tag = 'p', id = 'foo')
|
def add_tag(input, tag = "p", id = "foo")
|
||||||
%(<#{tag} id="#{id}">#{input}</#{tag}>)
|
%(<#{tag} id="#{id}">#{input}</#{tag}>)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -34,7 +32,7 @@ class OutputTest < Minitest::Test
|
|||||||
def setup
|
def setup
|
||||||
@assigns = {
|
@assigns = {
|
||||||
'best_cars' => 'bmw',
|
'best_cars' => 'bmw',
|
||||||
'car' => { 'bmw' => 'good', 'gm' => 'bad' },
|
'car' => { 'bmw' => 'good', 'gm' => 'bad' }
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -47,9 +45,9 @@ class OutputTest < Minitest::Test
|
|||||||
|
|
||||||
def test_variable_traversing_with_two_brackets
|
def test_variable_traversing_with_two_brackets
|
||||||
text = %({{ site.data.menu[include.menu][include.locale] }})
|
text = %({{ site.data.menu[include.menu][include.locale] }})
|
||||||
assert_equal 'it works!', Template.parse(text).render!(
|
assert_equal "it works!", Template.parse(text).render!(
|
||||||
'site' => { 'data' => { 'menu' => { 'foo' => { 'bar' => 'it works!' } } } },
|
"site" => { "data" => { "menu" => { "foo" => { "bar" => "it works!" } } } },
|
||||||
'include' => { 'menu' => 'foo', 'locale' => 'bar' }
|
"include" => { "menu" => "foo", "locale" => "bar" }
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -7,217 +7,217 @@ class ParseTreeVisitorTest < Minitest::Test
|
|||||||
|
|
||||||
def test_variable
|
def test_variable
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({{ test }}))
|
visit(%({{ test }}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_varible_with_filter
|
def test_varible_with_filter
|
||||||
assert_equal(
|
assert_equal(
|
||||||
%w[test infilter],
|
["test", "infilter"],
|
||||||
visit(%({{ test | split: infilter }}))
|
visit(%({{ test | split: infilter }}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_dynamic_variable
|
def test_dynamic_variable
|
||||||
assert_equal(
|
assert_equal(
|
||||||
%w[test inlookup],
|
["test", "inlookup"],
|
||||||
visit(%({{ test[inlookup] }}))
|
visit(%({{ test[inlookup] }}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_if_condition
|
def test_if_condition
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% if test %}{% endif %}))
|
visit(%({% if test %}{% endif %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_complex_if_condition
|
def test_complex_if_condition
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% if 1 == 1 and 2 == test %}{% endif %}))
|
visit(%({% if 1 == 1 and 2 == test %}{% endif %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_if_body
|
def test_if_body
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% if 1 == 1 %}{{ test }}{% endif %}))
|
visit(%({% if 1 == 1 %}{{ test }}{% endif %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_unless_condition
|
def test_unless_condition
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% unless test %}{% endunless %}))
|
visit(%({% unless test %}{% endunless %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_complex_unless_condition
|
def test_complex_unless_condition
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% unless 1 == 1 and 2 == test %}{% endunless %}))
|
visit(%({% unless 1 == 1 and 2 == test %}{% endunless %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_unless_body
|
def test_unless_body
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% unless 1 == 1 %}{{ test }}{% endunless %}))
|
visit(%({% unless 1 == 1 %}{{ test }}{% endunless %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_elsif_condition
|
def test_elsif_condition
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% if 1 == 1 %}{% elsif test %}{% endif %}))
|
visit(%({% if 1 == 1 %}{% elsif test %}{% endif %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_complex_elsif_condition
|
def test_complex_elsif_condition
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% if 1 == 1 %}{% elsif 1 == 1 and 2 == test %}{% endif %}))
|
visit(%({% if 1 == 1 %}{% elsif 1 == 1 and 2 == test %}{% endif %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_elsif_body
|
def test_elsif_body
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% if 1 == 1 %}{% elsif 2 == 2 %}{{ test }}{% endif %}))
|
visit(%({% if 1 == 1 %}{% elsif 2 == 2 %}{{ test }}{% endif %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_else_body
|
def test_else_body
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% if 1 == 1 %}{% else %}{{ test }}{% endif %}))
|
visit(%({% if 1 == 1 %}{% else %}{{ test }}{% endif %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_case_left
|
def test_case_left
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% case test %}{% endcase %}))
|
visit(%({% case test %}{% endcase %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_case_condition
|
def test_case_condition
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% case 1 %}{% when test %}{% endcase %}))
|
visit(%({% case 1 %}{% when test %}{% endcase %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_case_when_body
|
def test_case_when_body
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% case 1 %}{% when 2 %}{{ test }}{% endcase %}))
|
visit(%({% case 1 %}{% when 2 %}{{ test }}{% endcase %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_case_else_body
|
def test_case_else_body
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% case 1 %}{% else %}{{ test }}{% endcase %}))
|
visit(%({% case 1 %}{% else %}{{ test }}{% endcase %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_for_in
|
def test_for_in
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% for x in test %}{% endfor %}))
|
visit(%({% for x in test %}{% endfor %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_for_limit
|
def test_for_limit
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% for x in (1..5) limit: test %}{% endfor %}))
|
visit(%({% for x in (1..5) limit: test %}{% endfor %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_for_offset
|
def test_for_offset
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% for x in (1..5) offset: test %}{% endfor %}))
|
visit(%({% for x in (1..5) offset: test %}{% endfor %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_for_body
|
def test_for_body
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% for x in (1..5) %}{{ test }}{% endfor %}))
|
visit(%({% for x in (1..5) %}{{ test }}{% endfor %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_tablerow_in
|
def test_tablerow_in
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% tablerow x in test %}{% endtablerow %}))
|
visit(%({% tablerow x in test %}{% endtablerow %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_tablerow_limit
|
def test_tablerow_limit
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% tablerow x in (1..5) limit: test %}{% endtablerow %}))
|
visit(%({% tablerow x in (1..5) limit: test %}{% endtablerow %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_tablerow_offset
|
def test_tablerow_offset
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% tablerow x in (1..5) offset: test %}{% endtablerow %}))
|
visit(%({% tablerow x in (1..5) offset: test %}{% endtablerow %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_tablerow_body
|
def test_tablerow_body
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% tablerow x in (1..5) %}{{ test }}{% endtablerow %}))
|
visit(%({% tablerow x in (1..5) %}{{ test }}{% endtablerow %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_cycle
|
def test_cycle
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% cycle test %}))
|
visit(%({% cycle test %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_assign
|
def test_assign
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% assign x = test %}))
|
visit(%({% assign x = test %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_capture
|
def test_capture
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% capture x %}{{ test }}{% endcapture %}))
|
visit(%({% capture x %}{{ test }}{% endcapture %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_include
|
def test_include
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% include test %}))
|
visit(%({% include test %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_include_with
|
def test_include_with
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% include "hai" with test %}))
|
visit(%({% include "hai" with test %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_include_for
|
def test_include_for
|
||||||
assert_equal(
|
assert_equal(
|
||||||
['test'],
|
["test"],
|
||||||
visit(%({% include "hai" for test %}))
|
visit(%({% include "hai" for test %}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
@@ -225,9 +225,9 @@ class ParseTreeVisitorTest < Minitest::Test
|
|||||||
def test_preserve_tree_structure
|
def test_preserve_tree_structure
|
||||||
assert_equal(
|
assert_equal(
|
||||||
[[nil, [
|
[[nil, [
|
||||||
[nil, [[nil, [['other', []]]]]],
|
[nil, [[nil, [["other", []]]]]],
|
||||||
['test', []],
|
["test", []],
|
||||||
['xs', []],
|
["xs", []]
|
||||||
]]],
|
]]],
|
||||||
traversal(%({% for x in xs offset: test %}{{ other }}{% endfor %})).visit
|
traversal(%({% for x in xs offset: test %}{{ other }}{% endfor %})).visit
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,43 +1,41 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class ParsingQuirksTest < Minitest::Test
|
class ParsingQuirksTest < Minitest::Test
|
||||||
include Liquid
|
include Liquid
|
||||||
|
|
||||||
def test_parsing_css
|
def test_parsing_css
|
||||||
text = ' div { font-weight: bold; } '
|
text = " div { font-weight: bold; } "
|
||||||
assert_equal text, Template.parse(text).render!
|
assert_equal text, Template.parse(text).render!
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_raise_on_single_close_bracet
|
def test_raise_on_single_close_bracet
|
||||||
assert_raises(SyntaxError) do
|
assert_raises(SyntaxError) do
|
||||||
Template.parse('text {{method} oh nos!')
|
Template.parse("text {{method} oh nos!")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_raise_on_label_and_no_close_bracets
|
def test_raise_on_label_and_no_close_bracets
|
||||||
assert_raises(SyntaxError) do
|
assert_raises(SyntaxError) do
|
||||||
Template.parse('TEST {{ ')
|
Template.parse("TEST {{ ")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_raise_on_label_and_no_close_bracets_percent
|
def test_raise_on_label_and_no_close_bracets_percent
|
||||||
assert_raises(SyntaxError) do
|
assert_raises(SyntaxError) do
|
||||||
Template.parse('TEST {% ')
|
Template.parse("TEST {% ")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_error_on_empty_filter
|
def test_error_on_empty_filter
|
||||||
assert Template.parse('{{test}}')
|
assert Template.parse("{{test}}")
|
||||||
|
|
||||||
with_error_mode(:lax) do
|
with_error_mode(:lax) do
|
||||||
assert Template.parse('{{|test}}')
|
assert Template.parse("{{|test}}")
|
||||||
end
|
end
|
||||||
|
|
||||||
with_error_mode(:strict) do
|
with_error_mode(:strict) do
|
||||||
assert_raises(SyntaxError) { Template.parse('{{|test}}') }
|
assert_raises(SyntaxError) { Template.parse("{{|test}}") }
|
||||||
assert_raises(SyntaxError) { Template.parse('{{test |a|b|}}') }
|
assert_raises(SyntaxError) { Template.parse("{{test |a|b|}}") }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -53,20 +51,20 @@ class ParsingQuirksTest < Minitest::Test
|
|||||||
def test_unexpected_characters_syntax_error
|
def test_unexpected_characters_syntax_error
|
||||||
with_error_mode(:strict) do
|
with_error_mode(:strict) do
|
||||||
assert_raises(SyntaxError) do
|
assert_raises(SyntaxError) do
|
||||||
markup = 'true && false'
|
markup = "true && false"
|
||||||
Template.parse("{% if #{markup} %} YES {% endif %}")
|
Template.parse("{% if #{markup} %} YES {% endif %}")
|
||||||
end
|
end
|
||||||
assert_raises(SyntaxError) do
|
assert_raises(SyntaxError) do
|
||||||
markup = 'false || true'
|
markup = "false || true"
|
||||||
Template.parse("{% if #{markup} %} YES {% endif %}")
|
Template.parse("{% if #{markup} %} YES {% endif %}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_no_error_on_lax_empty_filter
|
def test_no_error_on_lax_empty_filter
|
||||||
assert Template.parse('{{test |a|b|}}', error_mode: :lax)
|
assert Template.parse("{{test |a|b|}}", error_mode: :lax)
|
||||||
assert Template.parse('{{test}}', error_mode: :lax)
|
assert Template.parse("{{test}}", error_mode: :lax)
|
||||||
assert Template.parse('{{|test|}}', error_mode: :lax)
|
assert Template.parse("{{|test|}}", error_mode: :lax)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_meaningless_parens_lax
|
def test_meaningless_parens_lax
|
||||||
@@ -79,9 +77,9 @@ class ParsingQuirksTest < Minitest::Test
|
|||||||
|
|
||||||
def test_unexpected_characters_silently_eat_logic_lax
|
def test_unexpected_characters_silently_eat_logic_lax
|
||||||
with_error_mode(:lax) do
|
with_error_mode(:lax) do
|
||||||
markup = 'true && false'
|
markup = "true && false"
|
||||||
assert_template_result(' YES ', "{% if #{markup} %} YES {% endif %}")
|
assert_template_result(' YES ', "{% if #{markup} %} YES {% endif %}")
|
||||||
markup = 'false || true'
|
markup = "false || true"
|
||||||
assert_template_result('', "{% if #{markup} %} YES {% endif %}")
|
assert_template_result('', "{% if #{markup} %} YES {% endif %}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -114,7 +112,7 @@ class ParsingQuirksTest < Minitest::Test
|
|||||||
|
|
||||||
def test_extra_dots_in_ranges
|
def test_extra_dots_in_ranges
|
||||||
with_error_mode(:lax) do
|
with_error_mode(:lax) do
|
||||||
assert_template_result('12345', '{% for i in (1...5) %}{{ i }}{% endfor %}')
|
assert_template_result('12345', "{% for i in (1...5) %}{{ i }}{% endfor %}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class RenderProfilingTest < Minitest::Test
|
class RenderProfilingTest < Minitest::Test
|
||||||
@@ -74,7 +72,7 @@ class RenderProfilingTest < Minitest::Test
|
|||||||
t = Template.parse("{% include 'a_template' %}", profile: true)
|
t = Template.parse("{% include 'a_template' %}", profile: true)
|
||||||
t.render!
|
t.render!
|
||||||
|
|
||||||
assert t.profiler.total_render_time >= 0, 'Total render time was not calculated'
|
assert t.profiler.total_render_time >= 0, "Total render time was not calculated"
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_profiling_uses_include_to_mark_children
|
def test_profiling_uses_include_to_mark_children
|
||||||
@@ -91,7 +89,7 @@ class RenderProfilingTest < Minitest::Test
|
|||||||
|
|
||||||
include_node = t.profiler[1]
|
include_node = t.profiler[1]
|
||||||
include_node.children.each do |child|
|
include_node.children.each do |child|
|
||||||
assert_equal 'a_template', child.partial
|
assert_equal "a_template", child.partial
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -101,12 +99,12 @@ class RenderProfilingTest < Minitest::Test
|
|||||||
|
|
||||||
a_template = t.profiler[1]
|
a_template = t.profiler[1]
|
||||||
a_template.children.each do |child|
|
a_template.children.each do |child|
|
||||||
assert_equal 'a_template', child.partial
|
assert_equal "a_template", child.partial
|
||||||
end
|
end
|
||||||
|
|
||||||
b_template = t.profiler[2]
|
b_template = t.profiler[2]
|
||||||
b_template.children.each do |child|
|
b_template.children.each do |child|
|
||||||
assert_equal 'b_template', child.partial
|
assert_equal "b_template", child.partial
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -116,12 +114,12 @@ class RenderProfilingTest < Minitest::Test
|
|||||||
|
|
||||||
a_template1 = t.profiler[1]
|
a_template1 = t.profiler[1]
|
||||||
a_template1.children.each do |child|
|
a_template1.children.each do |child|
|
||||||
assert_equal 'a_template', child.partial
|
assert_equal "a_template", child.partial
|
||||||
end
|
end
|
||||||
|
|
||||||
a_template2 = t.profiler[2]
|
a_template2 = t.profiler[2]
|
||||||
a_template2.children.each do |child|
|
a_template2.children.each do |child|
|
||||||
assert_equal 'a_template', child.partial
|
assert_equal "a_template", child.partial
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -130,7 +128,7 @@ class RenderProfilingTest < Minitest::Test
|
|||||||
t.render!
|
t.render!
|
||||||
|
|
||||||
timing_count = 0
|
timing_count = 0
|
||||||
t.profiler.each do |_timing|
|
t.profiler.each do |timing|
|
||||||
timing_count += 1
|
timing_count += 1
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -138,7 +136,7 @@ class RenderProfilingTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_profiling_marks_children_of_if_blocks
|
def test_profiling_marks_children_of_if_blocks
|
||||||
t = Template.parse('{% if true %} {% increment test %} {{ test }} {% endif %}', profile: true)
|
t = Template.parse("{% if true %} {% increment test %} {{ test }} {% endif %}", profile: true)
|
||||||
t.render!
|
t.render!
|
||||||
|
|
||||||
assert_equal 1, t.profiler.length
|
assert_equal 1, t.profiler.length
|
||||||
@@ -146,8 +144,8 @@ class RenderProfilingTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_profiling_marks_children_of_for_blocks
|
def test_profiling_marks_children_of_for_blocks
|
||||||
t = Template.parse('{% for item in collection %} {{ item }} {% endfor %}', profile: true)
|
t = Template.parse("{% for item in collection %} {{ item }} {% endfor %}", profile: true)
|
||||||
t.render!('collection' => %w[one two])
|
t.render!({ "collection" => ["one", "two"] })
|
||||||
|
|
||||||
assert_equal 1, t.profiler.length
|
assert_equal 1, t.profiler.length
|
||||||
# Will profile each invocation of the for block
|
# Will profile each invocation of the for block
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
module SecurityFilter
|
module SecurityFilter
|
||||||
@@ -59,22 +57,22 @@ class SecurityTest < Minitest::Test
|
|||||||
current_symbols = Symbol.all_symbols
|
current_symbols = Symbol.all_symbols
|
||||||
|
|
||||||
assigns = { 'drop' => Drop.new }
|
assigns = { 'drop' => Drop.new }
|
||||||
assert_equal '', Template.parse('{{ drop.custom_method_1 }}', assigns).render!
|
assert_equal "", Template.parse("{{ drop.custom_method_1 }}", assigns).render!
|
||||||
assert_equal '', Template.parse('{{ drop.custom_method_2 }}', assigns).render!
|
assert_equal "", Template.parse("{{ drop.custom_method_2 }}", assigns).render!
|
||||||
assert_equal '', Template.parse('{{ drop.custom_method_3 }}', assigns).render!
|
assert_equal "", Template.parse("{{ drop.custom_method_3 }}", assigns).render!
|
||||||
|
|
||||||
assert_equal [], (Symbol.all_symbols - current_symbols)
|
assert_equal [], (Symbol.all_symbols - current_symbols)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_max_depth_nested_blocks_does_not_raise_exception
|
def test_max_depth_nested_blocks_does_not_raise_exception
|
||||||
depth = Liquid::Block::MAX_DEPTH
|
depth = Liquid::Block::MAX_DEPTH
|
||||||
code = '{% if true %}' * depth + 'rendered' + '{% endif %}' * depth
|
code = "{% if true %}" * depth + "rendered" + "{% endif %}" * depth
|
||||||
assert_equal 'rendered', Template.parse(code).render!
|
assert_equal "rendered", Template.parse(code).render!
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_more_than_max_depth_nested_blocks_raises_exception
|
def test_more_than_max_depth_nested_blocks_raises_exception
|
||||||
depth = Liquid::Block::MAX_DEPTH + 1
|
depth = Liquid::Block::MAX_DEPTH + 1
|
||||||
code = '{% if true %}' * depth + 'rendered' + '{% endif %}' * depth
|
code = "{% if true %}" * depth + "rendered" + "{% endif %}" * depth
|
||||||
assert_raises(Liquid::StackLevelError) do
|
assert_raises(Liquid::StackLevelError) do
|
||||||
Template.parse(code).render!
|
Template.parse(code).render!
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# frozen_string_literal: true
|
# encoding: utf-8
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ class TestThing
|
|||||||
"woot: #{@foo}"
|
"woot: #{@foo}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def [](_whatever)
|
def [](whatever)
|
||||||
to_s
|
to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ end
|
|||||||
|
|
||||||
class TestDrop < Liquid::Drop
|
class TestDrop < Liquid::Drop
|
||||||
def test
|
def test
|
||||||
'testfoo'
|
"testfoo"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ class TestEnumerable < Liquid::Drop
|
|||||||
include Enumerable
|
include Enumerable
|
||||||
|
|
||||||
def each(&block)
|
def each(&block)
|
||||||
[{ 'foo' => 1, 'bar' => 2 }, { 'foo' => 2, 'bar' => 1 }, { 'foo' => 3, 'bar' => 3 }].each(&block)
|
[ { "foo" => 1, "bar" => 2 }, { "foo" => 2, "bar" => 1 }, { "foo" => 3, "bar" => 3 } ].each(&block)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -65,12 +65,12 @@ class StandardFiltersTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_downcase
|
def test_downcase
|
||||||
assert_equal 'testing', @filters.downcase('Testing')
|
assert_equal 'testing', @filters.downcase("Testing")
|
||||||
assert_equal '', @filters.downcase(nil)
|
assert_equal '', @filters.downcase(nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_upcase
|
def test_upcase
|
||||||
assert_equal 'TESTING', @filters.upcase('Testing')
|
assert_equal 'TESTING', @filters.upcase("Testing")
|
||||||
assert_equal '', @filters.upcase(nil)
|
assert_equal '', @filters.upcase(nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -91,22 +91,22 @@ class StandardFiltersTest < Minitest::Test
|
|||||||
@filters.slice('foobar', nil)
|
@filters.slice('foobar', nil)
|
||||||
end
|
end
|
||||||
assert_raises(Liquid::ArgumentError) do
|
assert_raises(Liquid::ArgumentError) do
|
||||||
@filters.slice('foobar', 0, '')
|
@filters.slice('foobar', 0, "")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_slice_on_arrays
|
def test_slice_on_arrays
|
||||||
input = 'foobar'.split(//)
|
input = 'foobar'.split(//)
|
||||||
assert_equal %w[o o b], @filters.slice(input, 1, 3)
|
assert_equal %w(o o b), @filters.slice(input, 1, 3)
|
||||||
assert_equal %w[o o b a r], @filters.slice(input, 1, 1000)
|
assert_equal %w(o o b a r), @filters.slice(input, 1, 1000)
|
||||||
assert_equal %w[], @filters.slice(input, 1, 0)
|
assert_equal %w(), @filters.slice(input, 1, 0)
|
||||||
assert_equal %w[o], @filters.slice(input, 1, 1)
|
assert_equal %w(o), @filters.slice(input, 1, 1)
|
||||||
assert_equal %w[b a r], @filters.slice(input, 3, 3)
|
assert_equal %w(b a r), @filters.slice(input, 3, 3)
|
||||||
assert_equal %w[a r], @filters.slice(input, -2, 2)
|
assert_equal %w(a r), @filters.slice(input, -2, 2)
|
||||||
assert_equal %w[a r], @filters.slice(input, -2, 1000)
|
assert_equal %w(a r), @filters.slice(input, -2, 1000)
|
||||||
assert_equal %w[r], @filters.slice(input, -1)
|
assert_equal %w(r), @filters.slice(input, -1)
|
||||||
assert_equal %w[], @filters.slice(input, 100, 10)
|
assert_equal %w(), @filters.slice(input, 100, 10)
|
||||||
assert_equal %w[], @filters.slice(input, -100, 10)
|
assert_equal %w(), @filters.slice(input, -100, 10)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_truncate
|
def test_truncate
|
||||||
@@ -114,16 +114,16 @@ class StandardFiltersTest < Minitest::Test
|
|||||||
assert_equal '1234567890', @filters.truncate('1234567890', 20)
|
assert_equal '1234567890', @filters.truncate('1234567890', 20)
|
||||||
assert_equal '...', @filters.truncate('1234567890', 0)
|
assert_equal '...', @filters.truncate('1234567890', 0)
|
||||||
assert_equal '1234567890', @filters.truncate('1234567890')
|
assert_equal '1234567890', @filters.truncate('1234567890')
|
||||||
assert_equal '测试...', @filters.truncate('测试测试测试测试', 5)
|
assert_equal "测试...", @filters.truncate("测试测试测试测试", 5)
|
||||||
assert_equal '12341', @filters.truncate('1234567890', 5, 1)
|
assert_equal '12341', @filters.truncate("1234567890", 5, 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_split
|
def test_split
|
||||||
assert_equal %w[12 34], @filters.split('12~34', '~')
|
assert_equal ['12', '34'], @filters.split('12~34', '~')
|
||||||
assert_equal ['A? ', ' ,Z'], @filters.split('A? ~ ~ ~ ,Z', '~ ~ ~')
|
assert_equal ['A? ', ' ,Z'], @filters.split('A? ~ ~ ~ ,Z', '~ ~ ~')
|
||||||
assert_equal ['A?Z'], @filters.split('A?Z', '~')
|
assert_equal ['A?Z'], @filters.split('A?Z', '~')
|
||||||
assert_equal [], @filters.split(nil, ' ')
|
assert_equal [], @filters.split(nil, ' ')
|
||||||
assert_equal %w[A Z], @filters.split('A1Z', 1)
|
assert_equal ['A', 'Z'], @filters.split('A1Z', 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_escape
|
def test_escape
|
||||||
@@ -169,12 +169,12 @@ class StandardFiltersTest < Minitest::Test
|
|||||||
assert_equal 'one two...', @filters.truncatewords('one two three', 2)
|
assert_equal 'one two...', @filters.truncatewords('one two three', 2)
|
||||||
assert_equal 'one two three', @filters.truncatewords('one two three')
|
assert_equal 'one two three', @filters.truncatewords('one two three')
|
||||||
assert_equal 'Two small (13” x 5.5” x 10” high) baskets fit inside one large basket (13”...', @filters.truncatewords('Two small (13” x 5.5” x 10” high) baskets fit inside one large basket (13” x 16” x 10.5” high) with cover.', 15)
|
assert_equal 'Two small (13” x 5.5” x 10” high) baskets fit inside one large basket (13”...', @filters.truncatewords('Two small (13” x 5.5” x 10” high) baskets fit inside one large basket (13” x 16” x 10.5” high) with cover.', 15)
|
||||||
assert_equal '测试测试测试测试', @filters.truncatewords('测试测试测试测试', 5)
|
assert_equal "测试测试测试测试", @filters.truncatewords('测试测试测试测试', 5)
|
||||||
assert_equal 'one two1', @filters.truncatewords('one two three', 2, 1)
|
assert_equal 'one two1', @filters.truncatewords("one two three", 2, 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_strip_html
|
def test_strip_html
|
||||||
assert_equal 'test', @filters.strip_html('<div>test</div>')
|
assert_equal 'test', @filters.strip_html("<div>test</div>")
|
||||||
assert_equal 'test', @filters.strip_html("<div id='test'>test</div>")
|
assert_equal 'test', @filters.strip_html("<div id='test'>test</div>")
|
||||||
assert_equal '', @filters.strip_html("<script type='text/javascript'>document.write('some stuff');</script>")
|
assert_equal '', @filters.strip_html("<script type='text/javascript'>document.write('some stuff');</script>")
|
||||||
assert_equal '', @filters.strip_html("<style type='text/css'>foo bar</style>")
|
assert_equal '', @filters.strip_html("<style type='text/css'>foo bar</style>")
|
||||||
@@ -183,7 +183,7 @@ class StandardFiltersTest < Minitest::Test
|
|||||||
assert_equal '', @filters.strip_html(nil)
|
assert_equal '', @filters.strip_html(nil)
|
||||||
|
|
||||||
# Quirk of the existing implementation
|
# Quirk of the existing implementation
|
||||||
assert_equal 'foo;', @filters.strip_html('<<<script </script>script>foo;</script>')
|
assert_equal 'foo;', @filters.strip_html("<<<script </script>script>foo;</script>")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_join
|
def test_join
|
||||||
@@ -194,163 +194,163 @@ class StandardFiltersTest < Minitest::Test
|
|||||||
|
|
||||||
def test_sort
|
def test_sort
|
||||||
assert_equal [1, 2, 3, 4], @filters.sort([4, 3, 2, 1])
|
assert_equal [1, 2, 3, 4], @filters.sort([4, 3, 2, 1])
|
||||||
assert_equal [{ 'a' => 1 }, { 'a' => 2 }, { 'a' => 3 }, { 'a' => 4 }], @filters.sort([{ 'a' => 4 }, { 'a' => 3 }, { 'a' => 1 }, { 'a' => 2 }], 'a')
|
assert_equal [{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }], @filters.sort([{ "a" => 4 }, { "a" => 3 }, { "a" => 1 }, { "a" => 2 }], "a")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_sort_with_nils
|
def test_sort_with_nils
|
||||||
assert_equal [1, 2, 3, 4, nil], @filters.sort([nil, 4, 3, 2, 1])
|
assert_equal [1, 2, 3, 4, nil], @filters.sort([nil, 4, 3, 2, 1])
|
||||||
assert_equal [{ 'a' => 1 }, { 'a' => 2 }, { 'a' => 3 }, { 'a' => 4 }, {}], @filters.sort([{ 'a' => 4 }, { 'a' => 3 }, {}, { 'a' => 1 }, { 'a' => 2 }], 'a')
|
assert_equal [{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }, {}], @filters.sort([{ "a" => 4 }, { "a" => 3 }, {}, { "a" => 1 }, { "a" => 2 }], "a")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_sort_when_property_is_sometimes_missing_puts_nils_last
|
def test_sort_when_property_is_sometimes_missing_puts_nils_last
|
||||||
input = [
|
input = [
|
||||||
{ 'price' => 4, 'handle' => 'alpha' },
|
{ "price" => 4, "handle" => "alpha" },
|
||||||
{ 'handle' => 'beta' },
|
{ "handle" => "beta" },
|
||||||
{ 'price' => 1, 'handle' => 'gamma' },
|
{ "price" => 1, "handle" => "gamma" },
|
||||||
{ 'handle' => 'delta' },
|
{ "handle" => "delta" },
|
||||||
{ 'price' => 2, 'handle' => 'epsilon' },
|
{ "price" => 2, "handle" => "epsilon" }
|
||||||
]
|
]
|
||||||
expectation = [
|
expectation = [
|
||||||
{ 'price' => 1, 'handle' => 'gamma' },
|
{ "price" => 1, "handle" => "gamma" },
|
||||||
{ 'price' => 2, 'handle' => 'epsilon' },
|
{ "price" => 2, "handle" => "epsilon" },
|
||||||
{ 'price' => 4, 'handle' => 'alpha' },
|
{ "price" => 4, "handle" => "alpha" },
|
||||||
{ 'handle' => 'delta' },
|
{ "handle" => "delta" },
|
||||||
{ 'handle' => 'beta' },
|
{ "handle" => "beta" }
|
||||||
]
|
]
|
||||||
assert_equal expectation, @filters.sort(input, 'price')
|
assert_equal expectation, @filters.sort(input, "price")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_sort_natural
|
def test_sort_natural
|
||||||
assert_equal %w[a B c D], @filters.sort_natural(%w[c D a B])
|
assert_equal ["a", "B", "c", "D"], @filters.sort_natural(["c", "D", "a", "B"])
|
||||||
assert_equal [{ 'a' => 'a' }, { 'a' => 'B' }, { 'a' => 'c' }, { 'a' => 'D' }], @filters.sort_natural([{ 'a' => 'D' }, { 'a' => 'c' }, { 'a' => 'a' }, { 'a' => 'B' }], 'a')
|
assert_equal [{ "a" => "a" }, { "a" => "B" }, { "a" => "c" }, { "a" => "D" }], @filters.sort_natural([{ "a" => "D" }, { "a" => "c" }, { "a" => "a" }, { "a" => "B" }], "a")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_sort_natural_with_nils
|
def test_sort_natural_with_nils
|
||||||
assert_equal ['a', 'B', 'c', 'D', nil], @filters.sort_natural([nil, 'c', 'D', 'a', 'B'])
|
assert_equal ["a", "B", "c", "D", nil], @filters.sort_natural([nil, "c", "D", "a", "B"])
|
||||||
assert_equal [{ 'a' => 'a' }, { 'a' => 'B' }, { 'a' => 'c' }, { 'a' => 'D' }, {}], @filters.sort_natural([{ 'a' => 'D' }, { 'a' => 'c' }, {}, { 'a' => 'a' }, { 'a' => 'B' }], 'a')
|
assert_equal [{ "a" => "a" }, { "a" => "B" }, { "a" => "c" }, { "a" => "D" }, {}], @filters.sort_natural([{ "a" => "D" }, { "a" => "c" }, {}, { "a" => "a" }, { "a" => "B" }], "a")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_sort_natural_when_property_is_sometimes_missing_puts_nils_last
|
def test_sort_natural_when_property_is_sometimes_missing_puts_nils_last
|
||||||
input = [
|
input = [
|
||||||
{ 'price' => '4', 'handle' => 'alpha' },
|
{ "price" => "4", "handle" => "alpha" },
|
||||||
{ 'handle' => 'beta' },
|
{ "handle" => "beta" },
|
||||||
{ 'price' => '1', 'handle' => 'gamma' },
|
{ "price" => "1", "handle" => "gamma" },
|
||||||
{ 'handle' => 'delta' },
|
{ "handle" => "delta" },
|
||||||
{ 'price' => 2, 'handle' => 'epsilon' },
|
{ "price" => 2, "handle" => "epsilon" }
|
||||||
]
|
]
|
||||||
expectation = [
|
expectation = [
|
||||||
{ 'price' => '1', 'handle' => 'gamma' },
|
{ "price" => "1", "handle" => "gamma" },
|
||||||
{ 'price' => 2, 'handle' => 'epsilon' },
|
{ "price" => 2, "handle" => "epsilon" },
|
||||||
{ 'price' => '4', 'handle' => 'alpha' },
|
{ "price" => "4", "handle" => "alpha" },
|
||||||
{ 'handle' => 'delta' },
|
{ "handle" => "delta" },
|
||||||
{ 'handle' => 'beta' },
|
{ "handle" => "beta" }
|
||||||
]
|
]
|
||||||
assert_equal expectation, @filters.sort_natural(input, 'price')
|
assert_equal expectation, @filters.sort_natural(input, "price")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_sort_natural_case_check
|
def test_sort_natural_case_check
|
||||||
input = [
|
input = [
|
||||||
{ 'key' => 'X' },
|
{ "key" => "X" },
|
||||||
{ 'key' => 'Y' },
|
{ "key" => "Y" },
|
||||||
{ 'key' => 'Z' },
|
{ "key" => "Z" },
|
||||||
{ 'fake' => 't' },
|
{ "fake" => "t" },
|
||||||
{ 'key' => 'a' },
|
{ "key" => "a" },
|
||||||
{ 'key' => 'b' },
|
{ "key" => "b" },
|
||||||
{ 'key' => 'c' },
|
{ "key" => "c" }
|
||||||
]
|
]
|
||||||
expectation = [
|
expectation = [
|
||||||
{ 'key' => 'a' },
|
{ "key" => "a" },
|
||||||
{ 'key' => 'b' },
|
{ "key" => "b" },
|
||||||
{ 'key' => 'c' },
|
{ "key" => "c" },
|
||||||
{ 'key' => 'X' },
|
{ "key" => "X" },
|
||||||
{ 'key' => 'Y' },
|
{ "key" => "Y" },
|
||||||
{ 'key' => 'Z' },
|
{ "key" => "Z" },
|
||||||
{ 'fake' => 't' },
|
{ "fake" => "t" }
|
||||||
]
|
]
|
||||||
assert_equal expectation, @filters.sort_natural(input, 'key')
|
assert_equal expectation, @filters.sort_natural(input, "key")
|
||||||
assert_equal %w[a b c X Y Z], @filters.sort_natural(%w[X Y Z a b c])
|
assert_equal ["a", "b", "c", "X", "Y", "Z"], @filters.sort_natural(["X", "Y", "Z", "a", "b", "c"])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_sort_empty_array
|
def test_sort_empty_array
|
||||||
assert_equal [], @filters.sort([], 'a')
|
assert_equal [], @filters.sort([], "a")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_sort_invalid_property
|
def test_sort_invalid_property
|
||||||
foo = [
|
foo = [
|
||||||
[1],
|
[1],
|
||||||
[2],
|
[2],
|
||||||
[3],
|
[3]
|
||||||
]
|
]
|
||||||
|
|
||||||
assert_raises Liquid::ArgumentError do
|
assert_raises Liquid::ArgumentError do
|
||||||
@filters.sort(foo, 'bar')
|
@filters.sort(foo, "bar")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_sort_natural_empty_array
|
def test_sort_natural_empty_array
|
||||||
assert_equal [], @filters.sort_natural([], 'a')
|
assert_equal [], @filters.sort_natural([], "a")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_sort_natural_invalid_property
|
def test_sort_natural_invalid_property
|
||||||
foo = [
|
foo = [
|
||||||
[1],
|
[1],
|
||||||
[2],
|
[2],
|
||||||
[3],
|
[3]
|
||||||
]
|
]
|
||||||
|
|
||||||
assert_raises Liquid::ArgumentError do
|
assert_raises Liquid::ArgumentError do
|
||||||
@filters.sort_natural(foo, 'bar')
|
@filters.sort_natural(foo, "bar")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_legacy_sort_hash
|
def test_legacy_sort_hash
|
||||||
assert_equal [{ a: 1, b: 2 }], @filters.sort(a: 1, b: 2)
|
assert_equal [{ a: 1, b: 2 }], @filters.sort({ a: 1, b: 2 })
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_numerical_vs_lexicographical_sort
|
def test_numerical_vs_lexicographical_sort
|
||||||
assert_equal [2, 10], @filters.sort([10, 2])
|
assert_equal [2, 10], @filters.sort([10, 2])
|
||||||
assert_equal [{ 'a' => 2 }, { 'a' => 10 }], @filters.sort([{ 'a' => 10 }, { 'a' => 2 }], 'a')
|
assert_equal [{ "a" => 2 }, { "a" => 10 }], @filters.sort([{ "a" => 10 }, { "a" => 2 }], "a")
|
||||||
assert_equal %w[10 2], @filters.sort(%w[10 2])
|
assert_equal ["10", "2"], @filters.sort(["10", "2"])
|
||||||
assert_equal [{ 'a' => '10' }, { 'a' => '2' }], @filters.sort([{ 'a' => '10' }, { 'a' => '2' }], 'a')
|
assert_equal [{ "a" => "10" }, { "a" => "2" }], @filters.sort([{ "a" => "10" }, { "a" => "2" }], "a")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_uniq
|
def test_uniq
|
||||||
assert_equal ['foo'], @filters.uniq('foo')
|
assert_equal ["foo"], @filters.uniq("foo")
|
||||||
assert_equal [1, 3, 2, 4], @filters.uniq([1, 1, 3, 2, 3, 1, 4, 3, 2, 1])
|
assert_equal [1, 3, 2, 4], @filters.uniq([1, 1, 3, 2, 3, 1, 4, 3, 2, 1])
|
||||||
assert_equal [{ 'a' => 1 }, { 'a' => 3 }, { 'a' => 2 }], @filters.uniq([{ 'a' => 1 }, { 'a' => 3 }, { 'a' => 1 }, { 'a' => 2 }], 'a')
|
assert_equal [{ "a" => 1 }, { "a" => 3 }, { "a" => 2 }], @filters.uniq([{ "a" => 1 }, { "a" => 3 }, { "a" => 1 }, { "a" => 2 }], "a")
|
||||||
testdrop = TestDrop.new
|
testdrop = TestDrop.new
|
||||||
assert_equal [testdrop], @filters.uniq([testdrop, TestDrop.new], 'test')
|
assert_equal [testdrop], @filters.uniq([testdrop, TestDrop.new], 'test')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_uniq_empty_array
|
def test_uniq_empty_array
|
||||||
assert_equal [], @filters.uniq([], 'a')
|
assert_equal [], @filters.uniq([], "a")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_uniq_invalid_property
|
def test_uniq_invalid_property
|
||||||
foo = [
|
foo = [
|
||||||
[1],
|
[1],
|
||||||
[2],
|
[2],
|
||||||
[3],
|
[3]
|
||||||
]
|
]
|
||||||
|
|
||||||
assert_raises Liquid::ArgumentError do
|
assert_raises Liquid::ArgumentError do
|
||||||
@filters.uniq(foo, 'bar')
|
@filters.uniq(foo, "bar")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_compact_empty_array
|
def test_compact_empty_array
|
||||||
assert_equal [], @filters.compact([], 'a')
|
assert_equal [], @filters.compact([], "a")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_compact_invalid_property
|
def test_compact_invalid_property
|
||||||
foo = [
|
foo = [
|
||||||
[1],
|
[1],
|
||||||
[2],
|
[2],
|
||||||
[3],
|
[3]
|
||||||
]
|
]
|
||||||
|
|
||||||
assert_raises Liquid::ArgumentError do
|
assert_raises Liquid::ArgumentError do
|
||||||
@filters.compact(foo, 'bar')
|
@filters.compact(foo, "bar")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -363,71 +363,71 @@ class StandardFiltersTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_map
|
def test_map
|
||||||
assert_equal [1, 2, 3, 4], @filters.map([{ 'a' => 1 }, { 'a' => 2 }, { 'a' => 3 }, { 'a' => 4 }], 'a')
|
assert_equal [1, 2, 3, 4], @filters.map([{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }], 'a')
|
||||||
assert_template_result 'abc', "{{ ary | map:'foo' | map:'bar' }}",
|
assert_template_result 'abc', "{{ ary | map:'foo' | map:'bar' }}",
|
||||||
'ary' => [{ 'foo' => { 'bar' => 'a' } }, { 'foo' => { 'bar' => 'b' } }, { 'foo' => { 'bar' => 'c' } }]
|
'ary' => [{ 'foo' => { 'bar' => 'a' } }, { 'foo' => { 'bar' => 'b' } }, { 'foo' => { 'bar' => 'c' } }]
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_map_doesnt_call_arbitrary_stuff
|
def test_map_doesnt_call_arbitrary_stuff
|
||||||
assert_template_result '', '{{ "foo" | map: "__id__" }}'
|
assert_template_result "", '{{ "foo" | map: "__id__" }}'
|
||||||
assert_template_result '', '{{ "foo" | map: "inspect" }}'
|
assert_template_result "", '{{ "foo" | map: "inspect" }}'
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_map_calls_to_liquid
|
def test_map_calls_to_liquid
|
||||||
t = TestThing.new
|
t = TestThing.new
|
||||||
assert_template_result 'woot: 1', '{{ foo | map: "whatever" }}', 'foo' => [t]
|
assert_template_result "woot: 1", '{{ foo | map: "whatever" }}', "foo" => [t]
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_map_on_hashes
|
def test_map_on_hashes
|
||||||
assert_template_result '4217', '{{ thing | map: "foo" | map: "bar" }}',
|
assert_template_result "4217", '{{ thing | map: "foo" | map: "bar" }}',
|
||||||
'thing' => { 'foo' => [{ 'bar' => 42 }, { 'bar' => 17 }] }
|
"thing" => { "foo" => [ { "bar" => 42 }, { "bar" => 17 } ] }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_legacy_map_on_hashes_with_dynamic_key
|
def test_legacy_map_on_hashes_with_dynamic_key
|
||||||
template = "{% assign key = 'foo' %}{{ thing | map: key | map: 'bar' }}"
|
template = "{% assign key = 'foo' %}{{ thing | map: key | map: 'bar' }}"
|
||||||
hash = { 'foo' => { 'bar' => 42 } }
|
hash = { "foo" => { "bar" => 42 } }
|
||||||
assert_template_result '42', template, 'thing' => hash
|
assert_template_result "42", template, "thing" => hash
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_sort_calls_to_liquid
|
def test_sort_calls_to_liquid
|
||||||
t = TestThing.new
|
t = TestThing.new
|
||||||
Liquid::Template.parse('{{ foo | sort: "whatever" }}').render('foo' => [t])
|
Liquid::Template.parse('{{ foo | sort: "whatever" }}').render("foo" => [t])
|
||||||
assert t.foo.positive?
|
assert t.foo > 0
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_map_over_proc
|
def test_map_over_proc
|
||||||
drop = TestDrop.new
|
drop = TestDrop.new
|
||||||
p = proc { drop }
|
p = proc{ drop }
|
||||||
templ = '{{ procs | map: "test" }}'
|
templ = '{{ procs | map: "test" }}'
|
||||||
assert_template_result 'testfoo', templ, 'procs' => [p]
|
assert_template_result "testfoo", templ, "procs" => [p]
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_map_over_drops_returning_procs
|
def test_map_over_drops_returning_procs
|
||||||
drops = [
|
drops = [
|
||||||
{
|
{
|
||||||
'proc' => -> { 'foo' },
|
"proc" => ->{ "foo" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'proc' => -> { 'bar' },
|
"proc" => ->{ "bar" }
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
templ = '{{ drops | map: "proc" }}'
|
templ = '{{ drops | map: "proc" }}'
|
||||||
assert_template_result 'foobar', templ, 'drops' => drops
|
assert_template_result "foobar", templ, "drops" => drops
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_map_works_on_enumerables
|
def test_map_works_on_enumerables
|
||||||
assert_template_result '123', '{{ foo | map: "foo" }}', 'foo' => TestEnumerable.new
|
assert_template_result "123", '{{ foo | map: "foo" }}', "foo" => TestEnumerable.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_map_returns_empty_on_2d_input_array
|
def test_map_returns_empty_on_2d_input_array
|
||||||
foo = [
|
foo = [
|
||||||
[1],
|
[1],
|
||||||
[2],
|
[2],
|
||||||
[3],
|
[3]
|
||||||
]
|
]
|
||||||
|
|
||||||
assert_raises Liquid::ArgumentError do
|
assert_raises Liquid::ArgumentError do
|
||||||
@filters.map(foo, 'bar')
|
@filters.map(foo, "bar")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -435,7 +435,7 @@ class StandardFiltersTest < Minitest::Test
|
|||||||
foo = [
|
foo = [
|
||||||
[1],
|
[1],
|
||||||
[2],
|
[2],
|
||||||
[3],
|
[3]
|
||||||
]
|
]
|
||||||
assert_raises Liquid::ArgumentError do
|
assert_raises Liquid::ArgumentError do
|
||||||
@filters.map(foo, nil)
|
@filters.map(foo, nil)
|
||||||
@@ -443,7 +443,7 @@ class StandardFiltersTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_sort_works_on_enumerables
|
def test_sort_works_on_enumerables
|
||||||
assert_template_result '213', '{{ foo | sort: "bar" | map: "foo" }}', 'foo' => TestEnumerable.new
|
assert_template_result "213", '{{ foo | sort: "bar" | map: "foo" }}', "foo" => TestEnumerable.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_first_and_last_call_to_liquid
|
def test_first_and_last_call_to_liquid
|
||||||
@@ -452,37 +452,37 @@ class StandardFiltersTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_truncate_calls_to_liquid
|
def test_truncate_calls_to_liquid
|
||||||
assert_template_result 'wo...', '{{ foo | truncate: 5 }}', 'foo' => TestThing.new
|
assert_template_result "wo...", '{{ foo | truncate: 5 }}', "foo" => TestThing.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_date
|
def test_date
|
||||||
assert_equal 'May', @filters.date(Time.parse('2006-05-05 10:00:00'), '%B')
|
assert_equal 'May', @filters.date(Time.parse("2006-05-05 10:00:00"), "%B")
|
||||||
assert_equal 'June', @filters.date(Time.parse('2006-06-05 10:00:00'), '%B')
|
assert_equal 'June', @filters.date(Time.parse("2006-06-05 10:00:00"), "%B")
|
||||||
assert_equal 'July', @filters.date(Time.parse('2006-07-05 10:00:00'), '%B')
|
assert_equal 'July', @filters.date(Time.parse("2006-07-05 10:00:00"), "%B")
|
||||||
|
|
||||||
assert_equal 'May', @filters.date('2006-05-05 10:00:00', '%B')
|
assert_equal 'May', @filters.date("2006-05-05 10:00:00", "%B")
|
||||||
assert_equal 'June', @filters.date('2006-06-05 10:00:00', '%B')
|
assert_equal 'June', @filters.date("2006-06-05 10:00:00", "%B")
|
||||||
assert_equal 'July', @filters.date('2006-07-05 10:00:00', '%B')
|
assert_equal 'July', @filters.date("2006-07-05 10:00:00", "%B")
|
||||||
|
|
||||||
assert_equal '2006-07-05 10:00:00', @filters.date('2006-07-05 10:00:00', '')
|
assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", "")
|
||||||
assert_equal '2006-07-05 10:00:00', @filters.date('2006-07-05 10:00:00', '')
|
assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", "")
|
||||||
assert_equal '2006-07-05 10:00:00', @filters.date('2006-07-05 10:00:00', '')
|
assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", "")
|
||||||
assert_equal '2006-07-05 10:00:00', @filters.date('2006-07-05 10:00:00', nil)
|
assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", nil)
|
||||||
|
|
||||||
assert_equal '07/05/2006', @filters.date('2006-07-05 10:00:00', '%m/%d/%Y')
|
assert_equal '07/05/2006', @filters.date("2006-07-05 10:00:00", "%m/%d/%Y")
|
||||||
|
|
||||||
assert_equal '07/16/2004', @filters.date('Fri Jul 16 01:00:00 2004', '%m/%d/%Y')
|
assert_equal "07/16/2004", @filters.date("Fri Jul 16 01:00:00 2004", "%m/%d/%Y")
|
||||||
assert_equal Date.today.year.to_s, @filters.date('now', '%Y')
|
assert_equal Date.today.year.to_s, @filters.date('now', '%Y')
|
||||||
assert_equal Date.today.year.to_s, @filters.date('today', '%Y')
|
assert_equal Date.today.year.to_s, @filters.date('today', '%Y')
|
||||||
assert_equal Date.today.year.to_s, @filters.date('Today', '%Y')
|
assert_equal Date.today.year.to_s, @filters.date('Today', '%Y')
|
||||||
|
|
||||||
assert_nil @filters.date(nil, '%B')
|
assert_nil @filters.date(nil, "%B")
|
||||||
|
|
||||||
assert_equal '', @filters.date('', '%B')
|
assert_equal '', @filters.date('', "%B")
|
||||||
|
|
||||||
with_timezone('UTC') do
|
with_timezone("UTC") do
|
||||||
assert_equal '07/05/2006', @filters.date(1_152_098_955, '%m/%d/%Y')
|
assert_equal "07/05/2006", @filters.date(1152098955, "%m/%d/%Y")
|
||||||
assert_equal '07/05/2006', @filters.date('1152098955', '%m/%d/%Y')
|
assert_equal "07/05/2006", @filters.date("1152098955", "%m/%d/%Y")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -502,10 +502,10 @@ class StandardFiltersTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_remove
|
def test_remove
|
||||||
assert_equal ' ', @filters.remove('a a a a', 'a')
|
assert_equal ' ', @filters.remove("a a a a", 'a')
|
||||||
assert_equal ' ', @filters.remove('1 1 1 1', 1)
|
assert_equal ' ', @filters.remove("1 1 1 1", 1)
|
||||||
assert_equal 'a a a', @filters.remove_first('a a a a', 'a ')
|
assert_equal 'a a a', @filters.remove_first("a a a a", 'a ')
|
||||||
assert_equal ' 1 1 1', @filters.remove_first('1 1 1 1', 1)
|
assert_equal ' 1 1 1', @filters.remove_first("1 1 1 1", 1)
|
||||||
assert_template_result 'a a a', "{{ 'a a a a' | remove_first: 'a ' }}"
|
assert_template_result 'a a a', "{{ 'a a a a' | remove_first: 'a ' }}"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -514,148 +514,148 @@ class StandardFiltersTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_strip
|
def test_strip
|
||||||
assert_template_result 'ab c', '{{ source | strip }}', 'source' => ' ab c '
|
assert_template_result 'ab c', "{{ source | strip }}", 'source' => " ab c "
|
||||||
assert_template_result 'ab c', '{{ source | strip }}', 'source' => " \tab c \n \t"
|
assert_template_result 'ab c', "{{ source | strip }}", 'source' => " \tab c \n \t"
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_lstrip
|
def test_lstrip
|
||||||
assert_template_result 'ab c ', '{{ source | lstrip }}', 'source' => ' ab c '
|
assert_template_result 'ab c ', "{{ source | lstrip }}", 'source' => " ab c "
|
||||||
assert_template_result "ab c \n \t", '{{ source | lstrip }}', 'source' => " \tab c \n \t"
|
assert_template_result "ab c \n \t", "{{ source | lstrip }}", 'source' => " \tab c \n \t"
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_rstrip
|
def test_rstrip
|
||||||
assert_template_result ' ab c', '{{ source | rstrip }}', 'source' => ' ab c '
|
assert_template_result " ab c", "{{ source | rstrip }}", 'source' => " ab c "
|
||||||
assert_template_result " \tab c", '{{ source | rstrip }}', 'source' => " \tab c \n \t"
|
assert_template_result " \tab c", "{{ source | rstrip }}", 'source' => " \tab c \n \t"
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_strip_newlines
|
def test_strip_newlines
|
||||||
assert_template_result 'abc', '{{ source | strip_newlines }}', 'source' => "a\nb\nc"
|
assert_template_result 'abc', "{{ source | strip_newlines }}", 'source' => "a\nb\nc"
|
||||||
assert_template_result 'abc', '{{ source | strip_newlines }}', 'source' => "a\r\nb\nc"
|
assert_template_result 'abc', "{{ source | strip_newlines }}", 'source' => "a\r\nb\nc"
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_newlines_to_br
|
def test_newlines_to_br
|
||||||
assert_template_result "a<br />\nb<br />\nc", '{{ source | newline_to_br }}', 'source' => "a\nb\nc"
|
assert_template_result "a<br />\nb<br />\nc", "{{ source | newline_to_br }}", 'source' => "a\nb\nc"
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_plus
|
def test_plus
|
||||||
assert_template_result '2', '{{ 1 | plus:1 }}'
|
assert_template_result "2", "{{ 1 | plus:1 }}"
|
||||||
assert_template_result '2.0', "{{ '1' | plus:'1.0' }}"
|
assert_template_result "2.0", "{{ '1' | plus:'1.0' }}"
|
||||||
|
|
||||||
assert_template_result '5', "{{ price | plus:'2' }}", 'price' => NumberLikeThing.new(3)
|
assert_template_result "5", "{{ price | plus:'2' }}", 'price' => NumberLikeThing.new(3)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_minus
|
def test_minus
|
||||||
assert_template_result '4', '{{ input | minus:operand }}', 'input' => 5, 'operand' => 1
|
assert_template_result "4", "{{ input | minus:operand }}", 'input' => 5, 'operand' => 1
|
||||||
assert_template_result '2.3', "{{ '4.3' | minus:'2' }}"
|
assert_template_result "2.3", "{{ '4.3' | minus:'2' }}"
|
||||||
|
|
||||||
assert_template_result '5', "{{ price | minus:'2' }}", 'price' => NumberLikeThing.new(7)
|
assert_template_result "5", "{{ price | minus:'2' }}", 'price' => NumberLikeThing.new(7)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_abs
|
def test_abs
|
||||||
assert_template_result '17', '{{ 17 | abs }}'
|
assert_template_result "17", "{{ 17 | abs }}"
|
||||||
assert_template_result '17', '{{ -17 | abs }}'
|
assert_template_result "17", "{{ -17 | abs }}"
|
||||||
assert_template_result '17', "{{ '17' | abs }}"
|
assert_template_result "17", "{{ '17' | abs }}"
|
||||||
assert_template_result '17', "{{ '-17' | abs }}"
|
assert_template_result "17", "{{ '-17' | abs }}"
|
||||||
assert_template_result '0', '{{ 0 | abs }}'
|
assert_template_result "0", "{{ 0 | abs }}"
|
||||||
assert_template_result '0', "{{ '0' | abs }}"
|
assert_template_result "0", "{{ '0' | abs }}"
|
||||||
assert_template_result '17.42', '{{ 17.42 | abs }}'
|
assert_template_result "17.42", "{{ 17.42 | abs }}"
|
||||||
assert_template_result '17.42', '{{ -17.42 | abs }}'
|
assert_template_result "17.42", "{{ -17.42 | abs }}"
|
||||||
assert_template_result '17.42', "{{ '17.42' | abs }}"
|
assert_template_result "17.42", "{{ '17.42' | abs }}"
|
||||||
assert_template_result '17.42', "{{ '-17.42' | abs }}"
|
assert_template_result "17.42", "{{ '-17.42' | abs }}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_times
|
def test_times
|
||||||
assert_template_result '12', '{{ 3 | times:4 }}'
|
assert_template_result "12", "{{ 3 | times:4 }}"
|
||||||
assert_template_result '0', "{{ 'foo' | times:4 }}"
|
assert_template_result "0", "{{ 'foo' | times:4 }}"
|
||||||
assert_template_result '6', "{{ '2.1' | times:3 | replace: '.','-' | plus:0}}"
|
assert_template_result "6", "{{ '2.1' | times:3 | replace: '.','-' | plus:0}}"
|
||||||
assert_template_result '7.25', '{{ 0.0725 | times:100 }}'
|
assert_template_result "7.25", "{{ 0.0725 | times:100 }}"
|
||||||
assert_template_result '-7.25', '{{ "-0.0725" | times:100 }}'
|
assert_template_result "-7.25", '{{ "-0.0725" | times:100 }}'
|
||||||
assert_template_result '7.25', '{{ "-0.0725" | times: -100 }}'
|
assert_template_result "7.25", '{{ "-0.0725" | times: -100 }}'
|
||||||
assert_template_result '4', '{{ price | times:2 }}', 'price' => NumberLikeThing.new(2)
|
assert_template_result "4", "{{ price | times:2 }}", 'price' => NumberLikeThing.new(2)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_divided_by
|
def test_divided_by
|
||||||
assert_template_result '4', '{{ 12 | divided_by:3 }}'
|
assert_template_result "4", "{{ 12 | divided_by:3 }}"
|
||||||
assert_template_result '4', '{{ 14 | divided_by:3 }}'
|
assert_template_result "4", "{{ 14 | divided_by:3 }}"
|
||||||
|
|
||||||
assert_template_result '5', '{{ 15 | divided_by:3 }}'
|
assert_template_result "5", "{{ 15 | divided_by:3 }}"
|
||||||
assert_equal 'Liquid error: divided by 0', Template.parse('{{ 5 | divided_by:0 }}').render
|
assert_equal "Liquid error: divided by 0", Template.parse("{{ 5 | divided_by:0 }}").render
|
||||||
|
|
||||||
assert_template_result '0.5', '{{ 2.0 | divided_by:4 }}'
|
assert_template_result "0.5", "{{ 2.0 | divided_by:4 }}"
|
||||||
assert_raises(Liquid::ZeroDivisionError) do
|
assert_raises(Liquid::ZeroDivisionError) do
|
||||||
assert_template_result '4', '{{ 1 | modulo: 0 }}'
|
assert_template_result "4", "{{ 1 | modulo: 0 }}"
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_template_result '5', '{{ price | divided_by:2 }}', 'price' => NumberLikeThing.new(10)
|
assert_template_result "5", "{{ price | divided_by:2 }}", 'price' => NumberLikeThing.new(10)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_modulo
|
def test_modulo
|
||||||
assert_template_result '1', '{{ 3 | modulo:2 }}'
|
assert_template_result "1", "{{ 3 | modulo:2 }}"
|
||||||
assert_raises(Liquid::ZeroDivisionError) do
|
assert_raises(Liquid::ZeroDivisionError) do
|
||||||
assert_template_result '4', '{{ 1 | modulo: 0 }}'
|
assert_template_result "4", "{{ 1 | modulo: 0 }}"
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_template_result '1', '{{ price | modulo:2 }}', 'price' => NumberLikeThing.new(3)
|
assert_template_result "1", "{{ price | modulo:2 }}", 'price' => NumberLikeThing.new(3)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_round
|
def test_round
|
||||||
assert_template_result '5', '{{ input | round }}', 'input' => 4.6
|
assert_template_result "5", "{{ input | round }}", 'input' => 4.6
|
||||||
assert_template_result '4', "{{ '4.3' | round }}"
|
assert_template_result "4", "{{ '4.3' | round }}"
|
||||||
assert_template_result '4.56', '{{ input | round: 2 }}', 'input' => 4.5612
|
assert_template_result "4.56", "{{ input | round: 2 }}", 'input' => 4.5612
|
||||||
assert_raises(Liquid::FloatDomainError) do
|
assert_raises(Liquid::FloatDomainError) do
|
||||||
assert_template_result '4', '{{ 1.0 | divided_by: 0.0 | round }}'
|
assert_template_result "4", "{{ 1.0 | divided_by: 0.0 | round }}"
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_template_result '5', '{{ price | round }}', 'price' => NumberLikeThing.new(4.6)
|
assert_template_result "5", "{{ price | round }}", 'price' => NumberLikeThing.new(4.6)
|
||||||
assert_template_result '4', '{{ price | round }}', 'price' => NumberLikeThing.new(4.3)
|
assert_template_result "4", "{{ price | round }}", 'price' => NumberLikeThing.new(4.3)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_ceil
|
def test_ceil
|
||||||
assert_template_result '5', '{{ input | ceil }}', 'input' => 4.6
|
assert_template_result "5", "{{ input | ceil }}", 'input' => 4.6
|
||||||
assert_template_result '5', "{{ '4.3' | ceil }}"
|
assert_template_result "5", "{{ '4.3' | ceil }}"
|
||||||
assert_raises(Liquid::FloatDomainError) do
|
assert_raises(Liquid::FloatDomainError) do
|
||||||
assert_template_result '4', '{{ 1.0 | divided_by: 0.0 | ceil }}'
|
assert_template_result "4", "{{ 1.0 | divided_by: 0.0 | ceil }}"
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_template_result '5', '{{ price | ceil }}', 'price' => NumberLikeThing.new(4.6)
|
assert_template_result "5", "{{ price | ceil }}", 'price' => NumberLikeThing.new(4.6)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_floor
|
def test_floor
|
||||||
assert_template_result '4', '{{ input | floor }}', 'input' => 4.6
|
assert_template_result "4", "{{ input | floor }}", 'input' => 4.6
|
||||||
assert_template_result '4', "{{ '4.3' | floor }}"
|
assert_template_result "4", "{{ '4.3' | floor }}"
|
||||||
assert_raises(Liquid::FloatDomainError) do
|
assert_raises(Liquid::FloatDomainError) do
|
||||||
assert_template_result '4', '{{ 1.0 | divided_by: 0.0 | floor }}'
|
assert_template_result "4", "{{ 1.0 | divided_by: 0.0 | floor }}"
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_template_result '5', '{{ price | floor }}', 'price' => NumberLikeThing.new(5.4)
|
assert_template_result "5", "{{ price | floor }}", 'price' => NumberLikeThing.new(5.4)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_at_most
|
def test_at_most
|
||||||
assert_template_result '4', '{{ 5 | at_most:4 }}'
|
assert_template_result "4", "{{ 5 | at_most:4 }}"
|
||||||
assert_template_result '5', '{{ 5 | at_most:5 }}'
|
assert_template_result "5", "{{ 5 | at_most:5 }}"
|
||||||
assert_template_result '5', '{{ 5 | at_most:6 }}'
|
assert_template_result "5", "{{ 5 | at_most:6 }}"
|
||||||
|
|
||||||
assert_template_result '4.5', '{{ 4.5 | at_most:5 }}'
|
assert_template_result "4.5", "{{ 4.5 | at_most:5 }}"
|
||||||
assert_template_result '5', '{{ width | at_most:5 }}', 'width' => NumberLikeThing.new(6)
|
assert_template_result "5", "{{ width | at_most:5 }}", 'width' => NumberLikeThing.new(6)
|
||||||
assert_template_result '4', '{{ width | at_most:5 }}', 'width' => NumberLikeThing.new(4)
|
assert_template_result "4", "{{ width | at_most:5 }}", 'width' => NumberLikeThing.new(4)
|
||||||
assert_template_result '4', '{{ 5 | at_most: width }}', 'width' => NumberLikeThing.new(4)
|
assert_template_result "4", "{{ 5 | at_most: width }}", 'width' => NumberLikeThing.new(4)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_at_least
|
def test_at_least
|
||||||
assert_template_result '5', '{{ 5 | at_least:4 }}'
|
assert_template_result "5", "{{ 5 | at_least:4 }}"
|
||||||
assert_template_result '5', '{{ 5 | at_least:5 }}'
|
assert_template_result "5", "{{ 5 | at_least:5 }}"
|
||||||
assert_template_result '6', '{{ 5 | at_least:6 }}'
|
assert_template_result "6", "{{ 5 | at_least:6 }}"
|
||||||
|
|
||||||
assert_template_result '5', '{{ 4.5 | at_least:5 }}'
|
assert_template_result "5", "{{ 4.5 | at_least:5 }}"
|
||||||
assert_template_result '6', '{{ width | at_least:5 }}', 'width' => NumberLikeThing.new(6)
|
assert_template_result "6", "{{ width | at_least:5 }}", 'width' => NumberLikeThing.new(6)
|
||||||
assert_template_result '5', '{{ width | at_least:5 }}', 'width' => NumberLikeThing.new(4)
|
assert_template_result "5", "{{ width | at_least:5 }}", 'width' => NumberLikeThing.new(4)
|
||||||
assert_template_result '6', '{{ 5 | at_least: width }}', 'width' => NumberLikeThing.new(6)
|
assert_template_result "6", "{{ 5 | at_least: width }}", 'width' => NumberLikeThing.new(6)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_append
|
def test_append
|
||||||
assigns = { 'a' => 'bc', 'b' => 'd' }
|
assigns = { 'a' => 'bc', 'b' => 'd' }
|
||||||
assert_template_result('bcd', "{{ a | append: 'd'}}", assigns)
|
assert_template_result('bcd', "{{ a | append: 'd'}}", assigns)
|
||||||
assert_template_result('bcd', '{{ a | append: b}}', assigns)
|
assert_template_result('bcd', "{{ a | append: b}}", assigns)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_concat
|
def test_concat
|
||||||
@@ -663,7 +663,7 @@ class StandardFiltersTest < Minitest::Test
|
|||||||
assert_equal [1, 2, 'a'], @filters.concat([1, 2], ['a'])
|
assert_equal [1, 2, 'a'], @filters.concat([1, 2], ['a'])
|
||||||
assert_equal [1, 2, 10], @filters.concat([1, 2], [10])
|
assert_equal [1, 2, 10], @filters.concat([1, 2], [10])
|
||||||
|
|
||||||
assert_raises(Liquid::ArgumentError, 'concat filter requires an array argument') do
|
assert_raises(Liquid::ArgumentError, "concat filter requires an array argument") do
|
||||||
@filters.concat([1, 2], 10)
|
@filters.concat([1, 2], 10)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -671,16 +671,16 @@ class StandardFiltersTest < Minitest::Test
|
|||||||
def test_prepend
|
def test_prepend
|
||||||
assigns = { 'a' => 'bc', 'b' => 'a' }
|
assigns = { 'a' => 'bc', 'b' => 'a' }
|
||||||
assert_template_result('abc', "{{ a | prepend: 'a'}}", assigns)
|
assert_template_result('abc', "{{ a | prepend: 'a'}}", assigns)
|
||||||
assert_template_result('abc', '{{ a | prepend: b}}', assigns)
|
assert_template_result('abc', "{{ a | prepend: b}}", assigns)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_default
|
def test_default
|
||||||
assert_equal 'foo', @filters.default('foo', 'bar')
|
assert_equal "foo", @filters.default("foo", "bar")
|
||||||
assert_equal 'bar', @filters.default(nil, 'bar')
|
assert_equal "bar", @filters.default(nil, "bar")
|
||||||
assert_equal 'bar', @filters.default('', 'bar')
|
assert_equal "bar", @filters.default("", "bar")
|
||||||
assert_equal 'bar', @filters.default(false, 'bar')
|
assert_equal "bar", @filters.default(false, "bar")
|
||||||
assert_equal 'bar', @filters.default([], 'bar')
|
assert_equal "bar", @filters.default([], "bar")
|
||||||
assert_equal 'bar', @filters.default({}, 'bar')
|
assert_equal "bar", @filters.default({}, "bar")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_cannot_access_private_methods
|
def test_cannot_access_private_methods
|
||||||
@@ -694,74 +694,74 @@ class StandardFiltersTest < Minitest::Test
|
|||||||
|
|
||||||
def test_where
|
def test_where
|
||||||
input = [
|
input = [
|
||||||
{ 'handle' => 'alpha', 'ok' => true },
|
{ "handle" => "alpha", "ok" => true },
|
||||||
{ 'handle' => 'beta', 'ok' => false },
|
{ "handle" => "beta", "ok" => false },
|
||||||
{ 'handle' => 'gamma', 'ok' => false },
|
{ "handle" => "gamma", "ok" => false },
|
||||||
{ 'handle' => 'delta', 'ok' => true },
|
{ "handle" => "delta", "ok" => true }
|
||||||
]
|
]
|
||||||
|
|
||||||
expectation = [
|
expectation = [
|
||||||
{ 'handle' => 'alpha', 'ok' => true },
|
{ "handle" => "alpha", "ok" => true },
|
||||||
{ 'handle' => 'delta', 'ok' => true },
|
{ "handle" => "delta", "ok" => true }
|
||||||
]
|
]
|
||||||
|
|
||||||
assert_equal expectation, @filters.where(input, 'ok', true)
|
assert_equal expectation, @filters.where(input, "ok", true)
|
||||||
assert_equal expectation, @filters.where(input, 'ok')
|
assert_equal expectation, @filters.where(input, "ok")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_where_no_key_set
|
def test_where_no_key_set
|
||||||
input = [
|
input = [
|
||||||
{ 'handle' => 'alpha', 'ok' => true },
|
{ "handle" => "alpha", "ok" => true },
|
||||||
{ 'handle' => 'beta' },
|
{ "handle" => "beta" },
|
||||||
{ 'handle' => 'gamma' },
|
{ "handle" => "gamma" },
|
||||||
{ 'handle' => 'delta', 'ok' => true },
|
{ "handle" => "delta", "ok" => true }
|
||||||
]
|
]
|
||||||
|
|
||||||
expectation = [
|
expectation = [
|
||||||
{ 'handle' => 'alpha', 'ok' => true },
|
{ "handle" => "alpha", "ok" => true },
|
||||||
{ 'handle' => 'delta', 'ok' => true },
|
{ "handle" => "delta", "ok" => true }
|
||||||
]
|
]
|
||||||
|
|
||||||
assert_equal expectation, @filters.where(input, 'ok', true)
|
assert_equal expectation, @filters.where(input, "ok", true)
|
||||||
assert_equal expectation, @filters.where(input, 'ok')
|
assert_equal expectation, @filters.where(input, "ok")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_where_non_array_map_input
|
def test_where_non_array_map_input
|
||||||
assert_equal [{ 'a' => 'ok' }], @filters.where({ 'a' => 'ok' }, 'a', 'ok')
|
assert_equal [{ "a" => "ok" }], @filters.where({ "a" => "ok" }, "a", "ok")
|
||||||
assert_equal [], @filters.where({ 'a' => 'not ok' }, 'a', 'ok')
|
assert_equal [], @filters.where({ "a" => "not ok" }, "a", "ok")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_where_indexable_but_non_map_value
|
def test_where_indexable_but_non_map_value
|
||||||
assert_raises(Liquid::ArgumentError) { @filters.where(1, 'ok', true) }
|
assert_raises(Liquid::ArgumentError) { @filters.where(1, "ok", true) }
|
||||||
assert_raises(Liquid::ArgumentError) { @filters.where(1, 'ok') }
|
assert_raises(Liquid::ArgumentError) { @filters.where(1, "ok") }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_where_non_boolean_value
|
def test_where_non_boolean_value
|
||||||
input = [
|
input = [
|
||||||
{ 'message' => 'Bonjour!', 'language' => 'French' },
|
{ "message" => "Bonjour!", "language" => "French" },
|
||||||
{ 'message' => 'Hello!', 'language' => 'English' },
|
{ "message" => "Hello!", "language" => "English" },
|
||||||
{ 'message' => 'Hallo!', 'language' => 'German' },
|
{ "message" => "Hallo!", "language" => "German" }
|
||||||
]
|
]
|
||||||
|
|
||||||
assert_equal [{ 'message' => 'Bonjour!', 'language' => 'French' }], @filters.where(input, 'language', 'French')
|
assert_equal [{ "message" => "Bonjour!", "language" => "French" }], @filters.where(input, "language", "French")
|
||||||
assert_equal [{ 'message' => 'Hallo!', 'language' => 'German' }], @filters.where(input, 'language', 'German')
|
assert_equal [{ "message" => "Hallo!", "language" => "German" }], @filters.where(input, "language", "German")
|
||||||
assert_equal [{ 'message' => 'Hello!', 'language' => 'English' }], @filters.where(input, 'language', 'English')
|
assert_equal [{ "message" => "Hello!", "language" => "English" }], @filters.where(input, "language", "English")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_where_array_of_only_unindexable_values
|
def test_where_array_of_only_unindexable_values
|
||||||
assert_nil @filters.where([nil], 'ok', true)
|
assert_nil @filters.where([nil], "ok", true)
|
||||||
assert_nil @filters.where([nil], 'ok')
|
assert_nil @filters.where([nil], "ok")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_where_no_target_value
|
def test_where_no_target_value
|
||||||
input = [
|
input = [
|
||||||
{ 'foo' => false },
|
{ "foo" => false },
|
||||||
{ 'foo' => true },
|
{ "foo" => true },
|
||||||
{ 'foo' => 'for sure' },
|
{ "foo" => "for sure" },
|
||||||
{ 'bar' => true },
|
{ "bar" => true }
|
||||||
]
|
]
|
||||||
|
|
||||||
assert_equal [{ 'foo' => true }, { 'foo' => 'for sure' }], @filters.where(input, 'foo')
|
assert_equal [{ "foo" => true }, { "foo" => "for sure" }], @filters.where(input, "foo")
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class BreakTagTest < Minitest::Test
|
class BreakTagTest < Minitest::Test
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class ContinueTagTest < Minitest::Test
|
class ContinueTagTest < Minitest::Test
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class ThingWithValue < Liquid::Drop
|
class ThingWithValue < Liquid::Drop
|
||||||
@@ -25,16 +23,16 @@ class ForTagTest < Minitest::Test
|
|||||||
yo
|
yo
|
||||||
|
|
||||||
HERE
|
HERE
|
||||||
template = <<~HERE
|
template = <<HERE
|
||||||
{%for item in array%}
|
{%for item in array%}
|
||||||
yo
|
yo
|
||||||
{%endfor%}
|
{%endfor%}
|
||||||
HERE
|
HERE
|
||||||
assert_template_result(expected, template, 'array' => [1, 2, 3])
|
assert_template_result(expected, template, 'array' => [1, 2, 3])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_for_reversed
|
def test_for_reversed
|
||||||
assigns = { 'array' => [1, 2, 3] }
|
assigns = { 'array' => [ 1, 2, 3] }
|
||||||
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
|
||||||
|
|
||||||
@@ -42,31 +40,31 @@ HERE
|
|||||||
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%}')
|
||||||
|
|
||||||
assert_raises(Liquid::ArgumentError) do
|
assert_raises(Liquid::ArgumentError) do
|
||||||
Template.parse('{% for i in (a..2) %}{% endfor %}').render!('a' => [1, 2])
|
Template.parse('{% for i in (a..2) %}{% endfor %}').render!("a" => [1, 2])
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_template_result(' 0 1 2 3 ', '{% for item in (a..3) %} {{item}} {% endfor %}', 'a' => 'invalid integer')
|
assert_template_result(' 0 1 2 3 ', '{% for item in (a..3) %} {{item}} {% endfor %}', "a" => "invalid integer")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_for_with_variable_range
|
def test_for_with_variable_range
|
||||||
assert_template_result(' 1 2 3 ', '{%for item in (1..foobar) %} {{item}} {%endfor%}', 'foobar' => 3)
|
assert_template_result(' 1 2 3 ', '{%for item in (1..foobar) %} {{item}} {%endfor%}', "foobar" => 3)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_for_with_hash_value_range
|
def test_for_with_hash_value_range
|
||||||
foobar = { 'value' => 3 }
|
foobar = { "value" => 3 }
|
||||||
assert_template_result(' 1 2 3 ', '{%for item in (1..foobar.value) %} {{item}} {%endfor%}', 'foobar' => foobar)
|
assert_template_result(' 1 2 3 ', '{%for item in (1..foobar.value) %} {{item}} {%endfor%}', "foobar" => foobar)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_for_with_drop_value_range
|
def test_for_with_drop_value_range
|
||||||
foobar = ThingWithValue.new
|
foobar = ThingWithValue.new
|
||||||
assert_template_result(' 1 2 3 ', '{%for item in (1..foobar.value) %} {{item}} {%endfor%}', 'foobar' => foobar)
|
assert_template_result(' 1 2 3 ', '{%for item in (1..foobar.value) %} {{item}} {%endfor%}', "foobar" => foobar)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_for_with_variable
|
def test_for_with_variable
|
||||||
assert_template_result(' 1 2 3 ', '{%for item in array%} {{item}} {%endfor%}', 'array' => [1, 2, 3])
|
assert_template_result(' 1 2 3 ', '{%for item in array%} {{item}} {%endfor%}', 'array' => [1, 2, 3])
|
||||||
assert_template_result('123', '{%for item in array%}{{item}}{%endfor%}', 'array' => [1, 2, 3])
|
assert_template_result('123', '{%for item in array%}{{item}}{%endfor%}', 'array' => [1, 2, 3])
|
||||||
assert_template_result('123', '{% for item in array %}{{item}}{% endfor %}', 'array' => [1, 2, 3])
|
assert_template_result('123', '{% for item in array %}{{item}}{% endfor %}', 'array' => [1, 2, 3])
|
||||||
assert_template_result('abcd', '{%for item in array%}{{item}}{%endfor%}', 'array' => %w[a b c d])
|
assert_template_result('abcd', '{%for item in array%}{{item}}{%endfor%}', 'array' => ['a', 'b', 'c', 'd'])
|
||||||
assert_template_result('a b c', '{%for item in array%}{{item}}{%endfor%}', 'array' => ['a', ' ', 'b', ' ', 'c'])
|
assert_template_result('a b c', '{%for item in array%}{{item}}{%endfor%}', 'array' => ['a', ' ', 'b', ' ', 'c'])
|
||||||
assert_template_result('abc', '{%for item in array%}{{item}}{%endfor%}', 'array' => ['a', '', 'b', '', 'c'])
|
assert_template_result('abc', '{%for item in array%}{{item}}{%endfor%}', 'array' => ['a', '', 'b', '', 'c'])
|
||||||
end
|
end
|
||||||
@@ -74,8 +72,8 @@ HERE
|
|||||||
def test_for_helpers
|
def test_for_helpers
|
||||||
assigns = { 'array' => [1, 2, 3] }
|
assigns = { 'array' => [1, 2, 3] }
|
||||||
assert_template_result(' 1/3 2/3 3/3 ',
|
assert_template_result(' 1/3 2/3 3/3 ',
|
||||||
'{%for item in array%} {{forloop.index}}/{{forloop.length}} {%endfor%}',
|
'{%for item in array%} {{forloop.index}}/{{forloop.length}} {%endfor%}',
|
||||||
assigns)
|
assigns)
|
||||||
assert_template_result(' 1 2 3 ', '{%for item in array%} {{forloop.index}} {%endfor%}', assigns)
|
assert_template_result(' 1 2 3 ', '{%for item in array%} {{forloop.index}} {%endfor%}', assigns)
|
||||||
assert_template_result(' 0 1 2 ', '{%for item in array%} {{forloop.index0}} {%endfor%}', assigns)
|
assert_template_result(' 0 1 2 ', '{%for item in array%} {{forloop.index0}} {%endfor%}', assigns)
|
||||||
assert_template_result(' 2 1 0 ', '{%for item in array%} {{forloop.rindex0}} {%endfor%}', assigns)
|
assert_template_result(' 2 1 0 ', '{%for item in array%} {{forloop.rindex0}} {%endfor%}', assigns)
|
||||||
@@ -87,8 +85,8 @@ HERE
|
|||||||
def test_for_and_if
|
def test_for_and_if
|
||||||
assigns = { 'array' => [1, 2, 3] }
|
assigns = { 'array' => [1, 2, 3] }
|
||||||
assert_template_result('+--',
|
assert_template_result('+--',
|
||||||
'{%for item in array%}{% if forloop.first %}+{% else %}-{% endif %}{%endfor%}',
|
'{%for item in array%}{% if forloop.first %}+{% else %}-{% endif %}{%endfor%}',
|
||||||
assigns)
|
assigns)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_for_else
|
def test_for_else
|
||||||
@@ -116,7 +114,7 @@ HERE
|
|||||||
exception = assert_raises(Liquid::ArgumentError) do
|
exception = assert_raises(Liquid::ArgumentError) do
|
||||||
Template.parse(template).render!(assigns)
|
Template.parse(template).render!(assigns)
|
||||||
end
|
end
|
||||||
assert_equal('Liquid error: invalid integer', exception.message)
|
assert_equal("Liquid error: invalid integer", exception.message)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_limiting_with_invalid_offset
|
def test_limiting_with_invalid_offset
|
||||||
@@ -130,7 +128,7 @@ HERE
|
|||||||
exception = assert_raises(Liquid::ArgumentError) do
|
exception = assert_raises(Liquid::ArgumentError) do
|
||||||
Template.parse(template).render!(assigns)
|
Template.parse(template).render!(assigns)
|
||||||
end
|
end
|
||||||
assert_equal('Liquid error: invalid integer', exception.message)
|
assert_equal("Liquid error: invalid integer", exception.message)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_dynamic_variable_limiting
|
def test_dynamic_variable_limiting
|
||||||
@@ -159,14 +157,14 @@ HERE
|
|||||||
{%for i in array.items offset:continue limit: 3 %}{{i}}{%endfor%}
|
{%for i in array.items offset:continue limit: 3 %}{{i}}{%endfor%}
|
||||||
next
|
next
|
||||||
{%for i in array.items offset:continue limit: 3 %}{{i}}{%endfor%}
|
{%for i in array.items offset:continue limit: 3 %}{{i}}{%endfor%}
|
||||||
MKUP
|
MKUP
|
||||||
expected = <<-XPCTD
|
expected = <<-XPCTD
|
||||||
123
|
123
|
||||||
next
|
next
|
||||||
456
|
456
|
||||||
next
|
next
|
||||||
789
|
789
|
||||||
XPCTD
|
XPCTD
|
||||||
assert_template_result(expected, markup, assigns)
|
assert_template_result(expected, markup, assigns)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -178,14 +176,14 @@ HERE
|
|||||||
{%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%}
|
{%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%}
|
||||||
next
|
next
|
||||||
{%for i in array.items offset:continue limit:1 %}{{i}}{%endfor%}
|
{%for i in array.items offset:continue limit:1 %}{{i}}{%endfor%}
|
||||||
MKUP
|
MKUP
|
||||||
expected = <<-XPCTD
|
expected = <<-XPCTD
|
||||||
123
|
123
|
||||||
next
|
next
|
||||||
456
|
456
|
||||||
next
|
next
|
||||||
7
|
7
|
||||||
XPCTD
|
XPCTD
|
||||||
assert_template_result(expected, markup, assigns)
|
assert_template_result(expected, markup, assigns)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -197,14 +195,14 @@ HERE
|
|||||||
{%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%}
|
{%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%}
|
||||||
next
|
next
|
||||||
{%for i in array.items offset:continue limit:1000 %}{{i}}{%endfor%}
|
{%for i in array.items offset:continue limit:1000 %}{{i}}{%endfor%}
|
||||||
MKUP
|
MKUP
|
||||||
expected = <<-XPCTD
|
expected = <<-XPCTD
|
||||||
123
|
123
|
||||||
next
|
next
|
||||||
456
|
456
|
||||||
next
|
next
|
||||||
7890
|
7890
|
||||||
XPCTD
|
XPCTD
|
||||||
assert_template_result(expected, markup, assigns)
|
assert_template_result(expected, markup, assigns)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -227,19 +225,19 @@ HERE
|
|||||||
assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] } }
|
assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] } }
|
||||||
|
|
||||||
markup = '{% for i in array.items %}{% break %}{% endfor %}'
|
markup = '{% for i in array.items %}{% break %}{% endfor %}'
|
||||||
expected = ''
|
expected = ""
|
||||||
assert_template_result(expected, markup, assigns)
|
assert_template_result(expected, markup, assigns)
|
||||||
|
|
||||||
markup = '{% for i in array.items %}{{ i }}{% break %}{% endfor %}'
|
markup = '{% for i in array.items %}{{ i }}{% break %}{% endfor %}'
|
||||||
expected = '1'
|
expected = "1"
|
||||||
assert_template_result(expected, markup, assigns)
|
assert_template_result(expected, markup, assigns)
|
||||||
|
|
||||||
markup = '{% for i in array.items %}{% break %}{{ i }}{% endfor %}'
|
markup = '{% for i in array.items %}{% break %}{{ i }}{% endfor %}'
|
||||||
expected = ''
|
expected = ""
|
||||||
assert_template_result(expected, markup, assigns)
|
assert_template_result(expected, markup, assigns)
|
||||||
|
|
||||||
markup = '{% for i in array.items %}{{ i }}{% if i > 3 %}{% break %}{% endif %}{% endfor %}'
|
markup = '{% for i in array.items %}{{ i }}{% if i > 3 %}{% break %}{% endif %}{% endfor %}'
|
||||||
expected = '1234'
|
expected = "1234"
|
||||||
assert_template_result(expected, markup, assigns)
|
assert_template_result(expected, markup, assigns)
|
||||||
|
|
||||||
# tests to ensure it only breaks out of the local for loop
|
# tests to ensure it only breaks out of the local for loop
|
||||||
@@ -267,23 +265,23 @@ HERE
|
|||||||
assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5] } }
|
assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5] } }
|
||||||
|
|
||||||
markup = '{% for i in array.items %}{% continue %}{% endfor %}'
|
markup = '{% for i in array.items %}{% continue %}{% endfor %}'
|
||||||
expected = ''
|
expected = ""
|
||||||
assert_template_result(expected, markup, assigns)
|
assert_template_result(expected, markup, assigns)
|
||||||
|
|
||||||
markup = '{% for i in array.items %}{{ i }}{% continue %}{% endfor %}'
|
markup = '{% for i in array.items %}{{ i }}{% continue %}{% endfor %}'
|
||||||
expected = '12345'
|
expected = "12345"
|
||||||
assert_template_result(expected, markup, assigns)
|
assert_template_result(expected, markup, assigns)
|
||||||
|
|
||||||
markup = '{% for i in array.items %}{% continue %}{{ i }}{% endfor %}'
|
markup = '{% for i in array.items %}{% continue %}{{ i }}{% endfor %}'
|
||||||
expected = ''
|
expected = ""
|
||||||
assert_template_result(expected, markup, assigns)
|
assert_template_result(expected, markup, assigns)
|
||||||
|
|
||||||
markup = '{% for i in array.items %}{% if i > 3 %}{% continue %}{% endif %}{{ i }}{% endfor %}'
|
markup = '{% for i in array.items %}{% if i > 3 %}{% continue %}{% endif %}{{ i }}{% endfor %}'
|
||||||
expected = '123'
|
expected = "123"
|
||||||
assert_template_result(expected, markup, assigns)
|
assert_template_result(expected, markup, assigns)
|
||||||
|
|
||||||
markup = '{% for i in array.items %}{% if i == 3 %}{% continue %}{% else %}{{ i }}{% endif %}{% endfor %}'
|
markup = '{% for i in array.items %}{% if i == 3 %}{% continue %}{% else %}{{ i }}{% endif %}{% endfor %}'
|
||||||
expected = '1245'
|
expected = "1245"
|
||||||
assert_template_result(expected, markup, assigns)
|
assert_template_result(expected, markup, assigns)
|
||||||
|
|
||||||
# tests to ensure it only continues the local for loop and not all of them.
|
# tests to ensure it only continues the local for loop and not all of them.
|
||||||
@@ -312,41 +310,41 @@ HERE
|
|||||||
# the functionality for backwards compatibility
|
# the functionality for backwards compatibility
|
||||||
|
|
||||||
assert_template_result('test string',
|
assert_template_result('test string',
|
||||||
'{%for val in string%}{{val}}{%endfor%}',
|
'{%for val in string%}{{val}}{%endfor%}',
|
||||||
'string' => 'test string')
|
'string' => "test string")
|
||||||
|
|
||||||
assert_template_result('test string',
|
assert_template_result('test string',
|
||||||
'{%for val in string limit:1%}{{val}}{%endfor%}',
|
'{%for val in string limit:1%}{{val}}{%endfor%}',
|
||||||
'string' => 'test string')
|
'string' => "test string")
|
||||||
|
|
||||||
assert_template_result('val-string-1-1-0-1-0-true-true-test string',
|
assert_template_result('val-string-1-1-0-1-0-true-true-test string',
|
||||||
'{%for val in string%}' \
|
'{%for val in string%}' \
|
||||||
'{{forloop.name}}-' \
|
'{{forloop.name}}-' \
|
||||||
'{{forloop.index}}-' \
|
'{{forloop.index}}-' \
|
||||||
'{{forloop.length}}-' \
|
'{{forloop.length}}-' \
|
||||||
'{{forloop.index0}}-' \
|
'{{forloop.index0}}-' \
|
||||||
'{{forloop.rindex}}-' \
|
'{{forloop.rindex}}-' \
|
||||||
'{{forloop.rindex0}}-' \
|
'{{forloop.rindex0}}-' \
|
||||||
'{{forloop.first}}-' \
|
'{{forloop.first}}-' \
|
||||||
'{{forloop.last}}-' \
|
'{{forloop.last}}-' \
|
||||||
'{{val}}{%endfor%}',
|
'{{val}}{%endfor%}',
|
||||||
'string' => 'test string')
|
'string' => "test string")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_for_parentloop_references_parent_loop
|
def test_for_parentloop_references_parent_loop
|
||||||
assert_template_result('1.1 1.2 1.3 2.1 2.2 2.3 ',
|
assert_template_result('1.1 1.2 1.3 2.1 2.2 2.3 ',
|
||||||
'{% for inner in outer %}{% for k in inner %}' \
|
'{% for inner in outer %}{% for k in inner %}' \
|
||||||
'{{ forloop.parentloop.index }}.{{ forloop.index }} ' \
|
'{{ forloop.parentloop.index }}.{{ forloop.index }} ' \
|
||||||
'{% endfor %}{% endfor %}',
|
'{% endfor %}{% endfor %}',
|
||||||
'outer' => [[1, 1, 1], [1, 1, 1]])
|
'outer' => [[1, 1, 1], [1, 1, 1]])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_for_parentloop_nil_when_not_present
|
def test_for_parentloop_nil_when_not_present
|
||||||
assert_template_result('.1 .2 ',
|
assert_template_result('.1 .2 ',
|
||||||
'{% for inner in outer %}' \
|
'{% for inner in outer %}' \
|
||||||
'{{ forloop.parentloop.index }}.{{ forloop.index }} ' \
|
'{{ forloop.parentloop.index }}.{{ forloop.index }} ' \
|
||||||
'{% endfor %}',
|
'{% endfor %}',
|
||||||
'outer' => [[1, 1, 1], [1, 1, 1]])
|
'outer' => [[1, 1, 1], [1, 1, 1]])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_inner_for_over_empty_input
|
def test_inner_for_over_empty_input
|
||||||
@@ -354,7 +352,7 @@ HERE
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_blank_string_not_iterable
|
def test_blank_string_not_iterable
|
||||||
assert_template_result('', '{% for char in characters %}I WILL NOT BE OUTPUT{% endfor %}', 'characters' => '')
|
assert_template_result('', "{% for char in characters %}I WILL NOT BE OUTPUT{% endfor %}", 'characters' => '')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_bad_variable_naming_in_for_loop
|
def test_bad_variable_naming_in_for_loop
|
||||||
@@ -370,6 +368,23 @@ HERE
|
|||||||
assert_template_result(expected, template, assigns)
|
assert_template_result(expected, template, assigns)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_overwriting_internal_variable
|
||||||
|
template = <<-HEREDOC
|
||||||
|
{% assign forloop = 'first' %}
|
||||||
|
|
||||||
|
{% for item in items %}
|
||||||
|
{{ forloop }}
|
||||||
|
{% assign forloop = 'second' %}
|
||||||
|
{{ forloop }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{{ forloop }}
|
||||||
|
HEREDOC
|
||||||
|
|
||||||
|
result = Liquid::Template.parse(template).render('items' => '1')
|
||||||
|
assert_equal 'Liquid::ForloopDrop Liquid::ForloopDrop second', result.split.map(&:strip).join(' ')
|
||||||
|
end
|
||||||
|
|
||||||
class LoaderDrop < Liquid::Drop
|
class LoaderDrop < Liquid::Drop
|
||||||
attr_accessor :each_called, :load_slice_called
|
attr_accessor :each_called, :load_slice_called
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class IfElseTagTest < Minitest::Test
|
class IfElseTagTest < Minitest::Test
|
||||||
@@ -8,7 +6,7 @@ class IfElseTagTest < Minitest::Test
|
|||||||
def test_if
|
def test_if
|
||||||
assert_template_result(' ', ' {% if false %} this text should not go into the output {% endif %} ')
|
assert_template_result(' ', ' {% if false %} this text should not go into the output {% endif %} ')
|
||||||
assert_template_result(' this text should go into the output ',
|
assert_template_result(' this text should go into the output ',
|
||||||
' {% if true %} this text should go into the output {% endif %} ')
|
' {% if true %} this text should go into the output {% endif %} ')
|
||||||
assert_template_result(' you rock ?', '{% if false %} you suck {% endif %} {% if true %} you rock {% endif %}?')
|
assert_template_result(' you rock ?', '{% if false %} you suck {% endif %} {% if true %} you rock {% endif %}?')
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -51,12 +49,12 @@ class IfElseTagTest < Minitest::Test
|
|||||||
|
|
||||||
def test_comparison_of_expressions_starting_with_and_or_or
|
def test_comparison_of_expressions_starting_with_and_or_or
|
||||||
assigns = { 'order' => { 'items_count' => 0 }, 'android' => { 'name' => 'Roy' } }
|
assigns = { 'order' => { 'items_count' => 0 }, 'android' => { 'name' => 'Roy' } }
|
||||||
assert_template_result('YES',
|
assert_template_result("YES",
|
||||||
"{% if android.name == 'Roy' %}YES{% endif %}",
|
"{% if android.name == 'Roy' %}YES{% endif %}",
|
||||||
assigns)
|
assigns)
|
||||||
assert_template_result('YES',
|
assert_template_result("YES",
|
||||||
'{% if order.items_count == 0 %}YES{% endif %}',
|
"{% if order.items_count == 0 %}YES{% endif %}",
|
||||||
assigns)
|
assigns)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_if_and
|
def test_if_and
|
||||||
@@ -77,14 +75,14 @@ class IfElseTagTest < Minitest::Test
|
|||||||
assert_template_result('', '{% if foo.bar %} NO {% endif %}', 'foo' => nil)
|
assert_template_result('', '{% if foo.bar %} NO {% endif %}', 'foo' => nil)
|
||||||
assert_template_result('', '{% if foo.bar %} NO {% endif %}', 'foo' => true)
|
assert_template_result('', '{% if foo.bar %} NO {% endif %}', 'foo' => true)
|
||||||
|
|
||||||
assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => 'text')
|
assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => "text")
|
||||||
assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => true)
|
assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => true)
|
||||||
assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => 1)
|
assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => 1)
|
||||||
assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => {})
|
assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => {})
|
||||||
assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => [])
|
assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => [])
|
||||||
assert_template_result(' YES ', '{% if "foo" %} YES {% endif %}')
|
assert_template_result(' YES ', '{% if "foo" %} YES {% endif %}')
|
||||||
assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => true })
|
assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => true })
|
||||||
assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => 'text' })
|
assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => "text" })
|
||||||
assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => 1 })
|
assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => 1 })
|
||||||
assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => {} })
|
assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => {} })
|
||||||
assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => [] })
|
assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => [] })
|
||||||
@@ -92,11 +90,11 @@ class IfElseTagTest < Minitest::Test
|
|||||||
assert_template_result(' YES ', '{% if var %} NO {% else %} YES {% endif %}', 'var' => false)
|
assert_template_result(' YES ', '{% if var %} NO {% else %} YES {% endif %}', 'var' => false)
|
||||||
assert_template_result(' YES ', '{% if var %} NO {% else %} YES {% endif %}', 'var' => nil)
|
assert_template_result(' YES ', '{% if var %} NO {% else %} YES {% endif %}', 'var' => nil)
|
||||||
assert_template_result(' YES ', '{% if var %} YES {% else %} NO {% endif %}', 'var' => true)
|
assert_template_result(' YES ', '{% if var %} YES {% else %} NO {% endif %}', 'var' => true)
|
||||||
assert_template_result(' YES ', '{% if "foo" %} YES {% else %} NO {% endif %}', 'var' => 'text')
|
assert_template_result(' YES ', '{% if "foo" %} YES {% else %} NO {% endif %}', 'var' => "text")
|
||||||
|
|
||||||
assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', 'foo' => { 'bar' => false })
|
assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', 'foo' => { 'bar' => false })
|
||||||
assert_template_result(' YES ', '{% if foo.bar %} YES {% else %} NO {% endif %}', 'foo' => { 'bar' => true })
|
assert_template_result(' YES ', '{% if foo.bar %} YES {% else %} NO {% endif %}', 'foo' => { 'bar' => true })
|
||||||
assert_template_result(' YES ', '{% if foo.bar %} YES {% else %} NO {% endif %}', 'foo' => { 'bar' => 'text' })
|
assert_template_result(' YES ', '{% if foo.bar %} YES {% else %} NO {% endif %}', 'foo' => { 'bar' => "text" })
|
||||||
assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', 'foo' => { 'notbar' => true })
|
assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', 'foo' => { 'notbar' => true })
|
||||||
assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', 'foo' => {})
|
assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', 'foo' => {})
|
||||||
assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', 'notfoo' => { 'bar' => true })
|
assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', 'notfoo' => { 'bar' => true })
|
||||||
@@ -134,7 +132,7 @@ class IfElseTagTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_syntax_error_no_variable
|
def test_syntax_error_no_variable
|
||||||
assert_raises(SyntaxError) { assert_template_result('', '{% if jerry == 1 %}') }
|
assert_raises(SyntaxError){ assert_template_result('', '{% if jerry == 1 %}') }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_syntax_error_no_expression
|
def test_syntax_error_no_expression
|
||||||
@@ -156,7 +154,7 @@ class IfElseTagTest < Minitest::Test
|
|||||||
Condition.operators['contains'] = :[]
|
Condition.operators['contains'] = :[]
|
||||||
|
|
||||||
assert_template_result('yes',
|
assert_template_result('yes',
|
||||||
%({% if 'gnomeslab-and-or-liquid' contains 'gnomeslab-and-or-liquid' %}yes{% endif %}))
|
%({% if 'gnomeslab-and-or-liquid' contains 'gnomeslab-and-or-liquid' %}yes{% endif %}))
|
||||||
ensure
|
ensure
|
||||||
Condition.operators['contains'] = original_op
|
Condition.operators['contains'] = original_op
|
||||||
end
|
end
|
||||||
@@ -168,7 +166,7 @@ class IfElseTagTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_multiple_conditions
|
def test_multiple_conditions
|
||||||
tpl = '{% if a or b and c %}true{% else %}false{% endif %}'
|
tpl = "{% if a or b and c %}true{% else %}false{% endif %}"
|
||||||
|
|
||||||
tests = {
|
tests = {
|
||||||
[true, true, true] => true,
|
[true, true, true] => true,
|
||||||
@@ -178,7 +176,7 @@ class IfElseTagTest < Minitest::Test
|
|||||||
[false, true, true] => true,
|
[false, true, true] => true,
|
||||||
[false, true, false] => false,
|
[false, true, false] => false,
|
||||||
[false, false, true] => false,
|
[false, false, true] => false,
|
||||||
[false, false, false] => false,
|
[false, false, false] => false
|
||||||
}
|
}
|
||||||
|
|
||||||
tests.each do |vals, expected|
|
tests.each do |vals, expected|
|
||||||
|
|||||||
@@ -1,39 +1,37 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class TestFileSystem
|
class TestFileSystem
|
||||||
def read_template_file(template_path)
|
def read_template_file(template_path)
|
||||||
case template_path
|
case template_path
|
||||||
when 'product'
|
when "product"
|
||||||
'Product: {{ product.title }} '
|
"Product: {{ product.title }} "
|
||||||
|
|
||||||
when 'locale_variables'
|
when "locale_variables"
|
||||||
'Locale: {{echo1}} {{echo2}}'
|
"Locale: {{echo1}} {{echo2}}"
|
||||||
|
|
||||||
when 'variant'
|
when "variant"
|
||||||
'Variant: {{ variant.title }}'
|
"Variant: {{ variant.title }}"
|
||||||
|
|
||||||
when 'nested_template'
|
when "nested_template"
|
||||||
"{% include 'header' %} {% include 'body' %} {% include 'footer' %}"
|
"{% include 'header' %} {% include 'body' %} {% include 'footer' %}"
|
||||||
|
|
||||||
when 'body'
|
when "body"
|
||||||
"body {% include 'body_detail' %}"
|
"body {% include 'body_detail' %}"
|
||||||
|
|
||||||
when 'nested_product_template'
|
when "nested_product_template"
|
||||||
"Product: {{ nested_product_template.title }} {%include 'details'%} "
|
"Product: {{ nested_product_template.title }} {%include 'details'%} "
|
||||||
|
|
||||||
when 'recursively_nested_template'
|
when "recursively_nested_template"
|
||||||
"-{% include 'recursively_nested_template' %}"
|
"-{% include 'recursively_nested_template' %}"
|
||||||
|
|
||||||
when 'pick_a_source'
|
when "pick_a_source"
|
||||||
'from TestFileSystem'
|
"from TestFileSystem"
|
||||||
|
|
||||||
when 'assignments'
|
when 'assignments'
|
||||||
"{% assign foo = 'bar' %}"
|
"{% assign foo = 'bar' %}"
|
||||||
|
|
||||||
when 'break'
|
when 'break'
|
||||||
'{% break %}'
|
"{% break %}"
|
||||||
|
|
||||||
else
|
else
|
||||||
template_path
|
template_path
|
||||||
@@ -42,14 +40,14 @@ class TestFileSystem
|
|||||||
end
|
end
|
||||||
|
|
||||||
class OtherFileSystem
|
class OtherFileSystem
|
||||||
def read_template_file(_template_path)
|
def read_template_file(template_path)
|
||||||
'from OtherFileSystem'
|
'from OtherFileSystem'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class CountingFileSystem
|
class CountingFileSystem
|
||||||
attr_reader :count
|
attr_reader :count
|
||||||
def read_template_file(_template_path)
|
def read_template_file(template_path)
|
||||||
@count ||= 0
|
@count ||= 0
|
||||||
@count += 1
|
@count += 1
|
||||||
'from CountingFileSystem'
|
'from CountingFileSystem'
|
||||||
@@ -57,19 +55,19 @@ class CountingFileSystem
|
|||||||
end
|
end
|
||||||
|
|
||||||
class CustomInclude < Liquid::Tag
|
class CustomInclude < Liquid::Tag
|
||||||
SYNTAX = /(#{Liquid::QUOTED_FRAGMENT}+)(\s+(?:with|for)\s+(#{Liquid::QUOTED_FRAGMENT}+))?/o.freeze
|
Syntax = /(#{Liquid::QuotedFragment}+)(\s+(?:with|for)\s+(#{Liquid::QuotedFragment}+))?/o
|
||||||
|
|
||||||
def initialize(tag_name, markup, tokens)
|
def initialize(tag_name, markup, tokens)
|
||||||
markup =~ SYNTAX
|
markup =~ Syntax
|
||||||
@template_name = Regexp.last_match(1)
|
@template_name = $1
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse(tokens); end
|
def parse(tokens)
|
||||||
|
end
|
||||||
|
|
||||||
def render_to_output_buffer(_context, output)
|
def render(context)
|
||||||
output << @template_name[1..-2]
|
@template_name[1..-2]
|
||||||
output
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -82,60 +80,60 @@ class IncludeTagTest < Minitest::Test
|
|||||||
|
|
||||||
def test_include_tag_looks_for_file_system_in_registers_first
|
def test_include_tag_looks_for_file_system_in_registers_first
|
||||||
assert_equal 'from OtherFileSystem',
|
assert_equal 'from OtherFileSystem',
|
||||||
Template.parse("{% include 'pick_a_source' %}").render!({}, registers: { file_system: OtherFileSystem.new })
|
Template.parse("{% include 'pick_a_source' %}").render!({}, registers: { file_system: OtherFileSystem.new })
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_include_tag_with
|
def test_include_tag_with
|
||||||
assert_template_result 'Product: Draft 151cm ',
|
assert_template_result "Product: Draft 151cm ",
|
||||||
"{% include 'product' with products[0] %}", 'products' => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }]
|
"{% include 'product' with products[0] %}", "products" => [ { 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' } ]
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_include_tag_with_default_name
|
def test_include_tag_with_default_name
|
||||||
assert_template_result 'Product: Draft 151cm ',
|
assert_template_result "Product: Draft 151cm ",
|
||||||
"{% include 'product' %}", 'product' => { 'title' => 'Draft 151cm' }
|
"{% include 'product' %}", "product" => { 'title' => 'Draft 151cm' }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_include_tag_for
|
def test_include_tag_for
|
||||||
assert_template_result 'Product: Draft 151cm Product: Element 155cm ',
|
assert_template_result "Product: Draft 151cm Product: Element 155cm ",
|
||||||
"{% include 'product' for products %}", 'products' => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }]
|
"{% include 'product' for products %}", "products" => [ { 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' } ]
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_include_tag_with_local_variables
|
def test_include_tag_with_local_variables
|
||||||
assert_template_result 'Locale: test123 ', "{% include 'locale_variables' echo1: 'test123' %}"
|
assert_template_result "Locale: test123 ", "{% include 'locale_variables' echo1: 'test123' %}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_include_tag_with_multiple_local_variables
|
def test_include_tag_with_multiple_local_variables
|
||||||
assert_template_result 'Locale: test123 test321',
|
assert_template_result "Locale: test123 test321",
|
||||||
"{% include 'locale_variables' echo1: 'test123', echo2: 'test321' %}"
|
"{% include 'locale_variables' echo1: 'test123', echo2: 'test321' %}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_include_tag_with_multiple_local_variables_from_context
|
def test_include_tag_with_multiple_local_variables_from_context
|
||||||
assert_template_result 'Locale: test123 test321',
|
assert_template_result "Locale: test123 test321",
|
||||||
"{% include 'locale_variables' echo1: echo1, echo2: more_echos.echo2 %}",
|
"{% include 'locale_variables' echo1: echo1, echo2: more_echos.echo2 %}",
|
||||||
'echo1' => 'test123', 'more_echos' => { 'echo2' => 'test321' }
|
'echo1' => 'test123', 'more_echos' => { "echo2" => 'test321' }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_included_templates_assigns_variables
|
def test_included_templates_assigns_variables
|
||||||
assert_template_result 'bar', "{% include 'assignments' %}{{ foo }}"
|
assert_template_result "bar", "{% include 'assignments' %}{{ foo }}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_nested_include_tag
|
def test_nested_include_tag
|
||||||
assert_template_result 'body body_detail', "{% include 'body' %}"
|
assert_template_result "body body_detail", "{% include 'body' %}"
|
||||||
|
|
||||||
assert_template_result 'header body body_detail footer', "{% include 'nested_template' %}"
|
assert_template_result "header body body_detail footer", "{% include 'nested_template' %}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_nested_include_with_variable
|
def test_nested_include_with_variable
|
||||||
assert_template_result 'Product: Draft 151cm details ',
|
assert_template_result "Product: Draft 151cm details ",
|
||||||
"{% include 'nested_product_template' with product %}", 'product' => { 'title' => 'Draft 151cm' }
|
"{% include 'nested_product_template' with product %}", "product" => { "title" => 'Draft 151cm' }
|
||||||
|
|
||||||
assert_template_result 'Product: Draft 151cm details Product: Element 155cm details ',
|
assert_template_result "Product: Draft 151cm details Product: Element 155cm details ",
|
||||||
"{% include 'nested_product_template' for products %}", 'products' => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }]
|
"{% include 'nested_product_template' for products %}", "products" => [{ "title" => 'Draft 151cm' }, { "title" => 'Element 155cm' }]
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_recursively_included_template_does_not_produce_endless_loop
|
def test_recursively_included_template_does_not_produce_endless_loop
|
||||||
infinite_file_system = Class.new do
|
infinite_file_system = Class.new do
|
||||||
def read_template_file(_template_path)
|
def read_template_file(template_path)
|
||||||
"-{% include 'loop' %}"
|
"-{% include 'loop' %}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -148,41 +146,41 @@ class IncludeTagTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_dynamically_choosen_template
|
def test_dynamically_choosen_template
|
||||||
assert_template_result 'Test123', '{% include template %}', 'template' => 'Test123'
|
assert_template_result "Test123", "{% include template %}", "template" => 'Test123'
|
||||||
assert_template_result 'Test321', '{% include template %}', 'template' => 'Test321'
|
assert_template_result "Test321", "{% include template %}", "template" => 'Test321'
|
||||||
|
|
||||||
assert_template_result 'Product: Draft 151cm ', '{% include template for product %}',
|
assert_template_result "Product: Draft 151cm ", "{% include template for product %}",
|
||||||
'template' => 'product', 'product' => { 'title' => 'Draft 151cm' }
|
"template" => 'product', 'product' => { 'title' => 'Draft 151cm' }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_include_tag_caches_second_read_of_same_partial
|
def test_include_tag_caches_second_read_of_same_partial
|
||||||
file_system = CountingFileSystem.new
|
file_system = CountingFileSystem.new
|
||||||
assert_equal 'from CountingFileSystemfrom CountingFileSystem',
|
assert_equal 'from CountingFileSystemfrom CountingFileSystem',
|
||||||
Template.parse("{% include 'pick_a_source' %}{% include 'pick_a_source' %}").render!({}, registers: { file_system: file_system })
|
Template.parse("{% include 'pick_a_source' %}{% include 'pick_a_source' %}").render!({}, registers: { file_system: file_system })
|
||||||
assert_equal 1, file_system.count
|
assert_equal 1, file_system.count
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_include_tag_doesnt_cache_partials_across_renders
|
def test_include_tag_doesnt_cache_partials_across_renders
|
||||||
file_system = CountingFileSystem.new
|
file_system = CountingFileSystem.new
|
||||||
assert_equal 'from CountingFileSystem',
|
assert_equal 'from CountingFileSystem',
|
||||||
Template.parse("{% include 'pick_a_source' %}").render!({}, registers: { file_system: file_system })
|
Template.parse("{% include 'pick_a_source' %}").render!({}, registers: { file_system: file_system })
|
||||||
assert_equal 1, file_system.count
|
assert_equal 1, file_system.count
|
||||||
|
|
||||||
assert_equal 'from CountingFileSystem',
|
assert_equal 'from CountingFileSystem',
|
||||||
Template.parse("{% include 'pick_a_source' %}").render!({}, registers: { file_system: file_system })
|
Template.parse("{% include 'pick_a_source' %}").render!({}, registers: { file_system: file_system })
|
||||||
assert_equal 2, file_system.count
|
assert_equal 2, file_system.count
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_include_tag_within_if_statement
|
def test_include_tag_within_if_statement
|
||||||
assert_template_result 'foo_if_true', "{% if true %}{% include 'foo_if_true' %}{% endif %}"
|
assert_template_result "foo_if_true", "{% if true %}{% include 'foo_if_true' %}{% endif %}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_custom_include_tag
|
def test_custom_include_tag
|
||||||
original_tag = Liquid::Template.tags['include']
|
original_tag = Liquid::Template.tags['include']
|
||||||
Liquid::Template.tags['include'] = CustomInclude
|
Liquid::Template.tags['include'] = CustomInclude
|
||||||
begin
|
begin
|
||||||
assert_equal 'custom_foo',
|
assert_equal "custom_foo",
|
||||||
Template.parse("{% include 'custom_foo' %}").render!
|
Template.parse("{% include 'custom_foo' %}").render!
|
||||||
ensure
|
ensure
|
||||||
Liquid::Template.tags['include'] = original_tag
|
Liquid::Template.tags['include'] = original_tag
|
||||||
end
|
end
|
||||||
@@ -192,8 +190,8 @@ class IncludeTagTest < Minitest::Test
|
|||||||
original_tag = Liquid::Template.tags['include']
|
original_tag = Liquid::Template.tags['include']
|
||||||
Liquid::Template.tags['include'] = CustomInclude
|
Liquid::Template.tags['include'] = CustomInclude
|
||||||
begin
|
begin
|
||||||
assert_equal 'custom_foo_if_true',
|
assert_equal "custom_foo_if_true",
|
||||||
Template.parse("{% if true %}{% include 'custom_foo_if_true' %}{% endif %}").render!
|
Template.parse("{% if true %}{% include 'custom_foo_if_true' %}{% endif %}").render!
|
||||||
ensure
|
ensure
|
||||||
Liquid::Template.tags['include'] = original_tag
|
Liquid::Template.tags['include'] = original_tag
|
||||||
end
|
end
|
||||||
@@ -209,16 +207,16 @@ class IncludeTagTest < Minitest::Test
|
|||||||
|
|
||||||
def test_passing_options_to_included_templates
|
def test_passing_options_to_included_templates
|
||||||
assert_raises(Liquid::SyntaxError) do
|
assert_raises(Liquid::SyntaxError) do
|
||||||
Template.parse('{% include template %}', error_mode: :strict).render!('template' => '{{ "X" || downcase }}')
|
Template.parse("{% include template %}", error_mode: :strict).render!("template" => '{{ "X" || downcase }}')
|
||||||
end
|
end
|
||||||
with_error_mode(:lax) do
|
with_error_mode(:lax) do
|
||||||
assert_equal 'x', Template.parse('{% include template %}', error_mode: :strict, include_options_blacklist: true).render!('template' => '{{ "X" || downcase }}')
|
assert_equal 'x', Template.parse("{% include template %}", error_mode: :strict, include_options_blacklist: true).render!("template" => '{{ "X" || downcase }}')
|
||||||
end
|
end
|
||||||
assert_raises(Liquid::SyntaxError) do
|
assert_raises(Liquid::SyntaxError) do
|
||||||
Template.parse('{% include template %}', error_mode: :strict, include_options_blacklist: [:locale]).render!('template' => '{{ "X" || downcase }}')
|
Template.parse("{% include template %}", error_mode: :strict, include_options_blacklist: [:locale]).render!("template" => '{{ "X" || downcase }}')
|
||||||
end
|
end
|
||||||
with_error_mode(:lax) do
|
with_error_mode(:lax) do
|
||||||
assert_equal 'x', Template.parse('{% include template %}', error_mode: :strict, include_options_blacklist: [:error_mode]).render!('template' => '{{ "X" || downcase }}')
|
assert_equal 'x', Template.parse("{% include template %}", error_mode: :strict, include_options_blacklist: [:error_mode]).render!("template" => '{{ "X" || downcase }}')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -234,11 +232,11 @@ class IncludeTagTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_including_via_variable_value
|
def test_including_via_variable_value
|
||||||
assert_template_result 'from TestFileSystem', "{% assign page = 'pick_a_source' %}{% include page %}"
|
assert_template_result "from TestFileSystem", "{% assign page = 'pick_a_source' %}{% include page %}"
|
||||||
|
|
||||||
assert_template_result 'Product: Draft 151cm ', "{% assign page = 'product' %}{% include page %}", 'product' => { 'title' => 'Draft 151cm' }
|
assert_template_result "Product: Draft 151cm ", "{% assign page = 'product' %}{% include page %}", "product" => { 'title' => 'Draft 151cm' }
|
||||||
|
|
||||||
assert_template_result 'Product: Draft 151cm ', "{% assign page = 'product' %}{% include page for foo %}", 'foo' => { 'title' => 'Draft 151cm' }
|
assert_template_result "Product: Draft 151cm ", "{% assign page = 'product' %}{% include page for foo %}", "foo" => { 'title' => 'Draft 151cm' }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_including_with_strict_variables
|
def test_including_with_strict_variables
|
||||||
@@ -249,7 +247,7 @@ class IncludeTagTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_break_through_include
|
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 }}{% break %}{{ i }}{% endfor %}"
|
||||||
assert_template_result '1', "{% for i in (1..3) %}{{ i }}{% include 'break' %}{{ i }}{% endfor %}"
|
assert_template_result "1", "{% for i in (1..3) %}{{ i }}{% include 'break' %}{{ i }}{% endfor %}"
|
||||||
end
|
end
|
||||||
end # IncludeTagTest
|
end # IncludeTagTest
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class IncrementTagTest < Minitest::Test
|
class IncrementTagTest < Minitest::Test
|
||||||
@@ -9,17 +7,17 @@ class IncrementTagTest < Minitest::Test
|
|||||||
assert_template_result('0', '{%increment port %}', {})
|
assert_template_result('0', '{%increment port %}', {})
|
||||||
assert_template_result('0 1', '{%increment port %} {%increment port%}', {})
|
assert_template_result('0 1', '{%increment port %} {%increment port%}', {})
|
||||||
assert_template_result('0 0 1 2 1',
|
assert_template_result('0 0 1 2 1',
|
||||||
'{%increment port %} {%increment starboard%} ' \
|
'{%increment port %} {%increment starboard%} ' \
|
||||||
'{%increment port %} {%increment port%} ' \
|
'{%increment port %} {%increment port%} ' \
|
||||||
'{%increment starboard %}', {})
|
'{%increment starboard %}', {})
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_dec
|
def test_dec
|
||||||
assert_template_result('9', '{%decrement port %}', 'port' => 10)
|
assert_template_result('9', '{%decrement port %}', { 'port' => 10 })
|
||||||
assert_template_result('-1 -2', '{%decrement port %} {%decrement port%}', {})
|
assert_template_result('-1 -2', '{%decrement port %} {%decrement port%}', {})
|
||||||
assert_template_result('1 5 2 2 5',
|
assert_template_result('1 5 2 2 5',
|
||||||
'{%increment port %} {%increment starboard%} ' \
|
'{%increment port %} {%increment starboard%} ' \
|
||||||
'{%increment port %} {%decrement port%} ' \
|
'{%increment port %} {%decrement port%} ' \
|
||||||
'{%decrement starboard %}', 'port' => 1, 'starboard' => 5)
|
'{%decrement starboard %}', { 'port' => 1, 'starboard' => 5 })
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class RawTagTest < Minitest::Test
|
class RawTagTest < Minitest::Test
|
||||||
@@ -7,7 +5,7 @@ class RawTagTest < Minitest::Test
|
|||||||
|
|
||||||
def test_tag_in_raw
|
def test_tag_in_raw
|
||||||
assert_template_result '{% comment %} test {% endcomment %}',
|
assert_template_result '{% comment %} test {% endcomment %}',
|
||||||
'{% raw %}{% comment %} test {% endcomment %}{% endraw %}'
|
'{% raw %}{% comment %} test {% endcomment %}{% endraw %}'
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_output_in_raw
|
def test_output_in_raw
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class StandardTagTest < Minitest::Test
|
class StandardTagTest < Minitest::Test
|
||||||
@@ -7,7 +5,7 @@ class StandardTagTest < Minitest::Test
|
|||||||
|
|
||||||
def test_no_transform
|
def test_no_transform
|
||||||
assert_template_result('this text should come out of the template without change...',
|
assert_template_result('this text should come out of the template without change...',
|
||||||
'this text should come out of the template without change...')
|
'this text should come out of the template without change...')
|
||||||
|
|
||||||
assert_template_result('blah', 'blah')
|
assert_template_result('blah', 'blah')
|
||||||
assert_template_result('<blah>', '<blah>')
|
assert_template_result('<blah>', '<blah>')
|
||||||
@@ -21,7 +19,7 @@ class StandardTagTest < Minitest::Test
|
|||||||
|
|
||||||
def test_has_a_block_which_does_nothing
|
def test_has_a_block_which_does_nothing
|
||||||
assert_template_result(%(the comment block should be removed .. right?),
|
assert_template_result(%(the comment block should be removed .. right?),
|
||||||
%(the comment block should be removed {%comment%} be gone.. {%endcomment%} .. right?))
|
%(the comment block should be removed {%comment%} be gone.. {%endcomment%} .. right?))
|
||||||
|
|
||||||
assert_template_result('', '{%comment%}{%endcomment%}')
|
assert_template_result('', '{%comment%}{%endcomment%}')
|
||||||
assert_template_result('', '{%comment%}{% endcomment %}')
|
assert_template_result('', '{%comment%}{% endcomment %}')
|
||||||
@@ -63,60 +61,60 @@ class StandardTagTest < Minitest::Test
|
|||||||
def test_capture
|
def test_capture
|
||||||
assigns = { 'var' => 'content' }
|
assigns = { 'var' => 'content' }
|
||||||
assert_template_result('content foo content foo ',
|
assert_template_result('content foo content foo ',
|
||||||
'{{ var2 }}{% capture var2 %}{{ var }} foo {% endcapture %}{{ var2 }}{{ var2 }}',
|
'{{ var2 }}{% capture var2 %}{{ var }} foo {% endcapture %}{{ var2 }}{{ var2 }}',
|
||||||
assigns)
|
assigns)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_capture_detects_bad_syntax
|
def test_capture_detects_bad_syntax
|
||||||
assert_raises(SyntaxError) do
|
assert_raises(SyntaxError) do
|
||||||
assert_template_result('content foo content foo ',
|
assert_template_result('content foo content foo ',
|
||||||
'{{ var2 }}{% capture %}{{ var }} foo {% endcapture %}{{ var2 }}{{ var2 }}',
|
'{{ var2 }}{% capture %}{{ var }} foo {% endcapture %}{{ var2 }}{{ var2 }}',
|
||||||
'var' => 'content')
|
{ 'var' => 'content' })
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_case
|
def test_case
|
||||||
assigns = { 'condition' => 2 }
|
assigns = { 'condition' => 2 }
|
||||||
assert_template_result(' its 2 ',
|
assert_template_result(' its 2 ',
|
||||||
'{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}',
|
'{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}',
|
||||||
assigns)
|
assigns)
|
||||||
|
|
||||||
assigns = { 'condition' => 1 }
|
assigns = { 'condition' => 1 }
|
||||||
assert_template_result(' its 1 ',
|
assert_template_result(' its 1 ',
|
||||||
'{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}',
|
'{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}',
|
||||||
assigns)
|
assigns)
|
||||||
|
|
||||||
assigns = { 'condition' => 3 }
|
assigns = { 'condition' => 3 }
|
||||||
assert_template_result('',
|
assert_template_result('',
|
||||||
'{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}',
|
'{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}',
|
||||||
assigns)
|
assigns)
|
||||||
|
|
||||||
assigns = { 'condition' => 'string here' }
|
assigns = { 'condition' => "string here" }
|
||||||
assert_template_result(' hit ',
|
assert_template_result(' hit ',
|
||||||
'{% case condition %}{% when "string here" %} hit {% endcase %}',
|
'{% case condition %}{% when "string here" %} hit {% endcase %}',
|
||||||
assigns)
|
assigns)
|
||||||
|
|
||||||
assigns = { 'condition' => 'bad string here' }
|
assigns = { 'condition' => "bad string here" }
|
||||||
assert_template_result('',
|
assert_template_result('',
|
||||||
'{% case condition %}{% when "string here" %} hit {% endcase %}',\
|
'{% case condition %}{% when "string here" %} hit {% endcase %}',\
|
||||||
assigns)
|
assigns)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_case_with_else
|
def test_case_with_else
|
||||||
assigns = { 'condition' => 5 }
|
assigns = { 'condition' => 5 }
|
||||||
assert_template_result(' hit ',
|
assert_template_result(' hit ',
|
||||||
'{% case condition %}{% when 5 %} hit {% else %} else {% endcase %}',
|
'{% case condition %}{% when 5 %} hit {% else %} else {% endcase %}',
|
||||||
assigns)
|
assigns)
|
||||||
|
|
||||||
assigns = { 'condition' => 6 }
|
assigns = { 'condition' => 6 }
|
||||||
assert_template_result(' else ',
|
assert_template_result(' else ',
|
||||||
'{% case condition %}{% when 5 %} hit {% else %} else {% endcase %}',
|
'{% case condition %}{% when 5 %} hit {% else %} else {% endcase %}',
|
||||||
assigns)
|
assigns)
|
||||||
|
|
||||||
assigns = { 'condition' => 6 }
|
assigns = { 'condition' => 6 }
|
||||||
assert_template_result(' else ',
|
assert_template_result(' else ',
|
||||||
'{% case condition %} {% when 5 %} hit {% else %} else {% endcase %}',
|
'{% case condition %} {% when 5 %} hit {% else %} else {% endcase %}',
|
||||||
assigns)
|
assigns)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_case_on_size
|
def test_case_on_size
|
||||||
@@ -130,87 +128,87 @@ class StandardTagTest < Minitest::Test
|
|||||||
|
|
||||||
def test_case_on_size_with_else
|
def test_case_on_size_with_else
|
||||||
assert_template_result('else',
|
assert_template_result('else',
|
||||||
'{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
|
'{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
|
||||||
'a' => [])
|
'a' => [])
|
||||||
|
|
||||||
assert_template_result('1',
|
assert_template_result('1',
|
||||||
'{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
|
'{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
|
||||||
'a' => [1])
|
'a' => [1])
|
||||||
|
|
||||||
assert_template_result('2',
|
assert_template_result('2',
|
||||||
'{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
|
'{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
|
||||||
'a' => [1, 1])
|
'a' => [1, 1])
|
||||||
|
|
||||||
assert_template_result('else',
|
assert_template_result('else',
|
||||||
'{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
|
'{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
|
||||||
'a' => [1, 1, 1])
|
'a' => [1, 1, 1])
|
||||||
|
|
||||||
assert_template_result('else',
|
assert_template_result('else',
|
||||||
'{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
|
'{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
|
||||||
'a' => [1, 1, 1, 1])
|
'a' => [1, 1, 1, 1])
|
||||||
|
|
||||||
assert_template_result('else',
|
assert_template_result('else',
|
||||||
'{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
|
'{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
|
||||||
'a' => [1, 1, 1, 1, 1])
|
'a' => [1, 1, 1, 1, 1])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_case_on_length_with_else
|
def test_case_on_length_with_else
|
||||||
assert_template_result('else',
|
assert_template_result('else',
|
||||||
'{% case a.empty? %}{% when true %}true{% when false %}false{% else %}else{% endcase %}',
|
'{% case a.empty? %}{% when true %}true{% when false %}false{% else %}else{% endcase %}',
|
||||||
{})
|
{})
|
||||||
|
|
||||||
assert_template_result('false',
|
assert_template_result('false',
|
||||||
'{% case false %}{% when true %}true{% when false %}false{% else %}else{% endcase %}',
|
'{% case false %}{% when true %}true{% when false %}false{% else %}else{% endcase %}',
|
||||||
{})
|
{})
|
||||||
|
|
||||||
assert_template_result('true',
|
assert_template_result('true',
|
||||||
'{% case true %}{% when true %}true{% when false %}false{% else %}else{% endcase %}',
|
'{% case true %}{% when true %}true{% when false %}false{% else %}else{% endcase %}',
|
||||||
{})
|
{})
|
||||||
|
|
||||||
assert_template_result('else',
|
assert_template_result('else',
|
||||||
'{% case NULL %}{% when true %}true{% when false %}false{% else %}else{% endcase %}',
|
'{% case NULL %}{% when true %}true{% when false %}false{% else %}else{% endcase %}',
|
||||||
{})
|
{})
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_assign_from_case
|
def test_assign_from_case
|
||||||
# Example from the shopify forums
|
# Example from the shopify forums
|
||||||
code = "{% case collection.handle %}{% when 'menswear-jackets' %}{% assign ptitle = 'menswear' %}{% when 'menswear-t-shirts' %}{% assign ptitle = 'menswear' %}{% else %}{% assign ptitle = 'womenswear' %}{% endcase %}{{ ptitle }}"
|
code = "{% case collection.handle %}{% when 'menswear-jackets' %}{% assign ptitle = 'menswear' %}{% when 'menswear-t-shirts' %}{% assign ptitle = 'menswear' %}{% else %}{% assign ptitle = 'womenswear' %}{% endcase %}{{ ptitle }}"
|
||||||
template = Liquid::Template.parse(code)
|
template = Liquid::Template.parse(code)
|
||||||
assert_equal 'menswear', template.render!('collection' => { 'handle' => 'menswear-jackets' })
|
assert_equal "menswear", template.render!("collection" => { 'handle' => 'menswear-jackets' })
|
||||||
assert_equal 'menswear', template.render!('collection' => { 'handle' => 'menswear-t-shirts' })
|
assert_equal "menswear", template.render!("collection" => { 'handle' => 'menswear-t-shirts' })
|
||||||
assert_equal 'womenswear', template.render!('collection' => { 'handle' => 'x' })
|
assert_equal "womenswear", template.render!("collection" => { 'handle' => 'x' })
|
||||||
assert_equal 'womenswear', template.render!('collection' => { 'handle' => 'y' })
|
assert_equal "womenswear", template.render!("collection" => { 'handle' => 'y' })
|
||||||
assert_equal 'womenswear', template.render!('collection' => { 'handle' => 'z' })
|
assert_equal "womenswear", template.render!("collection" => { 'handle' => 'z' })
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_case_when_or
|
def test_case_when_or
|
||||||
code = '{% case condition %}{% when 1 or 2 or 3 %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
|
code = '{% case condition %}{% when 1 or 2 or 3 %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
|
||||||
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 1)
|
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 1 })
|
||||||
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 2)
|
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 2 })
|
||||||
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 3)
|
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 3 })
|
||||||
assert_template_result(' its 4 ', code, 'condition' => 4)
|
assert_template_result(' its 4 ', code, { 'condition' => 4 })
|
||||||
assert_template_result('', code, 'condition' => 5)
|
assert_template_result('', code, { 'condition' => 5 })
|
||||||
|
|
||||||
code = '{% case condition %}{% when 1 or "string" or null %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
|
code = '{% case condition %}{% when 1 or "string" or null %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
|
||||||
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 1)
|
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 1 })
|
||||||
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 'string')
|
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 'string' })
|
||||||
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => nil)
|
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => nil })
|
||||||
assert_template_result('', code, 'condition' => 'something else')
|
assert_template_result('', code, { 'condition' => 'something else' })
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_case_when_comma
|
def test_case_when_comma
|
||||||
code = '{% case condition %}{% when 1, 2, 3 %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
|
code = '{% case condition %}{% when 1, 2, 3 %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
|
||||||
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 1)
|
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 1 })
|
||||||
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 2)
|
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 2 })
|
||||||
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 3)
|
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 3 })
|
||||||
assert_template_result(' its 4 ', code, 'condition' => 4)
|
assert_template_result(' its 4 ', code, { 'condition' => 4 })
|
||||||
assert_template_result('', code, 'condition' => 5)
|
assert_template_result('', code, { 'condition' => 5 })
|
||||||
|
|
||||||
code = '{% case condition %}{% when 1, "string", null %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
|
code = '{% case condition %}{% when 1, "string", null %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
|
||||||
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 1)
|
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 1 })
|
||||||
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 'string')
|
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 'string' })
|
||||||
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => nil)
|
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => nil })
|
||||||
assert_template_result('', code, 'condition' => 'something else')
|
assert_template_result('', code, { 'condition' => 'something else' })
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_assign
|
def test_assign
|
||||||
@@ -248,33 +246,33 @@ class StandardTagTest < Minitest::Test
|
|||||||
assert_template_result('one two one', '{%cycle "one", "two"%} {%cycle "one", "two"%} {%cycle "one", "two"%}')
|
assert_template_result('one two one', '{%cycle "one", "two"%} {%cycle "one", "two"%} {%cycle "one", "two"%}')
|
||||||
|
|
||||||
assert_template_result('text-align: left text-align: right',
|
assert_template_result('text-align: left text-align: right',
|
||||||
'{%cycle "text-align: left", "text-align: right" %} {%cycle "text-align: left", "text-align: right"%}')
|
'{%cycle "text-align: left", "text-align: right" %} {%cycle "text-align: left", "text-align: right"%}')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_multiple_cycles
|
def test_multiple_cycles
|
||||||
assert_template_result('1 2 1 1 2 3 1',
|
assert_template_result('1 2 1 1 2 3 1',
|
||||||
'{%cycle 1,2%} {%cycle 1,2%} {%cycle 1,2%} {%cycle 1,2,3%} {%cycle 1,2,3%} {%cycle 1,2,3%} {%cycle 1,2,3%}')
|
'{%cycle 1,2%} {%cycle 1,2%} {%cycle 1,2%} {%cycle 1,2,3%} {%cycle 1,2,3%} {%cycle 1,2,3%} {%cycle 1,2,3%}')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_multiple_named_cycles
|
def test_multiple_named_cycles
|
||||||
assert_template_result('one one two two one one',
|
assert_template_result('one one two two one one',
|
||||||
'{%cycle 1: "one", "two" %} {%cycle 2: "one", "two" %} {%cycle 1: "one", "two" %} {%cycle 2: "one", "two" %} {%cycle 1: "one", "two" %} {%cycle 2: "one", "two" %}')
|
'{%cycle 1: "one", "two" %} {%cycle 2: "one", "two" %} {%cycle 1: "one", "two" %} {%cycle 2: "one", "two" %} {%cycle 1: "one", "two" %} {%cycle 2: "one", "two" %}')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_multiple_named_cycles_with_names_from_context
|
def test_multiple_named_cycles_with_names_from_context
|
||||||
assigns = { 'var1' => 1, 'var2' => 2 }
|
assigns = { "var1" => 1, "var2" => 2 }
|
||||||
assert_template_result('one one two two one one',
|
assert_template_result('one one two two one one',
|
||||||
'{%cycle var1: "one", "two" %} {%cycle var2: "one", "two" %} {%cycle var1: "one", "two" %} {%cycle var2: "one", "two" %} {%cycle var1: "one", "two" %} {%cycle var2: "one", "two" %}', assigns)
|
'{%cycle var1: "one", "two" %} {%cycle var2: "one", "two" %} {%cycle var1: "one", "two" %} {%cycle var2: "one", "two" %} {%cycle var1: "one", "two" %} {%cycle var2: "one", "two" %}', assigns)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_size_of_array
|
def test_size_of_array
|
||||||
assigns = { 'array' => [1, 2, 3, 4] }
|
assigns = { "array" => [1, 2, 3, 4] }
|
||||||
assert_template_result('array has 4 elements', 'array has {{ array.size }} elements', assigns)
|
assert_template_result('array has 4 elements', "array has {{ array.size }} elements", assigns)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_size_of_hash
|
def test_size_of_hash
|
||||||
assigns = { 'hash' => { a: 1, b: 2, c: 3, d: 4 } }
|
assigns = { "hash" => { a: 1, b: 2, c: 3, d: 4 } }
|
||||||
assert_template_result('hash has 4 elements', 'hash has {{ hash.size }} elements', assigns)
|
assert_template_result('hash has 4 elements', "hash has {{ hash.size }} elements", assigns)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_illegal_symbols
|
def test_illegal_symbols
|
||||||
@@ -285,10 +283,10 @@ class StandardTagTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_ifchanged
|
def test_ifchanged
|
||||||
assigns = { 'array' => [1, 1, 2, 2, 3, 3] }
|
assigns = { 'array' => [ 1, 1, 2, 2, 3, 3] }
|
||||||
assert_template_result('123', '{%for item in array%}{%ifchanged%}{{item}}{% endifchanged %}{%endfor%}', assigns)
|
assert_template_result('123', '{%for item in array%}{%ifchanged%}{{item}}{% endifchanged %}{%endfor%}', assigns)
|
||||||
|
|
||||||
assigns = { 'array' => [1, 1, 1, 1] }
|
assigns = { 'array' => [ 1, 1, 1, 1] }
|
||||||
assert_template_result('1', '{%for item in array%}{%ifchanged%}{{item}}{% endifchanged %}{%endfor%}', assigns)
|
assert_template_result('1', '{%for item in array%}{%ifchanged%}{{item}}{% endifchanged %}{%endfor%}', assigns)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user