Twig.js Control Structures ->

if tag ->

should parse the contents of the if block if the expression is true

var test_template = twig({data: '{% if test %}true{% endif%}'});
test_template.render({test: true}).should.equal("true" );
test_template.render({test: false}).should.equal("" );
should call the if or else blocks based on the expression result

var test_template = twig({data: '{% if test %}true{% endif%}'});
test_template.render({test: true}).should.equal("true" );
test_template.render({test: false}).should.equal("" );
should support elseif

var test_template = twig({data: '{% if test %}1{% elseif other %}2{%else%}3{% endif%}'});
test_template.render({test: true, other:false}).should.equal("1" );
test_template.render({test: true, other:true}).should.equal("1" );
test_template.render({test: false, other:true}).should.equal("2" );
test_template.render({test: false, other:false}).should.equal("3" );
should be able to nest

var test_template = twig({data: '{% if test %}{% if test2 %}true{% else %}false{% endif%}{% else %}not{% endif%}'});
test_template.render({test: true, test2: true}).should.equal("true" );
test_template.render({test: true, test2: false}).should.equal("false" );
test_template.render({test: false, test2: true}).should.equal("not" );
test_template.render({test: false, test2: false}).should.equal("not" );

for tag ->

should provide value only for array input

var test_template = twig({data: '{% for value in test %}{{ value }}{% endfor %}'});
test_template.render({test: [1,2,3,4]}).should.equal("1234" );
test_template.render({test: []}).should.equal("" );
should provide both key and value for array input

var test_template = twig({data: '{% for key,value in test %}{{key}}:{{ value }}{% endfor %}'});
test_template.render({test: [1,2,3,4]}).should.equal("0:11:22:33:4" );
test_template.render({test: []}).should.equal("" );
should provide value only for object input

var test_template = twig({data: '{% for value in test %}{{ value }}{% endfor %}'});
test_template.render({test: {one: 1, two: 2, three: 3}}).should.equal("123" );
test_template.render({test: {}}).should.equal("" );
should provide both key and value for object input

var test_template = twig({data: '{% for key, value in test %}{{key}}:{{ value }}{% endfor %}'});
test_template.render({test: {one: 1, two: 2, three: 3}}).should.equal("one:1two:2three:3" );
test_template.render({test: {}}).should.equal("" );
should support else if the input is empty

var test_template = twig({data: '{% for key,value in test %}{{ value }}{% else %}else{% endfor %}'});
test_template.render({test: [1,2,3,4]}).should.equal("1234" );
test_template.render({test: []}).should.equal("else" );
should be able to nest

var test_template = twig({data: '{% for key,list in test %}{% for val in list %}{{ val }}{%endfor %}.{% else %}else{% endfor %}'});
test_template.render({test: [[1,2],[3,4],[5,6]]}).should.equal("12.34.56." );
test_template.render({test: []}).should.equal("else" );
should have a loop context item available

var test_template = twig({data: '{% for key,value in test %}{{ loop.index }}{% endfor %}'});
test_template.render({test: [1,2,3,4]}).should.equal("1234" );
test_template = twig({data: '{% for key,value in test %}{{ loop.index0 }}{% endfor %}'});
test_template.render({test: [1,2,3,4]}).should.equal("0123" );
test_template = twig({data: '{% for key,value in test %}{{ loop.revindex }}{% endfor %}'});
test_template.render({test: [1,2,3,4]}).should.equal("4321" );
test_template = twig({data: '{% for key,value in test %}{{ loop.revindex0 }}{% endfor %}'});
test_template.render({test: [1,2,3,4]}).should.equal("3210" );
test_template = twig({data: '{% for key,value in test %}{{ loop.length }}{% endfor %}'});
test_template.render({test: [1,2,3,4]}).should.equal("4444" );
test_template = twig({data: '{% for key,value in test %}{{ loop.first }}{% endfor %}'});
test_template.render({test: [1,2,3,4]}).should.equal("truefalsefalsefalse" );
test_template = twig({data: '{% for key,value in test %}{{ loop.last }}{% endfor %}'});
test_template.render({test: [1,2,3,4]}).should.equal("falsefalsefalsetrue" );

Twig.js Core ->

should save and load a template by reference


        // Define and save a template
        twig({
            id:   'test',
            data: '{{ "test" }}'
        });

        // Load and render the template
        twig({ref: 'test'}).render()
                .should.equal("test");
should be able to parse output tags with tag ends in strings

// Really all we care about here is not throwing exceptions.
twig({data: '{{ "test" }}'}).render().should.equal("test");
twig({data: '{{ " }} " }}'}).render().should.equal(" }} ");
twig({data: '{{ " \\"}} " }}'}).render().should.equal(' "}} ');
twig({data: "{{ ' }} ' }}"}).render().should.equal(" }} ");
twig({data: "{{ ' \\'}} ' }}"}).render().should.equal(" '}} ");

twig({data: '{{ " \'}} " }}'}).render().should.equal(" '}} ");
twig({data: "{{ ' \"}} ' }}"}).render().should.equal(' "}} ');
should be able to output numbers

twig({data: '{{ 12 }}'}).render().should.equal( "12" );
twig({data: '{{ 12.64 }}'}).render().should.equal( "12.64" );
twig({data: '{{ 0.64 }}'}).render().should.equal("0.64" );
should be able to output booleans

twig({data: '{{ true }}'}).render().should.equal( "true" );
twig({data: '{{ false }}'}).render().should.equal( "false" );
should be able to output strings

twig({data: '{{ "double" }}'}).render().should.equal("double");
twig({data: "{{ 'single' }}"}).render().should.equal('single');
twig({data: '{{ "dou\'ble" }}'}).render().should.equal("dou'ble");
twig({data: "{{ 'sin\"gle' }}"}).render().should.equal('sin"gle');
twig({data: '{{ "dou\\"ble" }}'}).render().should.equal("dou\"ble");
twig({data: "{{ 'sin\\'gle' }}"}).render().should.equal("sin'gle");
should be able to output arrays

twig({data: '{{ [1] }}'}).render().should.equal("1" );
twig({data: '{{ [1,2 ,3 ] }}'}).render().should.equal("1,2,3" );
twig({data: '{{ [1,2 ,3 , val ] }}'}).render({val: 4}).should.equal("1,2,3,4" );
twig({data: '{{ ["[to",\'the\' ,"string]" ] }}'}).render().should.equal('[to,the,string]' );
twig({data: '{{ ["[to",\'the\' ,"str\\"ing]" ] }}'}).render().should.equal('[to,the,str"ing]' );
should be able to output parse expressions in an array

twig({data: '{{ [1,2 ,1+2 ] }}'}).render().should.equal("1,2,3" );
twig({data: '{{ [1,2 ,3 , "-", [4,5, 6] ] }}'}).render({val: 4}).should.equal("1,2,3,-,4,5,6" );
twig({data: '{{ [a,b ,(1+2) * a ] }}'}).render({a:1,b:2}).should.equal("1,2,3" );
should be able to output variables

twig({data: '{{ orp }}'}).render({ orp: "test"}).should.equal("test");
twig({data: '{{ val }}'}).render({ val: function() {
                                              return "test"
                                          }}).should.equal("test");

Twig.js Expressions ->

Basic Operators ->

should support dot key notation

var test_template = twig({data: '{{ key.value }} {{ key.sub.test }}'});
var output = test_template.render({
    key: {
        value: "test",
        sub: {
            test: "value"
        }
    }
});
output.should.equal("test value");
should support square bracket key notation

var test_template = twig({data: '{{ key["value"] }} {{ key[\'sub\']["test"] }}'});
var output = test_template.render({
    key: {
        value: "test",
        sub: {
            test: "value"
        }
    }
});
output.should.equal("test value");
should support mixed dot and bracket key notation

var test_template = twig({data: '{{ key["value"] }} {{ key.sub[key.value] }} {{ s.t["u"].v["w"] }}'});
var output = test_template.render({
    key: {
        value: "test",
        sub: {
            test: "value"
        }
    },
    s: { t: { u: { v: { w: 'x' } } } }
});
output.should.equal("test value x" );
should add numbers

var test_template = twig({data: '{{ a + b }}'});
numeric_test_data.forEach(function(pair) {
    var output = test_template.render(pair);
    output.should.equal( (pair.a + pair.b).toString() );
});
should subtract numbers

var test_template = twig({data: '{{ a - b }}'});
numeric_test_data.forEach(function(pair) {
    var output = test_template.render(pair);
    output.should.equal( (pair.a - pair.b).toString() );
});
should multiply numbers

var test_template = twig({data: '{{ a * b }}'});
numeric_test_data.forEach(function(pair) {
    var output = test_template.render(pair);
    output.should.equal((pair.a * pair.b).toString() );
});
should divide numbers

var test_template = twig({data: '{{ a / b }}'});
numeric_test_data.forEach(function(pair) {
    var output = test_template.render(pair);
    output.should.equal((pair.a / pair.b).toString() );
});
should divide numbers and return an int result

var test_template = twig({data: '{{ a // b }}'});
numeric_test_data.forEach(function(pair) {
    var output = test_template.render(pair);
    // Get expected truncated result
    var c = parseInt(pair.a/pair.b);

    output.should.equal(c.toString() );
});
should raise numbers to a power

var test_template = twig({data: '{{ a ** b }}'});
var pow_test_data = [
    {a: 2, b:3, c: 8}
    , {a: 4, b:.5, c: 2}
    , {a: 5, b: 1, c: 5}
];
pow_test_data.forEach(function(pair) {
    var output = test_template.render(pair);
    output.should.equal(pair.c.toString() );
});
should concatanate values

twig({data: '{{ "test" ~ a }}'}).render({a:1234}).should.equal("test1234");
twig({data: '{{ a ~ "test" ~ a }}'}).render({a:1234}).should.equal("1234test1234");
twig({data: '{{ "this" ~ "test" }}'}).render({a:1234}).should.equal("thistest");

// Test numbers
var test_template = twig({data: '{{ a ~ b }}'});
numeric_test_data.forEach(function(pair) {
    var output = test_template.render(pair);
    output.should.equal(pair.a.toString() + pair.b.toString());
});
// Test strings
test_template = twig({data: '{{ a ~ b }}'});
string_data.forEach(function(pair) {
    var output = test_template.render(pair);
    output.should.equal(pair.a.toString() + pair.b.toString());
});
should handle multiple chained operations

var data = {a: 4.5, b: 10, c: 12,  d: -0.25, e:0, f: 65,  g: 21, h: -0.0002};
var test_template = twig({data: '{{a/b+c*d-e+f/g*h}}'});
var output = test_template.render(data);
var expected = data.a / data.b + data.c * data.d - data.e + data.f / data.g * data.h;
output.should.equal(expected.toString());
should handle parenthesis in chained operations

var data = {a: 4.5, b: 10, c: 12,  d: -0.25, e:0, f: 65,  g: 21, h: -0.0002};
var test_template = twig({data: '{{a   /(b+c )*d-(e+f)/(g*h)}}'});
var output = test_template.render(data);
var expected = data.a / (data.b + data.c) * data.d - (data.e + data.f) / (data.g * data.h);
output.should.equal(expected.toString());

Comparison Operators ->

should support less then

var test_template = twig({data: '{{ a < b }}'});
numeric_test_data.forEach(function(pair) {
    var output = test_template.render(pair);
    output.should.equal((pair.a < pair.b).toString() );
});
should support less then or equal

var test_template = twig({data: '{{ a <= b }}'});
numeric_test_data.forEach(function(pair) {
    var output = test_template.render(pair);
    output.should.equal((pair.a <= pair.b).toString() );
});
should support greater then

var test_template = twig({data: '{{ a > b }}'});
numeric_test_data.forEach(function(pair) {
    var output = test_template.render(pair);
    output.should.equal((pair.a > pair.b).toString() );
});
should support greater then or equal

var test_template = twig({data: '{{ a >= b }}'});
numeric_test_data.forEach(function(pair) {
    var output = test_template.render(pair);
    output.should.equal((pair.a >= pair.b).toString() );
});
should support equals

var test_template = twig({data: '{{ a == b }}'});
boolean_data.forEach(function(pair) {
    var output = test_template.render(pair);
    output.should.equal((pair.a == pair.b).toString() );
});
equality_data.forEach(function(pair) {
    var output = test_template.render(pair);
    output.should.equal((pair.a == pair.b).toString() );
});
should support not equals

var test_template = twig({data: '{{ a != b }}'});
boolean_data.forEach(function(pair) {
    var output = test_template.render(pair);
    output.should.equal((pair.a != pair.b).toString() );
});
equality_data.forEach(function(pair) {
    var output = test_template.render(pair);
    output.should.equal((pair.a != pair.b).toString() );
});
should support boolean or

var test_template = twig({data: '{{ a || b }}'});
boolean_data.forEach(function(pair) {
    var output = test_template.render(pair);
    output.should.equal((pair.a || pair.b).toString() );
});
test_template = twig({data: '{{ a or b }}'});
boolean_data.forEach(function(pair) {
    var output = test_template.render(pair);
    output.should.equal((pair.a || pair.b).toString() );
});
should support boolean and

var test_template = twig({data: '{{ a && b }}'});
boolean_data.forEach(function(pair) {
    var output = test_template.render(pair);
    output.should.equal((pair.a && pair.b).toString() );
});
test_template = twig({data: '{{ a and b }}'});
boolean_data.forEach(function(pair) {
    var output = test_template.render(pair);
    output.should.equal((pair.a && pair.b).toString() );
});
should support boolean not

var test_template = twig({data: '{{ not a }}'});
test_template.render({a:false}).should.equal(true.toString());
test_template.render({a:true}).should.equal(false.toString());

Other Operators ->

should support the ternary operator

var test_template = twig({data: '{{ a ? b:c }}'})
    , output_t = test_template.render({a: true,  b: "one", c: "two"})
    , output_f = test_template.render({a: false, b: "one", c: "two"});

output_t.should.equal( "one" );
output_f.should.equal( "two" );
should support the ternary operator with objects in it

var test_template2 = twig({data: '{{ (a ? {"a":e+f}:{"a":1}).a }}'})
    , output2 = test_template2.render({a: true, b: false, e: 1, f: 2});

output2.should.equal( "3" );
should support the ternary operator inside objects

var test_template2 = twig({data: '{{ {"b" : a || b ? {"a":e+f}:{"a":1} }.b.a }}'})
    , output2 = test_template2.render({a: false, b: false, e: 1, f: 2});

output2.should.equal( "1" );

Twig.js Filters ->

should chain

var test_template = twig({data: '{{ ["a", "b", "c"]|keys|reverse }}' });
test_template.render().should.equal("2,1,0" );

url_encode ->

should encode URLs

var test_template = twig({data: '{{ "http://google.com/?q=twig.js"|url_encode() }}' });
test_template.render().should.equal("http%3A%2F%2Fgoogle.com%2F%3Fq%3Dtwig.js" );

json_encode ->

should encode strings to json

var test_template = twig({data: '{{ test|json_encode }}' });
test_template.render({test:'value'}).should.equal('"value"' );
should encode numbers to json

var test_template = twig({data: '{{ test|json_encode }}' });
test_template.render({test:21}).should.equal('21' );
should encode arrays to json

var test_template = twig({data: '{{ [1,"b",3]|json_encode }}' });
test_template.render().should.equal('[1,"b",3]' );
should encode objects to json

var test_template = twig({data: '{{ {"a":[1,"b",3]}|json_encode }}' });
test_template.render().should.equal('{"a":[1,"b",3]}' );

upper ->

should convert text to uppercase

var test_template = twig({data: '{{ "hello"|upper }}' });
test_template.render().should.equal("HELLO" );

lower ->

should convert text to lowercase

var test_template = twig({data: '{{ "HELLO"|lower }}' });
test_template.render().should.equal("hello" );

capitalize ->

should capitalize the first word in a string

var test_template = twig({data: '{{ "hello world"|capitalize }}' });
test_template.render().should.equal("Hello world" );

title ->

should capitalize all the words in a string

var test_template = twig({data: '{{ "hello world"|title }}' });
test_template.render().should.equal("Hello World" );

length ->

should determine the length of a string

var test_template = twig({data: '{{ "test"|length }}' });
test_template.render().should.equal("4");
should determine the length of an array

var test_template = twig({data: '{{ [1,2,4,76,"tesrt"]|length }}' });
test_template.render().should.equal("5");
should determine the length of an object

var test_template = twig({data: '{{ {"a": "b", "c": "1", "test": "test"}|length }}' });
test_template.render().should.equal("3");

sort ->

should sort an array

var test_template = twig({data: '{{ [1,5,2,7]|sort }}' });
test_template.render().should.equal("1,2,5,7" );
        
test_template = twig({data: '{{ ["test","abc",2,7]|sort }}' });
test_template.render().should.equal("2,7,abc,test" );
should sort an object

var test_template = twig({data: "{% set obj =  {'c': 1,'d': 5,'t': 2,'e':7}|sort %}{% for key,value in obj|sort %}{{key}}:{{value}} {%endfor %}" });
test_template.render().should.equal("c:1 t:2 d:5 e:7 " );
        
test_template = twig({data: "{% set obj = {'m':'test','z':'abc','a':2,'y':7} %}{% for key,value in obj|sort %}{{key}}:{{value}} {%endfor %}" });
test_template.render().should.equal("a:2 y:7 z:abc m:test " );

reverse ->

should reverse an array

var test_template = twig({data: '{{ ["a", "b", "c"]|reverse }}' });
test_template.render().should.equal("c,b,a" );
should reverse an object

keys ->

should return the keys of an array

var test_template = twig({data: '{{ ["a", "b", "c"]|keys }}' });
test_template.render().should.equal("0,1,2" );
should return the keys of an object

var test_template = twig({data: '{{ {"a": 1, "b": 4, "c": 5}|keys }}' });
test_template.render().should.equal("a,b,c" );

test_template = twig({data: '{{ {"0":"a", "1":"b", "2":"c"}|keys }}' });
test_template.render().should.equal("0,1,2" );

merge ->

should merge two objects into an object

// Object merging
var test_template = twig({data: '{% set obj= {"a":"test", "b":"1"}|merge({"b":2,"c":3}) %}{% for key in obj|keys|sort %}{{key}}:{{obj[key]}} {%endfor %}' });
test_template.render().should.equal('a:test b:2 c:3 ' );
should merge two arrays into and array

// Array merging
var test_template = twig({data: '{% set obj= ["a", "b"]|merge(["c", "d"]) %}{% for key in obj|keys|sort %}{{key}}:{{obj[key]}} {%endfor %}' });
test_template.render().should.equal('0:a 1:b 2:c 3:d ' );
should merge an object and an array into an object

// Mixed merging
var test_template = twig({data: '{% set obj= ["a", "b"]|merge({"a": "c", "3":4}, ["c", "d"]) %}{% for key in obj|keys|sort %}{{key}}:{{obj[key]}} {%endfor %}' });
test_template.render().should.equal('0:a 1:b 3:4 4:c 5:d a:c ' );
        
// Mixed merging(2)
test_template = twig({data: '{% set obj= {"1":"a", "a":"b"}|merge(["c", "d"]) %}{% for key in obj|keys %}{{key}}:{{obj[key]}} {%endfor %}' });
test_template.render().should.equal('1:a a:b 2:c 3:d ' );

join ->

should join all values in an object

var test_template = twig({data: '{{ {"a":"1", "b": "b", "c":test}|join("-") }}' });
test_template.render({"test": "t"}).should.equal("1-b-t" );
should joing all values in an array

var test_template = twig({data: '{{ [1,2,4,76]|join }}' });
test_template.render().should.equal("12476" );
test_template = twig({data: '{{ [1+ 5,2,4,76]|join("-" ~ ".") }}' });
test_template.render().should.equal("6-.2-.4-.76" );

default ->

should not provide the default value if a key is defined and not empty

var test_template = twig({data: '{{ var|default("Not Defined") }}' });
test_template.render({"var":"value"}).should.equal("value" );
should provide a default value if a key is not defined

var test_template = twig({data: '{{ var|default("Not Defined") }}' });
test_template.render().should.equal("Not Defined" );
should provide a default value if a value is empty

var test_template = twig({data: '{{ ""|default("Empty String") }}' });
test_template.render().should.equal("Empty String" );
        
test_template = twig({data: '{{ var.key|default("Empty Key") }}' });
test_template.render({'var':{}}).should.equal("Empty Key" );

date ->

should recognize timestamps

           var template = twig({data: '{{ 27571323556134|date("d/m/Y @ H:i:s") }}'})
               , date = new Date(27571323556134); // 13/09/2843 @ 08:59:16 EST
           
           template.render().should.equal( stringDate(date) );
should recognize string date formats

           var template = twig({data: '{{ "Tue Aug 14 08:52:15 +0000 2007"|date("d/m/Y @ H:i:s") }}'})
               , date = new Date(1187081535000); // 14/08/2007 @ 04:52:15 EST

           template.render().should.equal( stringDate(date) );

replace ->

should replace strings provided in a map

var template = twig({data: '{{ "I like %this% and %that%."|replace({"%this%": foo, "%that%": "bar"}) }}'});
template.render({foo: "foo"}).should.equal("I like foo and bar." );

format ->

should replace formatting tags with parameters

var template = twig({data: '{{ "I like %s and %s."|format(foo, "bar") }}'});
template.render({foo: "foo"}).should.equal("I like foo and bar." );

striptags ->

should remove tags from a value

var template = twig({data: '{{ "<p>Test paragraph.</p><!-- Comment --> <a href=\\"#fragment\\">Other text</a>"|striptags }}'});
template.render().should.equal("Test paragraph. Other text" );

Twig.js Loader ->

should load a template from the filesystem asynchronously

twig({
    id:   'fs-node-async',
    path: 'test/templates/test.twig',
    load: function(template) {
        // Render the template
        template.render({
            test: "yes",
            flag: true
        }).should.equal("Test template = yes\n\nFlag set!");
        
        done();
    }
});
should load a template from the filesystem synchronously

var template = twig({
    id:   'fs-node-sync',
    path: 'test/templates/test.twig',
    async: false
});
// Render the template
template.render({
    test: "yes",
    flag: true
}).should.equal("Test template = yes\n\nFlag set!");

Twig.js Blocks ->

should load a parent template and render the default values

twig({
    id:   'remote-no-extends',
    path: 'test/templates/template.twig',
    async: false
});
    
// Load the template
twig({ref: 'remote-no-extends'}).render({ }).should.equal( "Default Title - body" );
should load a child template and replace the parent block's content

// Test loading a template from a remote endpoint
twig({
    id:   'child-extends',
    path: 'test/templates/child.twig',
            
    load: function(template) {
        template.render({ base: "template.twig" }).should.equal( "Other Title - child" );
        done();
    }
});
should include blocks from another template for horizontal reuse

// Test horizontal reuse
twig({
    id:   'use',
    path: 'test/templates/use.twig',
            
    load: function(template) {
        // Load the template
        template.render({ place: "diner" }).should.equal("Coming soon to a diner near you!" );
        done();
    }
});
should make the contents of blocks available after they're rendered

// Test rendering and loading one block
twig({
    id:   'blocks',
    path: 'test/templates/blocks.twig',

    load: function(template) {
        // Render the template with the blocks parameter
        template.render({ place: "block" }, {output: 'blocks'}).msg.should.equal("Coming soon to a block near you!" );
        done();
    }
});

Twig.js Functions ->

should allow you to define a function

twig({data: '{{ square(a) }}'}).render({a:4}).should.equal("16");
should chain with other expressions

twig({data: '{{ square(a) + 4 }}'}).render({a:4}).should.equal("20");
should chain with filters

twig({data: '{{ echo(a)|default("foo") }}'}).render().should.equal("foo");
should work in for loop expressions

twig({data: '{% for i in list(1, 2, 3) %}{{ i }},{% endfor %}'}).render().should.equal("1,2,3,");
should be able to differentiate between a function and a variable

twig({data: '{{ square ( square ) + square }}'}).render({square: 2}).should.equal("6");
should work with boolean operations

twig({data: '{% if echo(true) or echo(false) %}yes{% endif %}'}).render().should.equal("yes");
should execute functions passed as context values

twig({
    data: '{{ value }}'
}).render({
    value: function() {
        return "test";
    }
}).should.equal("test");
should execute functions passed as context values with this mapped to the context

twig({
    data: '{{ value }}'
}).render({
    test: "value",
    value: function() {
        return this.test;
    }
}).should.equal("value");
should execute functions passed as context values with arguments

twig({
    data: '{{ value(1, "test") }}'
}).render({
    value: function(a, b, c) {
        return a + "-" + b + "-" + (c===undefined?"true":"false");
    }
}).should.equal("1-test-true");
should execute functions passed as context value parameters with this mapped to the context

twig({
    data: '{{ value }}'
}).render({
    test: "value",
    value: function() {
        return this.test;
    }
}).should.equal("value");
should execute functions passed as context object parameters

twig({
    data: '{{ obj.value }}'
}).render({
    obj: {
         value: function() {
            return "test";
        }
    }
}).should.equal("test");
should execute functions passed as context object parameters with arguments

twig({
    data: '{{ obj.value(1, "test") }}'
}).render({
    obj: {
         value: function(a, b, c) {
            return a + "-" + b + "-" + (c===undefined?"true":"false");
        }
    }
}).should.equal("1-test-true");
should execute functions passed as context object parameters

twig({
    data: '{{ obj["value"] }}'
}).render({
    obj: {
         value: function() {
            return "test";
        }
    }
}).should.equal("test");
should execute functions passed as context object parameters with arguments

twig({
    data: '{{ obj["value"](1, "test") }}'
}).render({
    obj: {
         value: function(a, b, c) {
            return a + "-" + b + "-" + (c===undefined?"true":"false");
        }
    }
}).should.equal("1-test-true");

Built-in Functions ->

range ->

should work over a range of numbers

twig({data: '{% for i in range(0, 3) %}{{ i }},{% endfor %}'}).render().should.equal("0,1,2,3,");
should work over a range of letters

twig({data: '{% for i in range("a", "c") %}{{ i }},{% endfor %}'}).render().should.equal("a,b,c,");
should work with an interval

twig({data: '{% for i in range(1, 15, 3) %}{{ i }},{% endfor %}'}).render().should.equal("1,4,7,10,13,");

cycle ->

should cycle through an array of values

twig({data: '{% for i in range(0, 3) %}{{ cycle(["odd", "even"], i) }};{% endfor %}'}).render().should.equal("odd;even;odd;even;");

date ->

should understand timestamps

var date = new Date(946706400 * 1000);
twig({data: '{{ date(946706400)|date("d/m/Y @ H:i:s") }}'}).render().should.equal(stringDate(date));
should understand relative dates

twig({data: '{{ date("+1 day") > date() }}'}).render().should.equal("true");
twig({data: '{{ date("-1 day") > date() }}'}).render().should.equal("false");
should understand exact dates

var date = new Date("June 20, 2010 UTC");
            
twig({data: '{{ date("June 20, 2010 UTC")|date("d/m/Y @ H:i:s") }}'}).render().should.equal(stringDate(date));

Twig.js Tests ->

empty test ->

should identify numbers as not empty

// number
twig({data: '{{ 1 is empty }}'}).render().should.equal("false" );
twig({data: '{{ 0 is empty }}'}).render().should.equal("false" );
should identify empty strings

// String
twig({data: '{{ "" is empty }}'}).render().should.equal("true" );
twig({data: '{{ "test" is empty }}'}).render().should.equal("false" );
should identify empty arrays

// Array
twig({data: '{{ [] is empty }}'}).render().should.equal("true" );
twig({data: '{{ ["1"] is empty }}'}).render().should.equal("false" );
should identify empty objects

// Object
twig({data: '{{ {} is empty }}'}).render().should.equal("true" );
twig({data: '{{ {"a":"b"} is empty }}'}).render().should.equal("false" );
twig({data: '{{ {"a":"b"} is not empty }}'}).render().should.equal("true" );

odd test ->

should identify a number as odd

twig({data: '{{ (1 + 4) is odd }}'}).render().should.equal("true" );
twig({data: '{{ 6 is odd }}'}).render().should.equal("false" );

even test ->

should identify a number as even

twig({data: '{{ (1 + 4) is even }}'}).render().should.equal("false" );
twig({data: '{{ 6 is even }}'}).render().should.equal("true" );

divisibleby test ->

should determine if a number is divisible by the given number

twig({data: '{{ 5 is divisibleby(3) }}'}).render().should.equal("false" );
twig({data: '{{ 6 is divisibleby(3) }}'}).render().should.equal("true" );

defined test ->

should identify a key as defined if it exists in the render context

twig({data: '{{ key is defined }}'}).render().should.equal("false" );
twig({data: '{{ key is defined }}'}).render({key: "test"}).should.equal( "true" );

none test ->

should identify a key as none if it exists in the render context and is null

twig({data: '{{ key is none }}'}).render().should.equal("false");
twig({data: '{{ key is none }}'}).render({key: "test"}).should.equal("false");
twig({data: '{{ key is none }}'}).render({key: null}).should.equal("true");

sameas test ->

should identify the exact same type as true

twig({data: '{{ true is sameas(true) }}'}).render().should.equal("true");
twig({data: '{{ a is sameas(1) }}'}).render({a: 1}).should.equal("true");
twig({data: '{{ a is sameas("test") }}'}).render({a: "test"}).should.equal("true");
twig({data: '{{ a is sameas(true) }}'}).render({a: true}).should.equal("true");
should identify the different types as false

twig({data: '{{ false is sameas(true) }}'}).render().should.equal("false");
twig({data: '{{ true is sameas(1) }}'}).render().should.equal("false");
twig({data: '{{ false is sameas("") }}'}).render().should.equal("false");
twig({data: '{{ a is sameas(1) }}'}).render({a: "1"}).should.equal("false");