mirror of
https://github.com/kemko/liquid.git
synced 2026-01-02 08:15:41 +03:00
Compare commits
30 Commits
c-extensio
...
test-gem-i
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19a60ccee2 | ||
|
|
114a37d9ba | ||
|
|
30bd9ad957 | ||
|
|
2239921804 | ||
|
|
1ea178e7a8 | ||
|
|
5650c7eea1 | ||
|
|
553b0926ae | ||
|
|
2bac6267f9 | ||
|
|
628ab3dc6a | ||
|
|
2eb552c65d | ||
|
|
6e40746ce4 | ||
|
|
75068e8fa4 | ||
|
|
ad1152853a | ||
|
|
73098ac5bc | ||
|
|
8bc3792c0e | ||
|
|
3ef29c624c | ||
|
|
a85fb38769 | ||
|
|
6a1c3cff1a | ||
|
|
bde32018dd | ||
|
|
2a12f253bf | ||
|
|
f15d24509d | ||
|
|
09e4378cfb | ||
|
|
af0e26fb16 | ||
|
|
f5502e8152 | ||
|
|
c098235baa | ||
|
|
0e2bf768ba | ||
|
|
4c477c2087 | ||
|
|
cd7fc050b1 | ||
|
|
8291c5e72c | ||
|
|
7e45155aa9 |
@@ -1,7 +1,8 @@
|
||||
rvm:
|
||||
- 1.9.3
|
||||
- 2.0.0
|
||||
- 2.1.0
|
||||
- 2.1
|
||||
- 2.1.1
|
||||
- jruby-19mode
|
||||
- jruby-head
|
||||
- rbx-19mode
|
||||
@@ -10,7 +11,7 @@ matrix:
|
||||
- rvm: rbx-19mode
|
||||
- rvm: jruby-head
|
||||
|
||||
script: "rake test"
|
||||
script: "gem build liquid.gemspec && gem install liquid-3.0.0.gem"
|
||||
|
||||
notifications:
|
||||
disable: true
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
## 3.0.0 / not yet released / branch "master"
|
||||
|
||||
* ...
|
||||
* Add error messages for missing variables when :strict, see #352 [Daniel Gaiottino]
|
||||
* Properly set context rethrow_errors on render! #349 [Thierry Joyal, tjoyal]
|
||||
* Fix broken rendering of variables which are equal to false, see #345 [Florian Weingarten, fw42]
|
||||
* Remove ActionView template handler [Dylan Thacker-Smith, dylanahsmith]
|
||||
* Freeze lots of string literals for new Ruby 2.1 optimization, see #297 [Florian Weingarten, fw42]
|
||||
* Allow newlines in tags and variables, see #324 [Dylan Thacker-Smith, dylanahsmith]
|
||||
* Tag#parse is called after initialize, which now takes options instead of tokens as the 3rd argument. See #321 [Dylan Thacker-Smith, dylanahsmith]
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
[](http://travis-ci.org/Shopify/liquid)
|
||||
[](http://inch-ci.org/github/Shopify/liquid)
|
||||
|
||||
# Liquid template engine
|
||||
|
||||
* [Contributing guidelines](CONTRIBUTING.md)
|
||||
|
||||
2
Rakefile
2
Rakefile
@@ -8,7 +8,7 @@ task :default => 'test'
|
||||
desc 'run test suite with default parser'
|
||||
Rake::TestTask.new(:base_test) do |t|
|
||||
t.libs << '.' << 'lib' << 'test'
|
||||
t.test_files = FileList['test/liquid/**/*_test.rb']
|
||||
t.test_files = FileList['test/{integration,unit}/**/*_test.rb']
|
||||
t.verbose = false
|
||||
end
|
||||
|
||||
|
||||
8
init.rb
8
init.rb
@@ -1,8 +0,0 @@
|
||||
require 'liquid'
|
||||
require 'extras/liquid_view'
|
||||
|
||||
if defined? ActionView::Template and ActionView::Template.respond_to? :register_template_handler
|
||||
ActionView::Template
|
||||
else
|
||||
ActionView::Base
|
||||
end.register_template_handler(:liquid, LiquidView)
|
||||
@@ -1,51 +0,0 @@
|
||||
# LiquidView is a action view extension class. You can register it with rails
|
||||
# and use liquid as an template system for .liquid files
|
||||
#
|
||||
# Example
|
||||
#
|
||||
# ActionView::Base::register_template_handler :liquid, LiquidView
|
||||
class LiquidView
|
||||
PROTECTED_ASSIGNS = %w( template_root response _session template_class action_name request_origin session template
|
||||
_response url _request _cookies variables_added _flash params _headers request cookies
|
||||
ignore_missing_templates flash _params logger before_filter_chain_aborted headers )
|
||||
PROTECTED_INSTANCE_VARIABLES = %w( @_request @controller @_first_render @_memoized__pick_template @view_paths
|
||||
@helpers @assigns_added @template @_render_stack @template_format @assigns )
|
||||
|
||||
def self.call(template)
|
||||
"LiquidView.new(self).render(template, local_assigns)"
|
||||
end
|
||||
|
||||
def initialize(view)
|
||||
@view = view
|
||||
end
|
||||
|
||||
def render(template, local_assigns = nil)
|
||||
@view.controller.headers["Content-Type"] ||= 'text/html; charset=utf-8'
|
||||
|
||||
# Rails 2.2 Template has source, but not locals
|
||||
if template.respond_to?(:source) && !template.respond_to?(:locals)
|
||||
assigns = (@view.instance_variables - PROTECTED_INSTANCE_VARIABLES).inject({}) do |hash, ivar|
|
||||
hash[ivar[1..-1]] = @view.instance_variable_get(ivar)
|
||||
hash
|
||||
end
|
||||
else
|
||||
assigns = @view.assigns.reject{ |k,v| PROTECTED_ASSIGNS.include?(k) }
|
||||
end
|
||||
|
||||
source = template.respond_to?(:source) ? template.source : template
|
||||
local_assigns = (template.respond_to?(:locals) ? template.locals : local_assigns) || {}
|
||||
|
||||
if content_for_layout = @view.instance_variable_get("@content_for_layout")
|
||||
assigns['content_for_layout'] = content_for_layout
|
||||
end
|
||||
assigns.merge!(local_assigns.stringify_keys)
|
||||
|
||||
liquid = Liquid::Template.parse(source)
|
||||
liquid.render(assigns, :filters => [@view.controller.master_helper_module], :registers => {:action_view => @view, :controller => @view.controller})
|
||||
end
|
||||
|
||||
def compilable?
|
||||
false
|
||||
end
|
||||
|
||||
end
|
||||
@@ -15,6 +15,8 @@ module Liquid
|
||||
class Context
|
||||
attr_reader :scopes, :errors, :registers, :environments, :resource_limits
|
||||
|
||||
attr_accessor :rethrow_errors
|
||||
|
||||
def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = {})
|
||||
@environments = [environments].flatten
|
||||
@scopes = [(outer_scope || {})]
|
||||
@@ -194,7 +196,8 @@ module Liquid
|
||||
|
||||
if scope.nil?
|
||||
@environments.each do |e|
|
||||
if variable = lookup_and_evaluate(e, key)
|
||||
variable = lookup_and_evaluate(e, key)
|
||||
unless variable.nil?
|
||||
scope = e
|
||||
break
|
||||
end
|
||||
@@ -202,6 +205,7 @@ module Liquid
|
||||
end
|
||||
|
||||
scope ||= @environments.last || @scopes.last
|
||||
handle_not_found(key) unless scope.has_key?(key)
|
||||
variable ||= lookup_and_evaluate(scope, key)
|
||||
|
||||
variable = variable.to_liquid
|
||||
@@ -251,6 +255,7 @@ module 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
|
||||
handle_not_found(markup)
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -280,6 +285,10 @@ module Liquid
|
||||
end
|
||||
end
|
||||
end # squash_instance_assigns_with_environments
|
||||
|
||||
def handle_not_found(variable)
|
||||
@errors << "Variable {{#{variable}}} not found" if Template.error_mode == :strict
|
||||
end
|
||||
end # Context
|
||||
|
||||
end # Liquid
|
||||
|
||||
@@ -162,7 +162,7 @@ module Liquid
|
||||
input.to_s.gsub(/\n/, "<br />\n".freeze)
|
||||
end
|
||||
|
||||
# Reformat a date
|
||||
# Reformat a date using Ruby's core Time#strftime( string ) -> string
|
||||
#
|
||||
# %a - The abbreviated weekday name (``Sun'')
|
||||
# %A - The full weekday name (``Sunday'')
|
||||
@@ -176,6 +176,7 @@ module Liquid
|
||||
# %m - Month of the year (01..12)
|
||||
# %M - Minute of the hour (00..59)
|
||||
# %p - Meridian indicator (``AM'' or ``PM'')
|
||||
# %s - Number of seconds since 1970-01-01 00:00:00 UTC.
|
||||
# %S - Second of the minute (00..60)
|
||||
# %U - Week number of the current year,
|
||||
# starting with the first Sunday as the first
|
||||
@@ -190,34 +191,14 @@ module Liquid
|
||||
# %Y - Year with century
|
||||
# %Z - Time zone name
|
||||
# %% - Literal ``%'' character
|
||||
#
|
||||
# See also: http://www.ruby-doc.org/core/Time.html#method-i-strftime
|
||||
def date(input, format)
|
||||
return input if format.to_s.empty?
|
||||
|
||||
if format.to_s.empty?
|
||||
return input.to_s
|
||||
end
|
||||
return input unless date = to_date(input)
|
||||
|
||||
if ((input.is_a?(String) && !/\A\d+\z/.match(input.to_s).nil?) || input.is_a?(Integer)) && input.to_i > 0
|
||||
input = Time.at(input.to_i)
|
||||
end
|
||||
|
||||
date = if input.is_a?(String)
|
||||
case input.downcase
|
||||
when 'now'.freeze, 'today'.freeze
|
||||
Time.now
|
||||
else
|
||||
Time.parse(input)
|
||||
end
|
||||
else
|
||||
input
|
||||
end
|
||||
|
||||
if date.respond_to?(:strftime)
|
||||
date.strftime(format.to_s)
|
||||
else
|
||||
input
|
||||
end
|
||||
rescue
|
||||
input
|
||||
date.strftime(format.to_s)
|
||||
end
|
||||
|
||||
# Get the first element of the passed in array
|
||||
@@ -262,6 +243,21 @@ module Liquid
|
||||
apply_operation(input, operand, :%)
|
||||
end
|
||||
|
||||
def round(input, n = 0)
|
||||
result = to_number(input).round(to_number(n))
|
||||
result = result.to_f if result.is_a?(BigDecimal)
|
||||
result = result.to_i if n == 0
|
||||
result
|
||||
end
|
||||
|
||||
def ceil(input)
|
||||
to_number(input).ceil.to_i
|
||||
end
|
||||
|
||||
def floor(input)
|
||||
to_number(input).floor.to_i
|
||||
end
|
||||
|
||||
def default(input, default_value = "".freeze)
|
||||
is_blank = input.respond_to?(:empty?) ? input.empty? : !input
|
||||
is_blank ? default_value : input
|
||||
@@ -293,6 +289,23 @@ module Liquid
|
||||
end
|
||||
end
|
||||
|
||||
def to_date(obj)
|
||||
return obj if obj.respond_to?(:strftime)
|
||||
|
||||
case obj
|
||||
when 'now'.freeze, 'today'.freeze
|
||||
Time.now
|
||||
when /\A\d+\z/, Integer
|
||||
Time.at(obj.to_i)
|
||||
when String
|
||||
Time.parse(obj)
|
||||
else
|
||||
nil
|
||||
end
|
||||
rescue ArgumentError
|
||||
nil
|
||||
end
|
||||
|
||||
def apply_operation(input, operand, operation)
|
||||
result = to_number(input).send(operation, to_number(operand))
|
||||
result.is_a?(BigDecimal) ? result.to_f : result
|
||||
|
||||
@@ -22,6 +22,12 @@ module Liquid
|
||||
@@file_system = BlankFileSystem.new
|
||||
|
||||
class << self
|
||||
# Sets how strict the parser should be.
|
||||
# :lax acts like liquid 2.5 and silently ignores malformed tags in most cases.
|
||||
# :warn is the default and will give deprecation warnings when invalid syntax is used.
|
||||
# :strict will enforce correct syntax.
|
||||
attr_writer :error_mode
|
||||
|
||||
def file_system
|
||||
@@file_system
|
||||
end
|
||||
@@ -38,14 +44,6 @@ module Liquid
|
||||
@tags ||= {}
|
||||
end
|
||||
|
||||
# Sets how strict the parser should be.
|
||||
# :lax acts like liquid 2.5 and silently ignores malformed tags in most cases.
|
||||
# :warn is the default and will give deprecation warnings when invalid syntax is used.
|
||||
# :strict will enforce correct syntax.
|
||||
def error_mode=(mode)
|
||||
@error_mode = mode
|
||||
end
|
||||
|
||||
def error_mode
|
||||
@error_mode || :lax
|
||||
end
|
||||
@@ -60,7 +58,6 @@ module Liquid
|
||||
def parse(source, options = {})
|
||||
template = Template.new
|
||||
template.parse(source, options)
|
||||
template
|
||||
end
|
||||
end
|
||||
|
||||
@@ -114,7 +111,9 @@ module Liquid
|
||||
|
||||
context = case args.first
|
||||
when Liquid::Context
|
||||
args.shift
|
||||
c = args.shift
|
||||
c.rethrow_errors = true if @rethrow_errors
|
||||
c
|
||||
when Liquid::Drop
|
||||
drop = args.shift
|
||||
drop.context = Context.new([drop, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits)
|
||||
@@ -157,7 +156,8 @@ module Liquid
|
||||
end
|
||||
|
||||
def render!(*args)
|
||||
@rethrow_errors = true; render(*args)
|
||||
@rethrow_errors = true
|
||||
render(*args)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -26,5 +26,4 @@ Gem::Specification.new do |s|
|
||||
|
||||
s.add_development_dependency 'stackprof' if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.1.0")
|
||||
s.add_development_dependency 'rake'
|
||||
s.add_development_dependency 'activesupport'
|
||||
end
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
require 'rubygems'
|
||||
require 'benchmark'
|
||||
require File.dirname(__FILE__) + '/theme_runner'
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
require 'yaml'
|
||||
module Database
|
||||
|
||||
module Database
|
||||
# Load the standard vision toolkit database and re-arrage it to be simply exportable
|
||||
# to liquid as assigns. All this is based on Shopify
|
||||
def self.tables
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
require 'json'
|
||||
|
||||
module JsonFilter
|
||||
|
||||
def json(object)
|
||||
object.reject {|k,v| k == "collections" }.to_json
|
||||
JSON.dump(object.reject {|k,v| k == "collections" })
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -6,11 +6,6 @@
|
||||
# Shopify which is likely the biggest user of liquid in the world which something to the tune of several
|
||||
# million Template#render calls a day.
|
||||
|
||||
require 'rubygems'
|
||||
require 'active_support'
|
||||
require 'active_support/json'
|
||||
require 'yaml'
|
||||
require 'digest/md5'
|
||||
require File.dirname(__FILE__) + '/shopify/liquid'
|
||||
require File.dirname(__FILE__) + '/shopify/database.rb'
|
||||
|
||||
@@ -81,6 +76,3 @@ class ThemeRunner
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
23
test/integration/context_test.rb
Normal file
23
test/integration/context_test.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
require 'test_helper'
|
||||
|
||||
class ContextTest < Test::Unit::TestCase
|
||||
include Liquid
|
||||
|
||||
def test_override_global_filter
|
||||
global = Module.new do
|
||||
def notice(output)
|
||||
"Global #{output}"
|
||||
end
|
||||
end
|
||||
|
||||
local = Module.new do
|
||||
def notice(output)
|
||||
"Local #{output}"
|
||||
end
|
||||
end
|
||||
|
||||
Template.register_filter(global)
|
||||
assert_equal 'Global test', Template.parse("{{'test' | notice }}").render!
|
||||
assert_equal 'Local test', Template.parse("{{'test' | notice }}").render!({}, :filters => [local])
|
||||
end
|
||||
end
|
||||
@@ -3,12 +3,9 @@ require 'test_helper'
|
||||
class ParsingQuirksTest < Test::Unit::TestCase
|
||||
include Liquid
|
||||
|
||||
def test_error_with_css
|
||||
text = %| div { font-weight: bold; } |
|
||||
template = Template.parse(text)
|
||||
|
||||
assert_equal text, template.render!
|
||||
assert_equal [String], template.root.nodelist.collect {|i| i.class}
|
||||
def test_parsing_css
|
||||
text = " div { font-weight: bold; } "
|
||||
assert_equal text, Template.parse(text).render!
|
||||
end
|
||||
|
||||
def test_raise_on_single_close_bracet
|
||||
@@ -54,10 +54,10 @@ class SecurityTest < Test::Unit::TestCase
|
||||
def test_does_not_add_drop_methods_to_symbol_table
|
||||
current_symbols = Symbol.all_symbols
|
||||
|
||||
drop = Drop.new
|
||||
drop.invoke_drop("custom_method_1")
|
||||
drop.invoke_drop("custom_method_2")
|
||||
drop.invoke_drop("custom_method_3")
|
||||
assigns = { 'drop' => Drop.new }
|
||||
assert_equal "", Template.parse("{{ drop.custom_method_1 }}", assigns).render!
|
||||
assert_equal "", Template.parse("{{ drop.custom_method_2 }}", assigns).render!
|
||||
assert_equal "", Template.parse("{{ drop.custom_method_3 }}", assigns).render!
|
||||
|
||||
assert_equal [], (Symbol.all_symbols - current_symbols)
|
||||
end
|
||||
@@ -115,6 +115,13 @@ class StandardFiltersTest < Test::Unit::TestCase
|
||||
assert_equal [{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], @filters.sort([{"a" => 4}, {"a" => 3}, {"a" => 1}, {"a" => 2}], "a")
|
||||
end
|
||||
|
||||
def test_numerical_vs_lexicographical_sort
|
||||
assert_equal [2, 10], @filters.sort([10, 2])
|
||||
assert_equal [{"a" => 2}, {"a" => 10}], @filters.sort([{"a" => 10}, {"a" => 2}], "a")
|
||||
assert_equal ["10", "2"], @filters.sort(["10", "2"])
|
||||
assert_equal [{"a" => "10"}, {"a" => "2"}], @filters.sort([{"a" => "10"}, {"a" => "2"}], "a")
|
||||
end
|
||||
|
||||
def test_reverse
|
||||
assert_equal [4,3,2,1], @filters.reverse([1,2,3,4])
|
||||
end
|
||||
@@ -186,7 +193,6 @@ class StandardFiltersTest < Test::Unit::TestCase
|
||||
assert_equal "07/05/2006", @filters.date("1152098955", "%m/%d/%Y")
|
||||
end
|
||||
|
||||
|
||||
def test_first_last
|
||||
assert_equal 1, @filters.first([1,2,3])
|
||||
assert_equal 3, @filters.last([1,2,3])
|
||||
@@ -267,6 +273,22 @@ class StandardFiltersTest < Test::Unit::TestCase
|
||||
assert_template_result "1", "{{ 3 | modulo:2 }}"
|
||||
end
|
||||
|
||||
def test_round
|
||||
assert_template_result "5", "{{ input | round }}", 'input' => 4.6
|
||||
assert_template_result "4", "{{ '4.3' | round }}"
|
||||
assert_template_result "4.56", "{{ input | round: 2 }}", 'input' => 4.5612
|
||||
end
|
||||
|
||||
def test_ceil
|
||||
assert_template_result "5", "{{ input | ceil }}", 'input' => 4.6
|
||||
assert_template_result "5", "{{ '4.3' | ceil }}"
|
||||
end
|
||||
|
||||
def test_floor
|
||||
assert_template_result "4", "{{ input | floor }}", 'input' => 4.6
|
||||
assert_template_result "4", "{{ '4.3' | floor }}"
|
||||
end
|
||||
|
||||
def test_append
|
||||
assigns = {'a' => 'bc', 'b' => 'd' }
|
||||
assert_template_result('bcd',"{{ a | append: 'd'}}",assigns)
|
||||
@@ -1,5 +1,11 @@
|
||||
require 'test_helper'
|
||||
|
||||
class ThingWithValue < Liquid::Drop
|
||||
def value
|
||||
3
|
||||
end
|
||||
end
|
||||
|
||||
class ForTagTest < Test::Unit::TestCase
|
||||
include Liquid
|
||||
|
||||
@@ -34,6 +40,20 @@ HERE
|
||||
assert_template_result(' 1 2 3 ','{%for item in (1..3) %} {{item}} {%endfor%}')
|
||||
end
|
||||
|
||||
def test_for_with_variable_range
|
||||
assert_template_result(' 1 2 3 ','{%for item in (1..foobar) %} {{item}} {%endfor%}', "foobar" => 3)
|
||||
end
|
||||
|
||||
def test_for_with_hash_value_range
|
||||
foobar = { "value" => 3 }
|
||||
assert_template_result(' 1 2 3 ','{%for item in (1..foobar.value) %} {{item}} {%endfor%}', "foobar" => foobar)
|
||||
end
|
||||
|
||||
def test_for_with_drop_value_range
|
||||
foobar = ThingWithValue.new
|
||||
assert_template_result(' 1 2 3 ','{%for item in (1..foobar.value) %} {{item}} {%endfor%}', "foobar" => foobar)
|
||||
end
|
||||
|
||||
def test_for_with_variable
|
||||
assert_template_result(' 1 2 3 ','{%for item in array%} {{item}} {%endfor%}','array' => [1,2,3])
|
||||
assert_template_result('123','{%for item in array%}{{item}}{%endfor%}','array' => [1,2,3])
|
||||
@@ -295,16 +315,6 @@ HERE
|
||||
assert_template_result(expected, template, assigns)
|
||||
end
|
||||
|
||||
def test_for_nodelist
|
||||
template = Liquid::Template.parse('{% for item in items %}FOR{% endfor %}')
|
||||
assert_equal ['FOR'], template.root.nodelist[0].nodelist
|
||||
end
|
||||
|
||||
def test_for_else_nodelist
|
||||
template = Liquid::Template.parse('{% for item in items %}FOR{% else %}ELSE{% endfor %}')
|
||||
assert_equal ['FOR', 'ELSE'], template.root.nodelist[0].nodelist
|
||||
end
|
||||
|
||||
class LoaderDrop < Liquid::Drop
|
||||
attr_accessor :each_called, :load_slice_called
|
||||
|
||||
@@ -158,14 +158,9 @@ class IfElseTagTest < Test::Unit::TestCase
|
||||
%({% if 'gnomeslab-and-or-liquid' contains 'gnomeslab-and-or-liquid' %}yes{% endif %}))
|
||||
end
|
||||
|
||||
def test_if_nodelist
|
||||
template = Liquid::Template.parse('{% if true %}IF{% else %}ELSE{% endif %}')
|
||||
assert_equal ['IF', 'ELSE'], template.root.nodelist[0].nodelist
|
||||
end
|
||||
|
||||
def test_operators_are_whitelisted
|
||||
assert_raise(SyntaxError) do
|
||||
assert_template_result('', %({% if 1 or throw or or 1 %}yes{% endif %}))
|
||||
end
|
||||
end
|
||||
end # IfElseTest
|
||||
end
|
||||
@@ -3,12 +3,6 @@ require 'test_helper'
|
||||
class StandardTagTest < Test::Unit::TestCase
|
||||
include Liquid
|
||||
|
||||
def test_tag
|
||||
tag = Tag.parse('tag', [], [], {})
|
||||
assert_equal 'liquid::tag', tag.name
|
||||
assert_equal '', tag.render(Context.new)
|
||||
end
|
||||
|
||||
def test_no_transform
|
||||
assert_template_result('this text should come out of the template without change...',
|
||||
'this text should come out of the template without change...')
|
||||
@@ -22,29 +22,15 @@ class SomethingWithLength
|
||||
liquid_methods :length
|
||||
end
|
||||
|
||||
class ErroneousDrop < Liquid::Drop
|
||||
def bad_method
|
||||
raise 'ruby error in drop'
|
||||
end
|
||||
end
|
||||
|
||||
class TemplateTest < Test::Unit::TestCase
|
||||
include Liquid
|
||||
|
||||
def test_tokenize_strings
|
||||
assert_equal [' '], Template.new.send(:tokenize, ' ')
|
||||
assert_equal ['hello world'], Template.new.send(:tokenize, 'hello world')
|
||||
end
|
||||
|
||||
def test_tokenize_variables
|
||||
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 }}', ' '], Template.new.send(:tokenize, ' {{ funk }} ')
|
||||
end
|
||||
|
||||
def test_tokenize_blocks
|
||||
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 %} ")
|
||||
end
|
||||
|
||||
def test_instance_assigns_persist_on_same_template_object_between_parses
|
||||
t = Template.new
|
||||
assert_equal 'from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render!
|
||||
@@ -158,17 +144,13 @@ class TemplateTest < Test::Unit::TestCase
|
||||
assert_equal 'haha', t.parse("{{baz}}").render!(drop)
|
||||
end
|
||||
|
||||
def test_sets_default_localization_in_document
|
||||
t = Template.new
|
||||
t.parse('')
|
||||
assert_instance_of I18n, t.root.options[:locale]
|
||||
end
|
||||
def test_render_bang_force_rethrow_errors_on_passed_context
|
||||
context = Context.new({'drop' => ErroneousDrop.new})
|
||||
t = Template.new.parse('{{ drop.bad_method }}')
|
||||
|
||||
def test_sets_default_localization_in_context_with_quick_initialization
|
||||
t = Template.new
|
||||
t.parse('{{foo}}', :locale => I18n.new(fixture("en_locale.yml")))
|
||||
|
||||
assert_instance_of I18n, t.root.options[:locale]
|
||||
assert_equal fixture("en_locale.yml"), t.root.options[:locale].path
|
||||
e = assert_raises RuntimeError do
|
||||
t.render!(context)
|
||||
end
|
||||
assert_equal 'ruby error in drop', e.message
|
||||
end
|
||||
end
|
||||
72
test/integration/variable_test.rb
Normal file
72
test/integration/variable_test.rb
Normal file
@@ -0,0 +1,72 @@
|
||||
require 'test_helper'
|
||||
|
||||
class VariableTest < Test::Unit::TestCase
|
||||
include Liquid
|
||||
|
||||
def test_simple_variable
|
||||
template = Template.parse(%|{{test}}|)
|
||||
assert_equal 'worked', template.render!('test' => 'worked')
|
||||
assert_equal 'worked wonderfully', template.render!('test' => 'worked wonderfully')
|
||||
end
|
||||
|
||||
def test_simple_with_whitespaces
|
||||
template = Template.parse(%| {{ test }} |)
|
||||
assert_equal ' worked ', template.render!('test' => 'worked')
|
||||
assert_equal ' worked wonderfully ', template.render!('test' => 'worked wonderfully')
|
||||
end
|
||||
|
||||
def test_ignore_unknown
|
||||
template = Template.parse(%|{{ test }}|)
|
||||
assert_equal '', template.render!
|
||||
end
|
||||
|
||||
def test_hash_scoping
|
||||
template = Template.parse(%|{{ test.test }}|)
|
||||
assert_equal 'worked', template.render!('test' => {'test' => 'worked'})
|
||||
end
|
||||
|
||||
def test_false_renders_as_false
|
||||
assert_equal 'false', Template.parse("{{ foo }}").render!('foo' => false)
|
||||
end
|
||||
|
||||
def test_preset_assigns
|
||||
template = Template.parse(%|{{ test }}|)
|
||||
template.assigns['test'] = 'worked'
|
||||
assert_equal 'worked', template.render!
|
||||
end
|
||||
|
||||
def test_reuse_parsed_template
|
||||
template = Template.parse(%|{{ greeting }} {{ name }}|)
|
||||
template.assigns['greeting'] = 'Goodbye'
|
||||
assert_equal 'Hello Tobi', template.render!('greeting' => 'Hello', 'name' => 'Tobi')
|
||||
assert_equal 'Hello ', template.render!('greeting' => 'Hello', 'unknown' => 'Tobi')
|
||||
assert_equal 'Hello Brian', template.render!('greeting' => 'Hello', 'name' => 'Brian')
|
||||
assert_equal 'Goodbye Brian', template.render!('name' => 'Brian')
|
||||
assert_equal({'greeting'=>'Goodbye'}, template.assigns)
|
||||
end
|
||||
|
||||
def test_assigns_not_polluted_from_template
|
||||
template = Template.parse(%|{{ test }}{% assign test = 'bar' %}{{ test }}|)
|
||||
template.assigns['test'] = 'baz'
|
||||
assert_equal 'bazbar', template.render!
|
||||
assert_equal 'bazbar', template.render!
|
||||
assert_equal 'foobar', template.render!('test' => 'foo')
|
||||
assert_equal 'bazbar', template.render!
|
||||
end
|
||||
|
||||
def test_hash_with_default_proc
|
||||
template = Template.parse(%|Hello {{ test }}|)
|
||||
assigns = Hash.new { |h,k| raise "Unknown variable '#{k}'" }
|
||||
assigns['test'] = 'Tobi'
|
||||
assert_equal 'Hello Tobi', template.render!(assigns)
|
||||
assigns.delete('test')
|
||||
e = assert_raises(RuntimeError) {
|
||||
template.render!(assigns)
|
||||
}
|
||||
assert_equal "Unknown variable 'test'", e.message
|
||||
end
|
||||
|
||||
def test_multiline_variable
|
||||
assert_equal 'worked', Template.parse("{{\ntest\n}}").render!('test' => 'worked')
|
||||
end
|
||||
end
|
||||
@@ -1,6 +1,6 @@
|
||||
require 'test_helper'
|
||||
|
||||
class BlockTest < Test::Unit::TestCase
|
||||
class BlockUnitTest < Test::Unit::TestCase
|
||||
include Liquid
|
||||
|
||||
def test_blankspace
|
||||
@@ -1,6 +1,6 @@
|
||||
require 'test_helper'
|
||||
|
||||
class ConditionTest < Test::Unit::TestCase
|
||||
class ConditionUnitTest < Test::Unit::TestCase
|
||||
include Liquid
|
||||
|
||||
def test_basic_condition
|
||||
@@ -63,7 +63,7 @@ class ArrayLike
|
||||
end
|
||||
end
|
||||
|
||||
class ContextTest < Test::Unit::TestCase
|
||||
class ContextUnitTest < Test::Unit::TestCase
|
||||
include Liquid
|
||||
|
||||
def setup
|
||||
@@ -162,24 +162,6 @@ class ContextTest < Test::Unit::TestCase
|
||||
|
||||
end
|
||||
|
||||
def test_override_global_filter
|
||||
global = Module.new do
|
||||
def notice(output)
|
||||
"Global #{output}"
|
||||
end
|
||||
end
|
||||
|
||||
local = Module.new do
|
||||
def notice(output)
|
||||
"Local #{output}"
|
||||
end
|
||||
end
|
||||
|
||||
Template.register_filter(global)
|
||||
assert_equal 'Global test', Template.parse("{{'test' | notice }}").render!
|
||||
assert_equal 'Local test', Template.parse("{{'test' | notice }}").render!({}, :filters => [local])
|
||||
end
|
||||
|
||||
def test_only_intended_filters_make_it_there
|
||||
|
||||
filter = Module.new do
|
||||
@@ -475,4 +457,22 @@ class ContextTest < Test::Unit::TestCase
|
||||
assert_kind_of CategoryDrop, @context['category']
|
||||
assert_equal @context, @context['category'].context
|
||||
end
|
||||
|
||||
def test_strict_variables_not_found
|
||||
with_error_mode(:strict) do
|
||||
@context['does_not_exist']
|
||||
assert(@context.errors.length == 1)
|
||||
assert_equal(@context.errors[0], 'Variable {{does_not_exist}} not found')
|
||||
end
|
||||
end
|
||||
|
||||
def test_strict_nested_variables_not_found
|
||||
with_error_mode(:strict) do
|
||||
@context['hash'] = {'this' => 'exists'}
|
||||
@context['hash.does_not_exist']
|
||||
assert(@context.errors.length == 1)
|
||||
assert_equal(@context.errors[0], 'Variable {{hash.does_not_exist}} not found')
|
||||
end
|
||||
end
|
||||
|
||||
end # ContextTest
|
||||
@@ -1,6 +1,6 @@
|
||||
require 'test_helper'
|
||||
|
||||
class FileSystemTest < Test::Unit::TestCase
|
||||
class FileSystemUnitTest < Test::Unit::TestCase
|
||||
include Liquid
|
||||
|
||||
def test_default
|
||||
@@ -1,6 +1,6 @@
|
||||
require 'test_helper'
|
||||
|
||||
class I18nTest < Test::Unit::TestCase
|
||||
class I18nUnitTest < Test::Unit::TestCase
|
||||
include Liquid
|
||||
|
||||
def setup
|
||||
@@ -1,6 +1,6 @@
|
||||
require 'test_helper'
|
||||
|
||||
class LexerTest < Test::Unit::TestCase
|
||||
class LexerUnitTest < Test::Unit::TestCase
|
||||
include Liquid
|
||||
|
||||
def test_strings
|
||||
@@ -36,7 +36,7 @@ class TestClassC::LiquidDropClass
|
||||
end
|
||||
end
|
||||
|
||||
class ModuleExTest < Test::Unit::TestCase
|
||||
class ModuleExUnitTest < Test::Unit::TestCase
|
||||
include Liquid
|
||||
|
||||
def setup
|
||||
@@ -1,6 +1,6 @@
|
||||
require 'test_helper'
|
||||
|
||||
class ParserTest < Test::Unit::TestCase
|
||||
class ParserUnitTest < Test::Unit::TestCase
|
||||
include Liquid
|
||||
|
||||
def test_consume
|
||||
@@ -1,6 +1,6 @@
|
||||
require 'test_helper'
|
||||
|
||||
class RegexpTest < Test::Unit::TestCase
|
||||
class RegexpUnitTest < Test::Unit::TestCase
|
||||
include Liquid
|
||||
|
||||
def test_empty
|
||||
@@ -1,6 +1,6 @@
|
||||
require 'test_helper'
|
||||
|
||||
class StrainerTest < Test::Unit::TestCase
|
||||
class StrainerUnitTest < Test::Unit::TestCase
|
||||
include Liquid
|
||||
|
||||
module AccessScopeFilters
|
||||
11
test/unit/tag_unit_test.rb
Normal file
11
test/unit/tag_unit_test.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
require 'test_helper'
|
||||
|
||||
class TagUnitTest < Test::Unit::TestCase
|
||||
include Liquid
|
||||
|
||||
def test_tag
|
||||
tag = Tag.parse('tag', [], [], {})
|
||||
assert_equal 'liquid::tag', tag.name
|
||||
assert_equal '', tag.render(Context.new)
|
||||
end
|
||||
end
|
||||
@@ -1,10 +1,10 @@
|
||||
require 'test_helper'
|
||||
|
||||
class CaseTagTest < Test::Unit::TestCase
|
||||
class CaseTagUnitTest < Test::Unit::TestCase
|
||||
include Liquid
|
||||
|
||||
def test_case_nodelist
|
||||
template = Liquid::Template.parse('{% case var %}{% when true %}WHEN{% else %}ELSE{% endcase %}')
|
||||
assert_equal ['WHEN', 'ELSE'], template.root.nodelist[0].nodelist
|
||||
end
|
||||
end # CaseTest
|
||||
end
|
||||
13
test/unit/tags/for_tag_unit_test.rb
Normal file
13
test/unit/tags/for_tag_unit_test.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
require 'test_helper'
|
||||
|
||||
class ForTagUnitTest < Test::Unit::TestCase
|
||||
def test_for_nodelist
|
||||
template = Liquid::Template.parse('{% for item in items %}FOR{% endfor %}')
|
||||
assert_equal ['FOR'], template.root.nodelist[0].nodelist
|
||||
end
|
||||
|
||||
def test_for_else_nodelist
|
||||
template = Liquid::Template.parse('{% for item in items %}FOR{% else %}ELSE{% endfor %}')
|
||||
assert_equal ['FOR', 'ELSE'], template.root.nodelist[0].nodelist
|
||||
end
|
||||
end
|
||||
8
test/unit/tags/if_tag_unit_test.rb
Normal file
8
test/unit/tags/if_tag_unit_test.rb
Normal file
@@ -0,0 +1,8 @@
|
||||
require 'test_helper'
|
||||
|
||||
class IfTagUnitTest < Test::Unit::TestCase
|
||||
def test_if_nodelist
|
||||
template = Liquid::Template.parse('{% if true %}IF{% else %}ELSE{% endif %}')
|
||||
assert_equal ['IF', 'ELSE'], template.root.nodelist[0].nodelist
|
||||
end
|
||||
end
|
||||
19
test/unit/template_unit_test.rb
Normal file
19
test/unit/template_unit_test.rb
Normal file
@@ -0,0 +1,19 @@
|
||||
require 'test_helper'
|
||||
|
||||
class TemplateUnitTest < Test::Unit::TestCase
|
||||
include Liquid
|
||||
|
||||
def test_sets_default_localization_in_document
|
||||
t = Template.new
|
||||
t.parse('')
|
||||
assert_instance_of I18n, t.root.options[:locale]
|
||||
end
|
||||
|
||||
def test_sets_default_localization_in_context_with_quick_initialization
|
||||
t = Template.new
|
||||
t.parse('{{foo}}', :locale => I18n.new(fixture("en_locale.yml")))
|
||||
|
||||
assert_instance_of I18n, t.root.options[:locale]
|
||||
assert_equal fixture("en_locale.yml"), t.root.options[:locale].path
|
||||
end
|
||||
end
|
||||
29
test/unit/tokenizer_unit_test.rb
Normal file
29
test/unit/tokenizer_unit_test.rb
Normal file
@@ -0,0 +1,29 @@
|
||||
require 'test_helper'
|
||||
|
||||
class TokenizerTest < Test::Unit::TestCase
|
||||
def test_tokenize_strings
|
||||
assert_equal [' '], tokenize(' ')
|
||||
assert_equal ['hello world'], tokenize('hello world')
|
||||
end
|
||||
|
||||
def test_tokenize_variables
|
||||
assert_equal ['{{funk}}'], tokenize('{{funk}}')
|
||||
assert_equal [' ', '{{funk}}', ' '], tokenize(' {{funk}} ')
|
||||
assert_equal [' ', '{{funk}}', ' ', '{{so}}', ' ', '{{brother}}', ' '], tokenize(' {{funk}} {{so}} {{brother}} ')
|
||||
assert_equal [' ', '{{ funk }}', ' '], tokenize(' {{ funk }} ')
|
||||
end
|
||||
|
||||
def test_tokenize_blocks
|
||||
assert_equal ['{%comment%}'], tokenize('{%comment%}')
|
||||
assert_equal [' ', '{%comment%}', ' '], tokenize(' {%comment%} ')
|
||||
|
||||
assert_equal [' ', '{%comment%}', ' ', '{%endcomment%}', ' '], tokenize(' {%comment%} {%endcomment%} ')
|
||||
assert_equal [' ', '{% comment %}', ' ', '{% endcomment %}', ' '], tokenize(" {% comment %} {% endcomment %} ")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def tokenize(source)
|
||||
Liquid::Template.new.send(:tokenize, source)
|
||||
end
|
||||
end
|
||||
@@ -1,6 +1,6 @@
|
||||
require 'test_helper'
|
||||
|
||||
class VariableTest < Test::Unit::TestCase
|
||||
class VariableUnitTest < Test::Unit::TestCase
|
||||
include Liquid
|
||||
|
||||
def test_variable
|
||||
@@ -134,71 +134,3 @@ class VariableTest < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class VariableResolutionTest < Test::Unit::TestCase
|
||||
include Liquid
|
||||
|
||||
def test_simple_variable
|
||||
template = Template.parse(%|{{test}}|)
|
||||
assert_equal 'worked', template.render!('test' => 'worked')
|
||||
assert_equal 'worked wonderfully', template.render!('test' => 'worked wonderfully')
|
||||
end
|
||||
|
||||
def test_simple_with_whitespaces
|
||||
template = Template.parse(%| {{ test }} |)
|
||||
assert_equal ' worked ', template.render!('test' => 'worked')
|
||||
assert_equal ' worked wonderfully ', template.render!('test' => 'worked wonderfully')
|
||||
end
|
||||
|
||||
def test_ignore_unknown
|
||||
template = Template.parse(%|{{ test }}|)
|
||||
assert_equal '', template.render!
|
||||
end
|
||||
|
||||
def test_hash_scoping
|
||||
template = Template.parse(%|{{ test.test }}|)
|
||||
assert_equal 'worked', template.render!('test' => {'test' => 'worked'})
|
||||
end
|
||||
|
||||
def test_preset_assigns
|
||||
template = Template.parse(%|{{ test }}|)
|
||||
template.assigns['test'] = 'worked'
|
||||
assert_equal 'worked', template.render!
|
||||
end
|
||||
|
||||
def test_reuse_parsed_template
|
||||
template = Template.parse(%|{{ greeting }} {{ name }}|)
|
||||
template.assigns['greeting'] = 'Goodbye'
|
||||
assert_equal 'Hello Tobi', template.render!('greeting' => 'Hello', 'name' => 'Tobi')
|
||||
assert_equal 'Hello ', template.render!('greeting' => 'Hello', 'unknown' => 'Tobi')
|
||||
assert_equal 'Hello Brian', template.render!('greeting' => 'Hello', 'name' => 'Brian')
|
||||
assert_equal 'Goodbye Brian', template.render!('name' => 'Brian')
|
||||
assert_equal({'greeting'=>'Goodbye'}, template.assigns)
|
||||
end
|
||||
|
||||
def test_assigns_not_polluted_from_template
|
||||
template = Template.parse(%|{{ test }}{% assign test = 'bar' %}{{ test }}|)
|
||||
template.assigns['test'] = 'baz'
|
||||
assert_equal 'bazbar', template.render!
|
||||
assert_equal 'bazbar', template.render!
|
||||
assert_equal 'foobar', template.render!('test' => 'foo')
|
||||
assert_equal 'bazbar', template.render!
|
||||
end
|
||||
|
||||
def test_hash_with_default_proc
|
||||
template = Template.parse(%|Hello {{ test }}|)
|
||||
assigns = Hash.new { |h,k| raise "Unknown variable '#{k}'" }
|
||||
assigns['test'] = 'Tobi'
|
||||
assert_equal 'Hello Tobi', template.render!(assigns)
|
||||
assigns.delete('test')
|
||||
e = assert_raises(RuntimeError) {
|
||||
template.render!(assigns)
|
||||
}
|
||||
assert_equal "Unknown variable 'test'", e.message
|
||||
end
|
||||
|
||||
def test_multiline_variable
|
||||
assert_equal 'worked', Template.parse("{{\ntest\n}}").render!('test' => 'worked')
|
||||
end
|
||||
end # VariableTest
|
||||
Reference in New Issue
Block a user