Compare commits

...

31 Commits

Author SHA1 Message Date
DBA
0526348cae Gemspec
- rewritten
2010-08-24 11:57:26 +08:00
Tobias Lütke
a3fb7ba2b3 Merge branch 'master' of github.com:tobi/liquid
Conflicts:
	liquid.gemspec
2010-08-23 20:24:08 -04:00
Tobias Lütke
77cc0f2ed9 Version bump 2010-08-23 20:22:35 -04:00
DBA
3d43efe2bc Ruby compatibility issues
- regexp engines are different from 1.8 to 1.9, fixed the literal shorthand regexp accordingly
  - changed the shorthand regexp text from a match to a string scan
  - test_helper now loads rubygems unless RUBY_VERSION is > 1.9
2010-08-24 08:17:42 +08:00
DBA
772233d881 Readme: pre to code 2010-08-24 08:17:42 +08:00
DBA
90d1bc26d8 History
- updated (2.2.0 & 2.2.1)

Manifest
  - updated readme reference

Readme
  - Converted to markdown
  - cleaned up

Gemspec
  - updated to 2.2.1
2010-08-24 08:17:42 +08:00
DBA
c00a650492 Literal
- added support for literals [closes #6]

Code beautifier
  - indented some files
2010-08-24 08:17:42 +08:00
DBA
4819eb1a92 IF tag
- now properly allows operands to have conditions (eg and, or) [closes #13]
2010-08-24 08:17:41 +08:00
DBA
8579807d29 Conditions
- added test to assert that conditions can contain conditions within its value (eg 'a-and-b')

Tags
  - indented the if tag

Tests
  - added ruby-debug to the test_helper
  - indented some tests
2010-08-24 08:17:41 +08:00
DBA
daf786fd28 Test Helper
- added assert_template_result_matches
  - fixed indentation / white spacing
2010-08-24 08:17:41 +08:00
Tobias Lütke
101137045e remove swp files 2010-08-22 13:33:26 -04:00
DBA
8a0a8cfd99 FiltersTest
- added test that asserts nonexistent filters are ignored

Liquid
  - Bill's mind blowing liquid patch to support filter separators (|) in quoted strings (svn r7516).
  - This is a consolidation effort based on newrelic's liquid fork commit 88a5b891d009054d56b994c9448725c74e2b1e13
2010-08-23 01:30:05 +08:00
DBA
8304a046c9 Context
- Check arity of proc before calling, to prevent error when using ruby 1.9.1+

Code beautifer
  - context.rb
2010-08-23 01:30:03 +08:00
DBA
c72c84ea9b Tests
- Organized the files
  - Cleaned up some of the white spacing issues
  - A lot can still be done to make the tests more readable to the new developers
2010-08-23 01:30:01 +08:00
DBA
01145f872b Test Helper
- Removed unnecessary test helper file. The file being used is helper.rb
2010-08-23 01:30:00 +08:00
DBA
5409814552 Code beautifier
- standard_filter_test.rb
2010-08-23 01:30:00 +08:00
DBA
2d9331a234 StandardFilters
- Ruby 1.9.2-rc changed the float precision, thus the tests are now more generic and backwards compatible.
2010-08-23 01:30:00 +08:00
DBA
c59cde9d17 Code beautifier
- standardfilters.rb
  - standard_filter_test.rb
2010-08-23 01:30:00 +08:00
DBA
29e140b655 StandardFilters
- added escape_once, based on ActionView
2010-08-23 01:30:00 +08:00
DBA
a48332871a Test helper
- extras path now uses File.join instead of string concatenation
  - extras path is only loaded into $LOAD_PATH if it's not already part of it
2010-08-23 01:30:00 +08:00
DBA
bd7f867759 Code beautifier
- strainer_test.rb
2010-08-23 01:30:00 +08:00
DBA
8e4573a7bf Strainer
- respond_to_missing? is now a required method
2010-08-23 01:29:59 +08:00
DBA
5425679a96 Rakefile
- Updated to run with Ruby 1.9.2-p0
  - Fixed some indentations / white spacing
2010-08-23 01:29:59 +08:00
Tobias Lütke
6831eac902 Released gem 2.1.3 2010-08-05 18:07:05 -04:00
Dennis Theisen
13f98de7f3 Change behavior of capture tag to use existing variables if they already have been initialized in an outer scope. 2010-08-06 06:02:37 +08:00
Dennis Theisen
e26f509277 Fixed minor typos in inline documentation for assign and capture 2010-08-06 06:02:37 +08:00
James MacAulay
0417c9e723 Gem v2.1.2 2010-07-09 09:17:10 -04:00
James MacAulay
ffd48880e2 Gem v2.1.1 2010-07-09 09:11:49 -04:00
James MacAulay
6b79f25c87 rake release 2010-07-09 09:11:41 -04:00
James MacAulay
ff829e7996 fix if tag parsing with expressions starting with and/or 2010-07-07 16:48:23 -04:00
James MacAulay
d53a4e1834 rake default task is 'test' 2010-07-06 16:01:15 -04:00
48 changed files with 1170 additions and 982 deletions

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
*.gem *.gem
*.swp
pkg pkg

View File

@@ -1,3 +1,5 @@
* Make context and assign work the same
* Ruby 1.9.1 bugfixes * Ruby 1.9.1 bugfixes
* Fix LiquidView for Rails 2.2. Fix local assigns for all versions of Rails * Fix LiquidView for Rails 2.2. Fix local assigns for all versions of Rails

View File

@@ -1,3 +1,12 @@
2.2.1 / 2010-08-23
* Added support for literal tags
2.2.0 / 2010-08-22
* Compatible with Ruby 1.8.7, 1.9.1 and 1.9.2-p0
* Merged some changed made by the community
1.9.0 / 2008-03-04 1.9.0 / 2008-03-04
* Fixed gem install rake task * Fixed gem install rake task

View File

@@ -2,7 +2,7 @@ CHANGELOG
History.txt History.txt
MIT-LICENSE MIT-LICENSE
Manifest.txt Manifest.txt
README.txt README.md
Rakefile Rakefile
init.rb init.rb
lib/extras/liquid_view.rb lib/extras/liquid_view.rb

42
README.md Normal file
View File

@@ -0,0 +1,42 @@
# Liquid template engine
## Introduction
Liquid is a template engine which I wrote for very specific requirements
* It has to have beautiful and simple markup. Template engines which don't produce good looking markup are no fun to use.
* It needs to be non evaling and secure. Liquid templates are made so that users can edit them. You don't want to run code on your server which your users wrote.
* It has to be stateless. Compile and render steps have to be seperate so that the expensive parsing and compiling can be done once and later on you can just render it passing in a hash with local variables and objects.
## Why should I use Liquid
* You want to allow your users to edit the appearance of your application but don't want them to run **insecure code on your server**.
* You want to render templates directly from the database
* You like smarty (PHP) style template engines
* You need a template engine which does HTML just as well as emails
* You don't like the markup of your current templating engine
## What does it look like?
<code>
<ul id="products">
{% for product in products %}
<li>
<h2>{{product.name}}</h2>
Only {{product.price | price }}
{{product.description | prettyprint | paragraph }}
</li>
{% endfor %}
</ul>
</code>
## Howto use Liquid
Liquid supports a very simple API based around the Liquid::Template class.
For standard use you can just pass it the content of a file and call render with a parameters hash.
<pre>
@template = Liquid::Template.parse("hi {{name}}") # Parses and compiles the template
@template.render( 'name' => 'tobi' ) # => "hi tobi"
</pre>

View File

@@ -1,38 +0,0 @@
= Liquid template engine
Liquid is a template engine which I wrote for very specific requirements
* It has to have beautiful and simple markup.
Template engines which don't produce good looking markup are no fun to use.
* It needs to be non evaling and secure. Liquid templates are made so that users can edit them. You don't want to run code on your server which your users wrote.
* It has to be stateless. Compile and render steps have to be seperate so that the expensive parsing and compiling can be done once and later on you can
just render it passing in a hash with local variables and objects.
== Why should i use Liquid
* You want to allow your users to edit the appearance of your application but don't want them to run insecure code on your server.
* You want to render templates directly from the database
* You like smarty style template engines
* You need a template engine which does HTML just as well as Emails
* You don't like the markup of your current one
== What does it look like?
<ul id="products">
{% for product in products %}
<li>
<h2>{{product.name}}</h2>
Only {{product.price | price }}
{{product.description | prettyprint | paragraph }}
</li>
{% endfor %}
</ul>
== Howto use Liquid
Liquid supports a very simple API based around the Liquid::Template class.
For standard use you can just pass it the content of a file and call render with a parameters hash.
@template = Liquid::Template.parse("hi {{name}}") # Parses and compiles the template
@template.render( 'name' => 'tobi' ) # => "hi tobi"

View File

@@ -1,13 +1,16 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
$:.unshift File.join(File.dirname(__FILE__), 'test') unless $:.include? File.join(File.dirname(__FILE__), 'test')
require 'rubygems' require 'rubygems'
require 'rake' require 'rake'
require 'rake/testtask' require 'rake/testtask'
require 'rake/gempackagetask' require 'rake/gempackagetask'
task :default => 'test'
Rake::TestTask.new(:test) do |t| Rake::TestTask.new(:test) do |t|
t.libs << "lib" t.libs << '.' << 'lib' << 'test'
t.libs << "test" t.pattern = 'test/lib/**/*_test.rb'
t.pattern = 'test/*_test.rb'
t.verbose = false t.verbose = false
end end
@@ -16,22 +19,25 @@ Rake::GemPackageTask.new(gemspec) do |pkg|
pkg.gem_spec = gemspec pkg.gem_spec = gemspec
end end
desc "build the gem and release it to rubygems.org"
task :release => :gem do
sh "gem push pkg/liquid-#{gemspec.version}.gem"
end
namespace :profile do namespace :profile do
task :default => [:run] task :default => [:run]
desc "Run the liquid profile/perforamce coverage" desc "Run the liquid profile/perforamce coverage"
task :run do task :run do
ruby "performance/shopify.rb" ruby "performance/shopify.rb"
end end
desc "Run KCacheGrind" desc "Run KCacheGrind"
task :grind => :run do task :grind => :run do
system "kcachegrind /tmp/liquid.rubyprof_calltreeprinter.txt" system "kcachegrind /tmp/liquid.rubyprof_calltreeprinter.txt"
end end
end end

View File

@@ -38,13 +38,14 @@ module Liquid
StrictQuotedFragment = /"[^"]+"|'[^']+'|[^\s,\|,\:,\,]+/ StrictQuotedFragment = /"[^"]+"|'[^']+'|[^\s,\|,\:,\,]+/
FirstFilterArgument = /#{FilterArgumentSeparator}(?:#{StrictQuotedFragment})/ FirstFilterArgument = /#{FilterArgumentSeparator}(?:#{StrictQuotedFragment})/
OtherFilterArgument = /#{ArgumentSeparator}(?:#{StrictQuotedFragment})/ OtherFilterArgument = /#{ArgumentSeparator}(?:#{StrictQuotedFragment})/
SpacelessFilter = /#{FilterSeparator}(?:#{StrictQuotedFragment})(?:#{FirstFilterArgument}(?:#{OtherFilterArgument})*)?/ SpacelessFilter = /^(?:'[^']+'|"[^"]+"|[^'"])*#{FilterSeparator}(?:#{StrictQuotedFragment})(?:#{FirstFilterArgument}(?:#{OtherFilterArgument})*)?/
Expression = /(?:#{QuotedFragment}(?:#{SpacelessFilter})*)/ Expression = /(?:#{QuotedFragment}(?:#{SpacelessFilter})*)/
TagAttributes = /(\w+)\s*\:\s*(#{QuotedFragment})/ TagAttributes = /(\w+)\s*\:\s*(#{QuotedFragment})/
AnyStartingTag = /\{\{|\{\%/ AnyStartingTag = /\{\{|\{\%/
PartialTemplateParser = /#{TagStart}.*?#{TagEnd}|#{VariableStart}.*?#{VariableIncompleteEnd}/ PartialTemplateParser = /#{TagStart}.*?#{TagEnd}|#{VariableStart}.*?#{VariableIncompleteEnd}/
TemplateParser = /(#{PartialTemplateParser}|#{AnyStartingTag})/ TemplateParser = /(#{PartialTemplateParser}|#{AnyStartingTag})/
VariableParser = /\[[^\]]+\]|#{VariableSegment}+\??/ VariableParser = /\[[^\]]+\]|#{VariableSegment}+\??/
LiteralShorthand = /^(?:\{\{\{\s?)(.*?)(?:\s*\}\}\})$/
end end
require 'liquid/drop' require 'liquid/drop'

View File

@@ -28,8 +28,9 @@ module Liquid
@strainer ||= Strainer.create(self) @strainer ||= Strainer.create(self)
end end
# adds filters to this context. # Adds filters to this context.
# this does not register the filters with the main Template object. see <tt>Template.register_filter</tt> #
# Note that this does not register the filters with the main Template object. see <tt>Template.register_filter</tt>
# for that # for that
def add_filters(filters) def add_filters(filters)
filters = [filters].flatten.compact filters = [filters].flatten.compact
@@ -52,7 +53,6 @@ module Liquid
end end
end end
def invoke(method, *args) def invoke(method, *args)
if strainer.respond_to?(method) if strainer.respond_to?(method)
strainer.__send__(method, *args) strainer.__send__(method, *args)
@@ -61,43 +61,44 @@ module Liquid
end end
end end
# 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={})
raise StackLevelError, "Nesting too deep" if @scopes.length > 100 raise StackLevelError, "Nesting too deep" if @scopes.length > 100
@scopes.unshift(new_scope) @scopes.unshift(new_scope)
end end
# merge a hash of variables in the current local scope # Merge a hash of variables in the current local scope
def merge(new_scopes) def merge(new_scopes)
@scopes[0].merge!(new_scopes) @scopes[0].merge!(new_scopes)
end end
# 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
# pushes a new local scope on the stack, pops it at the end of the block # Pushes a new local scope on the stack, pops it at the end of the block
# #
# Example: # Example:
#
# context.stack do # context.stack do
# context['var'] = 'hi' # context['var'] = 'hi'
# end # end
# context['var] #=> nil
# #
# context['var] #=> nil
def stack(new_scope={},&block) def stack(new_scope={},&block)
result = nil result = nil
push(new_scope) push(new_scope)
begin begin
result = yield result = yield
ensure ensure
pop pop
end end
result result
end end
def clear_instance_assigns def clear_instance_assigns
@scopes[0] = {} @scopes[0] = {}
end end
@@ -116,139 +117,133 @@ module Liquid
end end
private private
# Look up variable, either resolve directly after considering the name. We can directly handle
# Look up variable, either resolve directly after considering the name. We can directly handle # Strings, digits, floats and booleans (true,false).
# Strings, digits, floats and booleans (true,false). If no match is made we lookup the variable in the current scope and # If no match is made we lookup the variable in the current scope and
# later move up to the parent blocks to see if we can resolve the variable somewhere up the tree. # later move up to the parent blocks to see if we can resolve the variable somewhere up the tree.
# Some special keywords return symbols. Those symbols are to be called on the rhs object in expressions # Some special keywords return symbols. Those symbols are to be called on the rhs object in expressions
# #
# Example: # Example:
# # products == empty #=> products.empty?
# products == empty #=> products.empty? def resolve(key)
# case key
def resolve(key) when nil, 'nil', 'null', ''
case key nil
when nil, 'nil', 'null', '' when 'true'
nil true
when 'true' when 'false'
true false
when 'false' when 'blank'
false :blank?
when 'blank' when 'empty' # Single quoted strings
:blank? :empty?
when 'empty' when /^'(.*)'$/ # Double quoted strings
:empty? $1.to_s
# Single quoted strings when /^"(.*)"$/ # Integer and floats
when /^'(.*)'$/ $1.to_s
$1.to_s when /^(\d+)$/ # Ranges
# Double quoted strings $1.to_i
when /^"(.*)"$/ when /^\((\S+)\.\.(\S+)\)$/ # Floats
$1.to_s (resolve($1).to_i..resolve($2).to_i)
# Integer and floats when /^(\d[\d\.]+)$/
when /^(\d+)$/ $1.to_f
$1.to_i else
# Ranges variable(key)
when /^\((\S+)\.\.(\S+)\)$/
(resolve($1).to_i..resolve($2).to_i)
# Floats
when /^(\d[\d\.]+)$/
$1.to_f
else
variable(key)
end
end
# fetches an object starting at the local scope and then moving up
# the hierachy
def find_variable(key)
scope = @scopes.find { |s| s.has_key?(key) }
if scope.nil?
@environments.each do |e|
if variable = lookup_and_evaluate(e, key)
scope = e
break
end
end
end
scope ||= @environments.last || @scopes.last
variable ||= lookup_and_evaluate(scope, key)
variable = variable.to_liquid
variable.context = self if variable.respond_to?(:context=)
return variable
end
# resolves namespaced queries gracefully.
#
# Example
#
# @context['hash'] = {"name" => 'tobi'}
# assert_equal 'tobi', @context['hash.name']
# assert_equal 'tobi', @context['hash["name"]']
#
def variable(markup)
parts = markup.scan(VariableParser)
square_bracketed = /^\[(.*)\]$/
first_part = parts.shift
if first_part =~ square_bracketed
first_part = resolve($1)
end
if object = find_variable(first_part)
parts.each do |part|
part = resolve($1) if part_resolved = (part =~ square_bracketed)
# If object is a hash- or array-like object we look for the
# presence of the key and if its available we return it
if object.respond_to?(:[]) and
((object.respond_to?(:has_key?) and object.has_key?(part)) or
(object.respond_to?(:fetch) and part.is_a?(Integer)))
# if its a proc we will replace the entry with the proc
res = lookup_and_evaluate(object, part)
object = res.to_liquid
# Some special cases. If the part wasn't in square brackets and
# no key with the same name was found we interpret following calls
# as commands and call them on the current object
elsif !part_resolved and object.respond_to?(part) and ['size', 'first', 'last'].include?(part)
object = object.send(part.intern).to_liquid
# No key was present with the desired value and it wasn't one of the directly supported
# keywords either. The only thing we got left is to return nil
else
return nil
end
# If we are dealing with a drop here we have to
object.context = self if object.respond_to?(:context=)
end end
end end
object # Fetches an object starting at the local scope and then moving up the hierachy
end def find_variable(key)
scope = @scopes.find { |s| s.has_key?(key) }
def lookup_and_evaluate(obj, key)
if (value = obj[key]).is_a?(Proc) && obj.respond_to?(:[]=) if scope.nil?
obj[key] = value.call(self) @environments.each do |e|
else if variable = lookup_and_evaluate(e, key)
value scope = e
end break
end end
def squash_instance_assigns_with_environments
@scopes.last.each_key do |k|
@environments.each do |env|
if env.has_key?(k)
scopes.last[k] = lookup_and_evaluate(env, k)
break
end end
end end
scope ||= @environments.last || @scopes.last
variable ||= lookup_and_evaluate(scope, key)
variable = variable.to_liquid
variable.context = self if variable.respond_to?(:context=)
return variable
end end
end
# Resolves namespaced queries gracefully.
end #
end # Example
# @context['hash'] = {"name" => 'tobi'}
# assert_equal 'tobi', @context['hash.name']
# assert_equal 'tobi', @context['hash["name"]']
def variable(markup)
parts = markup.scan(VariableParser)
square_bracketed = /^\[(.*)\]$/
first_part = parts.shift
if first_part =~ square_bracketed
first_part = resolve($1)
end
if object = find_variable(first_part)
parts.each do |part|
part = resolve($1) if part_resolved = (part =~ square_bracketed)
# If object is a hash- or array-like object we look for the
# presence of the key and if its available we return it
if object.respond_to?(:[]) and
((object.respond_to?(:has_key?) and object.has_key?(part)) or
(object.respond_to?(:fetch) and part.is_a?(Integer)))
# if its a proc we will replace the entry with the proc
res = lookup_and_evaluate(object, part)
object = res.to_liquid
# Some special cases. If the part wasn't in square brackets and
# no key with the same name was found we interpret following calls
# as commands and call them on the current object
elsif !part_resolved and object.respond_to?(part) and ['size', 'first', 'last'].include?(part)
object = object.send(part.intern).to_liquid
# No key was present with the desired value and it wasn't one of the directly supported
# keywords either. The only thing we got left is to return nil
else
return nil
end
# If we are dealing with a drop here we have to
object.context = self if object.respond_to?(:context=)
end
end
object
end # variable
def lookup_and_evaluate(obj, key)
if (value = obj[key]).is_a?(Proc) && obj.respond_to?(:[]=)
obj[key] = (value.arity == 0) ? value.call : value.call(self)
else
value
end
end # lookup_and_evaluate
def squash_instance_assigns_with_environments
@scopes.last.each_key do |k|
@environments.each do |env|
if env.has_key?(k)
scopes.last[k] = lookup_and_evaluate(env, k)
break
end
end
end
end # squash_instance_assigns_with_environments
end # Context
end # Liquid

View File

@@ -1,36 +1,40 @@
require 'cgi' require 'cgi'
module Liquid module Liquid
module StandardFilters module StandardFilters
# 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)
input.respond_to?(:size) ? input.size : 0 input.respond_to?(:size) ? input.size : 0
end end
# convert a input string to DOWNCASE # convert a input string to DOWNCASE
def downcase(input) def downcase(input)
input.to_s.downcase input.to_s.downcase
end end
# convert a input string to UPCASE # convert a input string to UPCASE
def upcase(input) def upcase(input)
input.to_s.upcase input.to_s.upcase
end end
# capitalize words in the input centence # capitalize words in the input centence
def capitalize(input) def capitalize(input)
input.to_s.capitalize input.to_s.capitalize
end end
def escape(input) def escape(input)
CGI.escapeHTML(input) rescue input CGI.escapeHTML(input) rescue input
end end
def escape_once(input)
ActionView::Helpers::TagHelper.escape_once(input) rescue input
end
alias_method :h, :escape alias_method :h, :escape
# 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 = "...")
if input.nil? then return end if input.nil? then return end
@@ -44,19 +48,19 @@ module Liquid
wordlist = input.to_s.split wordlist = input.to_s.split
l = words.to_i - 1 l = words.to_i - 1
l = 0 if l < 0 l = 0 if l < 0
wordlist.length > l ? wordlist[0..l].join(" ") + truncate_string : input wordlist.length > l ? wordlist[0..l].join(" ") + truncate_string : input
end end
def strip_html(input) def strip_html(input)
input.to_s.gsub(/<script.*?<\/script>/, '').gsub(/<.*?>/, '') input.to_s.gsub(/<script.*?<\/script>/, '').gsub(/<.*?>/, '')
end
# Remove all newlines from the string
def strip_newlines(input)
input.to_s.gsub(/\n/, '')
end end
# Remove all newlines from the string
def strip_newlines(input)
input.to_s.gsub(/\n/, '')
end
# Join elements of the array with certain character between them # Join elements of the array with certain character between them
def join(input, glue = ' ') def join(input, glue = ' ')
[input].flatten.join(glue) [input].flatten.join(glue)
@@ -73,8 +77,8 @@ module Liquid
elsif ary.first.respond_to?(property) elsif ary.first.respond_to?(property)
ary.sort {|a,b| a.send(property) <=> b.send(property) } ary.sort {|a,b| a.send(property) <=> b.send(property) }
end end
end end
# map/collect on a given property # map/collect on a given property
def map(input, property) def map(input, property)
ary = [input].flatten ary = [input].flatten
@@ -84,42 +88,42 @@ module Liquid
ary.map {|e| e.send(property) } ary.map {|e| e.send(property) }
end end
end end
# Replace occurrences of a string with another # Replace occurrences of a string with another
def replace(input, string, replacement = '') def replace(input, string, replacement = '')
input.to_s.gsub(string, replacement) input.to_s.gsub(string, replacement)
end end
# Replace the first occurrences of a string with another # Replace the first occurrences of a string with another
def replace_first(input, string, replacement = '') def replace_first(input, string, replacement = '')
input.to_s.sub(string, replacement) input.to_s.sub(string, replacement)
end end
# remove a substring # remove a substring
def remove(input, string) def remove(input, string)
input.to_s.gsub(string, '') input.to_s.gsub(string, '')
end end
# remove the first occurrences of a substring # remove the first occurrences of a substring
def remove_first(input, string) def remove_first(input, string)
input.to_s.sub(string, '') input.to_s.sub(string, '')
end end
# add one string to another # add one string to another
def append(input, string) def append(input, string)
input.to_s + string.to_s input.to_s + string.to_s
end end
# prepend a string to another # prepend a string to another
def prepend(input, string) def prepend(input, string)
string.to_s + input.to_s string.to_s + input.to_s
end end
# Add <br /> tags in front of all newlines in input string # Add <br /> tags in front of all newlines in input string
def newline_to_br(input) def newline_to_br(input)
input.to_s.gsub(/\n/, "<br />\n") input.to_s.gsub(/\n/, "<br />\n")
end end
# Reformat a date # Reformat a date
# #
# %a - The abbreviated weekday name (``Sun'') # %a - The abbreviated weekday name (``Sun'')
@@ -149,74 +153,74 @@ module Liquid
# %Z - Time zone name # %Z - Time zone name
# %% - Literal ``%'' character # %% - Literal ``%'' character
def date(input, format) def date(input, format)
if format.to_s.empty? if format.to_s.empty?
return input.to_s return input.to_s
end end
date = input.is_a?(String) ? Time.parse(input) : input date = input.is_a?(String) ? Time.parse(input) : input
if date.respond_to?(:strftime) if date.respond_to?(:strftime)
date.strftime(format.to_s) date.strftime(format.to_s)
else else
input input
end end
rescue => e rescue => e
input input
end end
# Get the first element of the passed in array # Get the first element of the passed in array
# #
# Example: # Example:
# {{ product.images | first | to_img }} # {{ product.images | first | to_img }}
# #
def first(array) def first(array)
array.first if array.respond_to?(:first) array.first if array.respond_to?(:first)
end end
# Get the last element of the passed in array # Get the last element of the passed in array
# #
# Example: # Example:
# {{ product.images | last | to_img }} # {{ product.images | last | to_img }}
# #
def last(array) def last(array)
array.last if array.respond_to?(:last) array.last if array.respond_to?(:last)
end end
# addition # addition
def plus(input, operand) def plus(input, operand)
to_number(input) + to_number(operand) to_number(input) + to_number(operand)
end end
# subtraction # subtraction
def minus(input, operand) def minus(input, operand)
to_number(input) - to_number(operand) to_number(input) - to_number(operand)
end end
# multiplication # multiplication
def times(input, operand) def times(input, operand)
to_number(input) * to_number(operand) to_number(input) * to_number(operand)
end end
# division # division
def divided_by(input, operand) def divided_by(input, operand)
to_number(input) / to_number(operand) to_number(input) / to_number(operand)
end end
private private
def to_number(obj) def to_number(obj)
case obj case obj
when Numeric when Numeric
obj obj
when String when String
(obj.strip =~ /^\d+\.\d+$/) ? obj.to_f : obj.to_i (obj.strip =~ /^\d+\.\d+$/) ? obj.to_f : obj.to_i
else else
0 0
end
end end
end
end end
Template.register_filter(StandardFilters) Template.register_filter(StandardFilters)
end end

View File

@@ -16,6 +16,9 @@ module Liquid
INTERNAL_METHOD = /^__/ INTERNAL_METHOD = /^__/
@@required_methods = Set.new([:__id__, :__send__, :respond_to?, :extend, :methods, :class, :object_id]) @@required_methods = Set.new([:__id__, :__send__, :respond_to?, :extend, :methods, :class, :object_id])
# Ruby 1.9.2 introduces Object#respond_to_missing?, which is invoked by Object#respond_to?
@@required_methods << :respond_to_missing? if Object.respond_to? :respond_to_missing?
@@filters = {} @@filters = {}
def initialize(context) def initialize(context)

View File

@@ -1,6 +1,7 @@
module Liquid module Liquid
class Tag class Tag
attr_accessor :nodelist attr_accessor :nodelist
def initialize(tag_name, markup, tokens) def initialize(tag_name, markup, tokens)
@@ -19,8 +20,7 @@ module Liquid
def render(context) def render(context)
'' ''
end end
end
end # Tag
end end # Tag

View File

@@ -6,7 +6,7 @@ module Liquid
# #
# You can then use the variable later in the page. # You can then use the variable later in the page.
# #
# {{ monkey }} # {{ foo }}
# #
class Assign < Tag class Assign < Tag
Syntax = /(#{VariableSignature}+)\s*=\s*(#{QuotedFragment}+)/ Syntax = /(#{VariableSignature}+)\s*=\s*(#{QuotedFragment}+)/
@@ -23,11 +23,11 @@ module Liquid
end end
def render(context) def render(context)
context.scopes.last[@to.to_s] = context[@from] context.scopes.last[@to] = context[@from]
'' ''
end end
end end
Template.register_tag('assign', Assign) Template.register_tag('assign', Assign)
end end

View File

@@ -6,7 +6,7 @@ module Liquid
# Monkeys! # Monkeys!
# {% endcapture %} # {% endcapture %}
# ... # ...
# <h1>{{ monkeys }}</h1> # <h1>{{ heading }}</h1>
# #
# Capture is useful for saving content for use later in your template, such as # Capture is useful for saving content for use later in your template, such as
# in a sidebar or footer. # in a sidebar or footer.
@@ -26,7 +26,7 @@ module Liquid
def render(context) def render(context)
output = super output = super
context[@to] = output.join context.scopes.last[@to] = output.join
'' ''
end end
end end

View File

@@ -1,9 +1,9 @@
module Liquid module Liquid
class Comment < Block class Comment < Block
def render(context) def render(context)
'' ''
end end
end end
Template.register_tag('comment', Comment) Template.register_tag('comment', Comment)
end end

View File

@@ -14,17 +14,16 @@ module Liquid
class If < Block class If < Block
SyntaxHelp = "Syntax Error in tag 'if' - Valid syntax: if [expression]" SyntaxHelp = "Syntax Error in tag 'if' - Valid syntax: if [expression]"
Syntax = /(#{QuotedFragment})\s*([=!<>a-z_]+)?\s*(#{QuotedFragment})?/ Syntax = /(#{QuotedFragment})\s*([=!<>a-z_]+)?\s*(#{QuotedFragment})?/
ExpressionsAndOperators = /(?:and|or|(?:\s*(?!\b(?:and|or)\b)(?:#{QuotedFragment}|\S+)\s*)+)/ ExpressionsAndOperators = /(?:\b(?:\s?and\s?|\s?or\s?)\b|(?:\s*(?!\b(?:\s?and\s?|\s?or\s?)\b)(?:#{QuotedFragment}|\S+)\s*)+)/
def initialize(tag_name, markup, tokens) def initialize(tag_name, markup, tokens)
@blocks = [] @blocks = []
push_block('if', markup) push_block('if', markup)
super super
end end
def unknown_tag(tag, markup, tokens) def unknown_tag(tag, markup, tokens)
if ['elsif', 'else'].include?(tag) if ['elsif', 'else'].include?(tag)
push_block(tag, markup) push_block(tag, markup)
@@ -32,49 +31,49 @@ module Liquid
super super
end end
end end
def render(context) def render(context)
context.stack do context.stack do
@blocks.each do |block| @blocks.each do |block|
if block.evaluate(context) if block.evaluate(context)
return render_all(block.attachment, context) return render_all(block.attachment, context)
end end
end end
'' ''
end end
end end
private
def push_block(tag, markup)
block = if tag == 'else'
ElseCondition.new
else
expressions = markup.scan(ExpressionsAndOperators).reverse
raise(SyntaxError, SyntaxHelp) unless expressions.shift =~ Syntax
condition = Condition.new($1, $2, $3) private
while not expressions.empty? def push_block(tag, markup)
operator = expressions.shift block = if tag == 'else'
ElseCondition.new
raise(SyntaxError, SyntaxHelp) unless expressions.shift.to_s =~ Syntax else
new_condition = Condition.new($1, $2, $3) expressions = markup.scan(ExpressionsAndOperators).reverse
new_condition.send(operator.to_sym, condition) raise(SyntaxError, SyntaxHelp) unless expressions.shift =~ Syntax
condition = new_condition
end condition = Condition.new($1, $2, $3)
condition while not expressions.empty?
operator = (expressions.shift).to_s.strip
raise(SyntaxError, SyntaxHelp) unless expressions.shift.to_s =~ Syntax
new_condition = Condition.new($1, $2, $3)
new_condition.send(operator.to_sym, condition)
condition = new_condition
end
condition
end
@blocks.push(block)
@nodelist = block.attach(Array.new)
end end
@blocks.push(block)
@nodelist = block.attach(Array.new)
end
end end
Template.register_tag('if', If) Template.register_tag('if', If)
end end

View File

@@ -0,0 +1,42 @@
module Liquid
class Literal < Block
# Class methods
# Converts a shorthand Liquid literal into its long representation.
#
# Currently the Template parser only knows how to handle the long version.
# So, it always checks if it is in the presence of a literal, in which case it gets converted through this method.
#
# Example:
# Liquid::Literal "{{{ hello world }}}" #=> "{% literal %} hello world {% endliteral %}"
def self.from_shorthand(literal)
literal =~ LiteralShorthand ? "{% literal %}#{$1}{% endliteral %}" : literal
end
# Public instance methods
def parse(tokens) # :nodoc:
@nodelist ||= []
@nodelist.clear
while token = tokens.shift
if token =~ FullToken && block_delimiter == $1
end_tag
return
else
@nodelist << token
end
end
# Make sure that its ok to end parsing in the current block.
# Effectively this method will throw and exception unless the current block is
# of type Document
assert_missing_delimitation!
end # parse
end
Template.register_tag('literal', Literal)
end

View File

@@ -55,7 +55,7 @@ module Liquid
# Parse source code. # Parse source code.
# Returns self for easy chaining # Returns self for easy chaining
def parse(source) def parse(source)
@root = Document.new(tokenize(source)) @root = Document.new(tokenize(Liquid::Literal.from_shorthand(source)))
self self
end end

View File

@@ -1,29 +1,23 @@
# -*- encoding: utf-8 -*-
Gem::Specification.new do |s| Gem::Specification.new do |s|
s.name = %q{liquid} s.platform = Gem::Platform::RUBY
s.version = "2.1.0"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.name = "liquid"
s.authors = ["Tobias Luetke"] s.version = '2.2.2'
s.date = %q{2009-04-13} s.summary = "A secure, non-evaling end user template engine with aesthetic markup."
s.description = %q{A secure, non-evaling end user template engine with aesthetic markup.}
s.email = %q{tobi@leetsoft.com}
s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt"]
s.files = ["CHANGELOG", "History.txt", "MIT-LICENSE", "Manifest.txt", "README.txt", "Rakefile", "lib/extras/liquid_view.rb", "lib/liquid.rb", "lib/liquid/block.rb", "lib/liquid/condition.rb", "lib/liquid/context.rb", "lib/liquid/document.rb", "lib/liquid/drop.rb", "lib/liquid/errors.rb", "lib/liquid/extensions.rb", "lib/liquid/file_system.rb", "lib/liquid/htmltags.rb", "lib/liquid/module_ex.rb", "lib/liquid/standardfilters.rb", "lib/liquid/strainer.rb", "lib/liquid/tag.rb", "lib/liquid/tags/assign.rb", "lib/liquid/tags/capture.rb", "lib/liquid/tags/case.rb", "lib/liquid/tags/comment.rb", "lib/liquid/tags/cycle.rb", "lib/liquid/tags/for.rb", "lib/liquid/tags/if.rb", "lib/liquid/tags/ifchanged.rb", "lib/liquid/tags/include.rb", "lib/liquid/tags/unless.rb", "lib/liquid/template.rb", "lib/liquid/variable.rb"]
s.has_rdoc = true
s.homepage = %q{http://www.liquidmarkup.org}
s.rdoc_options = ["--main", "README.txt"]
s.require_paths = ["lib"]
s.rubyforge_project = %q{liquid}
s.rubygems_version = %q{1.3.1}
s.summary = %q{A secure, non-evaling end user template engine with aesthetic markup.}
if s.respond_to? :specification_version then s.authors = ["Tobias Luetke"]
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION s.email = ["tobi@leetsoft.com"]
s.specification_version = 2 s.homepage = "http://www.liquidmarkup.org"
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then s.description = "A secure, non-evaling end user template engine with aesthetic markup."
else
end s.required_rubygems_version = ">= 1.3.7"
else
end s.files = Dir.glob("{lib}/**/*") + %w(MIT-LICENSE README.md)
s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.md"]
s.require_path = 'lib'
end end

View File

@@ -1,11 +0,0 @@
require File.dirname(__FILE__) + '/helper'
class AssignTest < Test::Unit::TestCase
include Liquid
def test_assigned_variable
assert_template_result('.foo.','{% assign foo = values %}.{{ foo[0] }}.', 'values' => %w{foo bar baz})
assert_template_result('.bar.','{% assign foo = values %}.{{ foo[1] }}.', 'values' => %w{foo bar baz})
end
end

View File

@@ -1,20 +0,0 @@
#!/usr/bin/env ruby
$LOAD_PATH.unshift(File.dirname(__FILE__)+ '/extra')
require 'test/unit'
require 'test/unit/assertions'
require 'caller'
require 'breakpoint'
require File.dirname(__FILE__) + '/../lib/liquid'
module Test
module Unit
module Assertions
include Liquid
def assert_template_result(expected, template, assigns={}, message=nil)
assert_equal expected, Template.parse(template).render(assigns)
end
end
end
end

View File

@@ -1,129 +0,0 @@
require File.dirname(__FILE__) + '/helper'
class TestFileSystem
def read_template_file(template_path)
case template_path
when "product"
"Product: {{ product.title }} "
when "locale_variables"
"Locale: {{echo1}} {{echo2}}"
when "variant"
"Variant: {{ variant.title }}"
when "nested_template"
"{% include 'header' %} {% include 'body' %} {% include 'footer' %}"
when "body"
"body {% include 'body_detail' %}"
when "nested_product_template"
"Product: {{ nested_product_template.title }} {%include 'details'%} "
when "recursively_nested_template"
"-{% include 'recursively_nested_template' %}"
when "pick_a_source"
"from TestFileSystem"
else
template_path
end
end
end
class OtherFileSystem
def read_template_file(template_path)
'from OtherFileSystem'
end
end
class IncludeTagTest < Test::Unit::TestCase
include Liquid
def setup
Liquid::Template.file_system = TestFileSystem.new
end
def test_include_tag_looks_for_file_system_in_registers_first
assert_equal 'from OtherFileSystem',
Template.parse("{% include 'pick_a_source' %}").render({}, :registers => {:file_system => OtherFileSystem.new})
end
def test_include_tag_with
assert_equal "Product: Draft 151cm ",
Template.parse("{% include 'product' with products[0] %}").render( "products" => [ {'title' => 'Draft 151cm'}, {'title' => 'Element 155cm'} ] )
end
def test_include_tag_with_default_name
assert_equal "Product: Draft 151cm ",
Template.parse("{% include 'product' %}").render( "product" => {'title' => 'Draft 151cm'} )
end
def test_include_tag_for
assert_equal "Product: Draft 151cm Product: Element 155cm ",
Template.parse("{% include 'product' for products %}").render( "products" => [ {'title' => 'Draft 151cm'}, {'title' => 'Element 155cm'} ] )
end
def test_include_tag_with_local_variables
assert_equal "Locale: test123 ",
Template.parse("{% include 'locale_variables' echo1: 'test123' %}").render
end
def test_include_tag_with_multiple_local_variables
assert_equal "Locale: test123 test321",
Template.parse("{% include 'locale_variables' echo1: 'test123', echo2: 'test321' %}").render
end
def test_include_tag_with_multiple_local_variables_from_context
assert_equal "Locale: test123 test321",
Template.parse("{% include 'locale_variables' echo1: echo1, echo2: more_echos.echo2 %}").render('echo1' => 'test123', 'more_echos' => { "echo2" => 'test321'})
end
def test_nested_include_tag
assert_equal "body body_detail",
Template.parse("{% include 'body' %}").render
assert_equal "header body body_detail footer",
Template.parse("{% include 'nested_template' %}").render
end
def test_nested_include_with_variable
assert_equal "Product: Draft 151cm details ",
Template.parse("{% include 'nested_product_template' with product %}").render("product" => {"title" => 'Draft 151cm'})
assert_equal "Product: Draft 151cm details Product: Element 155cm details ",
Template.parse("{% include 'nested_product_template' for products %}").render("products" => [{"title" => 'Draft 151cm'}, {"title" => 'Element 155cm'}])
end
def test_recursively_included_template_does_not_produce_endless_loop
infinite_file_system = Class.new do
def read_template_file(template_path)
"-{% include 'loop' %}"
end
end
Liquid::Template.file_system = infinite_file_system.new
assert_raise(Liquid::StackLevelError) do
Template.parse("{% include 'loop' %}").render!
end
end
def test_dynamically_choosen_template
assert_equal "Test123", Template.parse("{% include template %}").render("template" => 'Test123')
assert_equal "Test321", Template.parse("{% include template %}").render("template" => 'Test321')
assert_equal "Product: Draft 151cm ", Template.parse("{% include template for product %}").render("template" => 'product', 'product' => { 'title' => 'Draft 151cm'})
end
end

View File

@@ -0,0 +1,15 @@
require 'test_helper'
class AssignTest < Test::Unit::TestCase
include Liquid
def test_assigned_variable
assert_template_result('.foo.',
'{% assign foo = values %}.{{ foo[0] }}.',
'values' => %w{foo bar baz})
assert_template_result('.bar.',
'{% assign foo = values %}.{{ foo[1] }}.',
'values' => %w{foo bar baz})
end
end # AssignTest

View File

@@ -1,4 +1,4 @@
require File.dirname(__FILE__) + '/helper' require 'test_helper'
class VariableTest < Test::Unit::TestCase class VariableTest < Test::Unit::TestCase
include Liquid include Liquid
@@ -33,26 +33,26 @@ class VariableTest < Test::Unit::TestCase
def test_variable_many_embedded_fragments def test_variable_many_embedded_fragments
template = Liquid::Template.parse(" {{funk}} {{so}} {{brother}} ") template = Liquid::Template.parse(" {{funk}} {{so}} {{brother}} ")
assert_equal 7, template.root.nodelist.size assert_equal 7, template.root.nodelist.size
assert_equal [String, Variable, String, Variable, String, Variable, String], block_types(template.root.nodelist) assert_equal [String, Variable, String, Variable, String, Variable, String],
block_types(template.root.nodelist)
end end
def test_with_block def test_with_block
template = Liquid::Template.parse(" {% comment %} {% endcomment %} ") template = Liquid::Template.parse(" {% comment %} {% endcomment %} ")
assert_equal [String, Comment, String], block_types(template.root.nodelist) assert_equal [String, Comment, String], block_types(template.root.nodelist)
assert_equal 3, template.root.nodelist.size assert_equal 3, template.root.nodelist.size
end end
def test_with_custom_tag def test_with_custom_tag
Liquid::Template.register_tag("testtag", Block) Liquid::Template.register_tag("testtag", Block)
assert_nothing_thrown do assert_nothing_thrown do
template = Liquid::Template.parse( "{% testtag %} {% endtesttag %}") template = Liquid::Template.parse( "{% testtag %} {% endtesttag %}")
end end
end end
private private
def block_types(nodelist)
def block_types(nodelist) nodelist.collect { |node| node.class }
nodelist.collect { |node| node.class } end
end end # VariableTest
end

View File

@@ -0,0 +1,40 @@
require 'test_helper'
class CaptureTest < Test::Unit::TestCase
include Liquid
def test_captures_block_content_in_variable
assert_template_result("test string", "{% capture 'var' %}test string{% endcapture %}{{var}}", {})
end
def test_capture_to_variable_from_outer_scope_if_existing
template_source = <<-END_TEMPLATE
{% assign var = '' %}
{% if true %}
{% capture var %}first-block-string{% endcapture %}
{% endif %}
{% if true %}
{% capture var %}test-string{% endcapture %}
{% endif %}
{{var}}
END_TEMPLATE
template = Template.parse(template_source)
rendered = template.render
assert_equal "test-string", rendered.gsub(/\s/, '')
end
def test_assigning_from_capture
template_source = <<-END_TEMPLATE
{% assign first = '' %}
{% assign second = '' %}
{% for number in (1..3) %}
{% capture first %}{{number}}{% endcapture %}
{% assign second = first %}
{% endfor %}
{{ first }}-{{ second }}
END_TEMPLATE
template = Template.parse(template_source)
rendered = template.render
assert_equal "3-3", rendered.gsub(/\s/, '')
end
end # CaptureTest

View File

@@ -1,8 +1,8 @@
require File.dirname(__FILE__) + '/helper' require 'test_helper'
class ConditionTest < Test::Unit::TestCase class ConditionTest < Test::Unit::TestCase
include Liquid include Liquid
def test_basic_condition def test_basic_condition
assert_equal false, Condition.new('1', '==', '2').evaluate assert_equal false, Condition.new('1', '==', '2').evaluate
assert_equal true, Condition.new('1', '==', '1').evaluate assert_equal true, Condition.new('1', '==', '1').evaluate
@@ -47,69 +47,76 @@ class ConditionTest < Test::Unit::TestCase
def test_contains_works_on_arrays def test_contains_works_on_arrays
@context = Liquid::Context.new @context = Liquid::Context.new
@context['array'] = [1,2,3,4,5] @context['array'] = [1,2,3,4,5]
assert_evalutes_false "array", 'contains', '0' assert_evalutes_false "array", 'contains', '0'
assert_evalutes_true "array", 'contains', '1' assert_evalutes_true "array", 'contains', '1'
assert_evalutes_true "array", 'contains', '2' assert_evalutes_true "array", 'contains', '2'
assert_evalutes_true "array", 'contains', '3' assert_evalutes_true "array", 'contains', '3'
assert_evalutes_true "array", 'contains', '4' assert_evalutes_true "array", 'contains', '4'
assert_evalutes_true "array", 'contains', '5' assert_evalutes_true "array", 'contains', '5'
assert_evalutes_false "array", 'contains', '6' assert_evalutes_false "array", 'contains', '6'
assert_evalutes_false "array", 'contains', '"1"'
assert_evalutes_false "array", 'contains', '"1"' end
end
def test_contains_returns_false_for_nil_operands def test_contains_returns_false_for_nil_operands
@context = Liquid::Context.new @context = Liquid::Context.new
assert_evalutes_false "not_assigned", 'contains', '0' assert_evalutes_false "not_assigned", 'contains', '0'
assert_evalutes_false "0", 'contains', 'not_assigned' assert_evalutes_false "0", 'contains', 'not_assigned'
end end
def test_or_condition def test_or_condition
condition = Condition.new('1', '==', '2') condition = Condition.new('1', '==', '2')
assert_equal false, condition.evaluate assert_equal false, condition.evaluate
condition.or Condition.new('2', '==', '1') condition.or Condition.new('2', '==', '1')
assert_equal false, condition.evaluate assert_equal false, condition.evaluate
condition.or Condition.new('1', '==', '1') condition.or Condition.new('1', '==', '1')
assert_equal true, condition.evaluate assert_equal true, condition.evaluate
end end
def test_and_condition def test_and_condition
condition = Condition.new('1', '==', '1') condition = Condition.new('1', '==', '1')
assert_equal true, condition.evaluate assert_equal true, condition.evaluate
condition.and Condition.new('2', '==', '2') condition.and Condition.new('2', '==', '2')
assert_equal true, condition.evaluate assert_equal true, condition.evaluate
condition.and Condition.new('2', '==', '1') condition.and Condition.new('2', '==', '1')
assert_equal false, condition.evaluate assert_equal false, condition.evaluate
end end
def test_should_allow_custom_proc_operator def test_should_allow_custom_proc_operator
Condition.operators['starts_with'] = Proc.new { |cond, left, right| left =~ %r{^#{right}}} Condition.operators['starts_with'] = Proc.new { |cond, left, right| left =~ %r{^#{right}} }
assert_evalutes_true "'bob'", 'starts_with', "'b'" assert_evalutes_true "'bob'", 'starts_with', "'b'"
assert_evalutes_false "'bob'", 'starts_with', "'o'" assert_evalutes_false "'bob'", 'starts_with', "'o'"
ensure
Condition.operators.delete 'starts_with' ensure
Condition.operators.delete 'starts_with'
end
def test_left_or_right_may_contain_operators
@context = Liquid::Context.new
@context['one'] = @context['another'] = "gnomeslab-and-or-liquid"
assert_evalutes_true "one", '==', "another"
end end
private private
def assert_evalutes_true(left, op, right) def assert_evalutes_true(left, op, right)
assert Condition.new(left, op, right).evaluate(@context || Liquid::Context.new), "Evaluated false: #{left} #{op} #{right}" assert Condition.new(left, op, right).evaluate(@context || Liquid::Context.new),
"Evaluated false: #{left} #{op} #{right}"
end end
def assert_evalutes_false(left, op, right) def assert_evalutes_false(left, op, right)
assert !Condition.new(left, op, right).evaluate(@context || Liquid::Context.new), "Evaluated true: #{left} #{op} #{right}" assert !Condition.new(left, op, right).evaluate(@context || Liquid::Context.new),
"Evaluated true: #{left} #{op} #{right}"
end end
end end # ConditionTest

View File

@@ -1,4 +1,5 @@
require File.dirname(__FILE__) + '/helper' require 'test_helper'
class HundredCentes class HundredCentes
def to_liquid def to_liquid
100 100
@@ -62,7 +63,6 @@ class ArrayLike
end end
end end
class ContextTest < Test::Unit::TestCase class ContextTest < Test::Unit::TestCase
include Liquid include Liquid
@@ -262,10 +262,10 @@ class ContextTest < Test::Unit::TestCase
def test_hash_to_array_transition def test_hash_to_array_transition
@context['colors'] = { @context['colors'] = {
'Blue' => ['003366','336699', '6699CC', '99CCFF'], 'Blue' => ['003366','336699', '6699CC', '99CCFF'],
'Green' => ['003300','336633', '669966', '99CC99'], 'Green' => ['003300','336633', '669966', '99CC99'],
'Yellow' => ['CC9900','FFCC00', 'FFFF99', 'FFFFCC'], 'Yellow' => ['CC9900','FFCC00', 'FFFF99', 'FFFFCC'],
'Red' => ['660000','993333', 'CC6666', 'FF9999'] 'Red' => ['660000','993333', 'CC6666', 'FF9999']
} }
assert_equal '003366', @context['colors.Blue[0]'] assert_equal '003366', @context['colors.Blue[0]']
@@ -475,5 +475,4 @@ class ContextTest < Test::Unit::TestCase
assert_kind_of CategoryDrop, @context['category'] assert_kind_of CategoryDrop, @context['category']
assert_equal @context, @context['category'].context assert_equal @context, @context['category'].context
end end
end # ContextTest
end

View File

@@ -1,6 +1,4 @@
require 'test_helper'
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/helper'
class ContextDrop < Liquid::Drop class ContextDrop < Liquid::Drop
def scopes def scopes
@@ -10,7 +8,7 @@ class ContextDrop < Liquid::Drop
def scopes_as_array def scopes_as_array
(1..@context.scopes.size).to_a (1..@context.scopes.size).to_a
end end
def loop_pos def loop_pos
@context['forloop.index'] @context['forloop.index']
end end
@@ -18,13 +16,12 @@ class ContextDrop < Liquid::Drop
def break def break
Breakpoint.breakpoint Breakpoint.breakpoint
end end
def before_method(method) def before_method(method)
return @context[method] return @context[method]
end end
end end
class ProductDrop < Liquid::Drop class ProductDrop < Liquid::Drop
class TextDrop < Liquid::Drop class TextDrop < Liquid::Drop
@@ -50,42 +47,41 @@ class ProductDrop < Liquid::Drop
def catchall def catchall
CatchallDrop.new CatchallDrop.new
end end
def context def context
ContextDrop.new ContextDrop.new
end end
protected protected
def callmenot def callmenot
"protected" "protected"
end end
end end
class EnumerableDrop < Liquid::Drop
class EnumerableDrop < Liquid::Drop
def size def size
3 3
end end
def each def each
yield 1 yield 1
yield 2 yield 2
yield 3 yield 3
end end
end end
class DropsTest < Test::Unit::TestCase class DropsTest < Test::Unit::TestCase
include Liquid include Liquid
def test_product_drop def test_product_drop
assert_nothing_raised do assert_nothing_raised do
tpl = Liquid::Template.parse( ' ' ) tpl = Liquid::Template.parse( ' ' )
tpl.render('product' => ProductDrop.new) tpl.render('product' => ProductDrop.new)
end end
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
@@ -102,61 +98,56 @@ class DropsTest < Test::Unit::TestCase
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 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_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.new{|c| c['context.scopes'] }) assert_equal '1', Liquid::Template.parse( '{{ s }}' ).render('context' => ContextDrop.new, 's' => Proc.new{|c| c['context.scopes'] })
assert_equal '2', Liquid::Template.parse( '{%for i in dummy%}{{ s }}{%endfor%}' ).render('context' => ContextDrop.new, 's' => Proc.new{|c| c['context.scopes'] }, 'dummy' => [1]) assert_equal '2', Liquid::Template.parse( '{%for i in dummy%}{{ s }}{%endfor%}' ).render('context' => ContextDrop.new, 's' => Proc.new{|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.new{|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.new{|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
end # DropsTest
end

View File

@@ -1,89 +1,69 @@
require 'test_helper'
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/helper'
class ErrorDrop < Liquid::Drop class ErrorDrop < Liquid::Drop
def standard_error def standard_error
raise Liquid::StandardError, 'standard error' raise Liquid::StandardError, 'standard error'
end end
def argument_error def argument_error
raise Liquid::ArgumentError, 'argument error' raise Liquid::ArgumentError, 'argument error'
end end
def syntax_error def syntax_error
raise Liquid::SyntaxError, 'syntax error' raise Liquid::SyntaxError, 'syntax error'
end end
end
end
class ErrorHandlingTest < Test::Unit::TestCase class ErrorHandlingTest < Test::Unit::TestCase
include Liquid include Liquid
def test_standard_error def test_standard_error
assert_nothing_raised do assert_nothing_raised do
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
end end
def test_syntax
assert_nothing_raised do def test_syntax
assert_nothing_raised do
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
assert_nothing_raised do end
end
def test_argument
assert_nothing_raised do
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
end
def test_missing_endtag_parse_time_error
assert_raise(Liquid::SyntaxError) do
template = Liquid::Template.parse(' {% for a in b %} ... ')
end
end end
def test_missing_endtag_parse_time_error
assert_raise(Liquid::SyntaxError) do
template = Liquid::Template.parse(' {% for a in b %} ... ')
end
end
def test_unrecognized_operator def test_unrecognized_operator
assert_nothing_raised do assert_nothing_raised do
template = Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ') template = Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ')
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
end end
end # ErrorHandlingTest
end

View File

@@ -1,18 +1,17 @@
#!/usr/bin/env ruby require 'test_helper'
require File.dirname(__FILE__) + '/helper'
class FileSystemTest < Test::Unit::TestCase class FileSystemTest < Test::Unit::TestCase
include Liquid include Liquid
def test_default def test_default
assert_raise(FileSystemError) do assert_raise(FileSystemError) do
BlankFileSystem.new.read_template_file("dummy") BlankFileSystem.new.read_template_file("dummy")
end end
end end
def test_local def test_local
file_system = Liquid::LocalFileSystem.new("/some/path") file_system = Liquid::LocalFileSystem.new("/some/path")
assert_equal "/some/path/_mypartial.liquid" , file_system.full_path("mypartial") assert_equal "/some/path/_mypartial.liquid" , file_system.full_path("mypartial")
assert_equal "/some/path/dir/_mypartial.liquid", file_system.full_path("dir/mypartial") assert_equal "/some/path/dir/_mypartial.liquid", file_system.full_path("dir/mypartial")
assert_raise(FileSystemError) do assert_raise(FileSystemError) do
@@ -20,11 +19,11 @@ class FileSystemTest < Test::Unit::TestCase
end end
assert_raise(FileSystemError) do assert_raise(FileSystemError) do
file_system.full_path("/dir/../../dir/mypartial") file_system.full_path("/dir/../../dir/mypartial")
end end
assert_raise(FileSystemError) do assert_raise(FileSystemError) do
file_system.full_path("/etc/passwd") file_system.full_path("/etc/passwd")
end end
end end
end end # FileSystemTest

View File

@@ -1,5 +1,4 @@
#!/usr/bin/env ruby require 'test_helper'
require File.dirname(__FILE__) + '/helper'
module MoneyFilter module MoneyFilter
def money(input) def money(input)
@@ -27,6 +26,7 @@ class FiltersTest < Test::Unit::TestCase
def test_local_filter def test_local_filter
@context['var'] = 1000 @context['var'] = 1000
@context.add_filters(MoneyFilter) @context.add_filters(MoneyFilter)
assert_equal ' 1000$ ', Variable.new("var | money").render(@context) assert_equal ' 1000$ ', Variable.new("var | money").render(@context)
end end
@@ -40,17 +40,20 @@ class FiltersTest < Test::Unit::TestCase
@context['var'] = 1000 @context['var'] = 1000
@context.add_filters(MoneyFilter) @context.add_filters(MoneyFilter)
@context.add_filters(CanadianMoneyFilter) @context.add_filters(CanadianMoneyFilter)
assert_equal ' 1000$ CAD ', Variable.new("var | money").render(@context) assert_equal ' 1000$ CAD ', Variable.new("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, Variable.new("var | size").render(@context) assert_equal 4, Variable.new("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", Variable.new("var | join").render(@context) assert_equal "1 2 3 4", Variable.new("var | join").render(@context)
end end
@@ -59,22 +62,30 @@ class FiltersTest < Test::Unit::TestCase
@context['numbers'] = [2,1,4,3] @context['numbers'] = [2,1,4,3]
@context['words'] = ['expected', 'as', 'alphabetic'] @context['words'] = ['expected', 'as', 'alphabetic']
@context['arrays'] = [['flattened'], ['are']] @context['arrays'] = [['flattened'], ['are']]
assert_equal [1,2,3,4], Variable.new("numbers | sort").render(@context) assert_equal [1,2,3,4], Variable.new("numbers | sort").render(@context)
assert_equal ['alphabetic', 'as', 'expected'], assert_equal ['alphabetic', 'as', 'expected'], Variable.new("words | sort").render(@context)
Variable.new("words | sort").render(@context)
assert_equal [3], Variable.new("value | sort").render(@context) assert_equal [3], Variable.new("value | sort").render(@context)
assert_equal ['are', 'flattened'], Variable.new("arrays | sort").render(@context) assert_equal ['are', 'flattened'], Variable.new("arrays | sort").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", Variable.new("var | strip_html").render(@context) assert_equal "bla blub", Variable.new("var | strip_html").render(@context)
end end
def test_capitalize def test_capitalize
@context['var'] = "blub" @context['var'] = "blub"
assert_equal "Blub", Variable.new("var | capitalize").render(@context) assert_equal "Blub", Variable.new("var | capitalize").render(@context)
end end
def test_nonexistent_filter_is_ignored
@context['var'] = 1000
assert_equal 1000, Variable.new("var | xyzzy").render(@context)
end
end end
class FiltersInTemplate < Test::Unit::TestCase class FiltersInTemplate < Test::Unit::TestCase
@@ -92,4 +103,4 @@ class FiltersInTemplate < Test::Unit::TestCase
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 end # FiltersTest

View File

@@ -1,31 +1,29 @@
require File.dirname(__FILE__) + '/helper' require 'test_helper'
class HtmlTagTest < Test::Unit::TestCase class HtmlTagTest < Test::Unit::TestCase
include Liquid include Liquid
def test_html_table def test_html_table
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_html_table_with_different_cols def test_html_table_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_html_col_counter def test_html_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
end # HtmlTagTest
end

View File

@@ -0,0 +1,127 @@
require 'test_helper'
class TestFileSystem
def read_template_file(template_path)
case template_path
when "product"
"Product: {{ product.title }} "
when "locale_variables"
"Locale: {{echo1}} {{echo2}}"
when "variant"
"Variant: {{ variant.title }}"
when "nested_template"
"{% include 'header' %} {% include 'body' %} {% include 'footer' %}"
when "body"
"body {% include 'body_detail' %}"
when "nested_product_template"
"Product: {{ nested_product_template.title }} {%include 'details'%} "
when "recursively_nested_template"
"-{% include 'recursively_nested_template' %}"
when "pick_a_source"
"from TestFileSystem"
else
template_path
end
end
end
class OtherFileSystem
def read_template_file(template_path)
'from OtherFileSystem'
end
end
class IncludeTagTest < Test::Unit::TestCase
include Liquid
def setup
Liquid::Template.file_system = TestFileSystem.new
end
def test_include_tag_looks_for_file_system_in_registers_first
assert_equal 'from OtherFileSystem',
Template.parse("{% include 'pick_a_source' %}").render({}, :registers => {:file_system => OtherFileSystem.new})
end
def test_include_tag_with
assert_equal "Product: Draft 151cm ",
Template.parse("{% include 'product' with products[0] %}").render( "products" => [ {'title' => 'Draft 151cm'}, {'title' => 'Element 155cm'} ] )
end
def test_include_tag_with_default_name
assert_equal "Product: Draft 151cm ",
Template.parse("{% include 'product' %}").render( "product" => {'title' => 'Draft 151cm'} )
end
def test_include_tag_for
assert_equal "Product: Draft 151cm Product: Element 155cm ",
Template.parse("{% include 'product' for products %}").render( "products" => [ {'title' => 'Draft 151cm'}, {'title' => 'Element 155cm'} ] )
end
def test_include_tag_with_local_variables
assert_equal "Locale: test123 ",
Template.parse("{% include 'locale_variables' echo1: 'test123' %}").render
end
def test_include_tag_with_multiple_local_variables
assert_equal "Locale: test123 test321",
Template.parse("{% include 'locale_variables' echo1: 'test123', echo2: 'test321' %}").render
end
def test_include_tag_with_multiple_local_variables_from_context
assert_equal "Locale: test123 test321",
Template.parse("{% include 'locale_variables' echo1: echo1, echo2: more_echos.echo2 %}").render('echo1' => 'test123', 'more_echos' => { "echo2" => 'test321'})
end
def test_nested_include_tag
assert_equal "body body_detail",
Template.parse("{% include 'body' %}").render
assert_equal "header body body_detail footer",
Template.parse("{% include 'nested_template' %}").render
end
def test_nested_include_with_variable
assert_equal "Product: Draft 151cm details ",
Template.parse("{% include 'nested_product_template' with product %}").render("product" => {"title" => 'Draft 151cm'})
assert_equal "Product: Draft 151cm details Product: Element 155cm details ",
Template.parse("{% include 'nested_product_template' for products %}").render("products" => [{"title" => 'Draft 151cm'}, {"title" => 'Element 155cm'}])
end
def test_recursively_included_template_does_not_produce_endless_loop
infinite_file_system = Class.new do
def read_template_file(template_path)
"-{% include 'loop' %}"
end
end
Liquid::Template.file_system = infinite_file_system.new
assert_raise(Liquid::StackLevelError) do
Template.parse("{% include 'loop' %}").render!
end
end
def test_dynamically_choosen_template
assert_equal "Test123", Template.parse("{% include template %}").render("template" => 'Test123')
assert_equal "Test321", Template.parse("{% include template %}").render("template" => 'Test321')
assert_equal "Product: Draft 151cm ", Template.parse("{% include template for product %}").render("template" => 'product', 'product' => { 'title' => 'Draft 151cm'})
end
end # IncludeTagTest

View File

@@ -1,5 +1,4 @@
#!/usr/bin/env ruby require 'test_helper'
require File.dirname(__FILE__) + '/helper'
class TestClassA class TestClassA
liquid_methods :allowedA, :chainedB liquid_methods :allowedA, :chainedB
@@ -39,31 +38,31 @@ end
class ModuleExTest < Test::Unit::TestCase class ModuleExTest < Test::Unit::TestCase
include Liquid include Liquid
def setup def setup
@a = TestClassA.new @a = TestClassA.new
@b = TestClassB.new @b = TestClassB.new
@c = TestClassC.new @c = TestClassC.new
end end
def test_should_create_LiquidDropClass def test_should_create_LiquidDropClass
assert TestClassA::LiquidDropClass assert TestClassA::LiquidDropClass
assert TestClassB::LiquidDropClass assert TestClassB::LiquidDropClass
assert TestClassC::LiquidDropClass assert TestClassC::LiquidDropClass
end end
def test_should_respond_to_liquid def test_should_respond_to_liquid
assert @a.respond_to?(:to_liquid) assert @a.respond_to?(:to_liquid)
assert @b.respond_to?(:to_liquid) assert @b.respond_to?(:to_liquid)
assert @c.respond_to?(:to_liquid) assert @c.respond_to?(:to_liquid)
end end
def test_should_return_LiquidDropClass_object def test_should_return_LiquidDropClass_object
assert @a.to_liquid.is_a?(TestClassA::LiquidDropClass) assert @a.to_liquid.is_a?(TestClassA::LiquidDropClass)
assert @b.to_liquid.is_a?(TestClassB::LiquidDropClass) assert @b.to_liquid.is_a?(TestClassB::LiquidDropClass)
assert @c.to_liquid.is_a?(TestClassC::LiquidDropClass) assert @c.to_liquid.is_a?(TestClassC::LiquidDropClass)
end end
def test_should_respond_to_liquid_methods def test_should_respond_to_liquid_methods
assert @a.to_liquid.respond_to?(:allowedA) assert @a.to_liquid.respond_to?(:allowedA)
assert @a.to_liquid.respond_to?(:chainedB) assert @a.to_liquid.respond_to?(:chainedB)
@@ -84,6 +83,5 @@ class ModuleExTest < Test::Unit::TestCase
assert_equal 'another_allowedC', Liquid::Template.parse("{{ a.chainedB.chainedC.another_allowedC }}").render('a'=>@a) assert_equal 'another_allowedC', Liquid::Template.parse("{{ a.chainedB.chainedC.another_allowedC }}").render('a'=>@a)
assert_equal '', Liquid::Template.parse("{{ a.restricted }}").render('a'=>@a) assert_equal '', Liquid::Template.parse("{{ a.restricted }}").render('a'=>@a)
assert_equal '', Liquid::Template.parse("{{ a.unknown }}").render('a'=>@a) assert_equal '', Liquid::Template.parse("{{ a.unknown }}").render('a'=>@a)
end end
end # ModuleExTest
end

View File

@@ -1,20 +1,18 @@
#!/usr/bin/env ruby require 'test_helper'
require File.dirname(__FILE__) + '/helper'
module FunnyFilter module FunnyFilter
def make_funny(input) def make_funny(input)
'LOL' 'LOL'
end end
def cite_funny(input) def cite_funny(input)
"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
@@ -22,25 +20,24 @@ module FunnyFilter
def paragraph(input) def paragraph(input)
"<p>#{input}</p>" "<p>#{input}</p>"
end end
def link_to(name, url) def link_to(name, url)
%|<a href="#{url}">#{name}</a>| %|<a href="#{url}">#{name}</a>|
end end
end
end
class OutputTest < Test::Unit::TestCase class OutputTest < Test::Unit::TestCase
include Liquid include Liquid
def setup def setup
@assigns = { @assigns = {
'best_cars' => 'bmw', 'best_cars' => 'bmw',
'car' => {'bmw' => 'good', 'gm' => 'bad'} 'car' => {'bmw' => 'good', 'gm' => 'bad'}
} }
end end
def test_variable def test_variable
text = %| {{best_cars}} | text = %| {{best_cars}} |
expected = %| bmw | expected = %| bmw |
@@ -53,35 +50,35 @@ class OutputTest < Test::Unit::TestCase
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 :-( :-( |
@@ -105,17 +102,15 @@ class OutputTest < Test::Unit::TestCase
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

View File

@@ -1,5 +1,4 @@
#!/usr/bin/env ruby require 'test_helper'
require File.dirname(__FILE__) + '/helper'
class ParsingQuirksTest < Test::Unit::TestCase class ParsingQuirksTest < Test::Unit::TestCase
include Liquid include Liquid
@@ -7,48 +6,47 @@ class ParsingQuirksTest < Test::Unit::TestCase
def test_error_with_css def test_error_with_css
text = %| div { font-weight: bold; } | text = %| div { font-weight: bold; } |
template = Template.parse(text) template = Template.parse(text)
assert_equal text, template.render assert_equal text, template.render
assert_equal [String], template.root.nodelist.collect {|i| i.class} assert_equal [String], template.root.nodelist.collect {|i| i.class}
end end
def test_raise_on_single_close_bracet def test_raise_on_single_close_bracet
assert_raise(SyntaxError) do assert_raise(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_raise(SyntaxError) do assert_raise(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_raise(SyntaxError) do assert_raise(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_nothing_raised do assert_nothing_raised do
Template.parse("{{test |a|b|}}") Template.parse("{{test |a|b|}}")
Template.parse("{{test}}") Template.parse("{{test}}")
Template.parse("{{|test|}}") Template.parse("{{|test|}}")
end end
end end
def test_meaningless_parens def test_meaningless_parens
assigns = {'b' => 'bar', 'c' => 'baz'} assigns = {'b' => 'bar', 'c' => 'baz'}
markup = "a == 'foo' or (b == 'bar' and c == 'baz') or false" markup = "a == 'foo' or (b == 'bar' and c == 'baz') or false"
assert_template_result(' YES ',"{% if #{markup} %} YES {% endif %}", assigns) assert_template_result(' YES ',"{% if #{markup} %} YES {% endif %}", assigns)
end end
def test_unexpected_characters_silently_eat_logic def test_unexpected_characters_silently_eat_logic
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 # ParsingQuirksTest
end

View File

@@ -1,20 +1,20 @@
require File.dirname(__FILE__) + '/helper' require 'test_helper'
class RegexpTest < Test::Unit::TestCase class RegexpTest < Test::Unit::TestCase
include Liquid include Liquid
def test_empty def test_empty
assert_equal [], ''.scan(QuotedFragment) assert_equal [], ''.scan(QuotedFragment)
end end
def test_quote def test_quote
assert_equal ['"arg 1"'], '"arg 1"'.scan(QuotedFragment) assert_equal ['"arg 1"'], '"arg 1"'.scan(QuotedFragment)
end end
def test_words def test_words
assert_equal ['arg1', 'arg2'], 'arg1 arg2'.scan(QuotedFragment) assert_equal ['arg1', 'arg2'], 'arg1 arg2'.scan(QuotedFragment)
end end
def test_tags def test_tags
assert_equal ['<tr>', '</tr>'], '<tr> </tr>'.scan(QuotedFragment) assert_equal ['<tr>', '</tr>'], '<tr> </tr>'.scan(QuotedFragment)
assert_equal ['<tr></tr>'], '<tr></tr>'.scan(QuotedFragment) assert_equal ['<tr></tr>'], '<tr></tr>'.scan(QuotedFragment)
@@ -32,14 +32,18 @@ class RegexpTest < Test::Unit::TestCase
def test_quoted_words_in_the_middle def test_quoted_words_in_the_middle
assert_equal ['arg1', 'arg2', '"arg 3"', 'arg4'], 'arg1 arg2 "arg 3" arg4 '.scan(QuotedFragment) assert_equal ['arg1', 'arg2', '"arg 3"', 'arg4'], 'arg1 arg2 "arg 3" arg4 '.scan(QuotedFragment)
end end
def test_variable_parser def test_variable_parser
assert_equal ['var'], 'var'.scan(VariableParser) assert_equal ['var'], 'var'.scan(VariableParser)
assert_equal ['var', 'method'], 'var.method'.scan(VariableParser) assert_equal ['var', 'method'], 'var.method'.scan(VariableParser)
assert_equal ['var', '[method]'], 'var[method]'.scan(VariableParser) assert_equal ['var', '[method]'], 'var[method]'.scan(VariableParser)
assert_equal ['var', '[method]', '[0]'], 'var[method][0]'.scan(VariableParser) assert_equal ['var', '[method]', '[0]'], 'var[method][0]'.scan(VariableParser)
assert_equal ['var', '["method"]', '[0]'], 'var["method"][0]'.scan(VariableParser) assert_equal ['var', '["method"]', '[0]'], 'var["method"][0]'.scan(VariableParser)
assert_equal ['var', '[method]', '[0]', 'method'], 'var[method][0].method'.scan(VariableParser) assert_equal ['var', '[method]', '[0]', 'method'], 'var[method][0].method'.scan(VariableParser)
end end
end def test_literal_shorthand_regexp
assert_equal [["{% if 'gnomeslab' contains 'liquid' %}yes{% endif %}"]],
"{{{ {% if 'gnomeslab' contains 'liquid' %}yes{% endif %} }}}".scan(LiteralShorthand)
end
end # RegexpTest

View File

@@ -1,4 +1,4 @@
require File.dirname(__FILE__) + '/helper' require 'test_helper'
module SecurityFilter module SecurityFilter
def add_one(input) def add_one(input)
@@ -12,22 +12,22 @@ class SecurityTest < Test::Unit::TestCase
def test_no_instance_eval def test_no_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_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
@@ -35,7 +35,7 @@ class SecurityTest < Test::Unit::TestCase
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
end end # SecurityTest

View File

@@ -1,175 +1,180 @@
#!/usr/bin/env ruby require 'test_helper'
require File.dirname(__FILE__) + '/helper'
class Filters class Filters
include Liquid::StandardFilters include Liquid::StandardFilters
end end
class StandardFiltersTest < Test::Unit::TestCase class StandardFiltersTest < Test::Unit::TestCase
include Liquid include Liquid
def setup def setup
@filters = Filters.new @filters = Filters.new
end end
def test_size def test_size
assert_equal 3, @filters.size([1,2,3]) assert_equal 3, @filters.size([1,2,3])
assert_equal 0, @filters.size([]) assert_equal 0, @filters.size([])
assert_equal 0, @filters.size(nil) assert_equal 0, @filters.size(nil)
end end
def test_downcase def test_downcase
assert_equal 'testing', @filters.downcase("Testing") assert_equal 'testing', @filters.downcase("Testing")
assert_equal '', @filters.downcase(nil) assert_equal '', @filters.downcase(nil)
end end
def test_upcase def test_upcase
assert_equal 'TESTING', @filters.upcase("Testing") assert_equal 'TESTING', @filters.upcase("Testing")
assert_equal '', @filters.upcase(nil) assert_equal '', @filters.upcase(nil)
end end
def test_upcase def test_upcase
assert_equal 'TESTING', @filters.upcase("Testing") assert_equal 'TESTING', @filters.upcase("Testing")
assert_equal '', @filters.upcase(nil) assert_equal '', @filters.upcase(nil)
end end
def test_truncate def test_truncate
assert_equal '1234...', @filters.truncate('1234567890', 7) assert_equal '1234...', @filters.truncate('1234567890', 7)
assert_equal '1234567890', @filters.truncate('1234567890', 20) assert_equal '1234567890', @filters.truncate('1234567890', 20)
assert_equal '...', @filters.truncate('1234567890', 0) assert_equal '...', @filters.truncate('1234567890', 0)
assert_equal '1234567890', @filters.truncate('1234567890') assert_equal '1234567890', @filters.truncate('1234567890')
end end
def test_escape def test_escape
assert_equal '&lt;strong&gt;', @filters.escape('<strong>') assert_equal '&lt;strong&gt;', @filters.escape('<strong>')
assert_equal '&lt;strong&gt;', @filters.h('<strong>') assert_equal '&lt;strong&gt;', @filters.h('<strong>')
end end
def test_escape_once
assert_equal '&lt;strong&gt;', @filters.escape_once(@filters.escape('<strong>'))
end
def test_truncatewords def test_truncatewords
assert_equal 'one two three', @filters.truncatewords('one two three', 4) assert_equal 'one two three', @filters.truncatewords('one two three', 4)
assert_equal 'one two...', @filters.truncatewords('one two three', 2) assert_equal 'one two...', @filters.truncatewords('one two three', 2)
assert_equal 'one two three', @filters.truncatewords('one two three') assert_equal 'one two three', @filters.truncatewords('one two three')
assert_equal 'Two small (13&#8221; x 5.5&#8221; x 10&#8221; high) baskets fit inside one large basket (13&#8221;...', @filters.truncatewords('Two small (13&#8221; x 5.5&#8221; x 10&#8221; high) baskets fit inside one large basket (13&#8221; x 16&#8221; x 10.5&#8221; high) with cover.', 15) assert_equal 'Two small (13&#8221; x 5.5&#8221; x 10&#8221; high) baskets fit inside one large basket (13&#8221;...', @filters.truncatewords('Two small (13&#8221; x 5.5&#8221; x 10&#8221; high) baskets fit inside one large basket (13&#8221; x 16&#8221; x 10.5&#8221; high) with cover.', 15)
end end
def test_strip_html def test_strip_html
assert_equal 'test', @filters.strip_html("<div>test</div>") assert_equal 'test', @filters.strip_html("<div>test</div>")
assert_equal 'test', @filters.strip_html("<div id='test'>test</div>") assert_equal 'test', @filters.strip_html("<div id='test'>test</div>")
assert_equal '', @filters.strip_html("<script type='text/javascript'>document.write('some stuff');</script>") assert_equal '', @filters.strip_html("<script type='text/javascript'>document.write('some stuff');</script>")
assert_equal '', @filters.strip_html(nil) assert_equal '', @filters.strip_html(nil)
end end
def test_join def test_join
assert_equal '1 2 3 4', @filters.join([1,2,3,4]) assert_equal '1 2 3 4', @filters.join([1,2,3,4])
assert_equal '1 - 2 - 3 - 4', @filters.join([1,2,3,4], ' - ') assert_equal '1 - 2 - 3 - 4', @filters.join([1,2,3,4], ' - ')
end end
def test_sort def test_sort
assert_equal [1,2,3,4], @filters.sort([4,3,2,1]) assert_equal [1,2,3,4], @filters.sort([4,3,2,1])
assert_equal [{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], @filters.sort([{"a" => 4}, {"a" => 3}, {"a" => 1}, {"a" => 2}], "a") assert_equal [{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], @filters.sort([{"a" => 4}, {"a" => 3}, {"a" => 1}, {"a" => 2}], "a")
end end
def test_map def test_map
assert_equal [1,2,3,4], @filters.map([{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], 'a') assert_equal [1,2,3,4], @filters.map([{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], 'a')
assert_template_result 'abc', "{{ ary | map:'foo' | map:'bar' }}", assert_template_result 'abc', "{{ ary | map:'foo' | map:'bar' }}",
'ary' => [{'foo' => {'bar' => 'a'}}, {'foo' => {'bar' => 'b'}}, {'foo' => {'bar' => 'c'}}] 'ary' => [{'foo' => {'bar' => 'a'}}, {'foo' => {'bar' => 'b'}}, {'foo' => {'bar' => 'c'}}]
end end
def test_date def test_date
assert_equal 'May', @filters.date(Time.parse("2006-05-05 10:00:00"), "%B") assert_equal 'May', @filters.date(Time.parse("2006-05-05 10:00:00"), "%B")
assert_equal 'June', @filters.date(Time.parse("2006-06-05 10:00:00"), "%B") assert_equal 'June', @filters.date(Time.parse("2006-06-05 10:00:00"), "%B")
assert_equal 'July', @filters.date(Time.parse("2006-07-05 10:00:00"), "%B") assert_equal 'July', @filters.date(Time.parse("2006-07-05 10:00:00"), "%B")
assert_equal 'May', @filters.date("2006-05-05 10:00:00", "%B") assert_equal 'May', @filters.date("2006-05-05 10:00:00", "%B")
assert_equal 'June', @filters.date("2006-06-05 10:00:00", "%B") assert_equal 'June', @filters.date("2006-06-05 10:00:00", "%B")
assert_equal 'July', @filters.date("2006-07-05 10:00:00", "%B") assert_equal 'July', @filters.date("2006-07-05 10:00:00", "%B")
assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", "") assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", "")
assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", "") assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", "")
assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", "") assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", "")
assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", nil) assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", nil)
assert_equal '07/05/2006', @filters.date("2006-07-05 10:00:00", "%m/%d/%Y")
assert_equal '07/05/2006', @filters.date("2006-07-05 10:00:00", "%m/%d/%Y")
assert_equal "07/16/2004", @filters.date("Fri Jul 16 01:00:00 2004", "%m/%d/%Y") assert_equal "07/16/2004", @filters.date("Fri Jul 16 01:00:00 2004", "%m/%d/%Y")
assert_equal nil, @filters.date(nil, "%B") assert_equal nil, @filters.date(nil, "%B")
end end
def test_first_last def test_first_last
assert_equal 1, @filters.first([1,2,3]) assert_equal 1, @filters.first([1,2,3])
assert_equal 3, @filters.last([1,2,3]) assert_equal 3, @filters.last([1,2,3])
assert_equal nil, @filters.first([]) assert_equal nil, @filters.first([])
assert_equal nil, @filters.last([]) assert_equal nil, @filters.last([])
end end
def test_replace def test_replace
assert_equal 'b b b b', @filters.replace("a a a a", 'a', 'b') assert_equal 'b b b b', @filters.replace("a a a a", 'a', 'b')
assert_equal 'b a a a', @filters.replace_first("a a a a", 'a', 'b') assert_equal 'b a a a', @filters.replace_first("a a a a", 'a', 'b')
assert_template_result 'b a a a', "{{ 'a a a a' | replace_first: 'a', 'b' }}" assert_template_result 'b a a a', "{{ 'a a a a' | replace_first: 'a', 'b' }}"
end end
def test_remove def test_remove
assert_equal ' ', @filters.remove("a a a a", 'a') assert_equal ' ', @filters.remove("a a a a", 'a')
assert_equal 'a a a', @filters.remove_first("a a a a", 'a ') assert_equal 'a a a', @filters.remove_first("a a a a", 'a ')
assert_template_result 'a a a', "{{ 'a a a a' | remove_first: 'a ' }}" assert_template_result 'a a a', "{{ 'a a a a' | remove_first: 'a ' }}"
end end
def test_pipes_in_string_arguments def test_pipes_in_string_arguments
assert_template_result 'foobar', "{{ 'foo|bar' | remove: '|' }}" assert_template_result 'foobar', "{{ 'foo|bar' | remove: '|' }}"
end end
def test_strip_newlines def test_strip_newlines
assert_template_result 'abc', "{{ source | strip_newlines }}", 'source' => "a\nb\nc" assert_template_result 'abc', "{{ source | strip_newlines }}", 'source' => "a\nb\nc"
end end
def test_newlines_to_br def test_newlines_to_br
assert_template_result "a<br />\nb<br />\nc", "{{ source | newline_to_br }}", 'source' => "a\nb\nc" assert_template_result "a<br />\nb<br />\nc", "{{ source | newline_to_br }}", 'source' => "a\nb\nc"
end end
def test_plus def test_plus
assert_template_result "2", "{{ 1 | plus:1 }}" assert_template_result "2", "{{ 1 | plus:1 }}"
assert_template_result "2.0", "{{ '1' | plus:'1.0' }}" assert_template_result "2.0", "{{ '1' | plus:'1.0' }}"
end end
def test_minus def test_minus
assert_template_result "4", "{{ input | minus:operand }}", 'input' => 5, 'operand' => 1 assert_template_result "4", "{{ input | minus:operand }}", 'input' => 5, 'operand' => 1
assert_template_result "2.3", "{{ '4.3' | minus:'2' }}" assert_template_result "2.3", "{{ '4.3' | minus:'2' }}"
end end
def test_times def test_times
assert_template_result "12", "{{ 3 | times:4 }}" assert_template_result "12", "{{ 3 | times:4 }}"
assert_template_result "0", "{{ 'foo' | times:4 }}" assert_template_result "0", "{{ 'foo' | times:4 }}"
assert_template_result "6.3", "{{ '2.1' | times:3 }}"
# Ruby v1.9.2-rc1, or higher, backwards compatible Float test
assert_match(/(6\.3)|(6\.(0{13})1)/, Template.parse("{{ '2.1' | times:3 }}").render)
assert_template_result "6", "{{ '2.1' | times:3 | replace: '.','-' | plus:0}}" assert_template_result "6", "{{ '2.1' | times:3 | replace: '.','-' | plus:0}}"
end end
def test_divided_by def test_divided_by
assert_template_result "4", "{{ 12 | divided_by:3 }}" assert_template_result "4", "{{ 12 | divided_by:3 }}"
assert_template_result "4", "{{ 14 | divided_by:3 }}" assert_template_result "4", "{{ 14 | divided_by:3 }}"
assert_template_result "4.66666666666667", "{{ 14 | divided_by:'3.0' }}"
# Ruby v1.9.2-rc1, or higher, backwards compatible Float test
assert_match(/4\.(6{13,14})7/, Template.parse("{{ 14 | divided_by:'3.0' }}").render)
assert_template_result "5", "{{ 15 | divided_by:3 }}" assert_template_result "5", "{{ 15 | divided_by:3 }}"
assert_template_result "Liquid error: divided by 0", "{{ 5 | divided_by:0 }}" assert_template_result "Liquid error: divided by 0", "{{ 5 | divided_by:0 }}"
end end
def test_append def test_append
assigns = {'a' => 'bc', 'b' => 'd' } assigns = {'a' => 'bc', 'b' => 'd' }
assert_template_result('bcd',"{{ a | append: 'd'}}",assigns) assert_template_result('bcd',"{{ a | append: 'd'}}",assigns)
assert_template_result('bcd',"{{ a | append: b}}",assigns) assert_template_result('bcd',"{{ a | append: b}}",assigns)
end end
def test_prepend def test_prepend
assigns = {'a' => 'bc', 'b' => 'a' } assigns = {'a' => 'bc', 'b' => 'a' }
assert_template_result('abc',"{{ a | prepend: 'a'}}",assigns) assert_template_result('abc',"{{ a | prepend: 'a'}}",assigns)
assert_template_result('abc',"{{ a | prepend: b}}",assigns) assert_template_result('abc',"{{ a | prepend: b}}",assigns)
end end
def test_cannot_access_private_methods def test_cannot_access_private_methods
assert_template_result('a',"{{ 'a' | to_number }}") assert_template_result('a',"{{ 'a' | to_number }}")
end end
end # StandardFiltersTest
end

View File

@@ -1,5 +1,4 @@
#!/usr/bin/env ruby require 'test_helper'
require File.dirname(__FILE__) + '/helper'
class StrainerTest < Test::Unit::TestCase class StrainerTest < Test::Unit::TestCase
include Liquid include Liquid
@@ -12,10 +11,15 @@ class StrainerTest < Test::Unit::TestCase
assert_equal false, strainer.respond_to?('__send__') assert_equal false, strainer.respond_to?('__send__')
assert_equal true, strainer.respond_to?('size') # from the standard lib assert_equal true, strainer.respond_to?('size') # from the standard lib
end end
def test_should_respond_to_two_parameters def test_should_respond_to_two_parameters
strainer = Strainer.create(nil) strainer = Strainer.create(nil)
assert_equal true, strainer.respond_to?('size', false) assert_equal true, strainer.respond_to?('size', false)
end end
end # Asserts that Object#respond_to_missing? is not being undefined in Ruby versions where it has been implemented
# Currently this method is only present in Ruby v1.9.2, or higher
def test_object_respond_to_missing
assert_equal Object.respond_to?(:respond_to_missing?), Strainer.create(nil).respond_to?(:respond_to_missing?)
end
end # StrainerTest

View File

@@ -1,4 +1,4 @@
require File.dirname(__FILE__) + '/helper' require 'test_helper'
class IfElseTest < Test::Unit::TestCase class IfElseTest < Test::Unit::TestCase
include Liquid include Liquid
@@ -6,7 +6,7 @@ class IfElseTest < Test::Unit::TestCase
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
@@ -15,27 +15,27 @@ class IfElseTest < Test::Unit::TestCase
assert_template_result(' YES ','{% if true %} YES {% else %} NO {% endif %}') assert_template_result(' YES ','{% if true %} YES {% else %} NO {% endif %}')
assert_template_result(' YES ','{% if "foo" %} YES {% else %} NO {% endif %}') assert_template_result(' YES ','{% if "foo" %} YES {% else %} NO {% endif %}')
end end
def test_if_boolean
assert_template_result(' YES ','{% if var %} YES {% endif %}', 'var' => true)
end
def test_if_or
assert_template_result(' YES ','{% if a or b %} YES {% endif %}', 'a' => true, 'b' => true)
assert_template_result(' YES ','{% if a or b %} YES {% endif %}', 'a' => true, 'b' => false)
assert_template_result(' YES ','{% if a or b %} YES {% endif %}', 'a' => false, 'b' => true)
assert_template_result('', '{% if a or b %} YES {% endif %}', 'a' => false, 'b' => false)
assert_template_result(' YES ','{% if a or b or c %} YES {% endif %}', 'a' => false, 'b' => false, 'c' => true) def test_if_boolean
assert_template_result('', '{% if a or b or c %} YES {% endif %}', 'a' => false, 'b' => false, 'c' => false) assert_template_result(' YES ','{% if var %} YES {% endif %}', 'var' => true)
end end
def test_if_or
assert_template_result(' YES ','{% if a or b %} YES {% endif %}', 'a' => true, 'b' => true)
assert_template_result(' YES ','{% if a or b %} YES {% endif %}', 'a' => true, 'b' => false)
assert_template_result(' YES ','{% if a or b %} YES {% endif %}', 'a' => false, 'b' => true)
assert_template_result('', '{% if a or b %} YES {% endif %}', 'a' => false, 'b' => false)
assert_template_result(' YES ','{% if a or b or c %} YES {% endif %}', 'a' => false, 'b' => false, 'c' => true)
assert_template_result('', '{% if a or b or c %} YES {% endif %}', 'a' => false, 'b' => false, 'c' => false)
end
def test_if_or_with_operators def test_if_or_with_operators
assert_template_result(' YES ','{% if a == true or b == true %} YES {% endif %}', 'a' => true, 'b' => true) assert_template_result(' YES ','{% if a == true or b == true %} YES {% endif %}', 'a' => true, 'b' => true)
assert_template_result(' YES ','{% if a == true or b == false %} YES {% endif %}', 'a' => true, 'b' => true) assert_template_result(' YES ','{% if a == true or b == false %} YES {% endif %}', 'a' => true, 'b' => true)
assert_template_result('','{% if a == false or b == false %} YES {% endif %}', 'a' => true, 'b' => true) assert_template_result('','{% if a == false or b == false %} YES {% endif %}', 'a' => true, 'b' => true)
end end
def test_comparison_of_strings_containing_and_or_or def test_comparison_of_strings_containing_and_or_or
assert_nothing_raised do assert_nothing_raised do
awful_markup = "a == 'and' and b == 'or' and c == 'foo and bar' and d == 'bar or baz' and e == 'foo' and foo and bar" awful_markup = "a == 'and' and b == 'or' and c == 'foo and bar' and d == 'bar or baz' and e == 'foo' and foo and bar"
@@ -43,18 +43,32 @@ class IfElseTest < Test::Unit::TestCase
assert_template_result(' YES ',"{% if #{awful_markup} %} YES {% endif %}", assigns) assert_template_result(' YES ',"{% if #{awful_markup} %} YES {% endif %}", assigns)
end end
end end
def test_if_and def test_comparison_of_expressions_starting_with_and_or_or
assert_template_result(' YES ','{% if true and true %} YES {% endif %}') assigns = {'order' => {'items_count' => 0}, 'android' => {'name' => 'Roy'}}
assert_template_result('','{% if false and true %} YES {% endif %}') assert_nothing_raised do
assert_template_result('','{% if false and true %} YES {% endif %}') assert_template_result( "YES",
"{% if android.name == 'Roy' %}YES{% endif %}",
assigns)
end
assert_nothing_raised do
assert_template_result( "YES",
"{% if order.items_count == 0 %}YES{% endif %}",
assigns)
end
end end
def test_if_and
assert_template_result(' YES ','{% if true and true %} YES {% endif %}')
assert_template_result('','{% if false and true %} YES {% endif %}')
assert_template_result('','{% if false and true %} YES {% endif %}')
end
def test_hash_miss_generates_false def test_hash_miss_generates_false
assert_template_result('','{% if foo.bar %} NO {% endif %}', 'foo' => {}) assert_template_result('','{% if foo.bar %} NO {% endif %}', 'foo' => {})
end end
def test_if_from_variable def test_if_from_variable
assert_template_result('','{% if var %} NO {% endif %}', 'var' => false) assert_template_result('','{% if var %} NO {% endif %}', 'var' => false)
assert_template_result('','{% if var %} NO {% endif %}', 'var' => nil) assert_template_result('','{% if var %} NO {% endif %}', 'var' => nil)
@@ -62,7 +76,7 @@ class IfElseTest < Test::Unit::TestCase
assert_template_result('','{% if foo.bar %} NO {% endif %}', 'foo' => {}) assert_template_result('','{% if foo.bar %} NO {% endif %}', 'foo' => {})
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)
@@ -74,12 +88,12 @@ class IfElseTest < Test::Unit::TestCase
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' => [] })
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"})
@@ -87,19 +101,19 @@ class IfElseTest < Test::Unit::TestCase
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})
end end
def test_nested_if def test_nested_if
assert_template_result('', '{% if false %}{% if false %} NO {% endif %}{% endif %}') assert_template_result('', '{% if false %}{% if false %} NO {% endif %}{% endif %}')
assert_template_result('', '{% if false %}{% if true %} NO {% endif %}{% endif %}') assert_template_result('', '{% if false %}{% if true %} NO {% endif %}{% endif %}')
assert_template_result('', '{% if true %}{% if false %} NO {% endif %}{% endif %}') assert_template_result('', '{% if true %}{% if false %} NO {% endif %}{% endif %}')
assert_template_result(' YES ', '{% if true %}{% if true %} YES {% endif %}{% endif %}') assert_template_result(' YES ', '{% if true %}{% if true %} YES {% endif %}{% endif %}')
assert_template_result(' YES ', '{% if true %}{% if true %} YES {% else %} NO {% endif %}{% else %} NO {% endif %}') assert_template_result(' YES ', '{% if true %}{% if true %} YES {% else %} NO {% endif %}{% else %} NO {% endif %}')
assert_template_result(' YES ', '{% if true %}{% if false %} NO {% else %} YES {% endif %}{% else %} NO {% endif %}') assert_template_result(' YES ', '{% if true %}{% if false %} NO {% else %} YES {% endif %}{% else %} NO {% endif %}')
assert_template_result(' YES ', '{% if false %}{% if true %} NO {% else %} NONO {% endif %}{% else %} YES {% endif %}') assert_template_result(' YES ', '{% if false %}{% if true %} NO {% else %} NONO {% endif %}{% else %} YES {% endif %}')
end end
def test_comparisons_on_null def test_comparisons_on_null
assert_template_result('','{% if null < 10 %} NO {% endif %}') assert_template_result('','{% if null < 10 %} NO {% endif %}')
assert_template_result('','{% if null <= 10 %} NO {% endif %}') assert_template_result('','{% if null <= 10 %} NO {% endif %}')
@@ -111,29 +125,36 @@ class IfElseTest < Test::Unit::TestCase
assert_template_result('','{% if 10 >= null %} NO {% endif %}') assert_template_result('','{% if 10 >= null %} NO {% endif %}')
assert_template_result('','{% if 10 > null %} NO {% endif %}') assert_template_result('','{% if 10 > null %} NO {% endif %}')
end end
def test_else_if def test_else_if
assert_template_result('0','{% if 0 == 0 %}0{% elsif 1 == 1%}1{% else %}2{% endif %}') assert_template_result('0','{% if 0 == 0 %}0{% elsif 1 == 1%}1{% else %}2{% endif %}')
assert_template_result('1','{% if 0 != 0 %}0{% elsif 1 == 1%}1{% else %}2{% endif %}') assert_template_result('1','{% if 0 != 0 %}0{% elsif 1 == 1%}1{% else %}2{% endif %}')
assert_template_result('2','{% if 0 != 0 %}0{% elsif 1 != 1%}1{% else %}2{% endif %}') assert_template_result('2','{% if 0 != 0 %}0{% elsif 1 != 1%}1{% else %}2{% endif %}')
assert_template_result('elsif','{% if false %}if{% elsif true %}elsif{% endif %}') assert_template_result('elsif','{% if false %}if{% elsif true %}elsif{% endif %}')
end end
def test_syntax_error_no_variable def test_syntax_error_no_variable
assert_raise(SyntaxError){ assert_template_result('', '{% if jerry == 1 %}')} assert_raise(SyntaxError){ assert_template_result('', '{% if jerry == 1 %}')}
end end
def test_syntax_error_no_expression def test_syntax_error_no_expression
assert_raise(SyntaxError) { assert_template_result('', '{% if %}') } assert_raise(SyntaxError) { assert_template_result('', '{% if %}') }
end end
def test_if_with_custom_condition def test_if_with_custom_condition
Condition.operators['contains'] = :[] Condition.operators['contains'] = :[]
assert_template_result('yes', %({% if 'bob' contains 'o' %}yes{% endif %})) assert_template_result('yes', %({% if 'bob' contains 'o' %}yes{% endif %}))
assert_template_result('no', %({% if 'bob' contains 'f' %}yes{% else %}no{% endif %})) assert_template_result('no', %({% if 'bob' contains 'f' %}yes{% else %}no{% endif %}))
ensure ensure
Condition.operators.delete 'contains' Condition.operators.delete 'contains'
end end
end
def test_operators_are_ignored_unless_isolated
Condition.operators['contains'] = :[]
assert_template_result('yes',
%({% if 'gnomeslab-and-or-liquid' contains 'gnomeslab-and-or-liquid' %}yes{% endif %}))
end
end # IfElseTest

View File

@@ -0,0 +1,39 @@
require 'test_helper'
class LiteralTagTest < Test::Unit::TestCase
include Liquid
def test_empty_literal
assert_template_result '', '{% literal %}{% endliteral %}'
assert_template_result '', '{{{}}}'
end
def test_simple_literal_value
assert_template_result 'howdy',
'{% literal %}howdy{% endliteral %}'
end
def test_literals_ignore_liquid_markup
expected = %({% if 'gnomeslab' contain 'liquid' %}yes{ % endif %})
template = %({% literal %}#{expected}{% endliteral %})
assert_template_result expected, template
end
def test_shorthand_syntax
expected = %({% if 'gnomeslab' contain 'liquid' %}yes{ % endif %})
template = %({{{#{expected}}}})
assert_template_result expected, template
end
# Class methods
def test_from_shorthand
assert_equal '{% literal %}gnomeslab{% endliteral %}', Liquid::Literal.from_shorthand('{{{gnomeslab}}}')
end
def test_from_shorthand_ignores_improper_syntax
text = "{% if 'hi' == 'hi' %}hi{% endif %}"
assert_equal text, Liquid::Literal.from_shorthand(text)
end
end # AssignTest

View File

@@ -1,10 +1,8 @@
require File.dirname(__FILE__) + '/helper' require 'test_helper'
class StandardTagTest < Test::Unit::TestCase class StandardTagTest < Test::Unit::TestCase
include Liquid include Liquid
def test_tag def test_tag
tag = Tag.new('tag', [], []) tag = Tag.new('tag', [], [])
assert_equal 'liquid::tag', tag.name assert_equal 'liquid::tag', tag.name
@@ -14,6 +12,7 @@ class StandardTagTest < Test::Unit::TestCase
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>')
assert_template_result('|,.:','|,.:') assert_template_result('|,.:','|,.:')
@@ -85,43 +84,48 @@ 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 ','{%for item in array%} {{forloop.index}}/{{forloop.length}} {%endfor%}',assigns) assert_template_result(' 1/3 2/3 3/3 ',
assert_template_result(' 1 2 3 ','{%for item in array%} {{forloop.index}} {%endfor%}',assigns) '{%for item in array%} {{forloop.index}}/{{forloop.length}} {%endfor%}',
assert_template_result(' 0 1 2 ','{%for item in array%} {{forloop.index0}} {%endfor%}',assigns) assigns)
assert_template_result(' 2 1 0 ','{%for item in array%} {{forloop.rindex0}} {%endfor%}',assigns) assert_template_result(' 1 2 3 ', '{%for item in array%} {{forloop.index}} {%endfor%}', assigns)
assert_template_result(' 3 2 1 ','{%for item in array%} {{forloop.rindex}} {%endfor%}',assigns) assert_template_result(' 0 1 2 ', '{%for item in array%} {{forloop.index0}} {%endfor%}', assigns)
assert_template_result(' true false false ','{%for item in array%} {{forloop.first}} {%endfor%}',assigns) assert_template_result(' 2 1 0 ', '{%for item in array%} {{forloop.rindex0}} {%endfor%}', assigns)
assert_template_result(' false false true ','{%for item in array%} {{forloop.last}} {%endfor%}',assigns) assert_template_result(' 3 2 1 ', '{%for item in array%} {{forloop.rindex}} {%endfor%}', assigns)
assert_template_result(' true false false ', '{%for item in array%} {{forloop.first}} {%endfor%}', assigns)
assert_template_result(' false false true ', '{%for item in array%} {{forloop.last}} {%endfor%}', assigns)
end end
def test_for_and_if def test_for_and_if
assigns = {'array' => [1,2,3] } assigns = {'array' => [1,2,3] }
assert_template_result('+--', '{%for item in array%}{% if forloop.first %}+{% else %}-{% endif %}{%endfor%}', assigns) assert_template_result('+--',
'{%for item in array%}{% if forloop.first %}+{% else %}-{% endif %}{%endfor%}',
assigns)
end end
def test_limiting def test_limiting
assigns = {'array' => [1,2,3,4,5,6,7,8,9,0]} assigns = {'array' => [1,2,3,4,5,6,7,8,9,0]}
assert_template_result('12','{%for i in array limit:2 %}{{ i }}{%endfor%}',assigns) assert_template_result('12', '{%for i in array limit:2 %}{{ i }}{%endfor%}', assigns)
assert_template_result('1234','{%for i in array limit:4 %}{{ i }}{%endfor%}',assigns) assert_template_result('1234', '{%for i in array limit:4 %}{{ i }}{%endfor%}', assigns)
assert_template_result('3456','{%for i in array limit:4 offset:2 %}{{ i }}{%endfor%}',assigns) assert_template_result('3456', '{%for i in array limit:4 offset:2 %}{{ i }}{%endfor%}', assigns)
assert_template_result('3456','{%for i in array limit: 4 offset: 2 %}{{ i }}{%endfor%}',assigns) assert_template_result('3456', '{%for i in array limit: 4 offset: 2 %}{{ i }}{%endfor%}', assigns)
end end
def test_dynamic_variable_limiting def test_dynamic_variable_limiting
assigns = {'array' => [1,2,3,4,5,6,7,8,9,0]} assigns = {'array' => [1,2,3,4,5,6,7,8,9,0]}
assigns['limit'] = 2 assigns['limit'] = 2
assigns['offset'] = 2 assigns['offset'] = 2
assert_template_result('34','{%for i in array limit: limit offset: offset %}{{ i }}{%endfor%}',assigns)
assert_template_result('34', '{%for i in array limit: limit offset: offset %}{{ i }}{%endfor%}', assigns)
end end
def test_nested_for def test_nested_for
assigns = {'array' => [[1,2],[3,4],[5,6]] } assigns = {'array' => [[1,2],[3,4],[5,6]] }
assert_template_result('123456','{%for item in array%}{%for i in item%}{{ i }}{%endfor%}{%endfor%}',assigns) assert_template_result('123456', '{%for item in array%}{%for i in item%}{{ i }}{%endfor%}{%endfor%}', assigns)
end end
def test_offset_only def test_offset_only
assigns = {'array' => [1,2,3,4,5,6,7,8,9,0]} assigns = {'array' => [1,2,3,4,5,6,7,8,9,0]}
assert_template_result('890','{%for i in array offset:7 %}{{ i }}{%endfor%}',assigns) assert_template_result('890', '{%for i in array offset:7 %}{{ i }}{%endfor%}', assigns)
end end
def test_pause_resume def test_pause_resume
@@ -199,86 +203,131 @@ HERE
def test_assign def test_assign
assigns = {'var' => 'content' } assigns = {'var' => 'content' }
assert_template_result('var2: var2:content','var2:{{var2}} {%assign var2 = var%} var2:{{var2}}',assigns) assert_template_result('var2: var2:content', 'var2:{{var2}} {%assign var2 = var%} var2:{{var2}}', assigns)
end end
def test_hyphenated_assign def test_hyphenated_assign
assigns = {'a-b' => '1' } assigns = {'a-b' => '1' }
assert_template_result('a-b:1 a-b:2','a-b:{{a-b}} {%assign a-b = 2 %}a-b:{{a-b}}',assigns) assert_template_result('a-b:1 a-b:2', 'a-b:{{a-b}} {%assign a-b = 2 %}a-b:{{a-b}}', assigns)
end end
def test_assign_with_colon_and_spaces def test_assign_with_colon_and_spaces
assigns = {'var' => {'a:b c' => {'paged' => '1' }}} assigns = {'var' => {'a:b c' => {'paged' => '1' }}}
assert_template_result('var2: 1','{%assign var2 = var["a:b c"].paged %}var2: {{var2}}',assigns) assert_template_result('var2: 1', '{%assign var2 = var["a:b c"].paged %}var2: {{var2}}', assigns)
end end
def test_capture def test_capture
assigns = {'var' => 'content' } assigns = {'var' => 'content' }
assert_template_result('content foo content foo ','{{ var2 }}{% capture var2 %}{{ var }} foo {% endcapture %}{{ var2 }}{{ var2 }}', assigns) assert_template_result('content foo content foo ',
'{{ var2 }}{% capture var2 %}{{ var }} foo {% endcapture %}{{ var2 }}{{ var2 }}',
assigns)
end end
def test_capture_detects_bad_syntax def test_capture_detects_bad_syntax
assert_raise(SyntaxError) do assert_raise(SyntaxError) do
assert_template_result('content foo content foo ','{{ var2 }}{% capture %}{{ var }} foo {% endcapture %}{{ var2 }}{{ var2 }}', {'var' => 'content' }) assert_template_result('content foo content foo ',
'{{ var2 }}{% capture %}{{ var }} foo {% endcapture %}{{ var2 }}{{ var2 }}',
{'var' => 'content' })
end end
end end
def test_case def test_case
assigns = {'condition' => 2 } assigns = {'condition' => 2 }
assert_template_result(' its 2 ','{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}', assigns) assert_template_result(' its 2 ',
'{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}',
assigns)
assigns = {'condition' => 1 } assigns = {'condition' => 1 }
assert_template_result(' its 1 ','{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}', assigns) assert_template_result(' its 1 ',
'{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}',
assigns)
assigns = {'condition' => 3 } assigns = {'condition' => 3 }
assert_template_result('','{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}', assigns) assert_template_result('',
'{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}',
assigns)
assigns = {'condition' => "string here" } assigns = {'condition' => "string here" }
assert_template_result(' hit ','{% case condition %}{% when "string here" %} hit {% endcase %}', assigns) assert_template_result(' hit ',
'{% case condition %}{% when "string here" %} hit {% endcase %}',
assigns)
assigns = {'condition' => "bad string here" } assigns = {'condition' => "bad string here" }
assert_template_result('','{% case condition %}{% when "string here" %} hit {% endcase %}', assigns) assert_template_result('',
'{% case condition %}{% when "string here" %} hit {% endcase %}',\
assigns)
end end
def test_case_with_else def test_case_with_else
assigns = {'condition' => 5 } assigns = {'condition' => 5 }
assert_template_result(' hit ','{% case condition %}{% when 5 %} hit {% else %} else {% endcase %}', assigns) assert_template_result(' hit ',
'{% case condition %}{% when 5 %} hit {% else %} else {% endcase %}',
assigns)
assigns = {'condition' => 6 } assigns = {'condition' => 6 }
assert_template_result(' else ','{% case condition %}{% when 5 %} hit {% else %} else {% endcase %}', assigns) assert_template_result(' else ',
'{% case condition %}{% when 5 %} hit {% else %} else {% endcase %}',
assigns)
assigns = {'condition' => 6 } assigns = {'condition' => 6 }
assert_template_result(' else ','{% case condition %} {% when 5 %} hit {% else %} else {% endcase %}', assigns) assert_template_result(' else ',
'{% case condition %} {% when 5 %} hit {% else %} else {% endcase %}',
assigns)
end end
def test_case_on_size def test_case_on_size
assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => []) assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [])
assert_template_result('1' , '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1]) assert_template_result('1', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1])
assert_template_result('2' , '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1]) assert_template_result('2', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1])
assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1, 1]) assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1, 1])
assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1, 1, 1]) assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1, 1, 1])
assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1, 1, 1, 1]) assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1, 1, 1, 1])
end end
def test_case_on_size_with_else def test_case_on_size_with_else
assert_template_result('else', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}', 'a' => []) assert_template_result('else',
assert_template_result('1', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}', 'a' => [1]) '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
assert_template_result('2', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}', 'a' => [1, 1]) 'a' => [])
assert_template_result('else', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}', 'a' => [1, 1, 1])
assert_template_result('else', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}', 'a' => [1, 1, 1, 1]) assert_template_result('1',
assert_template_result('else', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}', 'a' => [1, 1, 1, 1, 1]) '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
'a' => [1])
assert_template_result('2',
'{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
'a' => [1, 1])
assert_template_result('else',
'{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
'a' => [1, 1, 1])
assert_template_result('else',
'{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
'a' => [1, 1, 1, 1])
assert_template_result('else',
'{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
'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', '{% case a.empty? %}{% when true %}true{% when false %}false{% else %}else{% endcase %}', {}) assert_template_result('else',
assert_template_result('false', '{% case false %}{% when true %}true{% when false %}false{% else %}else{% endcase %}', {}) '{% case a.empty? %}{% when true %}true{% when false %}false{% else %}else{% endcase %}',
assert_template_result('true', '{% case true %}{% when true %}true{% when false %}false{% else %}else{% endcase %}', {}) {})
assert_template_result('else', '{% case NULL %}{% when true %}true{% when false %}false{% else %}else{% endcase %}', {})
assert_template_result('false',
'{% case false %}{% when true %}true{% when false %}false{% else %}else{% endcase %}',
{})
assert_template_result('true',
'{% case true %}{% when true %}true{% when false %}false{% else %}else{% endcase %}',
{})
assert_template_result('else',
'{% case NULL %}{% when true %}true{% when false %}false{% else %}else{% endcase %}',
{})
end end
def test_assign_from_case def test_assign_from_case
@@ -331,7 +380,8 @@ HERE
end end
def test_assign_is_global def test_assign_is_global
assert_equal 'variable', Liquid::Template.parse( '{%for i in (1..2) %}{% assign a = "variable"%}{% endfor %}{{a}}' ).render assert_equal 'variable',
Liquid::Template.parse( '{%for i in (1..2) %}{% assign a = "variable"%}{% endfor %}{{a}}' ).render
end end
def test_case_detects_bad_syntax def test_case_detects_bad_syntax
@@ -345,31 +395,31 @@ HERE
end end
def test_cycle def test_cycle
assert_template_result('one','{%cycle "one", "two"%}') assert_template_result('one','{%cycle "one", "two"%}')
assert_template_result('one two','{%cycle "one", "two"%} {%cycle "one", "two"%}') assert_template_result('one two','{%cycle "one", "two"%} {%cycle "one", "two"%}')
assert_template_result(' two','{%cycle "", "two"%} {%cycle "", "two"%}') assert_template_result(' two','{%cycle "", "two"%} {%cycle "", "two"%}')
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','{%cycle "text-align: left", "text-align: right" %} {%cycle "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"%}')
end end
def test_multiple_cycles def test_multiple_cycles
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%}') 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%}')
end end
def test_multiple_named_cycles def test_multiple_named_cycles
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" %}') 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" %}')
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','{%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) 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)
end end
def test_size_of_array def test_size_of_array
@@ -383,10 +433,10 @@ HERE
end end
def test_illegal_symbols def test_illegal_symbols
assert_template_result('', '{% if true == empty %}?{% endif %}', {}) assert_template_result('', '{% if true == empty %}?{% endif %}', {})
assert_template_result('', '{% if true == null %}?{% endif %}', {}) assert_template_result('', '{% if true == null %}?{% endif %}', {})
assert_template_result('', '{% if empty == true %}?{% endif %}', {}) assert_template_result('', '{% if empty == true %}?{% endif %}', {})
assert_template_result('', '{% if null == true %}?{% endif %}', {}) assert_template_result('', '{% if null == true %}?{% endif %}', {})
end end
def test_for_reversed def test_for_reversed
@@ -402,4 +452,4 @@ HERE
assigns = {'array' => [ 1, 1, 1, 1] } assigns = {'array' => [ 1, 1, 1, 1] }
assert_template_result('1','{%for item in array%}{%ifchanged%}{{item}}{% endifchanged %}{%endfor%}',assigns) assert_template_result('1','{%for item in array%}{%ifchanged%}{{item}}{% endifchanged %}{%endfor%}',assigns)
end end
end end # StandardTagTest

View File

@@ -1,10 +1,8 @@
#!/usr/bin/env ruby require 'test_helper'
require File.dirname(__FILE__) + '/helper'
class StatementsTest < Test::Unit::TestCase class StatementsTest < Test::Unit::TestCase
include Liquid include Liquid
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 %} |
expected = %| true | expected = %| true |
@@ -69,46 +67,46 @@ class StatementsTest < Test::Unit::TestCase
expected = %| false | expected = %| false |
assert_equal expected, Template.parse(text).render assert_equal expected, Template.parse(text).render
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 %} |
expected = %| true | expected = %| true |
assert_equal expected, Template.parse(text).render('var' => 'hello there!') assert_equal expected, Template.parse(text).render('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 %} |
expected = %| true | expected = %| true |
assert_equal expected, Template.parse(text).render('var' => 'hello there!') assert_equal expected, Template.parse(text).render('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 %} |
expected = %| true | expected = %| true |
assert_equal expected, Template.parse(text).render('var' => 'hello there!') assert_equal expected, Template.parse(text).render('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 %} |
expected = %| true | expected = %| true |
assert_equal expected, Template.parse(text).render('var' => 'hello there!') assert_equal expected, Template.parse(text).render('var' => 'hello there!')
end end
#def test_is_nil #def test_is_nil
# text = %| {% if var != nil %} true {% else %} false {% end %} | # text = %| {% if var != nil %} true {% else %} false {% end %} |
# @template.assigns = { 'var' => 'hello there!'} # @template.assigns = { 'var' => 'hello there!'}
# expected = %| true | # expected = %| true |
# assert_equal expected, @template.parse(text) # assert_equal expected, @template.parse(text)
#end #end
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 %} |
expected = %| true | expected = %| true |
assert_equal expected, Template.parse(text).render('array' => []) assert_equal expected, Template.parse(text).render('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 %} |
expected = %| false | expected = %| false |
assert_equal expected, Template.parse(text).render('array' => [1,2,3]) assert_equal expected, Template.parse(text).render('array' => [1,2,3])
@@ -133,5 +131,4 @@ class StatementsTest < Test::Unit::TestCase
expected = %| true | expected = %| true |
assert_equal expected, Template.parse(text).render('var' => 1 ) assert_equal expected, Template.parse(text).render('var' => 1 )
end end
end # StatementsTest
end

View File

@@ -1,4 +1,4 @@
require File.dirname(__FILE__) + '/helper' require 'test_helper'
class UnlessElseTest < Test::Unit::TestCase class UnlessElseTest < Test::Unit::TestCase
include Liquid include Liquid
@@ -6,7 +6,7 @@ class UnlessElseTest < Test::Unit::TestCase
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
@@ -23,5 +23,4 @@ class UnlessElseTest < Test::Unit::TestCase
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

View File

@@ -1,52 +1,52 @@
require File.dirname(__FILE__) + '/helper' require 'test_helper'
class TemplateTest < Test::Unit::TestCase class TemplateTest < Test::Unit::TestCase
include Liquid include Liquid
def test_tokenize_strings def test_tokenize_strings
assert_equal [' '], Template.new.send(:tokenize, ' ') assert_equal [' '], Template.new.send(:tokenize, ' ')
assert_equal ['hello world'], Template.new.send(:tokenize, 'hello world') assert_equal ['hello world'], Template.new.send(:tokenize, 'hello world')
end end
def test_tokenize_variables def test_tokenize_variables
assert_equal ['{{funk}}'], Template.new.send(:tokenize, '{{funk}}') assert_equal ['{{funk}}'], Template.new.send(:tokenize, '{{funk}}')
assert_equal [' ', '{{funk}}', ' '], Template.new.send(:tokenize, ' {{funk}} ') assert_equal [' ', '{{funk}}', ' '], Template.new.send(:tokenize, ' {{funk}} ')
assert_equal [' ', '{{funk}}', ' ', '{{so}}', ' ', '{{brother}}', ' '], Template.new.send(:tokenize, ' {{funk}} {{so}} {{brother}} ') assert_equal [' ', '{{funk}}', ' ', '{{so}}', ' ', '{{brother}}', ' '], Template.new.send(:tokenize, ' {{funk}} {{so}} {{brother}} ')
assert_equal [' ', '{{ funk }}', ' '], Template.new.send(:tokenize, ' {{ funk }} ') assert_equal [' ', '{{ funk }}', ' '], Template.new.send(:tokenize, ' {{ funk }} ')
end end
def test_tokenize_blocks def test_tokenize_blocks
assert_equal ['{%comment%}'], Template.new.send(:tokenize, '{%comment%}') assert_equal ['{%comment%}'], Template.new.send(:tokenize, '{%comment%}')
assert_equal [' ', '{%comment%}', ' '], Template.new.send(:tokenize, ' {%comment%} ') assert_equal [' ', '{%comment%}', ' '], Template.new.send(:tokenize, ' {%comment%} ')
assert_equal [' ', '{%comment%}', ' ', '{%endcomment%}', ' '], Template.new.send(:tokenize, ' {%comment%} {%endcomment%} ') assert_equal [' ', '{%comment%}', ' ', '{%endcomment%}', ' '], Template.new.send(:tokenize, ' {%comment%} {%endcomment%} ')
assert_equal [' ', '{% comment %}', ' ', '{% endcomment %}', ' '], Template.new.send(:tokenize, " {% comment %} {% endcomment %} ") assert_equal [' ', '{% comment %}', ' ', '{% endcomment %}', ' '], Template.new.send(:tokenize, " {% comment %} {% endcomment %} ")
end end
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_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
@@ -71,5 +71,4 @@ class TemplateTest < Test::Unit::TestCase
assert_equal '1', t.render(assigns) assert_equal '1', t.render(assigns)
@global = nil @global = nil
end end
end # TemplateTest
end

View File

@@ -1,5 +1,4 @@
#!/usr/bin/env ruby require 'test_helper'
require File.dirname(__FILE__) + '/helper'
class VariableTest < Test::Unit::TestCase class VariableTest < Test::Unit::TestCase
include Liquid include Liquid
@@ -131,7 +130,7 @@ class VariableResolutionTest < Test::Unit::TestCase
template = Template.parse(%|{{ test.test }}|) template = Template.parse(%|{{ test.test }}|)
assert_equal 'worked', template.render('test' => {'test' => 'worked'}) assert_equal 'worked', template.render('test' => {'test' => 'worked'})
end end
def test_preset_assigns def test_preset_assigns
template = Template.parse(%|{{ test }}|) template = Template.parse(%|{{ test }}|)
template.assigns['test'] = 'worked' template.assigns['test'] = 'worked'
@@ -168,5 +167,4 @@ class VariableResolutionTest < Test::Unit::TestCase
} }
assert_equal "Unknown variable 'test'", e.message assert_equal "Unknown variable 'test'", e.message
end end
end # VariableTest
end

View File

@@ -1,20 +1,34 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
$LOAD_PATH.unshift(File.dirname(__FILE__)+ '/extra') extras_path = File.join File.dirname(__FILE__), 'extra'
$LOAD_PATH.unshift(extras_path) unless $LOAD_PATH.include? extras_path
require 'rubygems' unless RUBY_VERSION =~ /^(?:1.9.*)$/
require 'test/unit' require 'test/unit'
require 'test/unit/assertions' require 'test/unit/assertions'
require 'caller' require 'caller'
require 'breakpoint' require 'breakpoint'
require File.dirname(__FILE__) + '/../lib/liquid' require 'ruby-debug'
require File.join File.dirname(__FILE__), '..', 'lib', 'liquid'
module Test module Test
module Unit module Unit
module Assertions module Assertions
include Liquid include Liquid
def assert_template_result(expected, template, assigns={}, message=nil)
assert_equal expected, Template.parse(template).render(assigns) def assert_template_result(expected, template, assigns = {}, message = nil)
end assert_equal expected, Template.parse(template).render(assigns)
end end
end
end def assert_template_result_matches(expected, template, assigns = {}, message = nil)
return assert_template_result(expected, template, assigns, message) unless expected.is_a? Regexp
assert_match expected, Template.parse(template).render(assigns)
end
end # Assertions
end # Unit
end # Test