mirror of
https://github.com/kemko/liquid.git
synced 2026-01-03 16:55:40 +03:00
Compare commits
4 Commits
render-for
...
rubocop-up
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d0917493d | ||
|
|
ef8a6dcda1 | ||
|
|
0dd22af7d6 | ||
|
|
da9051eb18 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,6 +4,7 @@
|
|||||||
pkg
|
pkg
|
||||||
*.rbc
|
*.rbc
|
||||||
.rvmrc
|
.rvmrc
|
||||||
|
.idea
|
||||||
.ruby-version
|
.ruby-version
|
||||||
Gemfile.lock
|
Gemfile.lock
|
||||||
.bundle
|
.bundle
|
||||||
|
|||||||
13
.rubocop.yml
13
.rubocop.yml
@@ -1,17 +1,10 @@
|
|||||||
inherit_from:
|
inherit_from:
|
||||||
- 'https://shopify.github.io/ruby-style-guide/rubocop.yml'
|
- .rubocop.shopify.yml
|
||||||
- .rubocop_todo.yml
|
|
||||||
|
|
||||||
require: rubocop-performance
|
require: rubocop-performance
|
||||||
|
|
||||||
Performance:
|
Performance:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
|
|
||||||
AllCops:
|
Metrics/LineLength:
|
||||||
TargetRubyVersion: 2.4
|
Enabled: false
|
||||||
Exclude:
|
|
||||||
- 'vendor/bundle/**/*'
|
|
||||||
|
|
||||||
Naming/MethodName:
|
|
||||||
Exclude:
|
|
||||||
- 'example/server/liquid_servlet.rb'
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
# This configuration was generated by
|
|
||||||
# `rubocop --auto-gen-config`
|
|
||||||
# on 2019-09-11 06:34:25 +1000 using RuboCop version 0.74.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: 2
|
|
||||||
# Cop supports --auto-correct.
|
|
||||||
# Configuration parameters: EnforcedStyle.
|
|
||||||
# SupportedStyles: runtime_error, standard_error
|
|
||||||
Lint/InheritException:
|
|
||||||
Exclude:
|
|
||||||
- 'lib/liquid/interrupts.rb'
|
|
||||||
|
|
||||||
# Offense count: 98
|
|
||||||
# Cop supports --auto-correct.
|
|
||||||
# Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
|
|
||||||
# URISchemes: http, https
|
|
||||||
Metrics/LineLength:
|
|
||||||
Max: 294
|
|
||||||
|
|
||||||
# Offense count: 44
|
|
||||||
Naming/ConstantName:
|
|
||||||
Exclude:
|
|
||||||
- 'lib/liquid.rb'
|
|
||||||
- 'lib/liquid/block_body.rb'
|
|
||||||
- 'lib/liquid/tags/assign.rb'
|
|
||||||
- 'lib/liquid/tags/capture.rb'
|
|
||||||
- 'lib/liquid/tags/case.rb'
|
|
||||||
- 'lib/liquid/tags/cycle.rb'
|
|
||||||
- 'lib/liquid/tags/for.rb'
|
|
||||||
- 'lib/liquid/tags/if.rb'
|
|
||||||
- 'lib/liquid/tags/include.rb'
|
|
||||||
- 'lib/liquid/tags/raw.rb'
|
|
||||||
- 'lib/liquid/tags/table_row.rb'
|
|
||||||
- 'lib/liquid/variable.rb'
|
|
||||||
- 'performance/shopify/comment_form.rb'
|
|
||||||
- 'performance/shopify/paginate.rb'
|
|
||||||
- 'test/integration/tags/include_tag_test.rb'
|
|
||||||
|
|
||||||
# Offense count: 5
|
|
||||||
Style/ClassVars:
|
|
||||||
Exclude:
|
|
||||||
- 'lib/liquid/condition.rb'
|
|
||||||
- 'lib/liquid/strainer.rb'
|
|
||||||
- 'lib/liquid/template.rb'
|
|
||||||
26
.travis.yml
26
.travis.yml
@@ -1,26 +1,30 @@
|
|||||||
language: ruby
|
language: ruby
|
||||||
cache: bundler
|
|
||||||
|
|
||||||
rvm:
|
rvm:
|
||||||
- 2.4
|
- 2.4
|
||||||
- 2.5
|
- 2.5
|
||||||
- &latest_ruby 2.6
|
- 2.6
|
||||||
- 2.7
|
- 2.7
|
||||||
- ruby-head
|
- ruby-head
|
||||||
|
- jruby-head
|
||||||
|
- truffleruby
|
||||||
|
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- libgmp3-dev
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
|
||||||
- rvm: *latest_ruby
|
|
||||||
script: bundle exec rake memory_profile:run
|
|
||||||
name: Profiling Memory Usage
|
|
||||||
allow_failures:
|
allow_failures:
|
||||||
- rvm: ruby-head
|
- rvm: ruby-head
|
||||||
|
- rvm: jruby-head
|
||||||
|
|
||||||
branches:
|
install:
|
||||||
only:
|
- bundle install
|
||||||
- master
|
|
||||||
- gh-pages
|
script: bundle exec rake
|
||||||
- /.*-stable/
|
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
disable: true
|
disable: true
|
||||||
|
|||||||
3
Gemfile
3
Gemfile
@@ -10,7 +10,6 @@ gemspec
|
|||||||
group :benchmark, :test do
|
group :benchmark, :test do
|
||||||
gem 'benchmark-ips'
|
gem 'benchmark-ips'
|
||||||
gem 'memory_profiler'
|
gem 'memory_profiler'
|
||||||
gem 'terminal-table'
|
|
||||||
|
|
||||||
install_if -> { RUBY_PLATFORM !~ /mingw|mswin|java/ && RUBY_ENGINE != 'truffleruby' } do
|
install_if -> { RUBY_PLATFORM !~ /mingw|mswin|java/ && RUBY_ENGINE != 'truffleruby' } do
|
||||||
gem 'stackprof'
|
gem 'stackprof'
|
||||||
@@ -22,6 +21,6 @@ group :test do
|
|||||||
gem 'rubocop-performance', require: false
|
gem 'rubocop-performance', require: false
|
||||||
|
|
||||||
platform :mri, :truffleruby do
|
platform :mri, :truffleruby do
|
||||||
gem 'liquid-c', github: 'Shopify/liquid-c', ref: 'master'
|
gem 'liquid-c', github: 'Shopify/liquid-c', ref: '7ba926791ef8411984d0f3e41c6353fd716041c6'
|
||||||
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::ArgumentSeparator: , 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::ARGUMENT_SEPARATOR: , 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]
|
||||||
|
|
||||||
|
|||||||
@@ -106,9 +106,3 @@ template = Liquid::Template.parse("{{x}} {{y}}")
|
|||||||
template.render!({ 'x' => 1}, { strict_variables: true })
|
template.render!({ 'x' => 1}, { strict_variables: true })
|
||||||
#=> Liquid::UndefinedVariable: Liquid error: undefined variable y
|
#=> Liquid::UndefinedVariable: Liquid error: undefined variable y
|
||||||
```
|
```
|
||||||
|
|
||||||
### Usage tracking
|
|
||||||
|
|
||||||
To help track usages of a feature or code path in production, we have released opt-in usage tracking. To enable this, we provide an empty `Liquid:: Usage.increment` method which you can customize to your needs. The feature is well suited to https://github.com/Shopify/statsd-instrument. However, the choice of implementation is up to you.
|
|
||||||
|
|
||||||
Once you have enabled usage tracking, we recommend reporting any events through Github Issues that your system may be logging. It is highly likely this event has been added to consider deprecating or improving code specific to this event, so please raise any concerns.
|
|
||||||
35
Rakefile
35
Rakefile
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
require 'rake'
|
require 'rake'
|
||||||
require 'rake/testtask'
|
require 'rake/testtask'
|
||||||
$LOAD_PATH.unshift(File.expand_path("../lib", __FILE__))
|
$LOAD_PATH.unshift(File.expand_path('lib', __dir__))
|
||||||
require "liquid/version"
|
require 'liquid/version'
|
||||||
|
|
||||||
task(default: [:test, :rubocop])
|
task(default: %i[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|
|
||||||
@@ -37,6 +37,7 @@ task :test do
|
|||||||
Rake::Task['base_test'].invoke
|
Rake::Task['base_test'].invoke
|
||||||
|
|
||||||
if RUBY_ENGINE == 'ruby' || RUBY_ENGINE == 'truffleruby'
|
if RUBY_ENGINE == 'ruby' || RUBY_ENGINE == 'truffleruby'
|
||||||
|
|
||||||
ENV['LIQUID_C'] = '1'
|
ENV['LIQUID_C'] = '1'
|
||||||
|
|
||||||
ENV['LIQUID_PARSER_MODE'] = 'lax'
|
ENV['LIQUID_PARSER_MODE'] = 'lax'
|
||||||
@@ -51,7 +52,7 @@ 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
|
||||||
@@ -60,45 +61,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
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
module ProductsFilter
|
module ProductsFilter
|
||||||
def price(integer)
|
def price(integer)
|
||||||
format("$%.2d USD", integer / 100.0)
|
format('$%.2d USD', integer / 100.0)
|
||||||
end
|
end
|
||||||
|
|
||||||
def prettyprint(text)
|
def prettyprint(text)
|
||||||
@@ -30,17 +30,17 @@ class Servlet < LiquidServlet
|
|||||||
private
|
private
|
||||||
|
|
||||||
def products_list
|
def products_list
|
||||||
[{ 'name' => 'Arbor Draft', 'price' => 39900, 'description' => 'the *arbor draft* is a excellent product' },
|
[{ 'name' => 'Arbor Draft', 'price' => 39_900, 'description' => 'the *arbor draft* is a excellent product' },
|
||||||
{ 'name' => 'Arbor Element', 'price' => 40000, 'description' => 'the *arbor element* rocks for freestyling' },
|
{ 'name' => 'Arbor Element', 'price' => 40_000, 'description' => 'the *arbor element* rocks for freestyling' },
|
||||||
{ 'name' => 'Arbor Diamond', 'price' => 59900, 'description' => 'the *arbor diamond* is a made up product because im obsessed with arbor and have no creativity' }]
|
{ 'name' => 'Arbor Diamond', 'price' => 59_900, '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' => 39900, 'description' => 'the *arbor catalyst* is an advanced drop-through for freestyle and flatground performance and versatility' },
|
[{ 'name' => 'Arbor Catalyst', 'price' => 39_900, 'description' => 'the *arbor catalyst* is an advanced drop-through for freestyle and flatground performance and versatility' },
|
||||||
{ 'name' => 'Arbor Fish', 'price' => 40000, 'description' => 'the *arbor fish* is a compact pin that features an extended wheelbase and time-honored teardrop shape' }]
|
{ 'name' => 'Arbor Fish', 'price' => 40_000, '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,14 +1,17 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class LiquidServlet < WEBrick::HTTPServlet::AbstractServlet
|
class LiquidServlet < WEBrick::HTTPServlet::AbstractServlet
|
||||||
def do_GET(req, res)
|
def get(req, res)
|
||||||
handle(:get, req, res)
|
handle(:get, req, res)
|
||||||
end
|
end
|
||||||
|
|
||||||
def do_POST(req, res)
|
def 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)
|
||||||
@@ -19,7 +22,7 @@ class LiquidServlet < WEBrick::HTTPServlet::AbstractServlet
|
|||||||
@action = Regexp.last_match(1) || 'index'
|
@action = Regexp.last_match(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
|
||||||
|
|||||||
@@ -10,5 +10,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
|
||||||
|
|||||||
@@ -22,31 +22,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
|
||||||
FilterSeparator = /\|/
|
FILTER_SEPARATOR = /\|/.freeze
|
||||||
ArgumentSeparator = ','
|
ARGUMENT_SEPARATOR = ','
|
||||||
FilterArgumentSeparator = ':'
|
FILTER_ARGUMENT_SEPARATOR = ':'
|
||||||
VariableAttributeSeparator = '.'
|
VARIABLE_ATTRIBUTE_SEPARATOR = '.'
|
||||||
WhitespaceControl = '-'
|
WHITESPACE_CONTROL = '-'
|
||||||
TagStart = /\{\%/
|
TAG_START = /\{\%/.freeze
|
||||||
TagEnd = /\%\}/
|
TAG_END = /\%\}/.freeze
|
||||||
VariableSignature = /\(?[\w\-\.\[\]]\)?/
|
VARIABLE_SIGNATURE = /\(?[\w\-\.\[\]]\)?/.freeze
|
||||||
VariableSegment = /[\w\-]/
|
VARIABLE_SEGMENT = /[\w\-]/.freeze
|
||||||
VariableStart = /\{\{/
|
VARIABLE_START = /\{\{/.freeze
|
||||||
VariableEnd = /\}\}/
|
VARIABLE_END = /\}\}/.freeze
|
||||||
VariableIncompleteEnd = /\}\}?/
|
VARIABLE_INCOMPLETE_END = /\}\}?/.freeze
|
||||||
QuotedString = /"[^"]*"|'[^']*'/
|
QUOTED_STRING = /"[^"]*"|'[^']*'/.freeze
|
||||||
QuotedFragment = /#{QuotedString}|(?:[^\s,\|'"]|#{QuotedString})+/o
|
QUOTED_FRAGMENT = /#{QUOTED_STRING}|(?:[^\s,\|'"]|#{QUOTED_STRING})+/o.freeze
|
||||||
TagAttributes = /(\w+)\s*\:\s*(#{QuotedFragment})/o
|
TAG_ATTRIBUTES = /(\w+)\s*\:\s*(#{QUOTED_FRAGMENT})/o.freeze
|
||||||
AnyStartingTag = /#{TagStart}|#{VariableStart}/o
|
ANY_STARTING_TAG = /#{TAG_START}|#{VARIABLE_START}/o.freeze
|
||||||
PartialTemplateParser = /#{TagStart}.*?#{TagEnd}|#{VariableStart}.*?#{VariableIncompleteEnd}/om
|
PARTIAL_TEMPLATE_PARSER = /#{TAG_START}.*?#{TAG_END}|#{VARIABLE_START}.*?#{VARIABLE_INCOMPLETE_END}/om.freeze
|
||||||
TemplateParser = /(#{PartialTemplateParser}|#{AnyStartingTag})/om
|
TEMPLATE_PARSER = /(#{PARTIAL_TEMPLATE_PARSER}|#{ANY_STARTING_TAG})/om.freeze
|
||||||
VariableParser = /\[[^\]]+\]|#{VariableSegment}+\??/o
|
VARIABLE_PARSER = /\[[^\]]+\]|#{VARIABLE_SEGMENT}+\??/o.freeze
|
||||||
|
|
||||||
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'
|
||||||
@@ -76,12 +76,7 @@ require 'liquid/condition'
|
|||||||
require 'liquid/utils'
|
require 'liquid/utils'
|
||||||
require 'liquid/tokenizer'
|
require 'liquid/tokenizer'
|
||||||
require 'liquid/parse_context'
|
require 'liquid/parse_context'
|
||||||
require 'liquid/partial_cache'
|
|
||||||
require 'liquid/usage'
|
|
||||||
require 'liquid/register'
|
|
||||||
require 'liquid/static_registers'
|
|
||||||
|
|
||||||
# Load all the tags of the standard library
|
# Load all the tags of the standard library
|
||||||
#
|
#
|
||||||
Dir["#{__dir__}/liquid/tags/*.rb"].each { |f| require f }
|
Dir["#{__dir__}/liquid/tags/*.rb"].each { |f| require f }
|
||||||
Dir["#{__dir__}/liquid/registers/*.rb"].each { |f| require f }
|
|
||||||
|
|||||||
@@ -30,15 +30,15 @@ module Liquid
|
|||||||
|
|
||||||
def unknown_tag(tag, _params, _tokens)
|
def unknown_tag(tag, _params, _tokens)
|
||||||
if tag == 'else'
|
if tag == 'else'
|
||||||
raise SyntaxError, parse_context.locale.t("errors.syntax.unexpected_else",
|
raise SyntaxError, parse_context.locale.t('errors.syntax.unexpected_else',
|
||||||
block_name: block_name)
|
block_name: block_name)
|
||||||
elsif tag.start_with?('end')
|
elsif tag.start_with?('end')
|
||||||
raise SyntaxError, parse_context.locale.t("errors.syntax.invalid_delimiter",
|
raise SyntaxError, parse_context.locale.t('errors.syntax.invalid_delimiter',
|
||||||
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, parse_context.locale.t('errors.syntax.unknown_tag', tag: tag)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -53,18 +53,15 @@ module Liquid
|
|||||||
protected
|
protected
|
||||||
|
|
||||||
def parse_body(body, tokens)
|
def parse_body(body, tokens)
|
||||||
if parse_context.depth >= MAX_DEPTH
|
raise StackLevelError, 'Nesting too deep' if parse_context.depth >= MAX_DEPTH
|
||||||
raise StackLevelError, "Nesting too deep"
|
|
||||||
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
|
||||||
unless end_tag_name
|
raise SyntaxError, parse_context.locale.t('errors.syntax.tag_never_closed', block_name: block_name) unless end_tag_name
|
||||||
raise SyntaxError, parse_context.locale.t("errors.syntax.tag_never_closed", 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
|
||||||
|
|||||||
@@ -2,12 +2,11 @@
|
|||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class BlockBody
|
class BlockBody
|
||||||
LiquidTagToken = /\A\s*(\w+)\s*(.*?)\z/o
|
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 = "{%"
|
VAR_START = '{{'
|
||||||
VARSTART = "{{"
|
|
||||||
|
|
||||||
attr_reader :nodelist
|
attr_reader :nodelist
|
||||||
|
|
||||||
@@ -16,83 +15,36 @@ module Liquid
|
|||||||
@blank = true
|
@blank = true
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse(tokenizer, parse_context, &block)
|
def parse(tokenizer, parse_context)
|
||||||
parse_context.line_number = tokenizer.line_number
|
parse_context.line_number = tokenizer.line_number
|
||||||
|
|
||||||
if tokenizer.for_liquid_tag
|
|
||||||
parse_for_liquid_tag(tokenizer, parse_context, &block)
|
|
||||||
else
|
|
||||||
parse_for_document(tokenizer, parse_context, &block)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private def parse_for_liquid_tag(tokenizer, parse_context)
|
|
||||||
while (token = tokenizer.shift)
|
|
||||||
unless token.empty? || token =~ WhitespaceOrNothing
|
|
||||||
unless token =~ LiquidTagToken
|
|
||||||
# line isn't empty but didn't match tag syntax, yield and let the
|
|
||||||
# caller raise a syntax error
|
|
||||||
return yield token, token
|
|
||||||
end
|
|
||||||
tag_name = Regexp.last_match(1)
|
|
||||||
markup = Regexp.last_match(2)
|
|
||||||
unless (tag = registered_tags[tag_name])
|
|
||||||
# end parsing if we reach an unknown tag and let the caller decide
|
|
||||||
# determine how to proceed
|
|
||||||
return yield tag_name, markup
|
|
||||||
end
|
|
||||||
new_tag = tag.parse(tag_name, markup, tokenizer, parse_context)
|
|
||||||
@blank &&= new_tag.blank?
|
|
||||||
@nodelist << new_tag
|
|
||||||
end
|
|
||||||
parse_context.line_number = tokenizer.line_number
|
|
||||||
end
|
|
||||||
|
|
||||||
yield nil, nil
|
|
||||||
end
|
|
||||||
|
|
||||||
private def parse_for_document(tokenizer, parse_context, &block)
|
|
||||||
while (token = tokenizer.shift)
|
while (token = tokenizer.shift)
|
||||||
next if token.empty?
|
next if token.empty?
|
||||||
|
|
||||||
case
|
case
|
||||||
when token.start_with?(TAGSTART)
|
when token.start_with?(TAG_START)
|
||||||
whitespace_handler(token, parse_context)
|
whitespace_handler(token, parse_context)
|
||||||
unless token =~ FullToken
|
raise_missing_tag_terminator(token, parse_context) unless token =~ FULL_TOKEN
|
||||||
raise_missing_tag_terminator(token, parse_context)
|
tag_name = Regexp.last_match(1)
|
||||||
end
|
markup = Regexp.last_match(2)
|
||||||
tag_name = Regexp.last_match(2)
|
# fetch the tag from registered blocks
|
||||||
markup = Regexp.last_match(4)
|
|
||||||
|
|
||||||
if parse_context.line_number
|
|
||||||
# newlines inside the tag should increase the line number,
|
|
||||||
# particularly important for multiline {% liquid %} tags
|
|
||||||
parse_context.line_number += Regexp.last_match(1).count("\n") + Regexp.last_match(3).count("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
if tag_name == 'liquid'
|
|
||||||
liquid_tag_tokenizer = Tokenizer.new(markup, line_number: parse_context.line_number, for_liquid_tag: true)
|
|
||||||
next parse_for_liquid_tag(liquid_tag_tokenizer, parse_context, &block)
|
|
||||||
end
|
|
||||||
|
|
||||||
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?(VARSTART)
|
when token.start_with?(VAR_START)
|
||||||
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
|
||||||
if parse_context.trim_whitespace
|
token.lstrip! if parse_context.trim_whitespace
|
||||||
token.lstrip!
|
|
||||||
end
|
|
||||||
parse_context.trim_whitespace = false
|
parse_context.trim_whitespace = false
|
||||||
@nodelist << token
|
@nodelist << token
|
||||||
@blank &&= !!(token =~ WhitespaceOrNothing)
|
@blank &&= token.match?(WHITESPACE_OR_NOTHING)
|
||||||
end
|
end
|
||||||
parse_context.line_number = tokenizer.line_number
|
parse_context.line_number = tokenizer.line_number
|
||||||
end
|
end
|
||||||
@@ -101,13 +53,11 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def whitespace_handler(token, parse_context)
|
def whitespace_handler(token, parse_context)
|
||||||
if token[2] == WhitespaceControl
|
if token[2] == WHITESPACE_CONTROL
|
||||||
previous_token = @nodelist.last
|
previous_token = @nodelist.last
|
||||||
if previous_token.is_a?(String)
|
previous_token.rstrip! if previous_token.is_a?(String)
|
||||||
previous_token.rstrip!
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
parse_context.trim_whitespace = (token[-3] == WhitespaceControl)
|
parse_context.trim_whitespace = (token[-3] == WHITESPACE_CONTROL)
|
||||||
end
|
end
|
||||||
|
|
||||||
def blank?
|
def blank?
|
||||||
@@ -154,13 +104,7 @@ module Liquid
|
|||||||
private
|
private
|
||||||
|
|
||||||
def render_node(context, output, node)
|
def render_node(context, output, node)
|
||||||
if node.disabled?(context)
|
node.render_to_output_buffer(context, output)
|
||||||
output << node.disabled_error_message
|
|
||||||
return
|
|
||||||
end
|
|
||||||
disable_tags(context, node.disabled_tags) do
|
|
||||||
node.render_to_output_buffer(context, output)
|
|
||||||
end
|
|
||||||
rescue UndefinedVariable, UndefinedDropMethod, UndefinedFilter => e
|
rescue UndefinedVariable, UndefinedDropMethod, UndefinedFilter => e
|
||||||
context.handle_error(e, node.line_number)
|
context.handle_error(e, node.line_number)
|
||||||
rescue ::StandardError => e
|
rescue ::StandardError => e
|
||||||
@@ -168,19 +112,15 @@ module Liquid
|
|||||||
output << context.handle_error(e, line_number)
|
output << context.handle_error(e, line_number)
|
||||||
end
|
end
|
||||||
|
|
||||||
def disable_tags(context, tags, &block)
|
|
||||||
return yield if tags.empty?
|
|
||||||
context.registers[:disabled_tags].disable(tags, &block)
|
|
||||||
end
|
|
||||||
|
|
||||||
def raise_if_resource_limits_reached(context, length)
|
def raise_if_resource_limits_reached(context, length)
|
||||||
context.resource_limits.render_length += length
|
context.resource_limits.render_length += length
|
||||||
return unless context.resource_limits.reached?
|
return unless context.resource_limits.reached?
|
||||||
raise MemoryError, "Memory limits exceeded"
|
|
||||||
|
raise MemoryError, 'Memory limits exceeded'
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_variable(token, parse_context)
|
def create_variable(token, parse_context)
|
||||||
token.scan(ContentOfVariable) do |content|
|
token.scan(CONTENT_OF_VARIABLE) do |content|
|
||||||
markup = content.first
|
markup = content.first
|
||||||
return Variable.new(markup, parse_context)
|
return Variable.new(markup, parse_context)
|
||||||
end
|
end
|
||||||
@@ -188,11 +128,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: TagEnd.inspect)
|
raise SyntaxError, parse_context.locale.t('errors.syntax.tag_termination', token: token, tag_end: TAG_END.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: VariableEnd.inspect)
|
raise SyntaxError, parse_context.locale.t('errors.syntax.variable_termination', token: token, tag_end: VARIABLE_END.inspect)
|
||||||
end
|
end
|
||||||
|
|
||||||
def registered_tags
|
def registered_tags
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ 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) },
|
'==' => ->(cond, left, right) { cond.send(:equal_variables, left, right) },
|
||||||
'!=' => ->(cond, left, right) { !cond.send(:equal_variables, left, right) },
|
'!=' => ->(cond, left, right) { !cond.send(:equal_variables, left, right) },
|
||||||
'<>' => ->(cond, left, right) { !cond.send(:equal_variables, left, right) },
|
'<>' => ->(cond, left, right) { !cond.send(:equal_variables, left, right) },
|
||||||
@@ -27,8 +27,8 @@ module Liquid
|
|||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
|
|
||||||
def self.operators
|
class << self
|
||||||
@@operators
|
attr_accessor :operators
|
||||||
end
|
end
|
||||||
|
|
||||||
attr_reader :attachment, :child_condition
|
attr_reader :attachment, :child_condition
|
||||||
|
|||||||
@@ -14,38 +14,28 @@ module Liquid
|
|||||||
#
|
#
|
||||||
# context['bob'] #=> nil class Context
|
# context['bob'] #=> nil class Context
|
||||||
class Context
|
class Context
|
||||||
attr_reader :scopes, :errors, :registers, :environments, :resource_limits, :static_registers, :static_environments
|
attr_reader :scopes, :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
|
||||||
|
|
||||||
# rubocop:disable Metrics/ParameterLists
|
def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = nil)
|
||||||
def self.build(environments: {}, outer_scope: {}, registers: {}, rethrow_errors: false, resource_limits: nil, static_environments: {})
|
@environments = [environments].flatten
|
||||||
new(environments, outer_scope, registers, rethrow_errors, resource_limits, static_environments)
|
@scopes = [(outer_scope || {})]
|
||||||
end
|
@registers = registers
|
||||||
|
@errors = []
|
||||||
def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = nil, static_environments = {})
|
@partial = false
|
||||||
@environments = [environments]
|
@strict_variables = false
|
||||||
@environments.flatten!
|
@resource_limits = resource_limits || ResourceLimits.new(Template.default_resource_limits)
|
||||||
|
|
||||||
@static_environments = [static_environments].flat_map(&:freeze).freeze
|
|
||||||
@scopes = [(outer_scope || {})]
|
|
||||||
@registers = registers
|
|
||||||
@errors = []
|
|
||||||
@partial = false
|
|
||||||
@strict_variables = false
|
|
||||||
@resource_limits = resource_limits || ResourceLimits.new(Template.default_resource_limits)
|
|
||||||
@base_scope_depth = 0
|
|
||||||
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
|
||||||
if rethrow_errors
|
self.exception_renderer = ->(_e) { raise } if rethrow_errors
|
||||||
self.exception_renderer = ->(_e) { raise }
|
|
||||||
end
|
|
||||||
|
|
||||||
@interrupts = []
|
@interrupts = []
|
||||||
@filters = []
|
@filters = []
|
||||||
@global_filter = nil
|
@global_filter = nil
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics/ParameterLists
|
|
||||||
|
|
||||||
def warnings
|
def warnings
|
||||||
@warnings ||= []
|
@warnings ||= []
|
||||||
@@ -99,7 +89,7 @@ module Liquid
|
|||||||
# Push new local scope on the stack. use <tt>Context#stack</tt> instead
|
# Push new local scope on the stack. use <tt>Context#stack</tt> instead
|
||||||
def push(new_scope = {})
|
def push(new_scope = {})
|
||||||
@scopes.unshift(new_scope)
|
@scopes.unshift(new_scope)
|
||||||
check_overflow
|
raise StackLevelError, 'Nesting too deep' if @scopes.length > Block::MAX_DEPTH
|
||||||
end
|
end
|
||||||
|
|
||||||
# Merge a hash of variables in the current local scope
|
# Merge a hash of variables in the current local scope
|
||||||
@@ -110,6 +100,7 @@ module Liquid
|
|||||||
# Pop from the stack. use <tt>Context#stack</tt> instead
|
# Pop from the stack. use <tt>Context#stack</tt> instead
|
||||||
def pop
|
def pop
|
||||||
raise ContextError if @scopes.size == 1
|
raise ContextError if @scopes.size == 1
|
||||||
|
|
||||||
@scopes.shift
|
@scopes.shift
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -121,30 +112,19 @@ module Liquid
|
|||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# context['var] #=> nil
|
# context['var] #=> nil
|
||||||
def stack(new_scope = {})
|
def stack(new_scope = nil)
|
||||||
push(new_scope)
|
old_stack_used = @this_stack_used
|
||||||
|
if new_scope
|
||||||
|
push(new_scope)
|
||||||
|
@this_stack_used = true
|
||||||
|
else
|
||||||
|
@this_stack_used = false
|
||||||
|
end
|
||||||
|
|
||||||
yield
|
yield
|
||||||
ensure
|
ensure
|
||||||
pop
|
pop if @this_stack_used
|
||||||
end
|
@this_stack_used = old_stack_used
|
||||||
|
|
||||||
# Creates a new context inheriting resource limits, filters, environment etc.,
|
|
||||||
# but with an isolated scope.
|
|
||||||
def new_isolated_subcontext
|
|
||||||
check_overflow
|
|
||||||
|
|
||||||
Context.build(
|
|
||||||
resource_limits: resource_limits,
|
|
||||||
static_environments: static_environments,
|
|
||||||
registers: StaticRegisters.new(registers)
|
|
||||||
).tap do |subcontext|
|
|
||||||
subcontext.base_scope_depth = base_scope_depth + 1
|
|
||||||
subcontext.exception_renderer = exception_renderer
|
|
||||||
subcontext.filters = @filters
|
|
||||||
subcontext.strainer = nil
|
|
||||||
subcontext.errors = errors
|
|
||||||
subcontext.warnings = warnings
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def clear_instance_assigns
|
def clear_instance_assigns
|
||||||
@@ -153,6 +133,10 @@ module Liquid
|
|||||||
|
|
||||||
# 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
|
||||||
|
@this_stack_used = true
|
||||||
|
push({})
|
||||||
|
end
|
||||||
@scopes[0][key] = value
|
@scopes[0][key] = value
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -181,13 +165,25 @@ module Liquid
|
|||||||
# This was changed from find() to find_index() because this is a very hot
|
# This was changed from find() to find_index() because this is a very hot
|
||||||
# path and find_index() is optimized in MRI to reduce object allocation
|
# path and find_index() is optimized in MRI to reduce object allocation
|
||||||
index = @scopes.find_index { |s| s.key?(key) }
|
index = @scopes.find_index { |s| s.key?(key) }
|
||||||
|
scope = @scopes[index] if index
|
||||||
|
|
||||||
variable = if index
|
variable = nil
|
||||||
lookup_and_evaluate(@scopes[index], key, raise_on_not_found: raise_on_not_found)
|
|
||||||
else
|
if scope.nil?
|
||||||
try_variable_find_in_environments(key, raise_on_not_found: raise_on_not_found)
|
@environments.each do |e|
|
||||||
|
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
|
||||||
|
# then it is the value we are looking for.
|
||||||
|
if !variable.nil? || @strict_variables && raise_on_not_found
|
||||||
|
scope = e
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scope ||= @environments.last || @scopes.last
|
||||||
|
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=)
|
||||||
|
|
||||||
@@ -195,9 +191,7 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def lookup_and_evaluate(obj, key, raise_on_not_found: true)
|
def lookup_and_evaluate(obj, key, raise_on_not_found: true)
|
||||||
if @strict_variables && raise_on_not_found && obj.respond_to?(:key?) && !obj.key?(key)
|
raise Liquid::UndefinedVariable, "undefined variable #{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 = obj[key]
|
||||||
|
|
||||||
@@ -208,43 +202,13 @@ module Liquid
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
attr_writer :base_scope_depth, :warnings, :errors, :strainer, :filters
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
attr_reader :base_scope_depth
|
|
||||||
|
|
||||||
def try_variable_find_in_environments(key, raise_on_not_found:)
|
|
||||||
@environments.each do |environment|
|
|
||||||
found_variable = lookup_and_evaluate(environment, key, raise_on_not_found: raise_on_not_found)
|
|
||||||
if !found_variable.nil? || @strict_variables && raise_on_not_found
|
|
||||||
return found_variable
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@static_environments.each do |environment|
|
|
||||||
found_variable = lookup_and_evaluate(environment, key, raise_on_not_found: raise_on_not_found)
|
|
||||||
if !found_variable.nil? || @strict_variables && raise_on_not_found
|
|
||||||
return found_variable
|
|
||||||
end
|
|
||||||
end
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_overflow
|
|
||||||
raise StackLevelError, "Nesting too deep" if overflow?
|
|
||||||
end
|
|
||||||
|
|
||||||
def overflow?
|
|
||||||
base_scope_depth + @scopes.length > Block::MAX_DEPTH
|
|
||||||
end
|
|
||||||
|
|
||||||
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 => exc
|
rescue Liquid::InternalError => e
|
||||||
exc
|
e
|
||||||
end
|
end
|
||||||
|
|
||||||
def squash_instance_assigns_with_environments
|
def squash_instance_assigns_with_environments
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ module Liquid
|
|||||||
def unknown_tag(tag, parse_context)
|
def unknown_tag(tag, parse_context)
|
||||||
case tag
|
case tag
|
||||||
when 'else', 'end'
|
when 'else', 'end'
|
||||||
raise SyntaxError, parse_context.locale.t("errors.syntax.unexpected_outer_tag", tag: tag)
|
raise SyntaxError, parse_context.locale.t('errors.syntax.unexpected_outer_tag', tag: tag)
|
||||||
else
|
else
|
||||||
raise SyntaxError, parse_context.locale.t("errors.syntax.unknown_tag", tag: tag)
|
raise SyntaxError, parse_context.locale.t('errors.syntax.unknown_tag', tag: tag)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -28,6 +28,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&.strict_variables
|
||||||
|
|
||||||
raise Liquid::UndefinedDropMethod, "undefined method #{method}"
|
raise Liquid::UndefinedDropMethod, "undefined method #{method}"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -69,7 +70,7 @@ module Liquid
|
|||||||
|
|
||||||
if include?(Enumerable)
|
if include?(Enumerable)
|
||||||
blacklist += Enumerable.public_instance_methods
|
blacklist += Enumerable.public_instance_methods
|
||||||
blacklist -= [:sort, :count, :first, :min, :max]
|
blacklist -= %i[sort count first min max include?]
|
||||||
end
|
end
|
||||||
|
|
||||||
whitelist = [:to_liquid] + (public_instance_methods - blacklist)
|
whitelist = [:to_liquid] + (public_instance_methods - blacklist)
|
||||||
|
|||||||
@@ -7,12 +7,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 +22,20 @@ module Liquid
|
|||||||
private
|
private
|
||||||
|
|
||||||
def message_prefix
|
def message_prefix
|
||||||
str = +""
|
str = +''
|
||||||
str << if is_a?(SyntaxError)
|
str << if is_a?(SyntaxError)
|
||||||
"Liquid syntax error"
|
'Liquid syntax error'
|
||||||
else
|
else
|
||||||
"Liquid error"
|
'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
|
||||||
|
|||||||
@@ -23,11 +23,11 @@ module Liquid
|
|||||||
'empty' => MethodLiteral.new(:empty?, '').freeze
|
'empty' => MethodLiteral.new(:empty?, '').freeze
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
SINGLE_QUOTED_STRING = /\A'(.*)'\z/m
|
SINGLE_QUOTED_STRING = /\A'(.*)'\z/m.freeze
|
||||||
DOUBLE_QUOTED_STRING = /\A"(.*)"\z/m
|
DOUBLE_QUOTED_STRING = /\A"(.*)"\z/m.freeze
|
||||||
INTEGERS_REGEX = /\A(-?\d+)\z/
|
INTEGERS_REGEX = /\A(-?\d+)\z/.freeze
|
||||||
FLOATS_REGEX = /\A(-?\d[\d\.]+)\z/
|
FLOATS_REGEX = /\A(-?\d[\d\.]+)\z/.freeze
|
||||||
RANGES_REGEX = /\A\((\S+)\.\.(\S+)\)\z/
|
RANGES_REGEX = /\A\((\S+)\.\.(\S+)\)\z/.freeze
|
||||||
|
|
||||||
def self.parse(markup)
|
def self.parse(markup)
|
||||||
if LITERALS.key?(markup)
|
if LITERALS.key?(markup)
|
||||||
|
|||||||
@@ -17,7 +17,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 +46,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')
|
||||||
@root = root
|
@root = root
|
||||||
@pattern = pattern
|
@pattern = pattern
|
||||||
end
|
end
|
||||||
@@ -59,7 +59,7 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def full_path(template_path)
|
def full_path(template_path)
|
||||||
raise FileSystemError, "Illegal template name '#{template_path}'" unless %r{\A[^./][a-zA-Z0-9_/]+\z}.match?(template_path)
|
raise FileSystemError, "Illegal template name '#{template_path}'" unless template_path =~ %r{\A[^./][a-zA-Z0-9_/]+\z}
|
||||||
|
|
||||||
full_path = if template_path.include?('/')
|
full_path = if template_path.include?('/')
|
||||||
File.join(root, File.dirname(template_path), @pattern % File.basename(template_path))
|
File.join(root, File.dirname(template_path), @pattern % File.basename(template_path))
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ 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)
|
||||||
|
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ module Liquid
|
|||||||
attr_reader :message
|
attr_reader :message
|
||||||
|
|
||||||
def initialize(message = nil)
|
def initialize(message = nil)
|
||||||
@message = message || "interrupt"
|
@message = message || 'interrupt'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Interrupt that is thrown whenever a {% break %} is called.
|
# Interrupt that is thrown whenever a {% break %} is called.
|
||||||
class BreakInterrupt < Interrupt; end
|
class BreakInterrupt < RuntimeError; end
|
||||||
|
|
||||||
# Interrupt that is thrown whenever a {% continue %} is called.
|
# Interrupt that is thrown whenever a {% continue %} is called.
|
||||||
class ContinueInterrupt < Interrupt; end
|
class ContinueInterrupt < RuntimeError; end
|
||||||
end
|
end
|
||||||
|
|||||||
79
lib/liquid/legacy.rb
Normal file
79
lib/liquid/legacy.rb
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
# 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,6 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "strscan"
|
require 'strscan'
|
||||||
module Liquid
|
module Liquid
|
||||||
class Lexer
|
class Lexer
|
||||||
SPECIALS = {
|
SPECIALS = {
|
||||||
@@ -15,13 +15,13 @@ module Liquid
|
|||||||
'?' => :question,
|
'?' => :question,
|
||||||
'-' => :dash,
|
'-' => :dash,
|
||||||
}.freeze
|
}.freeze
|
||||||
IDENTIFIER = /[a-zA-Z_][\w-]*\??/
|
IDENTIFIER = /[a-zA-Z_][\w-]*\??/.freeze
|
||||||
SINGLE_STRING_LITERAL = /'[^\']*'/
|
SINGLE_STRING_LITERAL = /'[^\']*'/.freeze
|
||||||
DOUBLE_STRING_LITERAL = /"[^\"]*"/
|
DOUBLE_STRING_LITERAL = /"[^\"]*"/.freeze
|
||||||
NUMBER_LITERAL = /-?\d+(\.\d+)?/
|
NUMBER_LITERAL = /-?\d+(\.\d+)?/.freeze
|
||||||
DOTDOT = /\.\./
|
DOTDOT = /\.\./.freeze
|
||||||
COMPARISON_OPERATOR = /==|!=|<>|<=?|>=?|contains(?=\s)/
|
COMPARISON_OPERATOR = /==|!=|<>|<=?|>=?|contains(?=\s)/.freeze
|
||||||
WHITESPACE_OR_NOTHING = /\s*/
|
WHITESPACE_OR_NOTHING = /\s*/.freeze
|
||||||
|
|
||||||
def initialize(input)
|
def initialize(input)
|
||||||
@ss = StringScanner.new(input)
|
@ss = StringScanner.new(input)
|
||||||
@@ -33,18 +33,13 @@ 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 = if (t = @ss.scan(COMPARISON_OPERATOR))
|
|
||||||
[:comparison, t]
|
tok = if (t = @ss.scan(COMPARISON_OPERATOR)) then [:comparison, t]
|
||||||
elsif (t = @ss.scan(SINGLE_STRING_LITERAL))
|
elsif (t = @ss.scan(SINGLE_STRING_LITERAL)) then [:string, t]
|
||||||
[:string, t]
|
elsif (t = @ss.scan(DOUBLE_STRING_LITERAL)) then [:string, t]
|
||||||
elsif (t = @ss.scan(DOUBLE_STRING_LITERAL))
|
elsif (t = @ss.scan(NUMBER_LITERAL)) then [:number, t]
|
||||||
[:string, t]
|
elsif (t = @ss.scan(IDENTIFIER)) then [:id, t]
|
||||||
elsif (t = @ss.scan(NUMBER_LITERAL))
|
elsif (t = @ss.scan(DOTDOT)) then [:dotdot, t]
|
||||||
[:number, t]
|
|
||||||
elsif (t = @ss.scan(IDENTIFIER))
|
|
||||||
[:id, t]
|
|
||||||
elsif (t = @ss.scan(DOTDOT))
|
|
||||||
[:dotdot, t]
|
|
||||||
else
|
else
|
||||||
c = @ss.getch
|
c = @ss.getch
|
||||||
if (s = SPECIALS[c])
|
if (s = SPECIALS[c])
|
||||||
|
|||||||
@@ -22,8 +22,5 @@
|
|||||||
tag_never_closed: "'%{block_name}' tag was never closed"
|
tag_never_closed: "'%{block_name}' tag was never closed"
|
||||||
meta_syntax_error: "Liquid syntax error: #{e.message}"
|
meta_syntax_error: "Liquid syntax error: #{e.message}"
|
||||||
table_row: "Syntax Error in 'table_row loop' - Valid syntax: table_row [item] in [collection] cols=3"
|
table_row: "Syntax Error in 'table_row loop' - Valid syntax: table_row [item] in [collection] cols=3"
|
||||||
render: "Syntax error in tag 'render' - Template name must be a quoted string"
|
|
||||||
argument:
|
argument:
|
||||||
include: "Argument error in tag 'include' - Illegal template name"
|
include: "Argument error in tag 'include' - Illegal template name"
|
||||||
disabled:
|
|
||||||
tag: "usage is not allowed in this context"
|
|
||||||
|
|||||||
@@ -14,9 +14,8 @@ module Liquid
|
|||||||
|
|
||||||
def consume(type = nil)
|
def consume(type = nil)
|
||||||
token = @tokens[@p]
|
token = @tokens[@p]
|
||||||
if type && token[0] != type
|
raise SyntaxError, "Expected #{type} but found #{@tokens[@p].first}" 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
|
||||||
@@ -27,6 +26,7 @@ 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,6 +36,7 @@ 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
|
||||||
@@ -43,10 +44,11 @@ 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 = [:string, :number].freeze
|
SINGLE_TOKEN_EXPRESSION_TYPES = %i[string number].freeze
|
||||||
private_constant :SINGLE_TOKEN_EXPRESSION_TYPES
|
private_constant :SINGLE_TOKEN_EXPRESSION_TYPES
|
||||||
|
|
||||||
def expression
|
def expression
|
||||||
@@ -68,11 +70,9 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def argument
|
def argument
|
||||||
str = +""
|
str = +''
|
||||||
# might be a keyword argument (identifier: expression)
|
# might be a keyword argument (identifier: expression)
|
||||||
if look(:id) && look(:colon, 1)
|
str << consume << consume << ' ' if look(:id) && look(:colon, 1)
|
||||||
str << consume << consume << ' '
|
|
||||||
end
|
|
||||||
|
|
||||||
str << expression
|
str << expression
|
||||||
str
|
str
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
|
||||||
class PartialCache
|
|
||||||
def self.load(template_name, context:, parse_context:)
|
|
||||||
cached_partials = (context.registers[:cached_partials] ||= {})
|
|
||||||
cached = cached_partials[template_name]
|
|
||||||
return cached if cached
|
|
||||||
|
|
||||||
file_system = (context.registers[:file_system] ||= Liquid::Template.file_system)
|
|
||||||
source = file_system.read_template_file(template_name)
|
|
||||||
parse_context.partial = true
|
|
||||||
|
|
||||||
partial = Liquid::Template.parse(source, parse_context)
|
|
||||||
cached_partials[template_name] = partial
|
|
||||||
ensure
|
|
||||||
parse_context.partial = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -46,7 +46,7 @@ module Liquid
|
|||||||
include Enumerable
|
include Enumerable
|
||||||
|
|
||||||
class Timing
|
class Timing
|
||||||
attr_reader :code, :partial, :line_number, :children, :total_time, :self_time
|
attr_reader :code, :partial, :line_number, :children
|
||||||
|
|
||||||
def initialize(node, partial)
|
def initialize(node, partial)
|
||||||
@code = node.respond_to?(:raw) ? node.raw : node
|
@code = node.respond_to?(:raw) ? node.raw : node
|
||||||
@@ -65,17 +65,6 @@ module Liquid
|
|||||||
|
|
||||||
def finish
|
def finish
|
||||||
@end_time = Time.now
|
@end_time = Time.now
|
||||||
@total_time = @end_time - @start_time
|
|
||||||
|
|
||||||
if @children.empty?
|
|
||||||
@self_time = @total_time
|
|
||||||
else
|
|
||||||
total_children_time = 0
|
|
||||||
@children.each do |child|
|
|
||||||
total_children_time += child.total_time
|
|
||||||
end
|
|
||||||
@self_time = @total_time - total_children_time
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_time
|
def render_time
|
||||||
@@ -109,10 +98,10 @@ module Liquid
|
|||||||
Thread.current[:liquid_profiler]
|
Thread.current[:liquid_profiler]
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(partial_name = "<root>")
|
def initialize
|
||||||
@partial_stack = [partial_name]
|
@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,6 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
|
||||||
class Register
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
module Liquid
|
|
||||||
class DisabledTags < Register
|
|
||||||
def initialize
|
|
||||||
@disabled_tags = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
def disabled?(tag)
|
|
||||||
@disabled_tags.key?(tag) && @disabled_tags[tag] > 0
|
|
||||||
end
|
|
||||||
|
|
||||||
def disable(tags)
|
|
||||||
tags.each(&method(:increment))
|
|
||||||
yield
|
|
||||||
ensure
|
|
||||||
tags.each(&method(:decrement))
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def increment(tag)
|
|
||||||
@disabled_tags[tag] ||= 0
|
|
||||||
@disabled_tags[tag] += 1
|
|
||||||
end
|
|
||||||
|
|
||||||
def decrement(tag)
|
|
||||||
@disabled_tags[tag] -= 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Template.add_register(:disabled_tags, DisabledTags.new)
|
|
||||||
end
|
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
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]
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ module Liquid
|
|||||||
'"' => '"',
|
'"' => '"',
|
||||||
"'" => ''',
|
"'" => ''',
|
||||||
}.freeze
|
}.freeze
|
||||||
HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/
|
HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/.freeze
|
||||||
STRIP_HTML_BLOCKS = Regexp.union(
|
STRIP_HTML_BLOCKS = Regexp.union(
|
||||||
%r{<script.*?</script>}m,
|
%r{<script.*?</script>}m,
|
||||||
/<!--.*?-->/m,
|
/<!--.*?-->/m,
|
||||||
%r{<style.*?</style>}m
|
%r{<style.*?</style>}m
|
||||||
)
|
)
|
||||||
STRIP_HTML_TAGS = /<.*?>/m
|
STRIP_HTML_TAGS = /<.*?>/m.freeze
|
||||||
|
|
||||||
# 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,8 +74,9 @@ 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 = '...')
|
||||||
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
|
||||||
@@ -84,13 +85,14 @@ module Liquid
|
|||||||
input_str.length > length ? input_str[0...l].concat(truncate_string_str) : input_str
|
input_str.length > length ? input_str[0...l].concat(truncate_string_str) : input_str
|
||||||
end
|
end
|
||||||
|
|
||||||
def truncatewords(input, words = 15, truncate_string = "...")
|
def truncatewords(input, words = 15, truncate_string = '...')
|
||||||
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(' ').concat(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.
|
||||||
@@ -128,13 +130,13 @@ module Liquid
|
|||||||
|
|
||||||
# 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 = ' ')
|
||||||
InputIterator.new(input, context).join(glue)
|
InputIterator.new(input).join(glue)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Sort elements of the array
|
# Sort elements of the array
|
||||||
# provide optional property with which to sort an array of hashes or drops
|
# provide optional property with which to sort an array of hashes or drops
|
||||||
def sort(input, property = nil)
|
def sort(input, property = nil)
|
||||||
ary = InputIterator.new(input, context)
|
ary = InputIterator.new(input)
|
||||||
|
|
||||||
return [] if ary.empty?
|
return [] if ary.empty?
|
||||||
|
|
||||||
@@ -154,7 +156,7 @@ module Liquid
|
|||||||
# Sort elements of an array ignoring case if strings
|
# Sort elements of an array ignoring case if strings
|
||||||
# provide optional property with which to sort an array of hashes or drops
|
# provide optional property with which to sort an array of hashes or drops
|
||||||
def sort_natural(input, property = nil)
|
def sort_natural(input, property = nil)
|
||||||
ary = InputIterator.new(input, context)
|
ary = InputIterator.new(input)
|
||||||
|
|
||||||
return [] if ary.empty?
|
return [] if ary.empty?
|
||||||
|
|
||||||
@@ -174,7 +176,7 @@ module Liquid
|
|||||||
# Filter the elements of an array to those with a certain property value.
|
# Filter the elements of an array to those with a certain property value.
|
||||||
# By default the target is any truthy value.
|
# By default the target is any truthy value.
|
||||||
def where(input, property, target_value = nil)
|
def where(input, property, target_value = nil)
|
||||||
ary = InputIterator.new(input, context)
|
ary = InputIterator.new(input)
|
||||||
|
|
||||||
if ary.empty?
|
if ary.empty?
|
||||||
[]
|
[]
|
||||||
@@ -196,7 +198,7 @@ module Liquid
|
|||||||
# Remove duplicate elements from an array
|
# Remove duplicate elements from an array
|
||||||
# provide optional property with which to determine uniqueness
|
# provide optional property with which to determine uniqueness
|
||||||
def uniq(input, property = nil)
|
def uniq(input, property = nil)
|
||||||
ary = InputIterator.new(input, context)
|
ary = InputIterator.new(input)
|
||||||
|
|
||||||
if property.nil?
|
if property.nil?
|
||||||
ary.uniq
|
ary.uniq
|
||||||
@@ -213,16 +215,16 @@ module Liquid
|
|||||||
|
|
||||||
# Reverse the elements of an array
|
# Reverse the elements of an array
|
||||||
def reverse(input)
|
def reverse(input)
|
||||||
ary = InputIterator.new(input, context)
|
ary = InputIterator.new(input)
|
||||||
ary.reverse
|
ary.reverse
|
||||||
end
|
end
|
||||||
|
|
||||||
# map/collect on a given property
|
# map/collect on a given property
|
||||||
def map(input, property)
|
def map(input, property)
|
||||||
InputIterator.new(input, context).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'
|
||||||
e
|
e
|
||||||
elsif e.respond_to?(:[])
|
elsif e.respond_to?(:[])
|
||||||
r = e[property]
|
r = e[property]
|
||||||
@@ -236,7 +238,7 @@ module Liquid
|
|||||||
# Remove nils within an array
|
# Remove nils within an array
|
||||||
# provide optional property with which to check for nil
|
# provide optional property with which to check for nil
|
||||||
def compact(input, property = nil)
|
def compact(input, property = nil)
|
||||||
ary = InputIterator.new(input, context)
|
ary = InputIterator.new(input)
|
||||||
|
|
||||||
if property.nil?
|
if property.nil?
|
||||||
ary.compact
|
ary.compact
|
||||||
@@ -277,10 +279,9 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def concat(input, array)
|
def concat(input, array)
|
||||||
unless array.respond_to?(:to_ary)
|
raise ArgumentError, 'concat filter requires an array argument' unless array.respond_to?(:to_ary)
|
||||||
raise ArgumentError, "concat filter requires an array argument"
|
|
||||||
end
|
InputIterator.new(input).concat(array)
|
||||||
InputIterator.new(input, context).concat(array)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# prepend a string to another
|
# prepend a string to another
|
||||||
@@ -421,26 +422,16 @@ module Liquid
|
|||||||
result.is_a?(BigDecimal) ? result.to_f : result
|
result.is_a?(BigDecimal) ? result.to_f : result
|
||||||
end
|
end
|
||||||
|
|
||||||
# Set a default value when the input is nil, false or empty
|
def default(input, default_value = '')
|
||||||
#
|
if !input || input.respond_to?(:empty?) && input.empty?
|
||||||
# Example:
|
default_value
|
||||||
# {{ product.title | default: "No Title" }}
|
else
|
||||||
#
|
input
|
||||||
# Use `allow_false` when an input should only be tested against nil or empty and not false.
|
end
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# {{ product.title | default: "No Title", allow_false: true }}
|
|
||||||
#
|
|
||||||
def default(input, default_value = '', options = {})
|
|
||||||
options = {} unless options.is_a?(Hash)
|
|
||||||
false_check = options['allow_false'] ? input.nil? : !input
|
|
||||||
false_check || (input.respond_to?(:empty?) && input.empty?) ? default_value : input
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
attr_reader :context
|
|
||||||
|
|
||||||
def raise_property_error(property)
|
def raise_property_error(property)
|
||||||
raise Liquid::ArgumentError, "cannot select the property '#{property}'"
|
raise Liquid::ArgumentError, "cannot select the property '#{property}'"
|
||||||
end
|
end
|
||||||
@@ -469,8 +460,7 @@ module Liquid
|
|||||||
class InputIterator
|
class InputIterator
|
||||||
include Enumerable
|
include Enumerable
|
||||||
|
|
||||||
def initialize(input, context)
|
def initialize(input)
|
||||||
@context = context
|
|
||||||
@input = if input.is_a?(Array)
|
@input = if input.is_a?(Array)
|
||||||
input.flatten
|
input.flatten
|
||||||
elsif input.is_a?(Hash)
|
elsif input.is_a?(Hash)
|
||||||
@@ -509,7 +499,6 @@ module Liquid
|
|||||||
|
|
||||||
def each
|
def each
|
||||||
@input.each do |e|
|
@input.each do |e|
|
||||||
e.context = @context if e.respond_to?(:context=)
|
|
||||||
yield(e.respond_to?(:to_liquid) ? e.to_liquid : e)
|
yield(e.respond_to?(:to_liquid) ? e.to_liquid : e)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
|
||||||
class StaticRegisters
|
|
||||||
attr_reader :static, :registers
|
|
||||||
|
|
||||||
def initialize(registers = {})
|
|
||||||
@static = registers.is_a?(StaticRegisters) ? registers.static : registers
|
|
||||||
@registers = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
def []=(key, value)
|
|
||||||
@registers[key] = value
|
|
||||||
end
|
|
||||||
|
|
||||||
def [](key)
|
|
||||||
if @registers.key?(key)
|
|
||||||
@registers[key]
|
|
||||||
else
|
|
||||||
@static[key]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def delete(key)
|
|
||||||
@registers.delete(key)
|
|
||||||
end
|
|
||||||
|
|
||||||
def fetch(key, default = nil)
|
|
||||||
key?(key) ? self[key] : default
|
|
||||||
end
|
|
||||||
|
|
||||||
def key?(key)
|
|
||||||
@registers.key?(key) || @static.key?(key)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -9,12 +9,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 = @@global_strainer.filter_methods.dup
|
@filter_methods = Strainer.global_strainer.filter_methods.dup
|
||||||
filters.each { |f| add_filter(f) }
|
filters.each { |f| add_filter(f) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -24,11 +24,13 @@ 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 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?
|
||||||
@@ -41,8 +43,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)
|
||||||
@@ -50,7 +52,7 @@ 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)
|
||||||
|
|||||||
@@ -7,21 +7,13 @@ module Liquid
|
|||||||
include ParserSwitching
|
include ParserSwitching
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
def parse(tag_name, markup, tokenizer, parse_context)
|
def parse(tag_name, markup, tokenizer, options)
|
||||||
tag = new(tag_name, markup, parse_context)
|
tag = new(tag_name, markup, options)
|
||||||
tag.parse(tokenizer)
|
tag.parse(tokenizer)
|
||||||
tag
|
tag
|
||||||
end
|
end
|
||||||
|
|
||||||
def disable_tags(*tags)
|
|
||||||
disabled_tags.push(*tags)
|
|
||||||
end
|
|
||||||
|
|
||||||
private :new
|
private :new
|
||||||
|
|
||||||
def disabled_tags
|
|
||||||
@disabled_tags ||= []
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(tag_name, markup, parse_context)
|
def initialize(tag_name, markup, parse_context)
|
||||||
@@ -31,8 +23,7 @@ module Liquid
|
|||||||
@line_number = parse_context.line_number
|
@line_number = parse_context.line_number
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse(_tokens)
|
def parse(_tokens); end
|
||||||
end
|
|
||||||
|
|
||||||
def raw
|
def raw
|
||||||
"#{@tag_name} #{@markup}"
|
"#{@tag_name} #{@markup}"
|
||||||
@@ -46,14 +37,6 @@ module Liquid
|
|||||||
''
|
''
|
||||||
end
|
end
|
||||||
|
|
||||||
def disabled?(context)
|
|
||||||
context.registers[:disabled_tags].disabled?(tag_name)
|
|
||||||
end
|
|
||||||
|
|
||||||
def disabled_error_message
|
|
||||||
"#{tag_name} #{options[:locale].t('errors.disabled.tag')}"
|
|
||||||
end
|
|
||||||
|
|
||||||
# For backwards compatibility with custom tags. In a future release, the semantics
|
# 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`
|
# of the `render_to_output_buffer` method will become the default and the `render`
|
||||||
# method will be removed.
|
# method will be removed.
|
||||||
@@ -65,9 +48,5 @@ module Liquid
|
|||||||
def blank?
|
def blank?
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def disabled_tags
|
|
||||||
self.class.disabled_tags
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -10,21 +10,17 @@ module Liquid
|
|||||||
# {{ foo }}
|
# {{ foo }}
|
||||||
#
|
#
|
||||||
class Assign < Tag
|
class Assign < Tag
|
||||||
Syntax = /(#{VariableSignature}+)\s*=\s*(.*)\s*/om
|
SYNTAX = /(#{VARIABLE_SIGNATURE}+)\s*=\s*(.*)\s*/om.freeze
|
||||||
|
|
||||||
def self.syntax_error_translation_key
|
|
||||||
"errors.syntax.assign"
|
|
||||||
end
|
|
||||||
|
|
||||||
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 = Regexp.last_match(1)
|
||||||
@from = Variable.new(Regexp.last_match(2), options)
|
@from = Variable.new(Regexp.last_match(2), options)
|
||||||
else
|
else
|
||||||
raise SyntaxError, options[:locale].t(self.class.syntax_error_translation_key)
|
raise SyntaxError, options[:locale].t('errors.syntax.assign')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -13,14 +13,14 @@ module Liquid
|
|||||||
# in a sidebar or footer.
|
# in a sidebar or footer.
|
||||||
#
|
#
|
||||||
class Capture < Block
|
class Capture < Block
|
||||||
Syntax = /(#{VariableSignature}+)/o
|
SYNTAX = /(#{VARIABLE_SIGNATURE}+)/o.freeze
|
||||||
|
|
||||||
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 = Regexp.last_match(1)
|
||||||
else
|
else
|
||||||
raise SyntaxError, options[:locale].t("errors.syntax.capture")
|
raise SyntaxError, options[:locale].t('errors.syntax.capture')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class Case < Block
|
class Case < Block
|
||||||
Syntax = /(#{QuotedFragment})/o
|
SYNTAX = /(#{QUOTED_FRAGMENT})/o.freeze
|
||||||
WhenSyntax = /(#{QuotedFragment})(?:(?:\s+or\s+|\s*\,\s*)(#{QuotedFragment}.*))?/om
|
WHEN_SYNTAX = /(#{QUOTED_FRAGMENT})(?:(?:\s+or\s+|\s*\,\s*)(#{QUOTED_FRAGMENT}.*))?/om.freeze
|
||||||
|
|
||||||
attr_reader :blocks, :left
|
attr_reader :blocks, :left
|
||||||
|
|
||||||
@@ -11,10 +11,10 @@ module Liquid
|
|||||||
super
|
super
|
||||||
@blocks = []
|
@blocks = []
|
||||||
|
|
||||||
if markup =~ Syntax
|
if markup =~ SYNTAX
|
||||||
@left = Expression.parse(Regexp.last_match(1))
|
@left = Expression.parse(Regexp.last_match(1))
|
||||||
else
|
else
|
||||||
raise SyntaxError, options[:locale].t("errors.syntax.case")
|
raise SyntaxError, options[:locale].t('errors.syntax.case')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -39,14 +39,16 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def render_to_output_buffer(context, output)
|
def render_to_output_buffer(context, output)
|
||||||
execute_else_block = true
|
context.stack do
|
||||||
|
execute_else_block = true
|
||||||
|
|
||||||
@blocks.each do |block|
|
@blocks.each do |block|
|
||||||
if block.else?
|
if block.else?
|
||||||
block.attachment.render_to_output_buffer(context, output) if execute_else_block
|
block.attachment.render_to_output_buffer(context, output) if execute_else_block
|
||||||
elsif block.evaluate(context)
|
elsif block.evaluate(context)
|
||||||
execute_else_block = false
|
execute_else_block = false
|
||||||
block.attachment.render_to_output_buffer(context, output)
|
block.attachment.render_to_output_buffer(context, output)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -59,9 +61,7 @@ module Liquid
|
|||||||
body = BlockBody.new
|
body = BlockBody.new
|
||||||
|
|
||||||
while markup
|
while markup
|
||||||
unless markup =~ WhenSyntax
|
raise SyntaxError, options[:locale].t('errors.syntax.case_invalid_when') unless markup =~ WHEN_SYNTAX
|
||||||
raise SyntaxError, options[:locale].t("errors.syntax.case_invalid_when")
|
|
||||||
end
|
|
||||||
|
|
||||||
markup = Regexp.last_match(2)
|
markup = Regexp.last_match(2)
|
||||||
|
|
||||||
@@ -72,9 +72,7 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def record_else_condition(markup)
|
def record_else_condition(markup)
|
||||||
unless markup.strip.empty?
|
raise SyntaxError, options[:locale].t('errors.syntax.case_invalid_else') unless markup.strip.empty?
|
||||||
raise SyntaxError, options[:locale].t("errors.syntax.case_invalid_else")
|
|
||||||
end
|
|
||||||
|
|
||||||
block = ElseCondition.new
|
block = ElseCondition.new
|
||||||
block.attach(BlockBody.new)
|
block.attach(BlockBody.new)
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ module Liquid
|
|||||||
output
|
output
|
||||||
end
|
end
|
||||||
|
|
||||||
def unknown_tag(_tag, _markup, _tokens)
|
def unknown_tag(_tag, _markup, _tokens); end
|
||||||
end
|
|
||||||
|
|
||||||
def blank?
|
def blank?
|
||||||
true
|
true
|
||||||
|
|||||||
@@ -14,45 +14,47 @@ module Liquid
|
|||||||
# <div class="green"> Item five</div>
|
# <div class="green"> Item five</div>
|
||||||
#
|
#
|
||||||
class Cycle < Tag
|
class Cycle < Tag
|
||||||
SimpleSyntax = /\A#{QuotedFragment}+/o
|
SIMPLE_SYNTAX = /\A#{QUOTED_FRAGMENT}+/o.freeze
|
||||||
NamedSyntax = /\A(#{QuotedFragment})\s*\:\s*(.*)/om
|
NAMED_SYNTAX = /\A(#{QUOTED_FRAGMENT})\s*\:\s*(.*)/om.freeze
|
||||||
|
|
||||||
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 NamedSyntax
|
when NAMED_SYNTAX
|
||||||
@variables = variables_from_string(Regexp.last_match(2))
|
@variables = variables_from_string(Regexp.last_match(2))
|
||||||
@name = Expression.parse(Regexp.last_match(1))
|
@name = Expression.parse(Regexp.last_match(1))
|
||||||
when SimpleSyntax
|
when SIMPLE_SYNTAX
|
||||||
@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, options[:locale].t('errors.syntax.cycle')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_to_output_buffer(context, output)
|
def render_to_output_buffer(context, output)
|
||||||
context.registers[:cycle] ||= {}
|
context.registers[:cycle] ||= {}
|
||||||
|
|
||||||
key = context.evaluate(@name)
|
context.stack do
|
||||||
iteration = context.registers[:cycle][key].to_i
|
key = context.evaluate(@name)
|
||||||
|
iteration = context.registers[:cycle][key].to_i
|
||||||
|
|
||||||
val = context.evaluate(@variables[iteration])
|
val = context.evaluate(@variables[iteration])
|
||||||
|
|
||||||
if val.is_a?(Array)
|
if val.is_a?(Array)
|
||||||
val = val.join
|
val = val.join
|
||||||
elsif !val.is_a?(String)
|
elsif !val.is_a?(String)
|
||||||
val = val.to_s
|
val = val.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
output << val
|
||||||
|
|
||||||
|
iteration += 1
|
||||||
|
iteration = 0 if iteration >= @variables.size
|
||||||
|
context.registers[:cycle][key] = iteration
|
||||||
end
|
end
|
||||||
|
|
||||||
output << val
|
|
||||||
|
|
||||||
iteration += 1
|
|
||||||
iteration = 0 if iteration >= @variables.size
|
|
||||||
context.registers[:cycle][key] = iteration
|
|
||||||
|
|
||||||
output
|
output
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -60,7 +62,7 @@ module Liquid
|
|||||||
|
|
||||||
def variables_from_string(markup)
|
def variables_from_string(markup)
|
||||||
markup.split(',').collect do |var|
|
markup.split(',').collect do |var|
|
||||||
var =~ /\s*(#{QuotedFragment})\s*/o
|
var =~ /\s*(#{QUOTED_FRAGMENT})\s*/o
|
||||||
Regexp.last_match(1) ? Expression.parse(Regexp.last_match(1)) : nil
|
Regexp.last_match(1) ? Expression.parse(Regexp.last_match(1)) : nil
|
||||||
end.compact
|
end.compact
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
|
||||||
# Echo outputs an expression
|
|
||||||
#
|
|
||||||
# {% echo monkey %}
|
|
||||||
# {% echo user.name %}
|
|
||||||
#
|
|
||||||
# This is identical to variable output syntax, like {{ foo }}, but works
|
|
||||||
# inside {% liquid %} tags. The full syntax is supported, including filters:
|
|
||||||
#
|
|
||||||
# {% echo user | link %}
|
|
||||||
#
|
|
||||||
class Echo < Tag
|
|
||||||
def initialize(tag_name, markup, parse_context)
|
|
||||||
super
|
|
||||||
@variable = Variable.new(markup, parse_context)
|
|
||||||
end
|
|
||||||
|
|
||||||
def render(context)
|
|
||||||
@variable.render_to_output_buffer(context, +'')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Template.register_tag('echo', Echo)
|
|
||||||
end
|
|
||||||
@@ -46,7 +46,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(#{VariableSegment}+)\s+in\s+(#{QuotedFragment}+)\s*(reversed)?/o
|
SYNTAX = /\A(#{VARIABLE_SEGMENT}+)\s+in\s+(#{QUOTED_FRAGMENT}+)\s*(reversed)?/o.freeze
|
||||||
|
|
||||||
attr_reader :collection_name, :variable_name, :limit, :from
|
attr_reader :collection_name, :variable_name, :limit, :from
|
||||||
|
|
||||||
@@ -60,6 +60,7 @@ 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,6 +70,7 @@ module Liquid
|
|||||||
|
|
||||||
def unknown_tag(tag, markup, tokens)
|
def unknown_tag(tag, markup, tokens)
|
||||||
return super unless tag == 'else'
|
return super unless tag == 'else'
|
||||||
|
|
||||||
@else_block = BlockBody.new
|
@else_block = BlockBody.new
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -87,24 +89,25 @@ module Liquid
|
|||||||
protected
|
protected
|
||||||
|
|
||||||
def lax_parse(markup)
|
def lax_parse(markup)
|
||||||
if markup =~ Syntax
|
if markup =~ SYNTAX
|
||||||
@variable_name = Regexp.last_match(1)
|
@variable_name = Regexp.last_match(1)
|
||||||
collection_name = Regexp.last_match(2)
|
collection_name = Regexp.last_match(2)
|
||||||
@reversed = !!Regexp.last_match(3)
|
@reversed = !!Regexp.last_match(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(TagAttributes) do |key, value|
|
markup.scan(TAG_ATTRIBUTES) 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, options[:locale].t('errors.syntax.for')
|
||||||
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, options[:locale].t('errors.syntax.for_invalid_in') unless p.id?('in')
|
||||||
|
|
||||||
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)
|
||||||
@@ -112,8 +115,9 @@ module Liquid
|
|||||||
|
|
||||||
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') || p.id?('offset'))
|
||||||
raise SyntaxError, options[:locale].t("errors.syntax.for_invalid_attribute")
|
raise SyntaxError, options[:locale].t('errors.syntax.for_invalid_attribute')
|
||||||
end
|
end
|
||||||
|
|
||||||
p.consume
|
p.consume
|
||||||
set_attribute(attribute, p.expression)
|
set_attribute(attribute, p.expression)
|
||||||
end
|
end
|
||||||
@@ -173,6 +177,7 @@ module Liquid
|
|||||||
|
|
||||||
# Handle any interrupts if they exist.
|
# Handle any interrupts if they exist.
|
||||||
next unless context.interrupt?
|
next unless 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)
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ 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 = /(#{QuotedFragment})\s*([=!<>a-z_]+)?\s*(#{QuotedFragment})?/o
|
SYNTAX = /(#{QUOTED_FRAGMENT})\s*([=!<>a-z_]+)?\s*(#{QUOTED_FRAGMENT})?/o.freeze
|
||||||
ExpressionsAndOperators = /(?:\b(?:\s?and\s?|\s?or\s?)\b|(?:\s*(?!\b(?:\s?and\s?|\s?or\s?)\b)(?:#{QuotedFragment}|\S+)\s*)+)/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
|
||||||
BOOLEAN_OPERATORS = %w(and or).freeze
|
BOOLEAN_OPERATORS = %w[and or].freeze
|
||||||
|
|
||||||
attr_reader :blocks
|
attr_reader :blocks
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def unknown_tag(tag, markup, tokens)
|
def unknown_tag(tag, markup, tokens)
|
||||||
if ['elsif', 'else'].include?(tag)
|
if %w[elsif else].include?(tag)
|
||||||
push_block(tag, markup)
|
push_block(tag, markup)
|
||||||
else
|
else
|
||||||
super
|
super
|
||||||
@@ -42,9 +42,9 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def render_to_output_buffer(context, output)
|
def render_to_output_buffer(context, output)
|
||||||
@blocks.each do |block|
|
context.stack do
|
||||||
if block.evaluate(context)
|
@blocks.each do |block|
|
||||||
return block.attachment.render_to_output_buffer(context, output)
|
return block.attachment.render_to_output_buffer(context, output) if block.evaluate(context)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -65,18 +65,19 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def lax_parse(markup)
|
def lax_parse(markup)
|
||||||
expressions = markup.scan(ExpressionsAndOperators)
|
expressions = markup.scan(EXPRESSIONS_AND_OPERATORS)
|
||||||
raise SyntaxError, options[:locale].t("errors.syntax.if") unless expressions.pop =~ Syntax
|
raise SyntaxError, options[:locale].t('errors.syntax.if') 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(Regexp.last_match(1)), Regexp.last_match(2), Expression.parse(Regexp.last_match(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, options[:locale].t('errors.syntax.if') 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)))
|
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)
|
raise SyntaxError, options[:locale].t('errors.syntax.if') unless BOOLEAN_OPERATORS.include?(operator)
|
||||||
|
|
||||||
new_condition.send(operator, condition)
|
new_condition.send(operator, condition)
|
||||||
condition = new_condition
|
condition = new_condition
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,12 +3,14 @@
|
|||||||
module Liquid
|
module Liquid
|
||||||
class Ifchanged < Block
|
class Ifchanged < Block
|
||||||
def render_to_output_buffer(context, output)
|
def render_to_output_buffer(context, output)
|
||||||
block_output = +''
|
context.stack do
|
||||||
super(context, block_output)
|
block_output = +''
|
||||||
|
super(context, block_output)
|
||||||
|
|
||||||
if block_output != context.registers[:ifchanged]
|
if block_output != context.registers[:ifchanged]
|
||||||
context.registers[:ifchanged] = block_output
|
context.registers[:ifchanged] = block_output
|
||||||
output << block_output
|
output << block_output
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
output
|
output
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ module Liquid
|
|||||||
# {% include 'product' for products %}
|
# {% include 'product' for products %}
|
||||||
#
|
#
|
||||||
class Include < Tag
|
class Include < Tag
|
||||||
SYNTAX = /(#{QuotedFragment}+)(\s+(?:with|for)\s+(#{QuotedFragment}+))?(\s+(?:as)\s+(#{VariableSegment}+))?/o
|
SYNTAX = /(#{QUOTED_FRAGMENT}+)(\s+(?:with|for)\s+(#{QUOTED_FRAGMENT}+))?/o.freeze
|
||||||
Syntax = SYNTAX
|
|
||||||
|
|
||||||
attr_reader :template_name_expr, :variable_name_expr, :attributes
|
attr_reader :template_name_expr, :variable_name_expr, :attributes
|
||||||
|
|
||||||
@@ -29,34 +28,27 @@ module Liquid
|
|||||||
template_name = Regexp.last_match(1)
|
template_name = Regexp.last_match(1)
|
||||||
variable_name = Regexp.last_match(3)
|
variable_name = Regexp.last_match(3)
|
||||||
|
|
||||||
@alias_name = Regexp.last_match(5)
|
|
||||||
@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(TagAttributes) do |key, value|
|
markup.scan(TAG_ATTRIBUTES) 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, options[:locale].t('errors.syntax.include')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse(_tokens)
|
def parse(_tokens); end
|
||||||
end
|
|
||||||
|
|
||||||
def render_to_output_buffer(context, output)
|
def render_to_output_buffer(context, output)
|
||||||
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, options[:locale].t('errors.argument.include') unless template_name
|
||||||
|
|
||||||
partial = PartialCache.load(
|
partial = load_cached_partial(template_name, context)
|
||||||
template_name,
|
context_variable_name = template_name.split('/').last
|
||||||
context: context,
|
|
||||||
parse_context: parse_context
|
|
||||||
)
|
|
||||||
|
|
||||||
context_variable_name = @alias_name || template_name.split('/').last
|
|
||||||
|
|
||||||
variable = if @variable_name_expr
|
variable = if @variable_name_expr
|
||||||
context.evaluate(@variable_name_expr)
|
context.evaluate(@variable_name_expr)
|
||||||
@@ -92,9 +84,36 @@ module Liquid
|
|||||||
output
|
output
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
alias_method :parse_context, :options
|
alias_method :parse_context, :options
|
||||||
private :parse_context
|
private :parse_context
|
||||||
|
|
||||||
|
def load_cached_partial(template_name, context)
|
||||||
|
cached_partials = context.registers[:cached_partials] || {}
|
||||||
|
|
||||||
|
if (cached = cached_partials[template_name])
|
||||||
|
return cached
|
||||||
|
end
|
||||||
|
|
||||||
|
source = read_template_from_file_system(context)
|
||||||
|
begin
|
||||||
|
parse_context.partial = true
|
||||||
|
partial = Liquid::Template.parse(source, parse_context)
|
||||||
|
ensure
|
||||||
|
parse_context.partial = false
|
||||||
|
end
|
||||||
|
cached_partials[template_name] = partial
|
||||||
|
context.registers[:cached_partials] = cached_partials
|
||||||
|
partial
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_template_from_file_system(context)
|
||||||
|
file_system = context.registers[:file_system] || Liquid::Template.file_system
|
||||||
|
|
||||||
|
file_system.read_template_file(context.evaluate(@template_name_expr))
|
||||||
|
end
|
||||||
|
|
||||||
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
||||||
def children
|
def children
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ module Liquid
|
|||||||
def render_to_output_buffer(context, output)
|
def render_to_output_buffer(context, output)
|
||||||
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
|
output << value.to_s
|
||||||
output
|
output
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class Raw < Block
|
class Raw < Block
|
||||||
Syntax = /\A\s*\z/
|
SYNTAX = /\A\s*\z/.freeze
|
||||||
FullTokenPossiblyInvalid = /\A(.*)#{TagStart}\s*(\w+)\s*(.*)?#{TagEnd}\z/om
|
FULL_TOKEN_POSSIBLY_INVALID = /\A(.*)#{TAG_START}\s*(\w+)\s*(.*)?#{TAG_END}\z/om.freeze
|
||||||
|
|
||||||
def initialize(tag_name, markup, parse_context)
|
def initialize(tag_name, markup, parse_context)
|
||||||
super
|
super
|
||||||
@@ -14,14 +14,14 @@ module Liquid
|
|||||||
def parse(tokens)
|
def parse(tokens)
|
||||||
@body = +''
|
@body = +''
|
||||||
while (token = tokens.shift)
|
while (token = tokens.shift)
|
||||||
if token =~ FullTokenPossiblyInvalid
|
if token =~ FULL_TOKEN_POSSIBLY_INVALID
|
||||||
@body << Regexp.last_match(1) if Regexp.last_match(1) != ""
|
@body << Regexp.last_match(1) if Regexp.last_match(1) != ''
|
||||||
return if block_delimiter == Regexp.last_match(2)
|
return if block_delimiter == Regexp.last_match(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, parse_context.locale.t('errors.syntax.tag_never_closed', block_name: block_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_to_output_buffer(_context, output)
|
def render_to_output_buffer(_context, output)
|
||||||
@@ -40,9 +40,7 @@ module Liquid
|
|||||||
protected
|
protected
|
||||||
|
|
||||||
def ensure_valid_markup(tag_name, markup, parse_context)
|
def ensure_valid_markup(tag_name, markup, parse_context)
|
||||||
unless Syntax.match?(markup)
|
raise SyntaxError, parse_context.locale.t('errors.syntax.tag_unexpected_args', tag: tag_name) unless markup =~ SYNTAX
|
||||||
raise SyntaxError, parse_context.locale.t("errors.syntax.tag_unexpected_args", tag: tag_name)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,80 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
|
||||||
class Render < Tag
|
|
||||||
SYNTAX = /(#{QuotedString}+)(\s+(?:with|for)\s+(#{QuotedFragment}+))?(\s+(?:as)\s+(#{VariableSegment}+))?/o
|
|
||||||
|
|
||||||
disable_tags "include"
|
|
||||||
|
|
||||||
attr_reader :template_name_expr, :attributes
|
|
||||||
|
|
||||||
def initialize(tag_name, markup, options)
|
|
||||||
super
|
|
||||||
|
|
||||||
raise SyntaxError, options[:locale].t("errors.syntax.render") unless markup =~ SYNTAX
|
|
||||||
|
|
||||||
template_name = Regexp.last_match(1)
|
|
||||||
variable_name = Regexp.last_match(3)
|
|
||||||
|
|
||||||
@alias_name = Regexp.last_match(5)
|
|
||||||
@variable_name_expr = variable_name ? Expression.parse(variable_name) : nil
|
|
||||||
@template_name_expr = Expression.parse(template_name)
|
|
||||||
|
|
||||||
@attributes = {}
|
|
||||||
markup.scan(TagAttributes) do |key, value|
|
|
||||||
@attributes[key] = Expression.parse(value)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_to_output_buffer(context, output)
|
|
||||||
render_tag(context, output)
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_tag(context, output)
|
|
||||||
# Though we evaluate this here we will only ever parse it as a string literal.
|
|
||||||
template_name = context.evaluate(@template_name_expr)
|
|
||||||
raise ArgumentError, options[:locale].t("errors.argument.include") unless template_name
|
|
||||||
|
|
||||||
partial = PartialCache.load(
|
|
||||||
template_name,
|
|
||||||
context: context,
|
|
||||||
parse_context: parse_context
|
|
||||||
)
|
|
||||||
|
|
||||||
context_variable_name = @alias_name || template_name.split('/').last
|
|
||||||
|
|
||||||
render_partial_func = ->(var, forloop) {
|
|
||||||
inner_context = context.new_isolated_subcontext
|
|
||||||
inner_context.template_name = template_name
|
|
||||||
inner_context.partial = true
|
|
||||||
inner_context['forloop'] = forloop if forloop
|
|
||||||
@attributes.each do |key, value|
|
|
||||||
inner_context[key] = context.evaluate(value)
|
|
||||||
end
|
|
||||||
inner_context[context_variable_name] = var unless var.nil?
|
|
||||||
partial.render_to_output_buffer(inner_context, output)
|
|
||||||
forloop&.send(:increment!)
|
|
||||||
}
|
|
||||||
|
|
||||||
variable = @variable_name_expr ? context.evaluate(@variable_name_expr) : nil
|
|
||||||
if variable.is_a?(Array)
|
|
||||||
forloop = Liquid::ForloopDrop.new(template_name, variable.count, nil)
|
|
||||||
variable.each { |var| render_partial_func.call(var, forloop) }
|
|
||||||
else
|
|
||||||
render_partial_func.call(variable, nil)
|
|
||||||
end
|
|
||||||
|
|
||||||
output
|
|
||||||
end
|
|
||||||
|
|
||||||
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
|
||||||
def children
|
|
||||||
[
|
|
||||||
@node.template_name_expr,
|
|
||||||
] + @node.attributes.values
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Template.register_tag('render', Render)
|
|
||||||
end
|
|
||||||
@@ -2,21 +2,21 @@
|
|||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class TableRow < Block
|
class TableRow < Block
|
||||||
Syntax = /(\w+)\s+in\s+(#{QuotedFragment}+)/o
|
SYNTAX = /(\w+)\s+in\s+(#{QUOTED_FRAGMENT}+)/o.freeze
|
||||||
|
|
||||||
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 = Regexp.last_match(1)
|
||||||
@collection_name = Expression.parse(Regexp.last_match(2))
|
@collection_name = Expression.parse(Regexp.last_match(2))
|
||||||
@attributes = {}
|
@attributes = {}
|
||||||
markup.scan(TagAttributes) do |key, value|
|
markup.scan(TAG_ATTRIBUTES) 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, options[:locale].t('errors.syntax.table_row')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -44,9 +44,7 @@ module Liquid
|
|||||||
super
|
super
|
||||||
output << '</td>'
|
output << '</td>'
|
||||||
|
|
||||||
if tablerowloop.col_last && !tablerowloop.last
|
output << "</tr>\n<tr class=\"row#{tablerowloop.row + 1}\">" if tablerowloop.col_last && !tablerowloop.last
|
||||||
output << "</tr>\n<tr class=\"row#{tablerowloop.row + 1}\">"
|
|
||||||
end
|
|
||||||
|
|
||||||
tablerowloop.send(:increment!)
|
tablerowloop.send(:increment!)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -9,16 +9,14 @@ module Liquid
|
|||||||
#
|
#
|
||||||
class Unless < If
|
class Unless < If
|
||||||
def render_to_output_buffer(context, output)
|
def render_to_output_buffer(context, output)
|
||||||
# First condition is interpreted backwards ( if not )
|
context.stack do
|
||||||
first_block = @blocks.first
|
# First condition is interpreted backwards ( if not )
|
||||||
unless first_block.evaluate(context)
|
first_block = @blocks.first
|
||||||
return first_block.attachment.render_to_output_buffer(context, output)
|
return first_block.attachment.render_to_output_buffer(context, output) unless first_block.evaluate(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|
|
||||||
if block.evaluate(context)
|
return block.attachment.render_to_output_buffer(context, output) if block.evaluate(context)
|
||||||
return block.attachment.render_to_output_buffer(context, output)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,11 @@ 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
|
||||||
@@ -76,14 +80,6 @@ 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
|
||||||
@@ -92,14 +88,6 @@ module Liquid
|
|||||||
@tags ||= TagRegistry.new
|
@tags ||= TagRegistry.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_register(name, klass)
|
|
||||||
registers[name.to_sym] = klass
|
|
||||||
end
|
|
||||||
|
|
||||||
def registers
|
|
||||||
@registers ||= {}
|
|
||||||
end
|
|
||||||
|
|
||||||
def error_mode
|
def error_mode
|
||||||
@error_mode ||= :lax
|
@error_mode ||= :lax
|
||||||
end
|
end
|
||||||
@@ -181,9 +169,7 @@ module Liquid
|
|||||||
when Liquid::Context
|
when Liquid::Context
|
||||||
c = args.shift
|
c = args.shift
|
||||||
|
|
||||||
if @rethrow_errors
|
c.exception_renderer = ->(_e) { raise } if @rethrow_errors
|
||||||
c.exception_renderer = ->(_e) { raise }
|
|
||||||
end
|
|
||||||
|
|
||||||
c
|
c
|
||||||
when Liquid::Drop
|
when Liquid::Drop
|
||||||
@@ -194,31 +180,23 @@ 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
|
output = nil
|
||||||
|
|
||||||
context_register = context.registers.is_a?(StaticRegisters) ? context.registers.static : context.registers
|
|
||||||
|
|
||||||
case args.last
|
case args.last
|
||||||
when Hash
|
when Hash
|
||||||
options = args.pop
|
options = args.pop
|
||||||
output = options[:output] if options[:output]
|
output = options[:output] if options[:output]
|
||||||
|
|
||||||
options[:registers]&.each do |key, register|
|
registers.merge!(options[:registers]) if options[:registers].is_a?(Hash)
|
||||||
context_register[key] = register
|
|
||||||
end
|
|
||||||
|
|
||||||
apply_options_to_context(context, options)
|
apply_options_to_context(context, options)
|
||||||
when Module, Array
|
when Module, Array
|
||||||
context.add_filters(args.pop)
|
context.add_filters(args.pop)
|
||||||
end
|
end
|
||||||
|
|
||||||
Template.registers.each do |key, register|
|
|
||||||
context_register[key] = register
|
|
||||||
end
|
|
||||||
|
|
||||||
# Retrying a render resets resource usage
|
# Retrying a render resets resource usage
|
||||||
context.resource_limits.reset
|
context.resource_limits.reset
|
||||||
|
|
||||||
@@ -254,7 +232,7 @@ module Liquid
|
|||||||
if @profiling && !context.partial
|
if @profiling && !context.partial
|
||||||
raise "Profiler not loaded, require 'liquid/profiler' first" unless defined?(Liquid::Profiler)
|
raise "Profiler not loaded, require 'liquid/profiler' first" unless defined?(Liquid::Profiler)
|
||||||
|
|
||||||
@profiler = Profiler.new(context.template_name)
|
@profiler = Profiler.new
|
||||||
@profiler.start
|
@profiler.start
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
|||||||
@@ -2,33 +2,27 @@
|
|||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class Tokenizer
|
class Tokenizer
|
||||||
attr_reader :line_number, :for_liquid_tag
|
attr_reader :line_number
|
||||||
|
|
||||||
def initialize(source, line_numbers = false, line_number: nil, for_liquid_tag: false)
|
def initialize(source, line_numbers = false)
|
||||||
@source = source
|
@source = source
|
||||||
@line_number = line_number || (line_numbers ? 1 : nil)
|
@line_number = line_numbers ? 1 : nil
|
||||||
@for_liquid_tag = for_liquid_tag
|
|
||||||
@tokens = tokenize
|
@tokens = tokenize
|
||||||
end
|
end
|
||||||
|
|
||||||
def shift
|
def shift
|
||||||
(token = @tokens.shift) || return
|
token = @tokens.shift
|
||||||
|
@line_number += token.count("\n") if @line_number && token
|
||||||
if @line_number
|
|
||||||
@line_number += @for_liquid_tag ? 1 : token.count("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
token
|
token
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def tokenize
|
def tokenize
|
||||||
|
@source = @source.source if @source.respond_to?(:source)
|
||||||
return [] if @source.to_s.empty?
|
return [] if @source.to_s.empty?
|
||||||
|
|
||||||
return @source.split("\n") if @for_liquid_tag
|
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]&.empty?
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Liquid
|
|
||||||
module Usage
|
|
||||||
def self.increment(name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -21,13 +21,9 @@ module Liquid
|
|||||||
return [] unless collection.respond_to?(:each)
|
return [] unless collection.respond_to?(:each)
|
||||||
|
|
||||||
collection.each do |item|
|
collection.each do |item|
|
||||||
if to && to <= index
|
break if to && to <= index
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
if from <= index
|
segments << item if from <= index
|
||||||
segments << item
|
|
||||||
end
|
|
||||||
|
|
||||||
index += 1
|
index += 1
|
||||||
end
|
end
|
||||||
@@ -37,11 +33,12 @@ 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
|
||||||
|
|
||||||
@@ -52,7 +49,7 @@ module Liquid
|
|||||||
when Numeric
|
when Numeric
|
||||||
obj
|
obj
|
||||||
when String
|
when String
|
||||||
/\A-?\d+\.\d+\z/.match?(obj.strip) ? 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
|
||||||
@@ -67,6 +64,7 @@ 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
|
||||||
|
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ module Liquid
|
|||||||
# {{ user | link }}
|
# {{ user | link }}
|
||||||
#
|
#
|
||||||
class Variable
|
class Variable
|
||||||
FilterMarkupRegex = /#{FilterSeparator}\s*(.*)/om
|
FILTER_MARKUP_REGEX = /#{FILTER_SEPARATOR}\s*(.*)/om.freeze
|
||||||
FilterParser = /(?:\s+|#{QuotedFragment}|#{ArgumentSeparator})+/o
|
FILTER_PARSER = /(?:\s+|#{QUOTED_FRAGMENT}|#{ARGUMENT_SEPARATOR})+/o.freeze
|
||||||
FilterArgsRegex = /(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*((?:\w+\s*\:\s*)?#{QuotedFragment})/o
|
FILTER_ARGS_REGEX = /(?:#{FILTER_ARGUMENT_SEPARATOR}|#{ARGUMENT_SEPARATOR})\s*((?:\w+\s*\:\s*)?#{QUOTED_FRAGMENT})/o.freeze
|
||||||
JustTagAttributes = /\A#{TagAttributes}\z/o
|
JUST_TAG_ATTRIBUTES = /\A#{TAG_ATTRIBUTES}\z/o.freeze
|
||||||
MarkupWithQuotedFragment = /(#{QuotedFragment})(.*)/om
|
MARKUP_WITH_QUOTED_FRAGMENT = /(#{QUOTED_FRAGMENT})(.*)/om.freeze
|
||||||
|
|
||||||
attr_accessor :filters, :name, :line_number
|
attr_accessor :filters, :name, :line_number
|
||||||
attr_reader :parse_context
|
attr_reader :parse_context
|
||||||
@@ -43,17 +43,18 @@ module Liquid
|
|||||||
|
|
||||||
def lax_parse(markup)
|
def lax_parse(markup)
|
||||||
@filters = []
|
@filters = []
|
||||||
return unless markup =~ MarkupWithQuotedFragment
|
return unless markup =~ MARKUP_WITH_QUOTED_FRAGMENT
|
||||||
|
|
||||||
name_markup = Regexp.last_match(1)
|
name_markup = Regexp.last_match(1)
|
||||||
filter_markup = Regexp.last_match(2)
|
filter_markup = Regexp.last_match(2)
|
||||||
@name = Expression.parse(name_markup)
|
@name = Expression.parse(name_markup)
|
||||||
if filter_markup =~ FilterMarkupRegex
|
if filter_markup =~ FILTER_MARKUP_REGEX
|
||||||
filters = Regexp.last_match(1).scan(FilterParser)
|
filters = Regexp.last_match(1).scan(FILTER_PARSER)
|
||||||
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(FilterArgsRegex).flatten
|
filterargs = f.scan(FILTER_ARGS_REGEX).flatten
|
||||||
@filters << parse_filter_expressions(filtername, filterargs)
|
@filters << parse_filter_expressions(filtername, filterargs)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -104,21 +105,13 @@ module Liquid
|
|||||||
output
|
output
|
||||||
end
|
end
|
||||||
|
|
||||||
def disabled?(_context)
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
def disabled_tags
|
|
||||||
[]
|
|
||||||
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(JustTagAttributes))
|
if (matches = a.match(JUST_TAG_ATTRIBUTES))
|
||||||
keyword_args ||= {}
|
keyword_args ||= {}
|
||||||
keyword_args[matches[1]] = Expression.parse(matches[2])
|
keyword_args[matches[1]] = Expression.parse(matches[2])
|
||||||
else
|
else
|
||||||
@@ -146,7 +139,7 @@ module Liquid
|
|||||||
return unless obj.tainted?
|
return unless obj.tainted?
|
||||||
return if Template.taint_mode == :lax
|
return if Template.taint_mode == :lax
|
||||||
|
|
||||||
@markup =~ QuotedFragment
|
@markup =~ QUOTED_FRAGMENT
|
||||||
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")
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class VariableLookup
|
class VariableLookup
|
||||||
SQUARE_BRACKETED = /\A\[(.*)\]\z/m
|
SQUARE_BRACKETED = /\A\[(.*)\]\z/m.freeze
|
||||||
COMMAND_METHODS = ['size', 'first', 'last'].freeze
|
COMMAND_METHODS = %w[size first last].freeze
|
||||||
|
|
||||||
attr_reader :name, :lookups
|
attr_reader :name, :lookups
|
||||||
|
|
||||||
@@ -12,12 +12,10 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def initialize(markup)
|
def initialize(markup)
|
||||||
lookups = markup.scan(VariableParser)
|
lookups = markup.scan(VARIABLE_PARSER)
|
||||||
|
|
||||||
name = lookups.shift
|
name = lookups.shift
|
||||||
if name =~ SQUARE_BRACKETED
|
name = Expression.parse(Regexp.last_match(1)) if name =~ SQUARE_BRACKETED
|
||||||
name = Expression.parse(Regexp.last_match(1))
|
|
||||||
end
|
|
||||||
@name = name
|
@name = name
|
||||||
|
|
||||||
@lookups = lookups
|
@lookups = lookups
|
||||||
@@ -43,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)
|
||||||
@@ -61,6 +59,7 @@ 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,6 +1,5 @@
|
|||||||
# encoding: utf-8
|
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
VERSION = "4.0.3"
|
VERSION = '4.0.3'
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,32 +1,31 @@
|
|||||||
# encoding: utf-8
|
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
lib = File.expand_path('../lib/', __FILE__)
|
lib = File.expand_path('lib', __dir__)
|
||||||
$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.4.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('rake', '~> 11.3')
|
|
||||||
s.add_development_dependency('minitest')
|
s.add_development_dependency('minitest')
|
||||||
|
s.add_development_dependency('rake', '~> 11.3')
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -14,7 +14,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
|
||||||
|
|||||||
@@ -2,62 +2,25 @@
|
|||||||
|
|
||||||
require 'benchmark/ips'
|
require 'benchmark/ips'
|
||||||
require 'memory_profiler'
|
require 'memory_profiler'
|
||||||
require 'terminal-table'
|
|
||||||
require_relative 'theme_runner'
|
require_relative 'theme_runner'
|
||||||
|
|
||||||
class Profiler
|
def profile(phase, &block)
|
||||||
LOG_LABEL = "Profiling: ".rjust(14).freeze
|
puts
|
||||||
REPORTS_DIR = File.expand_path('.memprof', __dir__).freeze
|
puts "#{phase}:"
|
||||||
|
puts
|
||||||
|
|
||||||
def self.run
|
report = MemoryProfiler.report(&block)
|
||||||
puts
|
|
||||||
yield new
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize
|
report.pretty_print(
|
||||||
@allocated = []
|
color_output: true,
|
||||||
@retained = []
|
scale_bytes: true,
|
||||||
@headings = []
|
detailed_report: true
|
||||||
end
|
)
|
||||||
|
|
||||||
def profile(phase, &block)
|
|
||||||
print(LOG_LABEL)
|
|
||||||
print("#{phase}.. ".ljust(10))
|
|
||||||
report = MemoryProfiler.report(&block)
|
|
||||||
puts 'Done.'
|
|
||||||
@headings << phase.capitalize
|
|
||||||
@allocated << "#{report.scale_bytes(report.total_allocated_memsize)} (#{report.total_allocated} objects)"
|
|
||||||
@retained << "#{report.scale_bytes(report.total_retained_memsize)} (#{report.total_retained} objects)"
|
|
||||||
|
|
||||||
return if ENV['CI']
|
|
||||||
|
|
||||||
require 'fileutils'
|
|
||||||
report_file = File.join(REPORTS_DIR, "#{sanitize(phase)}.txt")
|
|
||||||
FileUtils.mkdir_p(REPORTS_DIR)
|
|
||||||
report.pretty_print(to_file: report_file, scale_bytes: true)
|
|
||||||
end
|
|
||||||
|
|
||||||
def tabulate
|
|
||||||
table = Terminal::Table.new(headings: @headings.unshift('Phase')) do |t|
|
|
||||||
t << @allocated.unshift('Total allocated')
|
|
||||||
t << @retained.unshift('Total retained')
|
|
||||||
end
|
|
||||||
|
|
||||||
puts
|
|
||||||
puts table
|
|
||||||
puts "\nDetailed report(s) saved to #{REPORTS_DIR}/" unless ENV['CI']
|
|
||||||
end
|
|
||||||
|
|
||||||
def sanitize(string)
|
|
||||||
string.downcase.gsub(/[\W]/, '-').squeeze('-')
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
Liquid::Template.error_mode = ARGV.first.to_sym if ARGV.first
|
Liquid::Template.error_mode = ARGV.first.to_sym if ARGV.first
|
||||||
|
|
||||||
runner = ThemeRunner.new
|
profiler = ThemeRunner.new
|
||||||
Profiler.run do |x|
|
|
||||||
x.profile('parse') { runner.compile }
|
profile('Parsing') { profiler.compile }
|
||||||
x.profile('render') { runner.render }
|
profile('Rendering') { profiler.render }
|
||||||
x.tabulate
|
|
||||||
end
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ Liquid::Template.error_mode = ARGV.first.to_sym if ARGV.first
|
|||||||
profiler = ThemeRunner.new
|
profiler = ThemeRunner.new
|
||||||
profiler.run
|
profiler.run
|
||||||
|
|
||||||
[:cpu, :object].each do |profile_type|
|
%i[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
|
||||||
@@ -22,5 +22,5 @@ profiler.run
|
|||||||
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,12 +1,12 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class CommentForm < Liquid::Block
|
class CommentForm < Liquid::Block
|
||||||
Syntax = /(#{Liquid::VariableSignature}+)/
|
SYNTAX = /(#{Liquid::VARIABLE_SIGNATURE}+)/.freeze
|
||||||
|
|
||||||
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 = Regexp.last_match(1)
|
||||||
@attributes = {}
|
@attributes = {}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -21,7 +21,9 @@ module Database
|
|||||||
db = db.each_with_object({}) do |(key, values), assigns|
|
db = db.each_with_object({}) do |(key, values), assigns|
|
||||||
assigns[key] = values.each_with_object({}) do |v, h|
|
assigns[key] = values.each_with_object({}) do |v, h|
|
||||||
h[v['handle']] = v
|
h[v['handle']] = v
|
||||||
|
h
|
||||||
end
|
end
|
||||||
|
assigns
|
||||||
end
|
end
|
||||||
|
|
||||||
# Some standard direct accessors so that the specialized templates
|
# Some standard direct accessors so that the specialized templates
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ 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
|
||||||
|
|||||||
@@ -3,12 +3,14 @@
|
|||||||
module MoneyFilter
|
module MoneyFilter
|
||||||
def money_with_currency(money)
|
def money_with_currency(money)
|
||||||
return '' if money.nil?
|
return '' if money.nil?
|
||||||
format("$ %.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?
|
||||||
format("$ %.2f", money / 100.0)
|
|
||||||
|
format('$ %.2f', money / 100.0)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Paginate < Liquid::Block
|
class Paginate < Liquid::Block
|
||||||
Syntax = /(#{Liquid::QuotedFragment})\s*(by\s*(\d+))?/
|
SYNTAX = /(#{Liquid::QUOTED_FRAGMENT})\s*(by\s*(\d+))?/.freeze
|
||||||
|
|
||||||
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 = Regexp.last_match(1)
|
||||||
@page_size = if Regexp.last_match(2)
|
@page_size = if Regexp.last_match(2)
|
||||||
Regexp.last_match(3).to_i
|
Regexp.last_match(3).to_i
|
||||||
@@ -15,7 +15,7 @@ class Paginate < Liquid::Block
|
|||||||
end
|
end
|
||||||
|
|
||||||
@attributes = { 'window_size' => 3 }
|
@attributes = { 'window_size' => 3 }
|
||||||
markup.scan(Liquid::TagAttributes) do |key, value|
|
markup.scan(Liquid::TAG_ATTRIBUTES) do |key, value|
|
||||||
@attributes[key] = value
|
@attributes[key] = value
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -45,7 +45,7 @@ class Paginate < Liquid::Block
|
|||||||
|
|
||||||
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 1 >= current_page
|
pagination['previous'] = link('« Previous', current_page - 1) unless current_page <= 1
|
||||||
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,6 +61,7 @@ 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
|
||||||
@@ -87,6 +88,6 @@ class Paginate < Liquid::Block
|
|||||||
end
|
end
|
||||||
|
|
||||||
def current_url
|
def current_url
|
||||||
"/collections/frontpage"
|
'/collections/frontpage'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -17,21 +17,21 @@ 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
|
||||||
|
|
||||||
def link_to_vendor(vendor)
|
def link_to_vendor(vendor)
|
||||||
if vendor
|
if vendor
|
||||||
link_to(vendor, url_for_vendor(vendor), vendor)
|
link_to vendor, url_for_vendor(vendor), vendor
|
||||||
else
|
else
|
||||||
'Unknown Vendor'
|
'Unknown Vendor'
|
||||||
end
|
end
|
||||||
@@ -39,7 +39,7 @@ module ShopFilter
|
|||||||
|
|
||||||
def link_to_type(type)
|
def link_to_type(type)
|
||||||
if type
|
if type
|
||||||
link_to(type, url_for_type(type), type)
|
link_to type, url_for_type(type), type
|
||||||
else
|
else
|
||||||
'Unknown Vendor'
|
'Unknown Vendor'
|
||||||
end
|
end
|
||||||
@@ -54,9 +54,7 @@ module ShopFilter
|
|||||||
end
|
end
|
||||||
|
|
||||||
def product_img_url(url, style = 'small')
|
def product_img_url(url, style = 'small')
|
||||||
unless url =~ %r{\Aproducts/([\w\-\_]+)\.(\w{2,4})}
|
raise ArgumentError, 'filter "size" can only be called on product images' unless url =~ %r{\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'
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
module WeightFilter
|
module WeightFilter
|
||||||
def weight(grams)
|
def weight(grams)
|
||||||
format("%.2f", grams / 1000)
|
format('%.2f', grams / 1000)
|
||||||
end
|
end
|
||||||
|
|
||||||
def weight_with_unit(grams)
|
def weight_with_unit(grams)
|
||||||
|
|||||||
@@ -12,29 +12,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
|
||||||
|
|||||||
@@ -33,77 +33,77 @@ class BlankTest < Minitest::Test
|
|||||||
|
|
||||||
def test_new_tags_are_not_blank_by_default
|
def test_new_tags_are_not_blank_by_default
|
||||||
with_custom_tag('foobar', FoobarTag) do
|
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
|
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
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ 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
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ 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 +16,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 +32,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 +47,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
|
||||||
|
|||||||
@@ -7,15 +7,15 @@ 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
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ end
|
|||||||
class ProductDrop < Liquid::Drop
|
class ProductDrop < Liquid::Drop
|
||||||
class TextDrop < Liquid::Drop
|
class TextDrop < Liquid::Drop
|
||||||
def array
|
def array
|
||||||
['text1', 'text2']
|
%w[text1 text2]
|
||||||
end
|
end
|
||||||
|
|
||||||
def text
|
def text
|
||||||
@@ -33,7 +33,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}"
|
+'catchall_method: ' << method.to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -50,13 +50,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
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ class DropsTest < Minitest::Test
|
|||||||
|
|
||||||
def test_product_drop
|
def test_product_drop
|
||||||
tpl = Liquid::Template.parse(' ')
|
tpl = Liquid::Template.parse(' ')
|
||||||
assert_equal(' ', tpl.render!('product' => ProductDrop.new))
|
assert_equal ' ', tpl.render!('product' => ProductDrop.new)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_rendering_raises_on_tainted_attr
|
def test_rendering_raises_on_tainted_attr
|
||||||
@@ -141,105 +141,100 @@ 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
|
||||||
output = Liquid::Template.parse(' {{ product.texts.text }} ').render!('product' => ProductDrop.new)
|
output = Liquid::Template.parse(' {{ product.texts.text }} ').render!('product' => ProductDrop.new)
|
||||||
assert_equal(' text1 ', output)
|
assert_equal ' text1 ', output
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_catchall_unknown_method
|
def test_catchall_unknown_method
|
||||||
output = Liquid::Template.parse(' {{ product.catchall.unknown }} ').render!('product' => ProductDrop.new)
|
output = Liquid::Template.parse(' {{ product.catchall.unknown }} ').render!('product' => ProductDrop.new)
|
||||||
assert_equal(' catchall_method: unknown ', output)
|
assert_equal ' catchall_method: unknown ', output
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_catchall_integer_argument_drop
|
def test_catchall_integer_argument_drop
|
||||||
output = Liquid::Template.parse(' {{ product.catchall[8] }} ').render!('product' => ProductDrop.new)
|
output = Liquid::Template.parse(' {{ product.catchall[8] }} ').render!('product' => ProductDrop.new)
|
||||||
assert_equal(' catchall_method: 8 ', output)
|
assert_equal ' catchall_method: 8 ', output
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_text_array_drop
|
def test_text_array_drop
|
||||||
output = Liquid::Template.parse('{% for text in product.texts.array %} {{text}} {% endfor %}').render!('product' => ProductDrop.new)
|
output = Liquid::Template.parse('{% for text in product.texts.array %} {{text}} {% endfor %}').render!('product' => ProductDrop.new)
|
||||||
assert_equal(' text1 text2 ', output)
|
assert_equal ' text1 text2 ', output
|
||||||
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
|
|
||||||
|
|
||||||
def test_context_drop_array_with_map
|
|
||||||
output = Liquid::Template.parse(' {{ contexts | map: "bar" }} ').render!('contexts' => [ContextDrop.new, ContextDrop.new], 'bar' => "carrot")
|
|
||||||
assert_equal(' carrotcarrot ', 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
|
||||||
|
|
||||||
def test_protected
|
def test_protected
|
||||||
output = Liquid::Template.parse(' {{ product.callmenot }} ').render!('product' => ProductDrop.new)
|
output = Liquid::Template.parse(' {{ product.callmenot }} ').render!('product' => ProductDrop.new)
|
||||||
assert_equal(' ', output)
|
assert_equal ' ', output
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_object_methods_not_allowed
|
def test_object_methods_not_allowed
|
||||||
[:dup, :clone, :singleton_class, :eval, :class_eval, :inspect].each do |method|
|
%i[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
|
def test_scope
|
||||||
assert_equal('1', Liquid::Template.parse('{{ context.scopes }}').render!('context' => ContextDrop.new))
|
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 '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]))
|
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
|
end
|
||||||
|
|
||||||
def test_scope_though_proc
|
def test_scope_though_proc
|
||||||
assert_equal('1', Liquid::Template.parse('{{ s }}').render!('context' => ContextDrop.new, 's' => proc { |c| c['context.scopes'] }))
|
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 '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]))
|
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
|
end
|
||||||
|
|
||||||
def test_scope_with_assigns
|
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"%}{{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 '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)
|
||||||
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
|
end
|
||||||
|
|
||||||
def test_scope_from_tags
|
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 '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 '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]))
|
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
|
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
|
||||||
|
|
||||||
def test_enumerable_drop
|
def test_enumerable_drop
|
||||||
assert_equal('123', Liquid::Template.parse('{% for c in collection %}{{c}}{% endfor %}').render!('collection' => EnumerableDrop.new))
|
assert_equal '123', Liquid::Template.parse('{% for c in collection %}{{c}}{% endfor %}').render!('collection' => EnumerableDrop.new)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_enumerable_drop_size
|
def test_enumerable_drop_size
|
||||||
assert_equal('3', Liquid::Template.parse('{{collection.size}}').render!('collection' => EnumerableDrop.new))
|
assert_equal '3', Liquid::Template.parse('{{collection.size}}').render!('collection' => EnumerableDrop.new)
|
||||||
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
|
||||||
["select", "each", "map", "cycle"].each do |method|
|
%w[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)
|
||||||
@@ -248,40 +243,33 @@ class DropsTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_some_enumerable_methods_still_get_invoked
|
def test_some_enumerable_methods_still_get_invoked
|
||||||
[:count, :max].each do |method|
|
%i[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)
|
||||||
|
|
||||||
[:min, :first].each do |method|
|
%i[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
|
||||||
|
|
||||||
def test_empty_string_value_access
|
def test_empty_string_value_access
|
||||||
assert_equal('', Liquid::Template.parse('{{ product[value] }}').render!('product' => ProductDrop.new, 'value' => ''))
|
assert_equal '', Liquid::Template.parse('{{ product[value] }}').render!('product' => ProductDrop.new, 'value' => '')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_nil_value_access
|
def test_nil_value_access
|
||||||
assert_equal('', Liquid::Template.parse('{{ product[value] }}').render!('product' => ProductDrop.new, 'value' => nil))
|
assert_equal '', Liquid::Template.parse('{{ product[value] }}').render!('product' => ProductDrop.new, 'value' => nil)
|
||||||
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
|
|
||||||
|
|
||||||
def test_invokable_methods
|
|
||||||
assert_equal(%w(to_liquid catchall user_input context texts).to_set, ProductDrop.invokable_methods)
|
|
||||||
assert_equal(%w(to_liquid scopes_as_array loop_pos scopes).to_set, ContextDrop.invokable_methods)
|
|
||||||
assert_equal(%w(to_liquid size max min first count).to_set, EnumerableDrop.invokable_methods)
|
|
||||||
assert_equal(%w(to_liquid max min sort count first).to_set, RealEnumerableDrop.invokable_methods)
|
|
||||||
end
|
end
|
||||||
end # DropsTest
|
end # DropsTest
|
||||||
|
|||||||
@@ -35,31 +35,31 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
TEXT
|
TEXT
|
||||||
|
|
||||||
output = Liquid::Template.parse(template, line_numbers: true).render('errors' => ErrorDrop.new)
|
output = Liquid::Template.parse(template, line_numbers: true).render('errors' => ErrorDrop.new)
|
||||||
assert_equal(expected, output)
|
assert_equal expected, output
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_standard_error
|
def test_standard_error
|
||||||
template = Liquid::Template.parse(' {{ errors.standard_error }} ')
|
template = Liquid::Template.parse(' {{ errors.standard_error }} ')
|
||||||
assert_equal(' Liquid error: standard error ', template.render('errors' => ErrorDrop.new))
|
assert_equal ' Liquid error: standard error ', template.render('errors' => ErrorDrop.new)
|
||||||
|
|
||||||
assert_equal(1, template.errors.size)
|
assert_equal 1, template.errors.size
|
||||||
assert_equal(StandardError, template.errors.first.class)
|
assert_equal StandardError, template.errors.first.class
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_syntax
|
def test_syntax
|
||||||
template = Liquid::Template.parse(' {{ errors.syntax_error }} ')
|
template = Liquid::Template.parse(' {{ errors.syntax_error }} ')
|
||||||
assert_equal(' Liquid syntax error: syntax error ', template.render('errors' => ErrorDrop.new))
|
assert_equal ' Liquid syntax error: syntax error ', template.render('errors' => ErrorDrop.new)
|
||||||
|
|
||||||
assert_equal(1, template.errors.size)
|
assert_equal 1, template.errors.size
|
||||||
assert_equal(SyntaxError, template.errors.first.class)
|
assert_equal SyntaxError, template.errors.first.class
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_argument
|
def test_argument
|
||||||
template = Liquid::Template.parse(' {{ errors.argument_error }} ')
|
template = Liquid::Template.parse(' {{ errors.argument_error }} ')
|
||||||
assert_equal(' Liquid error: argument error ', template.render('errors' => ErrorDrop.new))
|
assert_equal ' Liquid error: argument error ', template.render('errors' => ErrorDrop.new)
|
||||||
|
|
||||||
assert_equal(1, template.errors.size)
|
assert_equal 1, template.errors.size
|
||||||
assert_equal(ArgumentError, template.errors.first.class)
|
assert_equal ArgumentError, template.errors.first.class
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_missing_endtag_parse_time_error
|
def test_missing_endtag_parse_time_error
|
||||||
@@ -78,9 +78,9 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
|
|
||||||
def test_lax_unrecognized_operator
|
def test_lax_unrecognized_operator
|
||||||
template = Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', error_mode: :lax)
|
template = Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', error_mode: :lax)
|
||||||
assert_equal(' Liquid error: Unknown operator =! ', template.render)
|
assert_equal ' Liquid error: Unknown operator =! ', template.render
|
||||||
assert_equal(1, template.errors.size)
|
assert_equal 1, template.errors.size
|
||||||
assert_equal(Liquid::ArgumentError, template.errors.first.class)
|
assert_equal Liquid::ArgumentError, template.errors.first.class
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_with_line_numbers_adds_numbers_to_parser_errors
|
def test_with_line_numbers_adds_numbers_to_parser_errors
|
||||||
@@ -92,7 +92,7 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
|
|
||||||
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)
|
||||||
@@ -107,7 +107,7 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
|
|
||||||
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,11 @@ 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,11 +137,11 @@ 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
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_syntax_errors_in_nested_blocks_have_correct_line_number
|
def test_syntax_errors_in_nested_blocks_have_correct_line_number
|
||||||
@@ -155,40 +155,40 @@ 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
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_strict_error_messages
|
def test_strict_error_messages
|
||||||
err = assert_raises(SyntaxError) do
|
err = assert_raises(SyntaxError) do
|
||||||
Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', error_mode: :strict)
|
Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', error_mode: :strict)
|
||||||
end
|
end
|
||||||
assert_equal('Liquid syntax error: Unexpected character = in "1 =! 2"', err.message)
|
assert_equal 'Liquid syntax error: Unexpected character = in "1 =! 2"', err.message
|
||||||
|
|
||||||
err = assert_raises(SyntaxError) do
|
err = assert_raises(SyntaxError) do
|
||||||
Liquid::Template.parse('{{%%%}}', error_mode: :strict)
|
Liquid::Template.parse('{{%%%}}', error_mode: :strict)
|
||||||
end
|
end
|
||||||
assert_equal('Liquid syntax error: Unexpected character % in "{{%%%}}"', err.message)
|
assert_equal 'Liquid syntax error: Unexpected character % in "{{%%%}}"', err.message
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_warnings
|
def test_warnings
|
||||||
template = Liquid::Template.parse('{% if ~~~ %}{{%%%}}{% else %}{{ hello. }}{% endif %}', error_mode: :warn)
|
template = Liquid::Template.parse('{% if ~~~ %}{{%%%}}{% else %}{{ hello. }}{% endif %}', error_mode: :warn)
|
||||||
assert_equal(3, template.warnings.size)
|
assert_equal 3, template.warnings.size
|
||||||
assert_equal('Unexpected character ~ in "~~~"', template.warnings[0].to_s(false))
|
assert_equal 'Unexpected character ~ in "~~~"', template.warnings[0].to_s(false)
|
||||||
assert_equal('Unexpected character % in "{{%%%}}"', template.warnings[1].to_s(false))
|
assert_equal 'Unexpected character % in "{{%%%}}"', template.warnings[1].to_s(false)
|
||||||
assert_equal('Expected id but found end_of_string in "{{ hello. }}"', template.warnings[2].to_s(false))
|
assert_equal 'Expected id but found end_of_string in "{{ hello. }}"', template.warnings[2].to_s(false)
|
||||||
assert_equal('', template.render)
|
assert_equal '', template.render
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_warning_line_numbers
|
def test_warning_line_numbers
|
||||||
template = Liquid::Template.parse("{% if ~~~ %}\n{{%%%}}{% else %}\n{{ hello. }}{% endif %}", error_mode: :warn, line_numbers: true)
|
template = Liquid::Template.parse("{% if ~~~ %}\n{{%%%}}{% else %}\n{{ hello. }}{% endif %}", error_mode: :warn, line_numbers: true)
|
||||||
assert_equal('Liquid syntax error (line 1): Unexpected character ~ in "~~~"', template.warnings[0].message)
|
assert_equal 'Liquid syntax error (line 1): Unexpected character ~ in "~~~"', template.warnings[0].message
|
||||||
assert_equal('Liquid syntax error (line 2): Unexpected character % in "{{%%%}}"', template.warnings[1].message)
|
assert_equal 'Liquid syntax error (line 2): Unexpected character % in "{{%%%}}"', template.warnings[1].message
|
||||||
assert_equal('Liquid syntax error (line 3): Expected id but found end_of_string in "{{ hello. }}"', template.warnings[2].message)
|
assert_equal 'Liquid syntax error (line 3): Expected id but found end_of_string in "{{ hello. }}"', template.warnings[2].message
|
||||||
assert_equal(3, template.warnings.size)
|
assert_equal 3, template.warnings.size
|
||||||
assert_equal([1, 2, 3], template.warnings.map(&:line_number))
|
assert_equal [1, 2, 3], template.warnings.map(&:line_number)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Liquid should not catch Exceptions that are not subclasses of StandardError, like Interrupt and NoMemoryError
|
# Liquid should not catch Exceptions that are not subclasses of StandardError, like Interrupt and NoMemoryError
|
||||||
@@ -204,14 +204,14 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
|
|
||||||
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)
|
||||||
end
|
end
|
||||||
|
|
||||||
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 = ->(e) {
|
Liquid::Template.default_exception_renderer = lambda { |e|
|
||||||
exceptions << e
|
exceptions << e
|
||||||
''
|
''
|
||||||
}
|
}
|
||||||
@@ -219,8 +219,8 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
|
|
||||||
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)
|
||||||
ensure
|
ensure
|
||||||
Liquid::Template.default_exception_renderer = old_exception_renderer if old_exception_renderer
|
Liquid::Template.default_exception_renderer = old_exception_renderer if old_exception_renderer
|
||||||
end
|
end
|
||||||
@@ -228,22 +228,22 @@ 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 = ->(e) {
|
handler = lambda { |e|
|
||||||
exceptions << e
|
exceptions << e
|
||||||
e.cause
|
e.cause
|
||||||
}
|
}
|
||||||
|
|
||||||
output = template.render({ 'errors' => ErrorDrop.new }, exception_renderer: handler)
|
output = template.render({ 'errors' => ErrorDrop.new }, exception_renderer: handler)
|
||||||
|
|
||||||
assert_equal('This is a runtime error: runtime error', output)
|
assert_equal 'This is a runtime error: runtime error', output
|
||||||
assert_equal([Liquid::InternalError], exceptions.map(&:class))
|
assert_equal [Liquid::InternalError], exceptions.map(&:class)
|
||||||
assert_equal(exceptions, template.errors)
|
assert_equal exceptions, template.errors
|
||||||
assert_equal('#<RuntimeError: runtime error>', exceptions.first.cause.inspect)
|
assert_equal '#<RuntimeError: runtime error>', exceptions.first.cause.inspect
|
||||||
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
|
||||||
|
|
||||||
@@ -257,7 +257,7 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
ensure
|
ensure
|
||||||
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
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class FiltersTest < Minitest::Test
|
|||||||
|
|
||||||
module OverrideObjectMethodFilter
|
module OverrideObjectMethodFilter
|
||||||
def tap(_input)
|
def tap(_input)
|
||||||
"tap overridden"
|
'tap overridden'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -41,13 +41,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,49 +55,49 @@ 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'] = ['expected', 'as', 'alphabetic']
|
@context['words'] = %w[expected as alphabetic]
|
||||||
@context['arrays'] = ['flower', 'are']
|
@context['arrays'] = %w[flower are]
|
||||||
@context['case_sensitive'] = ['sensitive', 'Expected', 'case']
|
@context['case_sensitive'] = %w[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'] = ['case', 'Assert', 'Insensitive']
|
@context['words'] = %w[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)
|
||||||
|
|
||||||
# Test objects
|
# Test objects
|
||||||
assert_equal('A b C', Template.parse("{{objects | sort_natural: 'a' | map: 'a' | join}}").render(@context))
|
assert_equal 'A b C', Template.parse("{{objects | sort_natural: 'a' | map: 'a' | join}}").render(@context)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_compact
|
def test_compact
|
||||||
@@ -106,37 +106,37 @@ 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)
|
||||||
|
|
||||||
# Test objects
|
# Test objects
|
||||||
assert_equal('A C', Template.parse("{{objects | compact: 'a' | map: 'a' | join}}").render(@context))
|
assert_equal 'A C', Template.parse("{{objects | compact: 'a' | map: 'a' | join}}").render(@context)
|
||||||
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
|
||||||
@@ -144,14 +144,14 @@ class FiltersTest < Minitest::Test
|
|||||||
@context['input'] = 'hello %{first_name}, %{last_name}'
|
@context['input'] = 'hello %{first_name}, %{last_name}'
|
||||||
@context.add_filters(SubstituteFilter)
|
@context.add_filters(SubstituteFilter)
|
||||||
output = Template.parse(%({{ input | substitute: first_name: surname, last_name: 'doe' }})).render(@context)
|
output = Template.parse(%({{ input | substitute: first_name: surname, last_name: 'doe' }})).render(@context)
|
||||||
assert_equal('hello john, doe', output)
|
assert_equal 'hello john, doe', output
|
||||||
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 +160,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
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,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
|
||||||
|
|||||||
13
test/integration/legacy_test.rb
Normal file
13
test/integration/legacy_test.rb
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# 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
|
||||||
@@ -11,11 +11,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
|
||||||
|
|
||||||
@@ -42,84 +42,84 @@ class OutputTest < Minitest::Test
|
|||||||
text = %( {{best_cars}} )
|
text = %( {{best_cars}} )
|
||||||
|
|
||||||
expected = %( bmw )
|
expected = %( bmw )
|
||||||
assert_equal(expected, Template.parse(text).render!(@assigns))
|
assert_equal expected, Template.parse(text).render!(@assigns)
|
||||||
end
|
end
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
def test_variable_traversing
|
def test_variable_traversing
|
||||||
text = %( {{car.bmw}} {{car.gm}} {{car.bmw}} )
|
text = %( {{car.bmw}} {{car.gm}} {{car.bmw}} )
|
||||||
|
|
||||||
expected = %( good bad good )
|
expected = %( good bad good )
|
||||||
assert_equal(expected, Template.parse(text).render!(@assigns))
|
assert_equal expected, Template.parse(text).render!(@assigns)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_variable_piping
|
def test_variable_piping
|
||||||
text = %( {{ car.gm | make_funny }} )
|
text = %( {{ car.gm | make_funny }} )
|
||||||
expected = %( LOL )
|
expected = %( LOL )
|
||||||
|
|
||||||
assert_equal(expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]))
|
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_variable_piping_with_input
|
def test_variable_piping_with_input
|
||||||
text = %( {{ car.gm | cite_funny }} )
|
text = %( {{ car.gm | cite_funny }} )
|
||||||
expected = %( LOL: bad )
|
expected = %( LOL: bad )
|
||||||
|
|
||||||
assert_equal(expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]))
|
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_variable_piping_with_args
|
def test_variable_piping_with_args
|
||||||
text = %! {{ car.gm | add_smiley : ':-(' }} !
|
text = %! {{ car.gm | add_smiley : ':-(' }} !
|
||||||
expected = %| bad :-( |
|
expected = %| bad :-( |
|
||||||
|
|
||||||
assert_equal(expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]))
|
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_variable_piping_with_no_args
|
def test_variable_piping_with_no_args
|
||||||
text = %( {{ car.gm | add_smiley }} )
|
text = %( {{ car.gm | add_smiley }} )
|
||||||
expected = %| bad :-) |
|
expected = %| bad :-) |
|
||||||
|
|
||||||
assert_equal(expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]))
|
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_multiple_variable_piping_with_args
|
def test_multiple_variable_piping_with_args
|
||||||
text = %! {{ car.gm | add_smiley : ':-(' | add_smiley : ':-('}} !
|
text = %! {{ car.gm | add_smiley : ':-(' | add_smiley : ':-('}} !
|
||||||
expected = %| bad :-( :-( |
|
expected = %| bad :-( :-( |
|
||||||
|
|
||||||
assert_equal(expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]))
|
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_variable_piping_with_multiple_args
|
def test_variable_piping_with_multiple_args
|
||||||
text = %( {{ car.gm | add_tag : 'span', 'bar'}} )
|
text = %( {{ car.gm | add_tag : 'span', 'bar'}} )
|
||||||
expected = %( <span id="bar">bad</span> )
|
expected = %( <span id="bar">bad</span> )
|
||||||
|
|
||||||
assert_equal(expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]))
|
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_variable_piping_with_variable_args
|
def test_variable_piping_with_variable_args
|
||||||
text = %( {{ car.gm | add_tag : 'span', car.bmw}} )
|
text = %( {{ car.gm | add_tag : 'span', car.bmw}} )
|
||||||
expected = %( <span id="good">bad</span> )
|
expected = %( <span id="good">bad</span> )
|
||||||
|
|
||||||
assert_equal(expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]))
|
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_multiple_pipings
|
def test_multiple_pipings
|
||||||
text = %( {{ best_cars | cite_funny | paragraph }} )
|
text = %( {{ best_cars | cite_funny | paragraph }} )
|
||||||
expected = %( <p>LOL: bmw</p> )
|
expected = %( <p>LOL: bmw</p> )
|
||||||
|
|
||||||
assert_equal(expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]))
|
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_link_to
|
def test_link_to
|
||||||
text = %( {{ 'Typo' | link_to: 'http://typo.leetsoft.com' }} )
|
text = %( {{ 'Typo' | link_to: 'http://typo.leetsoft.com' }} )
|
||||||
expected = %( <a href="http://typo.leetsoft.com">Typo</a> )
|
expected = %( <a href="http://typo.leetsoft.com">Typo</a> )
|
||||||
|
|
||||||
assert_equal(expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]))
|
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
||||||
end
|
end
|
||||||
end # OutputTest
|
end # OutputTest
|
||||||
|
|||||||
@@ -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(
|
||||||
["test", "infilter"],
|
%w[test infilter],
|
||||||
visit(%({{ test | split: infilter }}))
|
visit(%({{ test | split: infilter }}))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_dynamic_variable
|
def test_dynamic_variable
|
||||||
assert_equal(
|
assert_equal(
|
||||||
["test", "inlookup"],
|
%w[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
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,38 +6,38 @@ 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 +53,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 +79,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 +114,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,27 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
|
||||||
|
|
||||||
class DisabledTagsTest < Minitest::Test
|
|
||||||
include Liquid
|
|
||||||
|
|
||||||
class DisableRaw < Block
|
|
||||||
disable_tags "raw"
|
|
||||||
end
|
|
||||||
|
|
||||||
class DisableRawEcho < Block
|
|
||||||
disable_tags "raw", "echo"
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_disables_raw
|
|
||||||
with_custom_tag('disable', DisableRaw) do
|
|
||||||
assert_template_result 'raw usage is not allowed in this contextfoo', '{% disable %}{% raw %}Foobar{% endraw %}{% echo "foo" %}{% enddisable %}'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_disables_echo_and_raw
|
|
||||||
with_custom_tag('disable', DisableRawEcho) do
|
|
||||||
assert_template_result 'raw usage is not allowed in this contextecho usage is not allowed in this context', '{% disable %}{% raw %}Foobar{% endraw %}{% echo "foo" %}{% enddisable %}'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -19,35 +19,35 @@ class RenderProfilingTest < Minitest::Test
|
|||||||
t = Template.parse("{{ 'a string' | upcase }}")
|
t = Template.parse("{{ 'a string' | upcase }}")
|
||||||
t.render!
|
t.render!
|
||||||
|
|
||||||
assert_nil(t.profiler)
|
assert_nil t.profiler
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_parse_makes_available_simple_profiling
|
def test_parse_makes_available_simple_profiling
|
||||||
t = Template.parse("{{ 'a string' | upcase }}", profile: true)
|
t = Template.parse("{{ 'a string' | upcase }}", profile: true)
|
||||||
t.render!
|
t.render!
|
||||||
|
|
||||||
assert_equal(1, t.profiler.length)
|
assert_equal 1, t.profiler.length
|
||||||
|
|
||||||
node = t.profiler[0]
|
node = t.profiler[0]
|
||||||
assert_equal(" 'a string' | upcase ", node.code)
|
assert_equal " 'a string' | upcase ", node.code
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_render_ignores_raw_strings_when_profiling
|
def test_render_ignores_raw_strings_when_profiling
|
||||||
t = Template.parse("This is raw string\nstuff\nNewline", profile: true)
|
t = Template.parse("This is raw string\nstuff\nNewline", profile: true)
|
||||||
t.render!
|
t.render!
|
||||||
|
|
||||||
assert_equal(0, t.profiler.length)
|
assert_equal 0, t.profiler.length
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_profiling_includes_line_numbers_of_liquid_nodes
|
def test_profiling_includes_line_numbers_of_liquid_nodes
|
||||||
t = Template.parse("{{ 'a string' | upcase }}\n{% increment test %}", profile: true)
|
t = Template.parse("{{ 'a string' | upcase }}\n{% increment test %}", profile: true)
|
||||||
t.render!
|
t.render!
|
||||||
assert_equal(2, t.profiler.length)
|
assert_equal 2, t.profiler.length
|
||||||
|
|
||||||
# {{ 'a string' | upcase }}
|
# {{ 'a string' | upcase }}
|
||||||
assert_equal(1, t.profiler[0].line_number)
|
assert_equal 1, t.profiler[0].line_number
|
||||||
# {{ increment test }}
|
# {{ increment test }}
|
||||||
assert_equal(2, t.profiler[1].line_number)
|
assert_equal 2, t.profiler[1].line_number
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_profiling_includes_line_numbers_of_included_partials
|
def test_profiling_includes_line_numbers_of_included_partials
|
||||||
@@ -57,9 +57,9 @@ class RenderProfilingTest < Minitest::Test
|
|||||||
included_children = t.profiler[0].children
|
included_children = t.profiler[0].children
|
||||||
|
|
||||||
# {% assign template_name = 'a_template' %}
|
# {% assign template_name = 'a_template' %}
|
||||||
assert_equal(1, included_children[0].line_number)
|
assert_equal 1, included_children[0].line_number
|
||||||
# {{ template_name }}
|
# {{ template_name }}
|
||||||
assert_equal(2, included_children[1].line_number)
|
assert_equal 2, included_children[1].line_number
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_profiling_times_the_rendering_of_tokens
|
def test_profiling_times_the_rendering_of_tokens
|
||||||
@@ -67,14 +67,14 @@ class RenderProfilingTest < Minitest::Test
|
|||||||
t.render!
|
t.render!
|
||||||
|
|
||||||
node = t.profiler[0]
|
node = t.profiler[0]
|
||||||
refute_nil(node.render_time)
|
refute_nil node.render_time
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_profiling_times_the_entire_render
|
def test_profiling_times_the_entire_render
|
||||||
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
|
||||||
@@ -82,7 +82,7 @@ class RenderProfilingTest < Minitest::Test
|
|||||||
t.render!
|
t.render!
|
||||||
|
|
||||||
include_node = t.profiler[1]
|
include_node = t.profiler[1]
|
||||||
assert_equal(2, include_node.children.length)
|
assert_equal 2, include_node.children.length
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_profiling_marks_children_with_the_name_of_included_partial
|
def test_profiling_marks_children_with_the_name_of_included_partial
|
||||||
@@ -91,7 +91,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 +101,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 +116,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
|
||||||
|
|
||||||
@@ -134,38 +134,23 @@ class RenderProfilingTest < Minitest::Test
|
|||||||
timing_count += 1
|
timing_count += 1
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal(2, timing_count)
|
assert_equal 2, timing_count
|
||||||
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
|
||||||
assert_equal(2, t.profiler[0].children.length)
|
assert_equal 2, t.profiler[0].children.length
|
||||||
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" => ["one", "two"])
|
t.render!('collection' => %w[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
|
||||||
assert_equal(2, t.profiler[0].children.length)
|
assert_equal 2, t.profiler[0].children.length
|
||||||
end
|
|
||||||
|
|
||||||
def test_profiling_supports_self_time
|
|
||||||
t = Template.parse("{% for item in collection %} {{ item }} {% endfor %}", profile: true)
|
|
||||||
t.render!("collection" => ["one", "two"])
|
|
||||||
leaf = t.profiler[0].children[0]
|
|
||||||
|
|
||||||
assert_operator leaf.self_time, :>, 0
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_profiling_supports_total_time
|
|
||||||
t = Template.parse("{% if true %} {% increment test %} {{ test }} {% endif %}", profile: true)
|
|
||||||
t.render!
|
|
||||||
|
|
||||||
assert_operator t.profiler[0].total_time, :>, 0
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -19,28 +19,28 @@ class SecurityTest < Minitest::Test
|
|||||||
text = %( {{ '1+1' | instance_eval }} )
|
text = %( {{ '1+1' | instance_eval }} )
|
||||||
expected = %( 1+1 )
|
expected = %( 1+1 )
|
||||||
|
|
||||||
assert_equal(expected, Template.parse(text).render!(@assigns))
|
assert_equal expected, Template.parse(text).render!(@assigns)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_no_existing_instance_eval
|
def test_no_existing_instance_eval
|
||||||
text = %( {{ '1+1' | __instance_eval__ }} )
|
text = %( {{ '1+1' | __instance_eval__ }} )
|
||||||
expected = %( 1+1 )
|
expected = %( 1+1 )
|
||||||
|
|
||||||
assert_equal(expected, Template.parse(text).render!(@assigns))
|
assert_equal expected, Template.parse(text).render!(@assigns)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_no_instance_eval_after_mixing_in_new_filter
|
def test_no_instance_eval_after_mixing_in_new_filter
|
||||||
text = %( {{ '1+1' | instance_eval }} )
|
text = %( {{ '1+1' | instance_eval }} )
|
||||||
expected = %( 1+1 )
|
expected = %( 1+1 )
|
||||||
|
|
||||||
assert_equal(expected, Template.parse(text).render!(@assigns))
|
assert_equal expected, Template.parse(text).render!(@assigns)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_no_instance_eval_later_in_chain
|
def test_no_instance_eval_later_in_chain
|
||||||
text = %( {{ '1+1' | add_one | instance_eval }} )
|
text = %( {{ '1+1' | add_one | instance_eval }} )
|
||||||
expected = %( 1+1 + 1 )
|
expected = %( 1+1 + 1 )
|
||||||
|
|
||||||
assert_equal(expected, Template.parse(text).render!(@assigns, filters: SecurityFilter))
|
assert_equal expected, Template.parse(text).render!(@assigns, filters: SecurityFilter)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_does_not_add_filters_to_symbol_table
|
def test_does_not_add_filters_to_symbol_table
|
||||||
@@ -49,32 +49,32 @@ class SecurityTest < Minitest::Test
|
|||||||
test = %( {{ "some_string" | a_bad_filter }} )
|
test = %( {{ "some_string" | a_bad_filter }} )
|
||||||
|
|
||||||
template = Template.parse(test)
|
template = Template.parse(test)
|
||||||
assert_equal([], (Symbol.all_symbols - current_symbols))
|
assert_equal [], (Symbol.all_symbols - current_symbols)
|
||||||
|
|
||||||
template.render!
|
template.render!
|
||||||
assert_equal([], (Symbol.all_symbols - current_symbols))
|
assert_equal [], (Symbol.all_symbols - current_symbols)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_does_not_add_drop_methods_to_symbol_table
|
def test_does_not_add_drop_methods_to_symbol_table
|
||||||
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
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
|
||||||
|
|
||||||
class EchoTest < Minitest::Test
|
|
||||||
include Liquid
|
|
||||||
|
|
||||||
def test_echo_outputs_its_input
|
|
||||||
assert_template_result('BAR', <<~LIQUID, 'variable-name' => 'bar')
|
|
||||||
{%- echo variable-name | upcase -%}
|
|
||||||
LIQUID
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -42,31 +42,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' => ['a', 'b', 'c', 'd'])
|
assert_template_result('abcd', '{%for item in array%}{{item}}{%endfor%}', 'array' => %w[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 +74,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 +87,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 +116,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 +130,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 +159,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 +178,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 +197,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 +227,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 +267,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,49 +312,49 @@ 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
|
||||||
assert_template_result('oo', '{% for a in (1..2) %}o{% for b in empty %}{% endfor %}{% endfor %}')
|
assert_template_result 'oo', '{% for a in (1..2) %}o{% for b in empty %}{% endfor %}{% endfor %}'
|
||||||
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
|
||||||
@@ -394,8 +394,8 @@ HERE
|
|||||||
expected = '12345'
|
expected = '12345'
|
||||||
template = '{% for item in items %}{{item}}{% endfor %}'
|
template = '{% for item in items %}{{item}}{% endfor %}'
|
||||||
assert_template_result(expected, template, assigns)
|
assert_template_result(expected, template, assigns)
|
||||||
assert(loader.each_called)
|
assert loader.each_called
|
||||||
assert(!loader.load_slice_called)
|
assert !loader.load_slice_called
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_iterate_with_load_slice_when_limit_applied
|
def test_iterate_with_load_slice_when_limit_applied
|
||||||
@@ -404,8 +404,8 @@ HERE
|
|||||||
expected = '1'
|
expected = '1'
|
||||||
template = '{% for item in items limit:1 %}{{item}}{% endfor %}'
|
template = '{% for item in items limit:1 %}{{item}}{% endfor %}'
|
||||||
assert_template_result(expected, template, assigns)
|
assert_template_result(expected, template, assigns)
|
||||||
assert(!loader.each_called)
|
assert !loader.each_called
|
||||||
assert(loader.load_slice_called)
|
assert loader.load_slice_called
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_iterate_with_load_slice_when_limit_and_offset_applied
|
def test_iterate_with_load_slice_when_limit_and_offset_applied
|
||||||
@@ -414,8 +414,8 @@ HERE
|
|||||||
expected = '34'
|
expected = '34'
|
||||||
template = '{% for item in items offset:2 limit:2 %}{{item}}{% endfor %}'
|
template = '{% for item in items offset:2 limit:2 %}{{item}}{% endfor %}'
|
||||||
assert_template_result(expected, template, assigns)
|
assert_template_result(expected, template, assigns)
|
||||||
assert(!loader.each_called)
|
assert !loader.each_called
|
||||||
assert(loader.load_slice_called)
|
assert loader.load_slice_called
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_iterate_with_load_slice_returns_same_results_as_without
|
def test_iterate_with_load_slice_returns_same_results_as_without
|
||||||
@@ -435,6 +435,6 @@ HERE
|
|||||||
Liquid::Template.parse('{% for i in (1..2) %}{{ standard_error }}{% endfor %}').render!(context)
|
Liquid::Template.parse('{% for i in (1..2) %}{{ standard_error }}{% endfor %}').render!(context)
|
||||||
end
|
end
|
||||||
|
|
||||||
assert(context.registers[:for_stack].empty?)
|
assert context.registers[:for_stack].empty?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -8,7 +8,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 +51,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 +77,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 +92,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 })
|
||||||
@@ -156,7 +156,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 +168,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,
|
||||||
|
|||||||
@@ -5,38 +5,35 @@ 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 "product_alias"
|
when 'locale_variables'
|
||||||
"Product: {{ product.title }} "
|
'Locale: {{echo1}} {{echo2}}'
|
||||||
|
|
||||||
when "locale_variables"
|
when 'variant'
|
||||||
"Locale: {{echo1}} {{echo2}}"
|
'Variant: {{ variant.title }}'
|
||||||
|
|
||||||
when "variant"
|
when 'nested_template'
|
||||||
"Variant: {{ variant.title }}"
|
|
||||||
|
|
||||||
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
|
||||||
@@ -60,16 +57,15 @@ class CountingFileSystem
|
|||||||
end
|
end
|
||||||
|
|
||||||
class CustomInclude < Liquid::Tag
|
class CustomInclude < Liquid::Tag
|
||||||
Syntax = /(#{Liquid::QuotedFragment}+)(\s+(?:with|for)\s+(#{Liquid::QuotedFragment}+))?/o
|
SYNTAX = /(#{Liquid::QUOTED_FRAGMENT}+)(\s+(?:with|for)\s+(#{Liquid::QUOTED_FRAGMENT}+))?/o.freeze
|
||||||
|
|
||||||
def initialize(tag_name, markup, tokens)
|
def initialize(tag_name, markup, tokens)
|
||||||
markup =~ Syntax
|
markup =~ SYNTAX
|
||||||
@template_name = Regexp.last_match(1)
|
@template_name = Regexp.last_match(1)
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse(tokens)
|
def parse(tokens); end
|
||||||
end
|
|
||||||
|
|
||||||
def render_to_output_buffer(_context, output)
|
def render_to_output_buffer(_context, output)
|
||||||
output << @template_name[1..-2]
|
output << @template_name[1..-2]
|
||||||
@@ -85,66 +81,56 @@ class IncludeTagTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
def test_include_tag_with_alias
|
|
||||||
assert_template_result("Product: Draft 151cm ",
|
|
||||||
"{% include 'product_alias' with products[0] as product %}", "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }])
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_include_tag_for_alias
|
|
||||||
assert_template_result("Product: Draft 151cm Product: Element 155cm ",
|
|
||||||
"{% include 'product_alias' for products as product %}", "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
|
||||||
@@ -162,41 +148,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
|
||||||
@@ -206,8 +192,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
|
||||||
@@ -218,21 +204,21 @@ class IncludeTagTest < Minitest::Test
|
|||||||
|
|
||||||
a = Liquid::Template.parse(' {% include "nested_template" %}')
|
a = Liquid::Template.parse(' {% include "nested_template" %}')
|
||||||
a.render!
|
a.render!
|
||||||
assert_empty(a.errors)
|
assert_empty a.errors
|
||||||
end
|
end
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
@@ -248,22 +234,22 @@ 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
|
||||||
template = Liquid::Template.parse("{% include 'simple' %}", error_mode: :warn)
|
template = Liquid::Template.parse("{% include 'simple' %}", error_mode: :warn)
|
||||||
template.render(nil, strict_variables: true)
|
template.render(nil, strict_variables: true)
|
||||||
|
|
||||||
assert_equal([], template.errors)
|
assert_equal [], template.errors
|
||||||
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
|
||||||
|
|||||||
@@ -9,17 +9,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,106 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
|
||||||
|
|
||||||
class LiquidTagTest < Minitest::Test
|
|
||||||
include Liquid
|
|
||||||
|
|
||||||
def test_liquid_tag
|
|
||||||
assert_template_result('1 2 3', <<~LIQUID, 'array' => [1, 2, 3])
|
|
||||||
{%- liquid
|
|
||||||
echo array | join: " "
|
|
||||||
-%}
|
|
||||||
LIQUID
|
|
||||||
|
|
||||||
assert_template_result('1 2 3', <<~LIQUID, 'array' => [1, 2, 3])
|
|
||||||
{%- liquid
|
|
||||||
for value in array
|
|
||||||
echo value
|
|
||||||
unless forloop.last
|
|
||||||
echo " "
|
|
||||||
endunless
|
|
||||||
endfor
|
|
||||||
-%}
|
|
||||||
LIQUID
|
|
||||||
|
|
||||||
assert_template_result('4 8 12 6', <<~LIQUID, 'array' => [1, 2, 3])
|
|
||||||
{%- liquid
|
|
||||||
for value in array
|
|
||||||
assign double_value = value | times: 2
|
|
||||||
echo double_value | times: 2
|
|
||||||
unless forloop.last
|
|
||||||
echo " "
|
|
||||||
endunless
|
|
||||||
endfor
|
|
||||||
|
|
||||||
echo " "
|
|
||||||
echo double_value
|
|
||||||
-%}
|
|
||||||
LIQUID
|
|
||||||
|
|
||||||
assert_template_result('abc', <<~LIQUID)
|
|
||||||
{%- liquid echo "a" -%}
|
|
||||||
b
|
|
||||||
{%- liquid echo "c" -%}
|
|
||||||
LIQUID
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_liquid_tag_errors
|
|
||||||
assert_match_syntax_error("syntax error (line 1): Unknown tag 'error'", <<~LIQUID)
|
|
||||||
{%- liquid error no such tag -%}
|
|
||||||
LIQUID
|
|
||||||
|
|
||||||
assert_match_syntax_error("syntax error (line 7): Unknown tag 'error'", <<~LIQUID)
|
|
||||||
{{ test }}
|
|
||||||
|
|
||||||
{%-
|
|
||||||
liquid
|
|
||||||
for value in array
|
|
||||||
|
|
||||||
error no such tag
|
|
||||||
endfor
|
|
||||||
-%}
|
|
||||||
LIQUID
|
|
||||||
|
|
||||||
assert_match_syntax_error("syntax error (line 2): Unknown tag '!!! the guards are vigilant'", <<~LIQUID)
|
|
||||||
{%- liquid
|
|
||||||
!!! the guards are vigilant
|
|
||||||
-%}
|
|
||||||
LIQUID
|
|
||||||
|
|
||||||
assert_match_syntax_error("syntax error (line 4): 'for' tag was never closed", <<~LIQUID)
|
|
||||||
{%- liquid
|
|
||||||
for value in array
|
|
||||||
echo 'forgot to close the for tag'
|
|
||||||
-%}
|
|
||||||
LIQUID
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_line_number_is_correct_after_a_blank_token
|
|
||||||
assert_match_syntax_error("syntax error (line 3): Unknown tag 'error'", "{% liquid echo ''\n\n error %}")
|
|
||||||
assert_match_syntax_error("syntax error (line 3): Unknown tag 'error'", "{% liquid echo ''\n \n error %}")
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_cannot_open_blocks_living_past_a_liquid_tag
|
|
||||||
assert_match_syntax_error("syntax error (line 3): 'if' tag was never closed", <<~LIQUID)
|
|
||||||
{%- liquid
|
|
||||||
if true
|
|
||||||
-%}
|
|
||||||
{%- endif -%}
|
|
||||||
LIQUID
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_quirk_can_close_blocks_created_before_a_liquid_tag
|
|
||||||
assert_template_result("42", <<~LIQUID)
|
|
||||||
{%- if true -%}
|
|
||||||
42
|
|
||||||
{%- liquid endif -%}
|
|
||||||
LIQUID
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_liquid_tag_in_raw
|
|
||||||
assert_template_result("{% liquid echo 'test' %}\n", <<~LIQUID)
|
|
||||||
{% raw %}{% liquid echo 'test' %}{% endraw %}
|
|
||||||
LIQUID
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -6,23 +6,23 @@ class RawTagTest < Minitest::Test
|
|||||||
include Liquid
|
include Liquid
|
||||||
|
|
||||||
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
|
||||||
assert_template_result('{{ test }}', '{% raw %}{{ test }}{% endraw %}')
|
assert_template_result '{{ test }}', '{% raw %}{{ test }}{% endraw %}'
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_open_tag_in_raw
|
def test_open_tag_in_raw
|
||||||
assert_template_result(' Foobar {% invalid ', '{% raw %} Foobar {% invalid {% endraw %}')
|
assert_template_result ' Foobar {% invalid ', '{% raw %} Foobar {% invalid {% endraw %}'
|
||||||
assert_template_result(' Foobar invalid %} ', '{% raw %} Foobar invalid %} {% endraw %}')
|
assert_template_result ' Foobar invalid %} ', '{% raw %} Foobar invalid %} {% endraw %}'
|
||||||
assert_template_result(' Foobar {{ invalid ', '{% raw %} Foobar {{ invalid {% endraw %}')
|
assert_template_result ' Foobar {{ invalid ', '{% raw %} Foobar {{ invalid {% endraw %}'
|
||||||
assert_template_result(' Foobar invalid }} ', '{% raw %} Foobar invalid }} {% endraw %}')
|
assert_template_result ' Foobar invalid }} ', '{% raw %} Foobar invalid }} {% endraw %}'
|
||||||
assert_template_result(' Foobar {% invalid {% {% endraw ', '{% raw %} Foobar {% invalid {% {% endraw {% endraw %}')
|
assert_template_result ' Foobar {% invalid {% {% endraw ', '{% raw %} Foobar {% invalid {% {% endraw {% endraw %}'
|
||||||
assert_template_result(' Foobar {% {% {% ', '{% raw %} Foobar {% {% {% {% endraw %}')
|
assert_template_result ' Foobar {% {% {% ', '{% raw %} Foobar {% {% {% {% endraw %}'
|
||||||
assert_template_result(' test {% raw %} {% endraw %}', '{% raw %} test {% raw %} {% {% endraw %}endraw %}')
|
assert_template_result ' test {% raw %} {% endraw %}', '{% raw %} test {% raw %} {% {% endraw %}endraw %}'
|
||||||
assert_template_result(' Foobar {{ invalid 1', '{% raw %} Foobar {{ invalid {% endraw %}{{ 1 }}')
|
assert_template_result ' Foobar {{ invalid 1', '{% raw %} Foobar {{ invalid {% endraw %}{{ 1 }}'
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_invalid_raw
|
def test_invalid_raw
|
||||||
|
|||||||
@@ -1,217 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'test_helper'
|
|
||||||
|
|
||||||
class RenderTagTest < Minitest::Test
|
|
||||||
include Liquid
|
|
||||||
|
|
||||||
def test_render_with_no_arguments
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new('source' => 'rendered content')
|
|
||||||
assert_template_result('rendered content', '{% render "source" %}')
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_render_tag_looks_for_file_system_in_registers_first
|
|
||||||
file_system = StubFileSystem.new('pick_a_source' => 'from register file system')
|
|
||||||
assert_equal('from register file system',
|
|
||||||
Template.parse('{% render "pick_a_source" %}').render!({}, registers: { file_system: file_system }))
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_render_passes_named_arguments_into_inner_scope
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new('product' => '{{ inner_product.title }}')
|
|
||||||
assert_template_result('My Product', '{% render "product", inner_product: outer_product %}',
|
|
||||||
'outer_product' => { 'title' => 'My Product' })
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_render_accepts_literals_as_arguments
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new('snippet' => '{{ price }}')
|
|
||||||
assert_template_result('123', '{% render "snippet", price: 123 %}')
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_render_accepts_multiple_named_arguments
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new('snippet' => '{{ one }} {{ two }}')
|
|
||||||
assert_template_result('1 2', '{% render "snippet", one: 1, two: 2 %}')
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_render_does_not_inherit_parent_scope_variables
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new('snippet' => '{{ outer_variable }}')
|
|
||||||
assert_template_result('', '{% assign outer_variable = "should not be visible" %}{% render "snippet" %}')
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_render_does_not_inherit_variable_with_same_name_as_snippet
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new('snippet' => '{{ snippet }}')
|
|
||||||
assert_template_result('', "{% assign snippet = 'should not be visible' %}{% render 'snippet' %}")
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_render_sets_the_correct_template_name_for_errors
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new('snippet' => '{{ unsafe }}')
|
|
||||||
|
|
||||||
with_taint_mode :error do
|
|
||||||
template = Liquid::Template.parse('{% render "snippet", unsafe: unsafe %}')
|
|
||||||
context = Context.new('unsafe' => (+'unsafe').tap(&:taint))
|
|
||||||
template.render(context)
|
|
||||||
|
|
||||||
assert_equal [Liquid::TaintedError], template.errors.map(&:class)
|
|
||||||
assert_equal 'snippet', template.errors.first.template_name
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_render_sets_the_correct_template_name_for_warnings
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new('snippet' => '{{ unsafe }}')
|
|
||||||
|
|
||||||
with_taint_mode :warn do
|
|
||||||
template = Liquid::Template.parse('{% render "snippet", unsafe: unsafe %}')
|
|
||||||
context = Context.new('unsafe' => (+'unsafe').tap(&:taint))
|
|
||||||
template.render(context)
|
|
||||||
|
|
||||||
assert_equal [Liquid::TaintedError], context.warnings.map(&:class)
|
|
||||||
assert_equal 'snippet', context.warnings.first.template_name
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_render_does_not_mutate_parent_scope
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new('snippet' => '{% assign inner = 1 %}')
|
|
||||||
assert_template_result('', "{% render 'snippet' %}{{ inner }}")
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_nested_render_tag
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new(
|
|
||||||
'one' => "one {% render 'two' %}",
|
|
||||||
'two' => 'two'
|
|
||||||
)
|
|
||||||
assert_template_result('one two', "{% render 'one' %}")
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_recursively_rendered_template_does_not_produce_endless_loop
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new('loop' => '{% render "loop" %}')
|
|
||||||
|
|
||||||
assert_raises Liquid::StackLevelError do
|
|
||||||
Template.parse('{% render "loop" %}').render!
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_sub_contexts_count_towards_the_same_recursion_limit
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new(
|
|
||||||
'loop_render' => '{% render "loop_render" %}',
|
|
||||||
)
|
|
||||||
assert_raises Liquid::StackLevelError do
|
|
||||||
Template.parse('{% render "loop_render" %}').render!
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_dynamically_choosen_templates_are_not_allowed
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new('snippet' => 'should not be rendered')
|
|
||||||
|
|
||||||
assert_raises Liquid::SyntaxError do
|
|
||||||
Liquid::Template.parse("{% assign name = 'snippet' %}{% render name %}")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_include_tag_caches_second_read_of_same_partial
|
|
||||||
file_system = StubFileSystem.new('snippet' => 'echo')
|
|
||||||
assert_equal('echoecho',
|
|
||||||
Template.parse('{% render "snippet" %}{% render "snippet" %}')
|
|
||||||
.render!({}, registers: { file_system: file_system }))
|
|
||||||
assert_equal(1, file_system.file_read_count)
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_render_tag_doesnt_cache_partials_across_renders
|
|
||||||
file_system = StubFileSystem.new('snippet' => 'my message')
|
|
||||||
|
|
||||||
assert_equal('my message',
|
|
||||||
Template.parse('{% include "snippet" %}').render!({}, registers: { file_system: file_system }))
|
|
||||||
assert_equal(1, file_system.file_read_count)
|
|
||||||
|
|
||||||
assert_equal('my message',
|
|
||||||
Template.parse('{% include "snippet" %}').render!({}, registers: { file_system: file_system }))
|
|
||||||
assert_equal(2, file_system.file_read_count)
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_render_tag_within_if_statement
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new('snippet' => 'my message')
|
|
||||||
assert_template_result('my message', '{% if true %}{% render "snippet" %}{% endif %}')
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_break_through_render
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new('break' => '{% break %}')
|
|
||||||
assert_template_result('1', '{% for i in (1..3) %}{{ i }}{% break %}{{ i }}{% endfor %}')
|
|
||||||
assert_template_result('112233', '{% for i in (1..3) %}{{ i }}{% render "break" %}{{ i }}{% endfor %}')
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_increment_is_isolated_between_renders
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new('incr' => '{% increment %}')
|
|
||||||
assert_template_result('010', '{% increment %}{% increment %}{% render "incr" %}')
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_decrement_is_isolated_between_renders
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new('decr' => '{% decrement %}')
|
|
||||||
assert_template_result('-1-2-1', '{% decrement %}{% decrement %}{% render "decr" %}')
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_includes_will_not_render_inside_render_tag
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new(
|
|
||||||
'foo' => 'bar',
|
|
||||||
'test_include' => '{% include "foo" %}'
|
|
||||||
)
|
|
||||||
|
|
||||||
assert_template_result('include usage is not allowed in this context', '{% render "test_include" %}')
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_includes_will_not_render_inside_nested_sibling_tags
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new(
|
|
||||||
'foo' => 'bar',
|
|
||||||
'nested_render_with_sibling_include' => '{% render "test_include" %}{% include "foo" %}',
|
|
||||||
'test_include' => '{% include "foo" %}'
|
|
||||||
)
|
|
||||||
|
|
||||||
assert_template_result('include usage is not allowed in this contextinclude usage is not allowed in this context', '{% render "nested_render_with_sibling_include" %}')
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_render_tag_with
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new(
|
|
||||||
'product' => "Product: {{ product.title }} ",
|
|
||||||
'product_alias' => "Product: {{ product.title }} ",
|
|
||||||
)
|
|
||||||
|
|
||||||
assert_template_result("Product: Draft 151cm ",
|
|
||||||
"{% render 'product' with products[0] %}", "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }])
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_render_tag_with_alias
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new(
|
|
||||||
'product' => "Product: {{ product.title }} ",
|
|
||||||
'product_alias' => "Product: {{ product.title }} ",
|
|
||||||
)
|
|
||||||
|
|
||||||
assert_template_result("Product: Draft 151cm ",
|
|
||||||
"{% render 'product_alias' with products[0] as product %}", "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }])
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_render_tag_for_alias
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new(
|
|
||||||
'product' => "Product: {{ product.title }} ",
|
|
||||||
'product_alias' => "Product: {{ product.title }} ",
|
|
||||||
)
|
|
||||||
|
|
||||||
assert_template_result("Product: Draft 151cm Product: Element 155cm ",
|
|
||||||
"{% render 'product_alias' for products as product %}", "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }])
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_render_tag_for
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new(
|
|
||||||
'product' => "Product: {{ product.title }} ",
|
|
||||||
'product_alias' => "Product: {{ product.title }} ",
|
|
||||||
)
|
|
||||||
|
|
||||||
assert_template_result("Product: Draft 151cm Product: Element 155cm ",
|
|
||||||
"{% render 'product' for products %}", "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }])
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_render_tag_forloop
|
|
||||||
Liquid::Template.file_system = StubFileSystem.new(
|
|
||||||
'product' => "Product: {{ product.title }} {% if forloop.first %}first{% endif %} {% if forloop.last %}last{% endif %} index:{{ forloop.index }} ",
|
|
||||||
)
|
|
||||||
|
|
||||||
assert_template_result("Product: Draft 151cm first index:1 Product: Element 155cm last index:2 ",
|
|
||||||
"{% render 'product' for products %}", "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -7,7 +7,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 +21,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 +63,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,57 +130,57 @@ 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
|
||||||
@@ -214,7 +214,7 @@ class StandardTagTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_assign
|
def test_assign
|
||||||
assert_template_result('variable', '{% assign a = "variable"%}{{a}}')
|
assert_template_result 'variable', '{% assign a = "variable"%}{{a}}'
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_assign_unassigned
|
def test_assign_unassigned
|
||||||
@@ -223,11 +223,11 @@ class StandardTagTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_assign_an_empty_string
|
def test_assign_an_empty_string
|
||||||
assert_template_result('', '{% assign a = ""%}{{a}}')
|
assert_template_result '', '{% assign a = ""%}{{a}}'
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_assign_is_global
|
def test_assign_is_global
|
||||||
assert_template_result('variable', '{%for i in (1..2) %}{% assign a = "variable"%}{% endfor %}{{a}}')
|
assert_template_result 'variable', '{%for i in (1..2) %}{% assign a = "variable"%}{% endfor %}{{a}}'
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_case_detects_bad_syntax
|
def test_case_detects_bad_syntax
|
||||||
@@ -248,33 +248,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
|
||||||
@@ -293,6 +293,6 @@ class StandardTagTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_multiline_tag
|
def test_multiline_tag
|
||||||
assert_template_result('0 1 2 3', "0{%\nfor i in (1..3)\n%} {{\ni\n}}{%\nendfor\n%}")
|
assert_template_result '0 1 2 3', "0{%\nfor i in (1..3)\n%} {{\ni\n}}{%\nendfor\n%}"
|
||||||
end
|
end
|
||||||
end # StandardTagTest
|
end # StandardTagTest
|
||||||
|
|||||||
@@ -7,75 +7,75 @@ class StatementsTest < Minitest::Test
|
|||||||
|
|
||||||
def test_true_eql_true
|
def test_true_eql_true
|
||||||
text = ' {% if true == true %} true {% else %} false {% endif %} '
|
text = ' {% if true == true %} true {% else %} false {% endif %} '
|
||||||
assert_template_result(' true ', text)
|
assert_template_result ' true ', text
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_true_not_eql_true
|
def test_true_not_eql_true
|
||||||
text = ' {% if true != true %} true {% else %} false {% endif %} '
|
text = ' {% if true != true %} true {% else %} false {% endif %} '
|
||||||
assert_template_result(' false ', text)
|
assert_template_result ' false ', text
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_true_lq_true
|
def test_true_lq_true
|
||||||
text = ' {% if 0 > 0 %} true {% else %} false {% endif %} '
|
text = ' {% if 0 > 0 %} true {% else %} false {% endif %} '
|
||||||
assert_template_result(' false ', text)
|
assert_template_result ' false ', text
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_one_lq_zero
|
def test_one_lq_zero
|
||||||
text = ' {% if 1 > 0 %} true {% else %} false {% endif %} '
|
text = ' {% if 1 > 0 %} true {% else %} false {% endif %} '
|
||||||
assert_template_result(' true ', text)
|
assert_template_result ' true ', text
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_zero_lq_one
|
def test_zero_lq_one
|
||||||
text = ' {% if 0 < 1 %} true {% else %} false {% endif %} '
|
text = ' {% if 0 < 1 %} true {% else %} false {% endif %} '
|
||||||
assert_template_result(' true ', text)
|
assert_template_result ' true ', text
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_zero_lq_or_equal_one
|
def test_zero_lq_or_equal_one
|
||||||
text = ' {% if 0 <= 0 %} true {% else %} false {% endif %} '
|
text = ' {% if 0 <= 0 %} true {% else %} false {% endif %} '
|
||||||
assert_template_result(' true ', text)
|
assert_template_result ' true ', text
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_zero_lq_or_equal_one_involving_nil
|
def test_zero_lq_or_equal_one_involving_nil
|
||||||
text = ' {% if null <= 0 %} true {% else %} false {% endif %} '
|
text = ' {% if null <= 0 %} true {% else %} false {% endif %} '
|
||||||
assert_template_result(' false ', text)
|
assert_template_result ' false ', text
|
||||||
|
|
||||||
text = ' {% if 0 <= null %} true {% else %} false {% endif %} '
|
text = ' {% if 0 <= null %} true {% else %} false {% endif %} '
|
||||||
assert_template_result(' false ', text)
|
assert_template_result ' false ', text
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_zero_lqq_or_equal_one
|
def test_zero_lqq_or_equal_one
|
||||||
text = ' {% if 0 >= 0 %} true {% else %} false {% endif %} '
|
text = ' {% if 0 >= 0 %} true {% else %} false {% endif %} '
|
||||||
assert_template_result(' true ', text)
|
assert_template_result ' true ', text
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_strings
|
def test_strings
|
||||||
text = " {% if 'test' == 'test' %} true {% else %} false {% endif %} "
|
text = " {% if 'test' == 'test' %} true {% else %} false {% endif %} "
|
||||||
assert_template_result(' true ', text)
|
assert_template_result ' true ', text
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_strings_not_equal
|
def test_strings_not_equal
|
||||||
text = " {% if 'test' != 'test' %} true {% else %} false {% endif %} "
|
text = " {% if 'test' != 'test' %} true {% else %} false {% endif %} "
|
||||||
assert_template_result(' false ', text)
|
assert_template_result ' false ', text
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_var_strings_equal
|
def test_var_strings_equal
|
||||||
text = ' {% if var == "hello there!" %} true {% else %} false {% endif %} '
|
text = ' {% if var == "hello there!" %} true {% else %} false {% endif %} '
|
||||||
assert_template_result(' true ', text, 'var' => 'hello there!')
|
assert_template_result ' true ', text, 'var' => 'hello there!'
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_var_strings_are_not_equal
|
def test_var_strings_are_not_equal
|
||||||
text = ' {% if "hello there!" == var %} true {% else %} false {% endif %} '
|
text = ' {% if "hello there!" == var %} true {% else %} false {% endif %} '
|
||||||
assert_template_result(' true ', text, 'var' => 'hello there!')
|
assert_template_result ' true ', text, 'var' => 'hello there!'
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_var_and_long_string_are_equal
|
def test_var_and_long_string_are_equal
|
||||||
text = " {% if var == 'hello there!' %} true {% else %} false {% endif %} "
|
text = " {% if var == 'hello there!' %} true {% else %} false {% endif %} "
|
||||||
assert_template_result(' true ', text, 'var' => 'hello there!')
|
assert_template_result ' true ', text, 'var' => 'hello there!'
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_var_and_long_string_are_equal_backwards
|
def test_var_and_long_string_are_equal_backwards
|
||||||
text = " {% if 'hello there!' == var %} true {% else %} false {% endif %} "
|
text = " {% if 'hello there!' == var %} true {% else %} false {% endif %} "
|
||||||
assert_template_result(' true ', text, 'var' => 'hello there!')
|
assert_template_result ' true ', text, 'var' => 'hello there!'
|
||||||
end
|
end
|
||||||
|
|
||||||
# def test_is_nil
|
# def test_is_nil
|
||||||
@@ -87,27 +87,27 @@ class StatementsTest < Minitest::Test
|
|||||||
|
|
||||||
def test_is_collection_empty
|
def test_is_collection_empty
|
||||||
text = ' {% if array == empty %} true {% else %} false {% endif %} '
|
text = ' {% if array == empty %} true {% else %} false {% endif %} '
|
||||||
assert_template_result(' true ', text, 'array' => [])
|
assert_template_result ' true ', text, 'array' => []
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_is_not_collection_empty
|
def test_is_not_collection_empty
|
||||||
text = ' {% if array == empty %} true {% else %} false {% endif %} '
|
text = ' {% if array == empty %} true {% else %} false {% endif %} '
|
||||||
assert_template_result(' false ', text, 'array' => [1, 2, 3])
|
assert_template_result ' false ', text, 'array' => [1, 2, 3]
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_nil
|
def test_nil
|
||||||
text = ' {% if var == nil %} true {% else %} false {% endif %} '
|
text = ' {% if var == nil %} true {% else %} false {% endif %} '
|
||||||
assert_template_result(' true ', text, 'var' => nil)
|
assert_template_result ' true ', text, 'var' => nil
|
||||||
|
|
||||||
text = ' {% if var == null %} true {% else %} false {% endif %} '
|
text = ' {% if var == null %} true {% else %} false {% endif %} '
|
||||||
assert_template_result(' true ', text, 'var' => nil)
|
assert_template_result ' true ', text, 'var' => nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_not_nil
|
def test_not_nil
|
||||||
text = ' {% if var != nil %} true {% else %} false {% endif %} '
|
text = ' {% if var != nil %} true {% else %} false {% endif %} '
|
||||||
assert_template_result(' true ', text, 'var' => 1)
|
assert_template_result ' true ', text, 'var' => 1
|
||||||
|
|
||||||
text = ' {% if var != null %} true {% else %} false {% endif %} '
|
text = ' {% if var != null %} true {% else %} false {% endif %} '
|
||||||
assert_template_result(' true ', text, 'var' => 1)
|
assert_template_result ' true ', text, 'var' => 1
|
||||||
end
|
end
|
||||||
end # StatementsTest
|
end # StatementsTest
|
||||||
|
|||||||
@@ -19,48 +19,48 @@ class TableRowTest < Minitest::Test
|
|||||||
|
|
||||||
def test_table_row
|
def test_table_row
|
||||||
assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 4 </td><td class=\"col2\"> 5 </td><td class=\"col3\"> 6 </td></tr>\n",
|
assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 4 </td><td class=\"col2\"> 5 </td><td class=\"col3\"> 6 </td></tr>\n",
|
||||||
'{% tablerow n in numbers cols:3%} {{n}} {% endtablerow %}',
|
'{% tablerow n in numbers cols:3%} {{n}} {% endtablerow %}',
|
||||||
'numbers' => [1, 2, 3, 4, 5, 6])
|
'numbers' => [1, 2, 3, 4, 5, 6])
|
||||||
|
|
||||||
assert_template_result("<tr class=\"row1\">\n</tr>\n",
|
assert_template_result("<tr class=\"row1\">\n</tr>\n",
|
||||||
'{% tablerow n in numbers cols:3%} {{n}} {% endtablerow %}',
|
'{% tablerow n in numbers cols:3%} {{n}} {% endtablerow %}',
|
||||||
'numbers' => [])
|
'numbers' => [])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_table_row_with_different_cols
|
def test_table_row_with_different_cols
|
||||||
assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td><td class=\"col4\"> 4 </td><td class=\"col5\"> 5 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 6 </td></tr>\n",
|
assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td><td class=\"col4\"> 4 </td><td class=\"col5\"> 5 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 6 </td></tr>\n",
|
||||||
'{% tablerow n in numbers cols:5%} {{n}} {% endtablerow %}',
|
'{% tablerow n in numbers cols:5%} {{n}} {% endtablerow %}',
|
||||||
'numbers' => [1, 2, 3, 4, 5, 6])
|
'numbers' => [1, 2, 3, 4, 5, 6])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_table_col_counter
|
def test_table_col_counter
|
||||||
assert_template_result("<tr class=\"row1\">\n<td class=\"col1\">1</td><td class=\"col2\">2</td></tr>\n<tr class=\"row2\"><td class=\"col1\">1</td><td class=\"col2\">2</td></tr>\n<tr class=\"row3\"><td class=\"col1\">1</td><td class=\"col2\">2</td></tr>\n",
|
assert_template_result("<tr class=\"row1\">\n<td class=\"col1\">1</td><td class=\"col2\">2</td></tr>\n<tr class=\"row2\"><td class=\"col1\">1</td><td class=\"col2\">2</td></tr>\n<tr class=\"row3\"><td class=\"col1\">1</td><td class=\"col2\">2</td></tr>\n",
|
||||||
'{% tablerow n in numbers cols:2%}{{tablerowloop.col}}{% endtablerow %}',
|
'{% tablerow n in numbers cols:2%}{{tablerowloop.col}}{% endtablerow %}',
|
||||||
'numbers' => [1, 2, 3, 4, 5, 6])
|
'numbers' => [1, 2, 3, 4, 5, 6])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_quoted_fragment
|
def test_quoted_fragment
|
||||||
assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 4 </td><td class=\"col2\"> 5 </td><td class=\"col3\"> 6 </td></tr>\n",
|
assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 4 </td><td class=\"col2\"> 5 </td><td class=\"col3\"> 6 </td></tr>\n",
|
||||||
"{% tablerow n in collections.frontpage cols:3%} {{n}} {% endtablerow %}",
|
'{% tablerow n in collections.frontpage cols:3%} {{n}} {% endtablerow %}',
|
||||||
'collections' => { 'frontpage' => [1, 2, 3, 4, 5, 6] })
|
'collections' => { 'frontpage' => [1, 2, 3, 4, 5, 6] })
|
||||||
assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 4 </td><td class=\"col2\"> 5 </td><td class=\"col3\"> 6 </td></tr>\n",
|
assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 4 </td><td class=\"col2\"> 5 </td><td class=\"col3\"> 6 </td></tr>\n",
|
||||||
"{% tablerow n in collections['frontpage'] cols:3%} {{n}} {% endtablerow %}",
|
"{% tablerow n in collections['frontpage'] cols:3%} {{n}} {% endtablerow %}",
|
||||||
'collections' => { 'frontpage' => [1, 2, 3, 4, 5, 6] })
|
'collections' => { 'frontpage' => [1, 2, 3, 4, 5, 6] })
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_enumerable_drop
|
def test_enumerable_drop
|
||||||
assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 4 </td><td class=\"col2\"> 5 </td><td class=\"col3\"> 6 </td></tr>\n",
|
assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 4 </td><td class=\"col2\"> 5 </td><td class=\"col3\"> 6 </td></tr>\n",
|
||||||
'{% tablerow n in numbers cols:3%} {{n}} {% endtablerow %}',
|
'{% tablerow n in numbers cols:3%} {{n}} {% endtablerow %}',
|
||||||
'numbers' => ArrayDrop.new([1, 2, 3, 4, 5, 6]))
|
'numbers' => ArrayDrop.new([1, 2, 3, 4, 5, 6]))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_offset_and_limit
|
def test_offset_and_limit
|
||||||
assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 4 </td><td class=\"col2\"> 5 </td><td class=\"col3\"> 6 </td></tr>\n",
|
assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 4 </td><td class=\"col2\"> 5 </td><td class=\"col3\"> 6 </td></tr>\n",
|
||||||
'{% tablerow n in numbers cols:3 offset:1 limit:6%} {{n}} {% endtablerow %}',
|
'{% tablerow n in numbers cols:3 offset:1 limit:6%} {{n}} {% endtablerow %}',
|
||||||
'numbers' => [0, 1, 2, 3, 4, 5, 6, 7])
|
'numbers' => [0, 1, 2, 3, 4, 5, 6, 7])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_blank_string_not_iterable
|
def test_blank_string_not_iterable
|
||||||
assert_template_result("<tr class=\"row1\">\n</tr>\n", "{% tablerow char in characters cols:3 %}I WILL NOT BE OUTPUT{% endtablerow %}", 'characters' => '')
|
assert_template_result("<tr class=\"row1\">\n</tr>\n", '{% tablerow char in characters cols:3 %}I WILL NOT BE OUTPUT{% endtablerow %}', 'characters' => '')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ class UnlessElseTagTest < Minitest::Test
|
|||||||
def test_unless
|
def test_unless
|
||||||
assert_template_result(' ', ' {% unless true %} this text should not go into the output {% endunless %} ')
|
assert_template_result(' ', ' {% unless true %} this text should not go into the output {% endunless %} ')
|
||||||
assert_template_result(' this text should go into the output ',
|
assert_template_result(' this text should go into the output ',
|
||||||
' {% unless false %} this text should go into the output {% endunless %} ')
|
' {% unless false %} this text should go into the output {% endunless %} ')
|
||||||
assert_template_result(' you rock ?', '{% unless true %} you suck {% endunless %} {% unless false %} you rock {% endunless %}?')
|
assert_template_result(' you rock ?', '{% unless true %} you suck {% endunless %} {% unless false %} you rock {% endunless %}?')
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -19,10 +19,10 @@ class UnlessElseTagTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_unless_in_loop
|
def test_unless_in_loop
|
||||||
assert_template_result('23', '{% for i in choices %}{% unless i %}{{ forloop.index }}{% endunless %}{% endfor %}', 'choices' => [1, nil, false])
|
assert_template_result '23', '{% for i in choices %}{% unless i %}{{ forloop.index }}{% endunless %}{% endfor %}', 'choices' => [1, nil, false]
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_unless_else_in_loop
|
def test_unless_else_in_loop
|
||||||
assert_template_result(' TRUE 2 3 ', '{% for i in choices %}{% unless i %} {{ forloop.index }} {% else %} TRUE {% endunless %}{% endfor %}', 'choices' => [1, nil, false])
|
assert_template_result ' TRUE 2 3 ', '{% for i in choices %}{% unless i %} {{ forloop.index }} {% else %} TRUE {% endunless %}{% endfor %}', 'choices' => [1, nil, false]
|
||||||
end
|
end
|
||||||
end # UnlessElseTest
|
end # UnlessElseTest
|
||||||
|
|||||||
@@ -40,195 +40,195 @@ class TemplateTest < Minitest::Test
|
|||||||
|
|
||||||
def test_instance_assigns_persist_on_same_template_object_between_parses
|
def test_instance_assigns_persist_on_same_template_object_between_parses
|
||||||
t = Template.new
|
t = Template.new
|
||||||
assert_equal('from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render!)
|
assert_equal 'from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render!
|
||||||
assert_equal('from instance assigns', t.parse("{{ foo }}").render!)
|
assert_equal 'from instance assigns', t.parse('{{ foo }}').render!
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_warnings_is_not_exponential_time
|
def test_warnings_is_not_exponential_time
|
||||||
str = "false"
|
str = 'false'
|
||||||
100.times do
|
100.times do
|
||||||
str = "{% if true %}true{% else %}#{str}{% endif %}"
|
str = "{% if true %}true{% else %}#{str}{% endif %}"
|
||||||
end
|
end
|
||||||
|
|
||||||
t = Template.parse(str)
|
t = Template.parse(str)
|
||||||
assert_equal([], Timeout.timeout(1) { t.warnings })
|
assert_equal [], Timeout.timeout(1) { t.warnings }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_instance_assigns_persist_on_same_template_parsing_between_renders
|
def test_instance_assigns_persist_on_same_template_parsing_between_renders
|
||||||
t = Template.new.parse("{{ foo }}{% assign foo = 'foo' %}{{ foo }}")
|
t = Template.new.parse("{{ foo }}{% assign foo = 'foo' %}{{ foo }}")
|
||||||
assert_equal('foo', t.render!)
|
assert_equal 'foo', t.render!
|
||||||
assert_equal('foofoo', t.render!)
|
assert_equal 'foofoo', t.render!
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_custom_assigns_do_not_persist_on_same_template
|
def test_custom_assigns_do_not_persist_on_same_template
|
||||||
t = Template.new
|
t = Template.new
|
||||||
assert_equal('from custom assigns', t.parse("{{ foo }}").render!('foo' => 'from custom assigns'))
|
assert_equal 'from custom assigns', t.parse('{{ foo }}').render!('foo' => 'from custom assigns')
|
||||||
assert_equal('', t.parse("{{ foo }}").render!)
|
assert_equal '', t.parse('{{ foo }}').render!
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_custom_assigns_squash_instance_assigns
|
def test_custom_assigns_squash_instance_assigns
|
||||||
t = Template.new
|
t = Template.new
|
||||||
assert_equal('from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render!)
|
assert_equal 'from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render!
|
||||||
assert_equal('from custom assigns', t.parse("{{ foo }}").render!('foo' => 'from custom assigns'))
|
assert_equal 'from custom assigns', t.parse('{{ foo }}').render!('foo' => 'from custom assigns')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_persistent_assigns_squash_instance_assigns
|
def test_persistent_assigns_squash_instance_assigns
|
||||||
t = Template.new
|
t = Template.new
|
||||||
assert_equal('from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render!)
|
assert_equal 'from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render!
|
||||||
t.assigns['foo'] = 'from persistent assigns'
|
t.assigns['foo'] = 'from persistent assigns'
|
||||||
assert_equal('from persistent assigns', t.parse("{{ foo }}").render!)
|
assert_equal 'from persistent assigns', t.parse('{{ foo }}').render!
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_lambda_is_called_once_from_persistent_assigns_over_multiple_parses_and_renders
|
def test_lambda_is_called_once_from_persistent_assigns_over_multiple_parses_and_renders
|
||||||
t = Template.new
|
t = Template.new
|
||||||
t.assigns['number'] = -> {
|
t.assigns['number'] = lambda {
|
||||||
@global ||= 0
|
@global ||= 0
|
||||||
@global += 1
|
@global += 1
|
||||||
}
|
}
|
||||||
assert_equal('1', t.parse("{{number}}").render!)
|
assert_equal '1', t.parse('{{number}}').render!
|
||||||
assert_equal('1', t.parse("{{number}}").render!)
|
assert_equal '1', t.parse('{{number}}').render!
|
||||||
assert_equal('1', t.render!)
|
assert_equal '1', t.render!
|
||||||
@global = nil
|
@global = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_lambda_is_called_once_from_custom_assigns_over_multiple_parses_and_renders
|
def test_lambda_is_called_once_from_custom_assigns_over_multiple_parses_and_renders
|
||||||
t = Template.new
|
t = Template.new
|
||||||
assigns = { 'number' => -> {
|
assigns = { 'number' => lambda {
|
||||||
@global ||= 0
|
@global ||= 0
|
||||||
@global += 1
|
@global += 1
|
||||||
} }
|
} }
|
||||||
assert_equal('1', t.parse("{{number}}").render!(assigns))
|
assert_equal '1', t.parse('{{number}}').render!(assigns)
|
||||||
assert_equal('1', t.parse("{{number}}").render!(assigns))
|
assert_equal '1', t.parse('{{number}}').render!(assigns)
|
||||||
assert_equal('1', t.render!(assigns))
|
assert_equal '1', t.render!(assigns)
|
||||||
@global = nil
|
@global = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_resource_limits_works_with_custom_length_method
|
def test_resource_limits_works_with_custom_length_method
|
||||||
t = Template.parse("{% assign foo = bar %}")
|
t = Template.parse('{% assign foo = bar %}')
|
||||||
t.resource_limits.render_length_limit = 42
|
t.resource_limits.render_length_limit = 42
|
||||||
assert_equal("", t.render!("bar" => SomethingWithLength.new))
|
assert_equal '', t.render!('bar' => SomethingWithLength.new)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_resource_limits_render_length
|
def test_resource_limits_render_length
|
||||||
t = Template.parse("0123456789")
|
t = Template.parse('0123456789')
|
||||||
t.resource_limits.render_length_limit = 5
|
t.resource_limits.render_length_limit = 5
|
||||||
assert_equal("Liquid error: Memory limits exceeded", t.render)
|
assert_equal 'Liquid error: Memory limits exceeded', t.render
|
||||||
assert(t.resource_limits.reached?)
|
assert t.resource_limits.reached?
|
||||||
|
|
||||||
t.resource_limits.render_length_limit = 10
|
t.resource_limits.render_length_limit = 10
|
||||||
assert_equal("0123456789", t.render!)
|
assert_equal '0123456789', t.render!
|
||||||
refute_nil(t.resource_limits.render_length)
|
refute_nil t.resource_limits.render_length
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_resource_limits_render_score
|
def test_resource_limits_render_score
|
||||||
t = Template.parse("{% for a in (1..10) %} {% for a in (1..10) %} foo {% endfor %} {% endfor %}")
|
t = Template.parse('{% for a in (1..10) %} {% for a in (1..10) %} foo {% endfor %} {% endfor %}')
|
||||||
t.resource_limits.render_score_limit = 50
|
t.resource_limits.render_score_limit = 50
|
||||||
assert_equal("Liquid error: Memory limits exceeded", t.render)
|
assert_equal 'Liquid error: Memory limits exceeded', t.render
|
||||||
assert(t.resource_limits.reached?)
|
assert t.resource_limits.reached?
|
||||||
|
|
||||||
t = Template.parse("{% for a in (1..100) %} foo {% endfor %}")
|
t = Template.parse('{% for a in (1..100) %} foo {% endfor %}')
|
||||||
t.resource_limits.render_score_limit = 50
|
t.resource_limits.render_score_limit = 50
|
||||||
assert_equal("Liquid error: Memory limits exceeded", t.render)
|
assert_equal 'Liquid error: Memory limits exceeded', t.render
|
||||||
assert(t.resource_limits.reached?)
|
assert t.resource_limits.reached?
|
||||||
|
|
||||||
t.resource_limits.render_score_limit = 200
|
t.resource_limits.render_score_limit = 200
|
||||||
assert_equal((" foo " * 100), t.render!)
|
assert_equal (' foo ' * 100), t.render!
|
||||||
refute_nil(t.resource_limits.render_score)
|
refute_nil t.resource_limits.render_score
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_resource_limits_assign_score
|
def test_resource_limits_assign_score
|
||||||
t = Template.parse("{% assign foo = 42 %}{% assign bar = 23 %}")
|
t = Template.parse('{% assign foo = 42 %}{% assign bar = 23 %}')
|
||||||
t.resource_limits.assign_score_limit = 1
|
t.resource_limits.assign_score_limit = 1
|
||||||
assert_equal("Liquid error: Memory limits exceeded", t.render)
|
assert_equal 'Liquid error: Memory limits exceeded', t.render
|
||||||
assert(t.resource_limits.reached?)
|
assert t.resource_limits.reached?
|
||||||
|
|
||||||
t.resource_limits.assign_score_limit = 2
|
t.resource_limits.assign_score_limit = 2
|
||||||
assert_equal("", t.render!)
|
assert_equal '', t.render!
|
||||||
refute_nil(t.resource_limits.assign_score)
|
refute_nil t.resource_limits.assign_score
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_resource_limits_assign_score_counts_bytes_not_characters
|
def test_resource_limits_assign_score_counts_bytes_not_characters
|
||||||
t = Template.parse("{% assign foo = 'すごい' %}")
|
t = Template.parse("{% assign foo = 'すごい' %}")
|
||||||
t.render
|
t.render
|
||||||
assert_equal(9, t.resource_limits.assign_score)
|
assert_equal 9, t.resource_limits.assign_score
|
||||||
|
|
||||||
t = Template.parse("{% capture foo %}すごい{% endcapture %}")
|
t = Template.parse('{% capture foo %}すごい{% endcapture %}')
|
||||||
t.render
|
t.render
|
||||||
assert_equal(9, t.resource_limits.assign_score)
|
assert_equal 9, t.resource_limits.assign_score
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_resource_limits_assign_score_nested
|
def test_resource_limits_assign_score_nested
|
||||||
t = Template.parse("{% assign foo = 'aaaa' | reverse %}")
|
t = Template.parse("{% assign foo = 'aaaa' | reverse %}")
|
||||||
|
|
||||||
t.resource_limits.assign_score_limit = 3
|
t.resource_limits.assign_score_limit = 3
|
||||||
assert_equal("Liquid error: Memory limits exceeded", t.render)
|
assert_equal 'Liquid error: Memory limits exceeded', t.render
|
||||||
assert(t.resource_limits.reached?)
|
assert t.resource_limits.reached?
|
||||||
|
|
||||||
t.resource_limits.assign_score_limit = 5
|
t.resource_limits.assign_score_limit = 5
|
||||||
assert_equal("", t.render!)
|
assert_equal '', t.render!
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_resource_limits_aborts_rendering_after_first_error
|
def test_resource_limits_aborts_rendering_after_first_error
|
||||||
t = Template.parse("{% for a in (1..100) %} foo1 {% endfor %} bar {% for a in (1..100) %} foo2 {% endfor %}")
|
t = Template.parse('{% for a in (1..100) %} foo1 {% endfor %} bar {% for a in (1..100) %} foo2 {% endfor %}')
|
||||||
t.resource_limits.render_score_limit = 50
|
t.resource_limits.render_score_limit = 50
|
||||||
assert_equal("Liquid error: Memory limits exceeded", t.render)
|
assert_equal 'Liquid error: Memory limits exceeded', t.render
|
||||||
assert(t.resource_limits.reached?)
|
assert t.resource_limits.reached?
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_resource_limits_hash_in_template_gets_updated_even_if_no_limits_are_set
|
def test_resource_limits_hash_in_template_gets_updated_even_if_no_limits_are_set
|
||||||
t = Template.parse("{% for a in (1..100) %} {% assign foo = 1 %} {% endfor %}")
|
t = Template.parse('{% for a in (1..100) %} {% assign foo = 1 %} {% endfor %}')
|
||||||
t.render!
|
t.render!
|
||||||
assert(t.resource_limits.assign_score > 0)
|
assert t.resource_limits.assign_score.positive?
|
||||||
assert(t.resource_limits.render_score > 0)
|
assert t.resource_limits.render_score.positive?
|
||||||
assert(t.resource_limits.render_length > 0)
|
assert t.resource_limits.render_length.positive?
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_render_length_persists_between_blocks
|
def test_render_length_persists_between_blocks
|
||||||
t = Template.parse("{% if true %}aaaa{% endif %}")
|
t = Template.parse('{% if true %}aaaa{% endif %}')
|
||||||
t.resource_limits.render_length_limit = 7
|
t.resource_limits.render_length_limit = 7
|
||||||
assert_equal("Liquid error: Memory limits exceeded", t.render)
|
assert_equal 'Liquid error: Memory limits exceeded', t.render
|
||||||
t.resource_limits.render_length_limit = 8
|
t.resource_limits.render_length_limit = 8
|
||||||
assert_equal("aaaa", t.render)
|
assert_equal 'aaaa', t.render
|
||||||
|
|
||||||
t = Template.parse("{% if true %}aaaa{% endif %}{% if true %}bbb{% endif %}")
|
t = Template.parse('{% if true %}aaaa{% endif %}{% if true %}bbb{% endif %}')
|
||||||
t.resource_limits.render_length_limit = 13
|
t.resource_limits.render_length_limit = 13
|
||||||
assert_equal("Liquid error: Memory limits exceeded", t.render)
|
assert_equal 'Liquid error: Memory limits exceeded', t.render
|
||||||
t.resource_limits.render_length_limit = 14
|
t.resource_limits.render_length_limit = 14
|
||||||
assert_equal("aaaabbb", t.render)
|
assert_equal 'aaaabbb', t.render
|
||||||
|
|
||||||
t = Template.parse("{% if true %}a{% endif %}{% if true %}b{% endif %}{% if true %}a{% endif %}{% if true %}b{% endif %}{% if true %}a{% endif %}{% if true %}b{% endif %}")
|
t = Template.parse('{% if true %}a{% endif %}{% if true %}b{% endif %}{% if true %}a{% endif %}{% if true %}b{% endif %}{% if true %}a{% endif %}{% if true %}b{% endif %}')
|
||||||
t.resource_limits.render_length_limit = 5
|
t.resource_limits.render_length_limit = 5
|
||||||
assert_equal("Liquid error: Memory limits exceeded", t.render)
|
assert_equal 'Liquid error: Memory limits exceeded', t.render
|
||||||
t.resource_limits.render_length_limit = 11
|
t.resource_limits.render_length_limit = 11
|
||||||
assert_equal("Liquid error: Memory limits exceeded", t.render)
|
assert_equal 'Liquid error: Memory limits exceeded', t.render
|
||||||
t.resource_limits.render_length_limit = 12
|
t.resource_limits.render_length_limit = 12
|
||||||
assert_equal("ababab", t.render)
|
assert_equal 'ababab', t.render
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_render_length_uses_number_of_bytes_not_characters
|
def test_render_length_uses_number_of_bytes_not_characters
|
||||||
t = Template.parse("{% if true %}すごい{% endif %}")
|
t = Template.parse('{% if true %}すごい{% endif %}')
|
||||||
t.resource_limits.render_length_limit = 10
|
t.resource_limits.render_length_limit = 10
|
||||||
assert_equal("Liquid error: Memory limits exceeded", t.render)
|
assert_equal 'Liquid error: Memory limits exceeded', t.render
|
||||||
t.resource_limits.render_length_limit = 18
|
t.resource_limits.render_length_limit = 18
|
||||||
assert_equal("すごい", t.render)
|
assert_equal 'すごい', t.render
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_default_resource_limits_unaffected_by_render_with_context
|
def test_default_resource_limits_unaffected_by_render_with_context
|
||||||
context = Context.new
|
context = Context.new
|
||||||
t = Template.parse("{% for a in (1..100) %} {% assign foo = 1 %} {% endfor %}")
|
t = Template.parse('{% for a in (1..100) %} {% assign foo = 1 %} {% endfor %}')
|
||||||
t.render!(context)
|
t.render!(context)
|
||||||
assert(context.resource_limits.assign_score > 0)
|
assert context.resource_limits.assign_score.positive?
|
||||||
assert(context.resource_limits.render_score > 0)
|
assert context.resource_limits.render_score.positive?
|
||||||
assert(context.resource_limits.render_length > 0)
|
assert context.resource_limits.render_length.positive?
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_can_use_drop_as_context
|
def test_can_use_drop_as_context
|
||||||
t = Template.new
|
t = Template.new
|
||||||
t.registers['lulz'] = 'haha'
|
t.registers['lulz'] = 'haha'
|
||||||
drop = TemplateContextDrop.new
|
drop = TemplateContextDrop.new
|
||||||
assert_equal('fizzbuzz', t.parse('{{foo}}').render!(drop))
|
assert_equal 'fizzbuzz', t.parse('{{foo}}').render!(drop)
|
||||||
assert_equal('bar', t.parse('{{bar}}').render!(drop))
|
assert_equal 'bar', t.parse('{{bar}}').render!(drop)
|
||||||
assert_equal('haha', t.parse("{{baz}}").render!(drop))
|
assert_equal 'haha', t.parse('{{baz}}').render!(drop)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_render_bang_force_rethrow_errors_on_passed_context
|
def test_render_bang_force_rethrow_errors_on_passed_context
|
||||||
@@ -238,72 +238,72 @@ class TemplateTest < Minitest::Test
|
|||||||
e = assert_raises RuntimeError do
|
e = assert_raises RuntimeError do
|
||||||
t.render!(context)
|
t.render!(context)
|
||||||
end
|
end
|
||||||
assert_equal('ruby error in drop', e.message)
|
assert_equal 'ruby error in drop', e.message
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_exception_renderer_that_returns_string
|
def test_exception_renderer_that_returns_string
|
||||||
exception = nil
|
exception = nil
|
||||||
handler = ->(e) {
|
handler = lambda { |e|
|
||||||
exception = e
|
exception = e
|
||||||
'<!-- error -->'
|
'<!-- error -->'
|
||||||
}
|
}
|
||||||
|
|
||||||
output = Template.parse("{{ 1 | divided_by: 0 }}").render({}, exception_renderer: handler)
|
output = Template.parse('{{ 1 | divided_by: 0 }}').render({}, exception_renderer: handler)
|
||||||
|
|
||||||
assert(exception.is_a?(Liquid::ZeroDivisionError))
|
assert exception.is_a?(Liquid::ZeroDivisionError)
|
||||||
assert_equal('<!-- error -->', output)
|
assert_equal '<!-- error -->', output
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_exception_renderer_that_raises
|
def test_exception_renderer_that_raises
|
||||||
exception = nil
|
exception = nil
|
||||||
assert_raises(Liquid::ZeroDivisionError) do
|
assert_raises(Liquid::ZeroDivisionError) do
|
||||||
Template.parse("{{ 1 | divided_by: 0 }}").render({}, exception_renderer: ->(e) {
|
Template.parse('{{ 1 | divided_by: 0 }}').render({}, exception_renderer: lambda { |e|
|
||||||
exception = e
|
exception = e
|
||||||
raise
|
raise
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
assert(exception.is_a?(Liquid::ZeroDivisionError))
|
assert exception.is_a?(Liquid::ZeroDivisionError)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_global_filter_option_on_render
|
def test_global_filter_option_on_render
|
||||||
global_filter_proc = ->(output) { "#{output} filtered" }
|
global_filter_proc = ->(output) { "#{output} filtered" }
|
||||||
rendered_template = Template.parse("{{name}}").render({ "name" => "bob" }, global_filter: global_filter_proc)
|
rendered_template = Template.parse('{{name}}').render({ 'name' => 'bob' }, global_filter: global_filter_proc)
|
||||||
|
|
||||||
assert_equal('bob filtered', rendered_template)
|
assert_equal 'bob filtered', rendered_template
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_global_filter_option_when_native_filters_exist
|
def test_global_filter_option_when_native_filters_exist
|
||||||
global_filter_proc = ->(output) { "#{output} filtered" }
|
global_filter_proc = ->(output) { "#{output} filtered" }
|
||||||
rendered_template = Template.parse("{{name | upcase}}").render({ "name" => "bob" }, global_filter: global_filter_proc)
|
rendered_template = Template.parse('{{name | upcase}}').render({ 'name' => 'bob' }, global_filter: global_filter_proc)
|
||||||
|
|
||||||
assert_equal('BOB filtered', rendered_template)
|
assert_equal 'BOB filtered', rendered_template
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_undefined_variables
|
def test_undefined_variables
|
||||||
t = Template.parse("{{x}} {{y}} {{z.a}} {{z.b}} {{z.c.d}}")
|
t = Template.parse('{{x}} {{y}} {{z.a}} {{z.b}} {{z.c.d}}')
|
||||||
result = t.render({ 'x' => 33, 'z' => { 'a' => 32, 'c' => { 'e' => 31 } } }, strict_variables: true)
|
result = t.render({ 'x' => 33, 'z' => { 'a' => 32, 'c' => { 'e' => 31 } } }, strict_variables: true)
|
||||||
|
|
||||||
assert_equal('33 32 ', result)
|
assert_equal '33 32 ', result
|
||||||
assert_equal(3, t.errors.count)
|
assert_equal 3, t.errors.count
|
||||||
assert_instance_of(Liquid::UndefinedVariable, t.errors[0])
|
assert_instance_of Liquid::UndefinedVariable, t.errors[0]
|
||||||
assert_equal('Liquid error: undefined variable y', t.errors[0].message)
|
assert_equal 'Liquid error: undefined variable y', t.errors[0].message
|
||||||
assert_instance_of(Liquid::UndefinedVariable, t.errors[1])
|
assert_instance_of Liquid::UndefinedVariable, t.errors[1]
|
||||||
assert_equal('Liquid error: undefined variable b', t.errors[1].message)
|
assert_equal 'Liquid error: undefined variable b', t.errors[1].message
|
||||||
assert_instance_of(Liquid::UndefinedVariable, t.errors[2])
|
assert_instance_of Liquid::UndefinedVariable, t.errors[2]
|
||||||
assert_equal('Liquid error: undefined variable d', t.errors[2].message)
|
assert_equal 'Liquid error: undefined variable d', t.errors[2].message
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_nil_value_does_not_raise
|
def test_nil_value_does_not_raise
|
||||||
Liquid::Template.error_mode = :strict
|
Liquid::Template.error_mode = :strict
|
||||||
t = Template.parse("some{{x}}thing")
|
t = Template.parse('some{{x}}thing')
|
||||||
result = t.render!({ 'x' => nil }, strict_variables: true)
|
result = t.render!({ 'x' => nil }, strict_variables: true)
|
||||||
|
|
||||||
assert_equal(0, t.errors.count)
|
assert_equal 0, t.errors.count
|
||||||
assert_equal('something', result)
|
assert_equal 'something', result
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_undefined_variables_raise
|
def test_undefined_variables_raise
|
||||||
t = Template.parse("{{x}} {{y}} {{z.a}} {{z.b}} {{z.c.d}}")
|
t = Template.parse('{{x}} {{y}} {{z.a}} {{z.b}} {{z.c.d}}')
|
||||||
|
|
||||||
assert_raises UndefinedVariable do
|
assert_raises UndefinedVariable do
|
||||||
t.render!({ 'x' => 33, 'z' => { 'a' => 32, 'c' => { 'e' => 31 } } }, strict_variables: true)
|
t.render!({ 'x' => 33, 'z' => { 'a' => 32, 'c' => { 'e' => 31 } } }, strict_variables: true)
|
||||||
@@ -315,9 +315,9 @@ class TemplateTest < Minitest::Test
|
|||||||
t = Template.new.parse('{{ foo }} {{ woot }}')
|
t = Template.new.parse('{{ foo }} {{ woot }}')
|
||||||
result = t.render(d, strict_variables: true)
|
result = t.render(d, strict_variables: true)
|
||||||
|
|
||||||
assert_equal('foo ', result)
|
assert_equal 'foo ', result
|
||||||
assert_equal(1, t.errors.count)
|
assert_equal 1, t.errors.count
|
||||||
assert_instance_of(Liquid::UndefinedDropMethod, t.errors[0])
|
assert_instance_of Liquid::UndefinedDropMethod, t.errors[0]
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_undefined_drop_methods_raise
|
def test_undefined_drop_methods_raise
|
||||||
@@ -330,7 +330,7 @@ class TemplateTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_undefined_filters
|
def test_undefined_filters
|
||||||
t = Template.parse("{{a}} {{x | upcase | somefilter1 | somefilter2 | somefilter3}}")
|
t = Template.parse('{{a}} {{x | upcase | somefilter1 | somefilter2 | somefilter3}}')
|
||||||
filters = Module.new do
|
filters = Module.new do
|
||||||
def somefilter3(v)
|
def somefilter3(v)
|
||||||
"-#{v}-"
|
"-#{v}-"
|
||||||
@@ -338,14 +338,14 @@ class TemplateTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
result = t.render({ 'a' => 123, 'x' => 'foo' }, filters: [filters], strict_filters: true)
|
result = t.render({ 'a' => 123, 'x' => 'foo' }, filters: [filters], strict_filters: true)
|
||||||
|
|
||||||
assert_equal('123 ', result)
|
assert_equal '123 ', result
|
||||||
assert_equal(1, t.errors.count)
|
assert_equal 1, t.errors.count
|
||||||
assert_instance_of(Liquid::UndefinedFilter, t.errors[0])
|
assert_instance_of Liquid::UndefinedFilter, t.errors[0]
|
||||||
assert_equal('Liquid error: undefined filter somefilter1', t.errors[0].message)
|
assert_equal 'Liquid error: undefined filter somefilter1', t.errors[0].message
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_undefined_filters_raise
|
def test_undefined_filters_raise
|
||||||
t = Template.parse("{{x | somefilter1 | upcase | somefilter2}}")
|
t = Template.parse('{{x | somefilter1 | upcase | somefilter2}}')
|
||||||
|
|
||||||
assert_raises UndefinedFilter do
|
assert_raises UndefinedFilter do
|
||||||
t.render!({ 'x' => 'foo' }, strict_filters: true)
|
t.render!({ 'x' => 'foo' }, strict_filters: true)
|
||||||
@@ -353,12 +353,12 @@ class TemplateTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_using_range_literal_works_as_expected
|
def test_using_range_literal_works_as_expected
|
||||||
t = Template.parse("{% assign foo = (x..y) %}{{ foo }}")
|
t = Template.parse('{% assign foo = (x..y) %}{{ foo }}')
|
||||||
result = t.render('x' => 1, 'y' => 5)
|
result = t.render('x' => 1, 'y' => 5)
|
||||||
assert_equal('1..5', result)
|
assert_equal '1..5', result
|
||||||
|
|
||||||
t = Template.parse("{% assign nums = (x..y) %}{% for num in nums %}{{ num }}{% endfor %}")
|
t = Template.parse('{% assign nums = (x..y) %}{% for num in nums %}{{ num }}{% endfor %}')
|
||||||
result = t.render('x' => 1, 'y' => 5)
|
result = t.render('x' => 1, 'y' => 5)
|
||||||
assert_equal('12345', result)
|
assert_equal '12345', result
|
||||||
end
|
end
|
||||||
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