diff options
Diffstat (limited to 'node_modules/twig/docs/tests.md')
-rw-r--r-- | node_modules/twig/docs/tests.md | 3567 |
1 files changed, 0 insertions, 3567 deletions
diff --git a/node_modules/twig/docs/tests.md b/node_modules/twig/docs/tests.md deleted file mode 100644 index 5afa1b7..0000000 --- a/node_modules/twig/docs/tests.md +++ /dev/null @@ -1,3567 +0,0 @@ -# TOC - - [Twig.js Blocks ->](#twigjs-blocks--) - - [block function ->](#twigjs-blocks---block-function--) - - [block shorthand ->](#twigjs-blocks---block-shorthand--) - - [Twig.js Control Structures ->](#twigjs-control-structures--) - - [if tag ->](#twigjs-control-structures---if-tag--) - - [for tag ->](#twigjs-control-structures---for-tag--) - - [set tag ->](#twigjs-control-structures---set-tag--) - - [Twig.js Core ->](#twigjs-core--) - - [Key Notation ->](#twigjs-core---key-notation--) - - [Context ->](#twigjs-core---context--) - - [Twig.js Embed ->](#twigjs-embed--) - - [Twig.js Expressions ->](#twigjs-expressions--) - - [Basic Operators ->](#twigjs-expressions---basic-operators--) - - [Comparison Operators ->](#twigjs-expressions---comparison-operators--) - - [Other Operators ->](#twigjs-expressions---other-operators--) - - [Twig.js Extensions ->](#twigjs-extensions--) - - [Twig.js Filters ->](#twigjs-filters--) - - [url_encode ->](#twigjs-filters---url_encode--) - - [json_encode ->](#twigjs-filters---json_encode--) - - [upper ->](#twigjs-filters---upper--) - - [lower ->](#twigjs-filters---lower--) - - [capitalize ->](#twigjs-filters---capitalize--) - - [title ->](#twigjs-filters---title--) - - [length ->](#twigjs-filters---length--) - - [sort ->](#twigjs-filters---sort--) - - [reverse ->](#twigjs-filters---reverse--) - - [keys ->](#twigjs-filters---keys--) - - [merge ->](#twigjs-filters---merge--) - - [join ->](#twigjs-filters---join--) - - [default ->](#twigjs-filters---default--) - - [date ->](#twigjs-filters---date--) - - [replace ->](#twigjs-filters---replace--) - - [format ->](#twigjs-filters---format--) - - [striptags ->](#twigjs-filters---striptags--) - - [escape ->](#twigjs-filters---escape--) - - [e ->](#twigjs-filters---e--) - - [nl2br ->](#twigjs-filters---nl2br--) - - [truncate ->](#twigjs-filters---truncate--) - - [trim ->](#twigjs-filters---trim--) - - [number_format ->](#twigjs-filters---number_format--) - - [slice ->](#twigjs-filters---slice--) - - [abs ->](#twigjs-filters---abs--) - - [first ->](#twigjs-filters---first--) - - [split ->](#twigjs-filters---split--) - - [batch ->](#twigjs-filters---batch--) - - [last ->](#twigjs-filters---last--) - - [raw ->](#twigjs-filters---raw--) - - [round ->](#twigjs-filters---round--) - - [Twig.js Loader ->](#twigjs-loader--) - - [source ->](#twigjs-loader---source--) - - [Twig.js Include ->](#twigjs-include--) - - [Twig.js Functions ->](#twigjs-functions--) - - [Built-in Functions ->](#twigjs-functions---built-in-functions--) - - [range ->](#twigjs-functions---built-in-functions---range--) - - [cycle ->](#twigjs-functions---built-in-functions---cycle--) - - [date ->](#twigjs-functions---built-in-functions---date--) - - [dump ->](#twigjs-functions---built-in-functions---dump--) - - [block ->](#twigjs-functions---built-in-functions---block--) - - [attribute ->](#twigjs-functions---built-in-functions---attribute--) - - [template_from_string ->](#twigjs-functions---built-in-functions---template_from_string--) - - [random ->](#twigjs-functions---built-in-functions---random--) - - [min, max ->](#twigjs-functions---built-in-functions---min-max--) - - [Twig.js Loaders ->](#twigjs-loaders--) - - [custom loader ->](#twigjs-loaders---custom-loader--) - - [Twig.js Macro ->](#twigjs-macro--) - - [Twig.js Namespaces ->](#twigjs-namespaces--) - - [Twig.js Optional Functionality ->](#twigjs-optional-functionality--) - - [Twig.js Parsers ->](#twigjs-parsers--) - - [custom parser ->](#twigjs-parsers---custom-parser--) - - [Twig.js Path ->](#twigjs-path--) - - [relativePath ->](#twigjs-path---relativepath--) - - [url ->](#twigjs-path---relativepath---url--) - - [path ->](#twigjs-path---relativepath---path--) - - [parsePath ->](#twigjs-path---parsepath--) - - [Twig.js Regression Tests ->](#twigjs-regression-tests--) - - [Twig.js Tags ->](#twigjs-tags--) - - [Twig.js Tests ->](#twigjs-tests--) - - [empty test ->](#twigjs-tests---empty-test--) - - [odd test ->](#twigjs-tests---odd-test--) - - [even test ->](#twigjs-tests---even-test--) - - [divisibleby test ->](#twigjs-tests---divisibleby-test--) - - [defined test ->](#twigjs-tests---defined-test--) - - [none test ->](#twigjs-tests---none-test--) - - [sameas test ->](#twigjs-tests---sameas-test--) - - [iterable test ->](#twigjs-tests---iterable-test--) -<a name=""></a> - -<a name="twigjs-blocks--"></a> -# Twig.js Blocks -> -should load a parent template and render the default values. - -```js -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 understand {% endblock title %} syntax. - -```js -twig({ - id: 'endblock-extended-syntax', - path: 'test/templates/blocks-extended-syntax.twig', - async: false -}); -// Load the template -twig({ref: 'endblock-extended-syntax'}).render({ }).should.equal( "This is the only thing." ); -``` - -should load a child template and replace the parent block's content. - -```js -// 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 have access to a parent block content. - -```js -// Test loading a template from a remote endpoint -twig({ - id: 'child-parent', - path: 'test/templates/child-parent.twig', - load: function(template) { - template.render({ - base: "template.twig", - inner: ':value' - }).should.equal( "Other Title - body:value:child" ); - done(); - } -}); -``` - -should include blocks from another template for horizontal reuse. - -```js -// 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 allow overriding of included blocks. - -```js -// Test overriding of included blocks -twig({ - id: 'use-override-block', - path: 'test/templates/use-override-block.twig', - load: function(template) { - // Load the template - template.render({ place: "diner" }).should.equal("Sorry, can't come to a diner today." ); - done(); - } -}); -``` - -should allow overriding of included nested blocks. - -```js -// Test overriding of included blocks -twig({ - id: 'use-override-nested-block', - path: 'test/templates/use-override-nested-block.twig', - load: function(template) { - // Load the template - template.render().should.equal("parent:new-child1:new-child2"); - done(); - } -}); -``` - -should make the contents of blocks available after they're rendered. - -```js -// 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(); - } -}); -``` - -should render nested blocks. - -```js -// Test rendering of blocks within blocks -twig({ - id: 'blocks-nested', - path: 'test/templates/blocks-nested.twig', - load: function(template) { - template.render({ }).should.equal( "parent:child" ) - done(); - } -}) -``` - -should render extended nested blocks. - -```js -// Test rendering of blocks within blocks -twig({ - id: 'child-blocks-nested', - path: 'test/templates/child-blocks-nested.twig', - load: function(template) { - template.render({ base: "template.twig" }).should.equal( "Default Title - parent:child" ); - done(); - } -}) -``` - -should be able to extend to a absolute template path. - -```js -// Test loading a template from a remote endpoint -twig({ - base: 'test/templates', - path: 'test/templates/a/child.twig', - load: function(template) { - template.render({ base: "b/template.twig" }).should.equal( "Other Title - child" ); - done(); - } -}); -``` - -should extends blocks inline. - -```js -twig({ - id: 'inline-parent-template', - data: 'Title: {% block title %}parent{% endblock %}' -}); -twig({ - allowInlineIncludes: true, - data: '{% extends "inline-parent-template" %}{% block title %}child{% endblock %}' -}).render().should.equal("Title: child"); -``` - -<a name="twigjs-blocks---block-function--"></a> -## block function -> -should render block content from an included block. - -```js -twig({ - path: 'test/templates/block-function.twig', - load: function(template) { - template.render({ - base: "block-function-parent.twig", - val: "abcd" - }) - .should.equal( "Child content = abcd / Result: Child content = abcd" ); - done(); - } -}) -``` - -should render block content from a parent block. - -```js -twig({ - path: 'test/templates/block-parent.twig', - load: function(template) { - template.render({ - base: "block-function-parent.twig" - }) - .should.equal( "parent block / Result: parent block" ); - done(); - } -}) -``` - -should render block content with outer context. - -```js -twig({ - path: 'test/templates/block-outer-context.twig', - load: function(template) { - template.render({ - base: "block-outer-context.twig", - items: ["twig", "js", "rocks"] - }) - .should.equal( "Hello twig!Hello js!Hello rocks!twigjsrocks" ); - done(); - } -}) -``` - -should respect changes of the context made before calling the function. - -```js -twig({ - data: '{% set foo = "original" %}{% block test %}{{ foo }}{% endblock %} {% set foo = "changed" %}{{ block("test") }}' -}).render() -.should.equal("original changed"); -``` - -<a name="twigjs-blocks---block-shorthand--"></a> -## block shorthand -> -should render block content using shorthand syntax. - -```js -twig({ - data: '{% set prefix = "shorthand" %}{% block title (prefix ~ " - " ~ block_value)|title %}' -}) -.render({block_value: 'test succeeded'}) -.should.equal('Shorthand - Test Succeeded'); -``` - -should overload blocks from an extended template using shorthand syntax. - -```js -twig({ - allowInlineIncludes: true, - data: '{% extends "child-extends" %}{% block title "New Title" %}{% block body "new body uses the " ~ base ~ " template" %}' -}) -.render({ base: "template.twig" }) -.should.equal( "New Title - new body uses the template.twig template" ); -``` - -<a name="twigjs-control-structures--"></a> -# Twig.js Control Structures -> -<a name="twigjs-control-structures---if-tag--"></a> -## if tag -> -should parse the contents of the if block if the expression is true. - -```js -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. - -```js -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. - -```js -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. - -```js -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" ); -``` - -should support newlines in if statement. - -```js -var test_template = twig({data: '{% if test or\r\nother %}true{% endif%}'}); -test_template.render({test: true, other: false}).should.equal("true" ); -test_template.render({test: false, other: false}).should.equal("" ); -``` - -<a name="twigjs-control-structures---for-tag--"></a> -## for tag -> -should provide value only for array input. - -```js -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. - -```js -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. - -```js -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. - -```js -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. - -```js -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. - -```js -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 for arrays. - -```js -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" ); -``` - -should have a loop context item available for objects. - -```js -var test_template = twig({data: '{% for key,value in test %}{{ loop.index }}{% endfor %}'}); -test_template.render({test: {a:1,b:2,c:3,d:4}}).should.equal("1234" ); -test_template = twig({data: '{% for key,value in test %}{{ loop.index0 }}{% endfor %}'}); -test_template.render({test: {a:1,b:2,c:3,d:4}}).should.equal("0123" ); -test_template = twig({data: '{% for key,value in test %}{{ loop.revindex }}{% endfor %}'}); -test_template.render({test: {a:1,b:2,c:3,d:4}}).should.equal("4321" ); -test_template = twig({data: '{% for key,value in test %}{{ loop.revindex0 }}{% endfor %}'}); -test_template.render({test: {a:1,b:2,c:3,d:4}}).should.equal("3210" ); -test_template = twig({data: '{% for key,value in test %}{{ loop.length }}{% endfor %}'}); -test_template.render({test: {a:1,b:2,c:3,d:4}}).should.equal("4444" ); -test_template = twig({data: '{% for key,value in test %}{{ loop.first }}{% endfor %}'}); -test_template.render({test: {a:1,b:2,c:3,d:4}}).should.equal("truefalsefalsefalse" ); -test_template = twig({data: '{% for key,value in test %}{{ loop.last }}{% endfor %}'}); -test_template.render({test: {a:1,b:2,c:3,d:4}}).should.equal("falsefalsefalsetrue" ); -``` - -should have a loop context item available in child loops objects. - -```js -var test_template = twig({data: '{% for value in test %}{% for value in inner %}({{ loop.parent.loop.index }},{{ loop.index }}){% endfor %}{% endfor %}'}); -test_template.render({test: {a:1,b:2}, inner:[1,2,3]}).should.equal("(1,1)(1,2)(1,3)(2,1)(2,2)(2,3)"); -``` - -should support conditionals on for loops. - -```js -var test_template = twig({data: '{% for value in test if false %}{{ value }},{% endfor %}'}); -test_template.render({test: ["one", "two", "a", "b", "other"]}).should.equal(""); -test_template = twig({data: '{% for value in test if true %}{{ value }}{% endfor %}'}); -test_template.render({test: ["a", "s", "d", "f"]}).should.equal("asdf"); -test_template = twig({data: '{% for value in test if value|length > 2 %}{{ value }},{% endfor %}'}); -test_template.render({test: ["one", "two", "a", "b", "other"]}).should.equal("one,two,other,"); -test_template = twig({data: '{% for key,item in test if item.show %}{{key}}:{{ item.value }},{% endfor %}'}); -test_template.render({test: { - a: {show:true, value: "one"}, - b: {show:false, value: "two"}, - c: {show:true, value: "three"}}}).should.equal("a:one,c:three,"); -``` - -<a name="twigjs-control-structures---set-tag--"></a> -## set tag -> -should not set the global context from within a for loop. - -```js -var test_template = twig({data: '{% for value in [1] %}{% set foo="right" %}{% endfor %}{{ foo }}'}); -test_template.render().should.equal(""); -``` - -should set the global context from within a for loop when the variable is initialized outside of the loop. - -```js -var test_template = twig({data: '{% set foo="wrong" %}{% for value in [1] %}{% set foo="right" %}{% endfor %}{{ foo }}'}); -test_template.render().should.equal("right"); -``` - -should set the global context from within a nested for loop when the variable is initialized outside of the loop. - -```js -var test_template = twig({data: '{% set k = 0 %}{% for i in 0..2 %}{% for j in 0..2 %}{{ k }}{% set k = k + 1 %}{% endfor %}{% endfor %}'}); -test_template.render().should.equal("012345678"); -``` - -<a name="twigjs-core--"></a> -# Twig.js Core -> -should save and load a template by reference. - -```js -// Define and save a template - twig({ - id: 'test', - data: '{{ "test" }}' - }); - // Load and render the template - twig({ref: 'test'}).render() - .should.equal("test"); -``` - -should ignore comments. - -```js -twig({data: 'good {# comment #}morning'}).render().should.equal("good morning"); -twig({data: 'good{#comment#}morning'}).render().should.equal("goodmorning"); -``` - -should ignore output tags within comments. - -```js -twig({data: 'good {# {{ "Hello" }} #}morning'}).render().should.equal("good morning"); -twig({data: 'good{#c}}om{{m{{ent#}morning'}).render().should.equal("goodmorning"); -``` - -should ignore logic tags within comments. - -```js -twig({data: 'test {# {% bad syntax if not in comment %} #}test'}).render().should.equal("test test"); -twig({data: '{##}{##}test{# %}}}%}%{%{{% #}pass'}).render().should.equal("testpass"); -``` - -should ignore quotation marks within comments. - -```js -twig({data: "good {# don't stop #}morning"}).render().should.equal("good morning"); -twig({data: 'good{#"dont stop"#}morning'}).render().should.equal("goodmorning"); -twig({data: 'good {# "don\'t stop" #}morning'}).render().should.equal("good morning"); -twig({data: 'good{#"\'#}morning'}).render().should.equal("goodmorning"); -twig({data: 'good {#"\'"\'"\'#} day'}).render().should.equal("good day"); -twig({data: "a {# ' #}b{# ' #} c"}).render().should.equal("a b c"); -``` - -should be able to parse output tags with tag ends in strings. - -```js -// 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 parse whitespace control output tags. - -```js -twig({data: ' {{- "test" -}}'}).render().should.equal("test"); -twig({data: ' {{- "test" -}} '}).render().should.equal("test"); -twig({data: '\n{{- "test" -}}'}).render().should.equal("test"); -twig({data: '{{- "test" -}}\n'}).render().should.equal("test"); -twig({data: '\n{{- "test" -}}\n'}).render().should.equal("test"); -twig({data: '\t{{- "test" -}}\t'}).render().should.equal("test"); -twig({data: '\n\t{{- "test" -}}\n\t'}).render().should.equal("test"); -twig({data: '123\n\t{{- "test" -}}\n\t456'}).render().should.equal("123test456"); -twig({data: '\n{{- orp -}}\n'}).render({ orp: "test"}).should.equal("test"); -twig({data: '\n{{- [1,2 ,1+2 ] -}}\n'}).render().should.equal("1,2,3"); -twig({data: ' {{- "test" -}} {{- "test" -}}'}).render().should.equal("testtest"); -twig({data: '{{ "test" }} {{- "test" -}}'}).render().should.equal("testtest"); -twig({data: '{{- "test" -}} {{ "test" }}'}).render().should.equal("testtest"); -twig({data: '<>{{- "test" -}}<>'}).render().should.equal("<>test<>"); -``` - -should be able to parse mismatched opening whitespace control output tags. - -```js -twig({data: ' {{- "test" }}'}).render().should.equal("test"); -twig({data: '{{- "test" }}\n'}).render().should.equal("test\n"); -twig({data: '\t{{- "test" }}\t'}).render().should.equal("test\t"); -twig({data: '123\n\t{{- "test" }}\n\t456'}).render().should.equal("123test\n\t456"); -twig({data: '\n{{- [1,2 ,1+2 ] }}\n'}).render().should.equal("1,2,3\n"); -twig({data: ' {{- "test" }} {{- "test" }}'}).render().should.equal("testtest"); -twig({data: '{{ "test" }} {{- "test" }}'}).render().should.equal("testtest"); -twig({data: ' {{- "test" }} {{ "test" }}'}).render().should.equal("test test"); -twig({data: ' {{- "test" }} {{- "test" -}}'}).render().should.equal("testtest"); -twig({data: '<>{{- "test" }}'}).render().should.equal("<>test"); -``` - -should be able to parse mismatched closing whitespace control output tags. - -```js -twig({data: ' {{ "test" -}}'}).render().should.equal(" test"); -twig({data: '\n{{ "test" -}}\n'}).render().should.equal("\ntest"); -twig({data: '\t{{ "test" -}}\t'}).render().should.equal("\ttest"); -twig({data: '123\n\t{{ "test" -}}\n\t456'}).render().should.equal("123\n\ttest456"); -twig({data: '\n{{ [1,2 ,1+2 ] -}}\n'}).render().should.equal("\n1,2,3"); -twig({data: ' {{ "test" -}} {{ "test" -}}'}).render().should.equal(" testtest"); -twig({data: '{{ "test" }} {{ "test" -}} '}).render().should.equal("test test"); -twig({data: ' {{ "test" -}} {{ "test" }} '}).render().should.equal(" testtest "); -twig({data: ' {{ "test" -}} {{- "test" -}}'}).render().should.equal(" testtest"); -twig({data: '{{ "test" -}}<>'}).render().should.equal("test<>"); -``` - -should be able to parse whitespace control logic tags. - -```js -// Newlines directly after logic tokens are ignored -// So use double newlines -twig({data: '{%- if true -%}{{ "test" }}{% endif %}'}).render().should.equal("test"); -twig({data: '{%- if true -%}{{ "test" }}{%- endif -%}'}).render().should.equal("test"); -twig({data: ' {%- if true -%} {{ "test" }}{% endif %}'}).render().should.equal("test"); -twig({data: '\n{%- if true -%}\n\n{{ "test" }}{% endif %}'}).render().should.equal("test"); -twig({data: '\n\t{%- if true -%}\n\n\t{{ "test" }}{% endif %}'}).render().should.equal("test"); -twig({data: '123\n\t{%- if true -%}\n\n\t{{ "test" }}{% endif %}456'}).render().should.equal("123test456"); -twig({data: '\n\t{%- if true -%}\n\n\t{{ [1,2 ,1+2 ] }}{% endif %}'}).render().should.equal("1,2,3"); -twig({data: '<>{%- if true -%}test{% endif %}<>'}).render().should.equal("<>test<>"); -``` - -should be able to parse mismatched opening whitespace control logic tags. - -```js -twig({data: '{%- if true %}{{ "test" }}{% endif %}'}).render().should.equal("test"); -twig({data: '{%- if true %}{{ "test" }}{% endif %}'}).render().should.equal("test"); -twig({data: ' {% if true %} {{ "test" }}{% endif %}'}).render().should.equal(" test"); -twig({data: ' {%- if true %} {{ "test" }}{% endif %}'}).render().should.equal(" test"); -twig({data: '\n{% if true %}\n\n{{ "test" }}{% endif %}'}).render().should.equal("\n\ntest"); -twig({data: '\n{%- if true %}\n\n{{ "test" }}{% endif %}'}).render().should.equal("\ntest"); -twig({data: '\n\t{%- if true %}\n\n\t{{ "test" }}{% endif %}'}).render().should.equal("\n\ttest"); -twig({data: '123\n\t{%- if true %}\n\n\t{{ "test" }}{% endif %}456'}).render().should.equal("123\n\ttest456"); -twig({data: '\n\t{%- if true %}\n\n\t{{ [1,2 ,1+2 ] }}{% endif %}'}).render().should.equal("\n\t1,2,3"); -twig({data: '<>{%- if true %}test{% endif %}'}).render().should.equal("<>test"); -``` - -should be able to parse mismatched closing whitespace control logic tags. - -```js -twig({data: '{% if true %}{{ "test" }}{% endif %}'}).render().should.equal("test"); -twig({data: '{% if true -%} {{ "test" }}{% endif %}'}).render().should.equal("test"); -twig({data: ' {% if true -%} {{ "test" }}{% endif %}'}).render().should.equal(" test"); -twig({data: ' {% if true -%} {{ "test" }}{% endif %}'}).render().should.equal(" test"); -twig({data: '\n{% if true %}\n\n{{ "test" }}{% endif %}'}).render().should.equal("\n\ntest"); -twig({data: '\n{% if true -%}\n\n{{ "test" }}{% endif %}'}).render().should.equal("\ntest"); -twig({data: '\n\t{% if true -%}\n\n\t{{ "test" }}{% endif %}'}).render().should.equal("\n\ttest"); -twig({data: '123\n\t{% if true -%}\n\n\t{{ "test" }}{% endif %}456'}).render().should.equal("123\n\ttest456"); -twig({data: '\n\t{% if true -%}\n\n\t{{ [1,2 ,1+2 ] }}{% endif %}'}).render().should.equal("\n\t1,2,3"); -twig({data: '{% if true -%}<>test{% endif %}'}).render().should.equal("<>test"); -``` - -should be able to output numbers. - -```js -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. - -```js -twig({data: '{{ true }}'}).render().should.equal( "true" ); -twig({data: '{{ false }}'}).render().should.equal( "false" ); -``` - -should be able to output strings. - -```js -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 strings with newlines. - -```js -twig({data: "{{ 'a\nb\rc\r\nd' }}"}).render().should.equal("a\nb\rc\r\nd"); -``` - -should be able to output arrays. - -```js -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. - -```js -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. - -```js -twig({data: '{{ orp }}'}).render({ orp: "test"}).should.equal("test"); -twig({data: '{{ val }}'}).render({ val: function() { - return "test" - }}).should.equal("test"); -``` - -should recognize null. - -```js -twig({data: '{{ null == val }}'}).render({val: null}).should.equal( "true" ); -twig({data: '{{ null == val }}'}).render({val: undefined}).should.equal( "true" ); -twig({data: '{{ null == val }}'}).render({val: "test"}).should.equal( "false" ); -twig({data: '{{ null == val }}'}).render({val: 0}).should.equal( "false" ); -twig({data: '{{ null == val }}'}).render({val: false}).should.equal( "false" ); -``` - -should recognize object literals. - -```js -twig({data: '{% set at = {"foo": "test", bar: "other", 1:"zip"} %}{{ at.foo ~ at.bar ~ at.1 }}'}).render().should.equal( "testotherzip" ); -``` - -should allow newlines in object literals. - -```js -twig({data: '{% set at = {\n"foo": "test",\rbar: "other",\r\n1:"zip"\n} %}{{ at.foo ~ at.bar ~ at.1 }}'}).render().should.equal( "testotherzip" ); -``` - -should recognize null in an object. - -```js -twig({data: '{% set at = {"foo": null} %}{{ at.foo == val }}'}).render({val: null}).should.equal( "true" ); -``` - -should allow int 0 as a key in an object. - -```js -twig({data: '{% set at = {0: "value"} %}{{ at.0 }}'}).render().should.equal( "value" ); -``` - -should support set capture. - -```js -twig({data: '{% set foo %}bar{% endset %}{{foo}}'}).render().should.equal( "bar" ); -``` - -should support raw data. - -```js -twig({ - data: "before {% raw %}{{ test }} {% test2 %} {{{% endraw %} after" -}).render().should.equal( - "before {{ test }} {% test2 %} {{ after" -); -``` - -should support raw data using 'verbatim' tag. - -```js -twig({ - data: "before {% verbatim %}{{ test }} {% test2 %} {{{% endverbatim %} after" -}).render().should.equal( - "before {{ test }} {% test2 %} {{ after" -); -``` - -<a name="twigjs-core---key-notation--"></a> -## Key Notation -> -should support dot key notation. - -```js -twig({data: '{{ key.value }} {{ key.sub.test }}'}).render({ - key: { - value: "test", - sub: { - test: "value" - } - } -}).should.equal("test value"); -``` - -should support square bracket key notation. - -```js -twig({data: '{{ key["value"] }} {{ key[\'sub\']["test"] }}'}).render({ - key: { - value: "test", - sub: { - test: "value" - } - } -}).should.equal("test value"); -``` - -should support mixed dot and bracket key notation. - -```js -twig({data: '{{ key["value"] }} {{ key.sub[key.value] }} {{ s.t["u"].v["w"] }}'}).render({ - key: { - value: "test", - sub: { - test: "value" - } - }, - s: { t: { u: { v: { w: 'x' } } } } -}).should.equal("test value x" ); -``` - -should support dot key notation after a function. - -```js -var test_template = twig({data: '{{ key.fn().value }}'}); -var output = test_template.render({ - key: { - fn: function() { - return { - value: "test" - } - } - } -}); -output.should.equal("test"); -``` - -should support bracket key notation after a function. - -```js -var test_template = twig({data: '{{ key.fn()["value"] }}'}); -var output = test_template.render({ - key: { - fn: function() { - return { - value: "test 2" - } - } - } -}); -output.should.equal("test 2"); -``` - -should check for getKey methods if a key doesn't exist.. - -```js -twig({data: '{{ obj.value }}'}).render({ - obj: { - getValue: function() { - return "val"; - }, - isValue: function() { - return "not val"; - } - } -}).should.equal("val"); -``` - -should check for isKey methods if a key doesn't exist.. - -```js -twig({data: '{{ obj.value }}'}).render({ - obj: { - isValue: function() { - return "val"; - } - } -}).should.equal("val"); -``` - -should check for getKey methods on prototype objects.. - -```js -var object = { - getValue: function() { - return "val"; - } - }; -function Subobj() {}; -Subobj.prototype = object; -var subobj = new Subobj(); - - twig({data: '{{ obj.value }}'}).render({ - obj: subobj - }).should.equal("val"); -``` - -should return null if a period key doesn't exist.. - -```js -twig({data: '{{ obj.value == null }}'}).render({ - obj: {} -}).should.equal("true"); -``` - -should return null if a bracket key doesn't exist.. - -```js -twig({data: '{{ obj["value"] == null }}'}).render({ - obj: {} -}).should.equal("true"); -``` - -<a name="twigjs-core---context--"></a> -## Context -> -should be supported. - -```js -twig({data: '{{ _context.value }}'}).render({ - value: "test" -}).should.equal("test"); -``` - -should be an object even if it's not passed. - -```js -twig({data: '{{ _context|json_encode }}'}).render().should.equal("{}"); -``` - -should support {% set %} tag. - -```js -twig({data: '{% set value = "test" %}{{ _context.value }}'}).render().should.equal("test"); -``` - -should work correctly with properties named dynamically. - -```js -twig({data: '{{ _context[key] }}'}).render({ - key: "value", - value: "test" -}).should.equal("test"); -``` - -should not allow to override context using {% set %}. - -```js -twig({data: '{% set _context = "test" %}{{ _context|json_encode }}'}).render().should.equal('{"_context":"test"}'); -twig({data: '{% set _context = "test" %}{{ _context._context }}'}).render().should.equal("test"); -``` - -should support autoescape option. - -```js -twig({ - autoescape: true, - data: '{{ value }}' -}).render({ - value: "<test>&</test>" -}).should.equal('<test>&</test>'); -``` - -should support autoescape option with alternative strategy. - -```js -twig({ - autoescape: 'js', - data: '{{ value }}' -}).render({ - value: "<test>&</test>" -}).should.equal('\\x3Ctest\\x3E\\x26\\x3C\\x2Ftest\\x3E'); -``` - -should autoescape parent() output correctly. - -```js -twig({id: 'parent1', data: '{% block body %}<p>{{ value }}</p>{% endblock body %}'}); -twig({ - allowInlineIncludes: true, - autoescape: true, - data: '{% extends "parent1" %}{% block body %}{{ parent() }}{% endblock %}' -}).render({ - value: "<test>&</test>" -}).should.equal('<p><test>&</test></p>'); -``` - -should use a correct context in the extended template. - -```js -twig({id: 'parent', data: '{% block body %}{{ value }}{% endblock body %}'}); -twig({ - allowInlineIncludes: true, - data: '{% extends "parent" %}{% set value = "test" %}{% block body %}{{ parent() }}{% endblock %}' -}).render().should.equal("test"); -``` - -should use a correct context in the included template. - -```js -twig({id: 'included', data: '{{ value }}\n{% set value = "inc" %}{{ value }}\n'}); -twig({ - allowInlineIncludes: true, - data: '{% set value = "test" %}{% for i in [0, 1] %}{% include "included" %}{% endfor %}{{ value }}' -}).render().should.equal("test\ninc\ntest\ninc\ntest"); -``` - -<a name="twigjs-embed--"></a> -# Twig.js Embed -> -it should load embed and render. - -```js -twig({ - id: 'embed', - path: 'test/templates/embed-simple.twig', - async: false -}); -// Load the template -twig({ref: 'embed'}).render({ }).trim().should.equal( ['START', - 'A', - 'new header', - 'base footer', - 'B', - '', - 'A', - 'base header', - 'base footer', - 'extended', - 'B', - '', - 'A', - 'base header', - 'extended', - 'base footer', - 'extended', - 'B', - '', - 'A', - 'Super cool new header', - 'Cool footer', - 'B', - 'END'].join('\n') ); -``` - -<a name="twigjs-expressions--"></a> -# Twig.js Expressions -> -<a name="twigjs-expressions---basic-operators--"></a> -## Basic Operators -> -should parse parenthesis. - -```js -var test_template = twig({data: '{{ a - (b + c) }}'}), - d = {a: 10, b: 4, c: 2}, - output = test_template.render(d); -output.should.equal( (d.a - (d.b + d.c)).toString() ); -``` - -should parse nested parenthesis. - -```js -var test_template = twig({data: '{{ a - ((b) + (1 + c)) }}'}), - d = {a: 10, b: 4, c: 2}, - output = test_template.render(d); -output.should.equal( (d.a - (d.b + 1 + d.c)).toString() ); -``` - -should add numbers. - -```js -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. - -```js -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. - -```js -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. - -```js -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. - -```js -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. - -```js -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. - -```js -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 concatenate null and undefined values and not throw an exception. - -```js -twig({data: '{{ a ~ b }}'}).render().should.equal(""); -twig({data: '{{ a ~ b }}'}).render({ - a: null, - b: null -}).should.equal(""); -``` - -should handle multiple chained operations. - -```js -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. - -```js -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()); -``` - -<a name="twigjs-expressions---comparison-operators--"></a> -## Comparison Operators -> -should support less then. - -```js -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. - -```js -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. - -```js -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. - -```js -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. - -```js -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. - -```js -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. - -```js -var 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. - -```js -var 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. - -```js -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()); -``` - -<a name="twigjs-expressions---other-operators--"></a> -## Other Operators -> -should support the ternary operator. - -```js -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. - -```js -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. - -```js -var test_template2 = twig({data: '{{ {"b" : a or b ? {"a":e+f}:{"a":1} }.b.a }}'}) - , output2 = test_template2.render({a: false, b: false, e: 1, f: 2}); -output2.should.equal( "1" ); -``` - -should support in/containment functionality for arrays. - -```js -var test_template = twig({data: '{{ "a" in ["a", "b", "c"] }}'}); -test_template.render().should.equal(true.toString()); -var test_template = twig({data: '{{ "d" in ["a", "b", "c"] }}'}); -test_template.render().should.equal(false.toString()); -``` - -should support not in/containment functionality for arrays. - -```js -var test_template = twig({data: '{{ "a" not in ["a", "b", "c"] }}'}); -test_template.render().should.equal(false.toString()); -var test_template = twig({data: '{{ "d" not in ["a", "b", "c"] }}'}); -test_template.render().should.equal(true.toString()); -``` - -should support in/containment functionality for strings. - -```js -var test_template = twig({data: '{{ "at" in "hat" }}'}); -test_template.render().should.equal(true.toString()); -var test_template = twig({data: '{{ "d" in "not" }}'}); -test_template.render().should.equal(false.toString()); -``` - -should support not in/containment functionality for strings. - -```js -var test_template = twig({data: '{{ "at" not in "hat" }}'}); -test_template.render().should.equal(false.toString()); -var test_template = twig({data: '{{ "d" not in "not" }}'}); -test_template.render().should.equal(true.toString()); -``` - -should support in/containment functionality for objects. - -```js -var test_template = twig({data: '{{ "value" in {"key" : "value", "2": "other"} }}'}); -test_template.render().should.equal(true.toString()); -var test_template = twig({data: '{{ "d" in {"key_a" : "no"} }}'}); -test_template.render().should.equal(false.toString()); -``` - -should support not in/containment functionality for objects. - -```js -var test_template = twig({data: '{{ "value" not in {"key" : "value", "2": "other"} }}'}); -test_template.render().should.equal(false.toString()); -var test_template = twig({data: '{{ "d" not in {"key_a" : "no"} }}'}); -test_template.render().should.equal(true.toString()); -``` - -should support undefined and null for the in operator. - -```js -var test_template = twig({data: '{{ 0 in undefined }} {{ 0 in null }}'}); -test_template.render().should.equal(' '); -``` - -should support expressions as object keys. - -```js -var test_template; -test_template = twig({data: '{% set a = {(foo): "value"} %}{{ a.bar }}'}); -test_template.render({foo: 'bar'}).should.equal('value'); -test_template = twig({data: '{{ {(foo): "value"}.bar }}'}); -test_template.render({foo: 'bar'}).should.equal('value'); -``` - -<a name="twigjs-extensions--"></a> -# Twig.js Extensions -> -should be able to extend a meta-type tag. - -```js -var flags = {}; - Twig.extend(function(Twig) { - Twig.exports.extendTag({ - type: "flag", - regex: /^flag\s+(.+)$/, - next: [ ], - open: true, - compile: function (token) { - var expression = token.match[1]; - - // Compile the expression. - token.stack = Twig.expression.compile.apply(this, [{ - type: Twig.expression.type.expression, - value: expression - }]).stack; - - delete token.match; - return token; - }, - parse: function (token, context, chain) { - var name = Twig.expression.parse.apply(this, [token.stack, context]), - output = ''; - - flags[name] = true; - - return { - chain: false, - output: output - }; - } - }); - }); - var template = twig({data:"{% flag 'enabled' %}"}).render(); - flags.enabled.should.equal(true); -``` - -should be able to extend paired tags. - -```js -// demo data - var App = { - user: "john", - users: { - john: {level: "admin"}, - tom: {level: "user"} - } - }; - Twig.extend(function(Twig) { - // example of extending a tag type that would - // restrict content to the specified "level" - Twig.exports.extendTag({ - type: "auth", - regex: /^auth\s+(.+)$/, - next: ["endauth"], // match the type of the end tag - open: true, - compile: function (token) { - var expression = token.match[1]; - - // turn the string expression into tokens. - token.stack = Twig.expression.compile.apply(this, [{ - type: Twig.expression.type.expression, - value: expression - }]).stack; - - delete token.match; - return token; - }, - parse: function (token, context, chain) { - var level = Twig.expression.parse.apply(this, [token.stack, context]), - output = ""; - - if (App.users[App.currentUser].level == level) - { - output = Twig.parse.apply(this, [token.output, context]); - } - - return { - chain: chain, - output: output - }; - } - }); - Twig.exports.extendTag({ - type: "endauth", - regex: /^endauth$/, - next: [ ], - open: false - }); - }); - var template = twig({data:"Welcome{% auth 'admin' %} ADMIN{% endauth %}!"}); - - App.currentUser = "john"; - template.render().should.equal("Welcome ADMIN!"); - - App.currentUser = "tom"; - template.render().should.equal("Welcome!"); -``` - -should be able to extend the same tag twice, replacing it. - -```js -var flags = {}; -Twig.extend(function(Twig) { - Twig.exports.extendTag({ - type: "noop", - regex: /^noop$/, - next: [ ], - open: true, - parse: function (token, context, chain) { - return { - chain: false, - output: "noop1" - }; - } - }); -}); -var result = twig({data:"{% noop %}"}).render(); -result.should.equal("noop1"); -Twig.extend(function(Twig) { - Twig.exports.extendTag({ - type: "noop", - regex: /^noop$/, - next: [ ], - open: true, - parse: function (token, context, chain) { - return { - chain: false, - output: "noop2" - }; - } - }); -}); -var result = twig({data:"{% noop %}"}).render(); -result.should.equal("noop2"); -``` - -<a name="twigjs-filters--"></a> -# Twig.js Filters -> -should chain. - -```js -var test_template = twig({data: '{{ ["a", "b", "c"]|keys|reverse }}' }); -test_template.render().should.equal("2,1,0"); -``` - -<a name="twigjs-filters---url_encode--"></a> -## url_encode -> -should encode URLs. - -```js -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" ); -``` - -should handle undefined. - -```js -var test_template = twig({data: '{{ undef|url_encode() }}' }); -test_template.render().should.equal("" ); -``` - -should handle special characters. - -```js -var data = { "foo": "<foo> \\&\"'.,-_?/Ķä€台北[]{}\t\r\n\b\x80" }; -var test_template = twig({data: '{{ foo|url_encode() }}' }); -test_template.render(data).should.equal("%3Cfoo%3E%20%5C%26%22%27.%2C-_%3F%2F%C4%B6%C3%A4%E2%82%AC%E5%8F%B0%E5%8C%97%5B%5D%7B%7D%09%0D%0A%08%C2%80" ); -``` - -<a name="twigjs-filters---json_encode--"></a> -## json_encode -> -should encode strings to json. - -```js -var test_template = twig({data: '{{ test|json_encode }}' }); -test_template.render({test:'value'}).should.equal('"value"' ); -``` - -should encode numbers to json. - -```js -var test_template = twig({data: '{{ test|json_encode }}' }); -test_template.render({test:21}).should.equal('21' ); -``` - -should encode arrays to json. - -```js -var test_template = twig({data: '{{ [1,"b",3]|json_encode }}' }); -test_template.render().should.equal('[1,"b",3]' ); -``` - -should encode objects to json. - -```js -var test_template = twig({data: '{{ {"a":[1,"b",3]}|json_encode }}' }); -test_template.render().should.equal('{"a":[1,"b",3]}' ); -``` - -should retain key order in an object. - -```js -twig({data: '{{ { "foo": 1, "bar": 2, "baz": 3 }|json_encode }}'}).render().should.equal( '{"foo":1,"bar":2,"baz":3}' ); -``` - -should not add additional information to objects. - -```js -twig({data: '{{ { "foo": 1, "bar": [1, 2, 3], "baz": { "a": "a", "b": "b" } }|json_encode }}'}).render().should.equal( '{"foo":1,"bar":[1,2,3],"baz":{"a":"a","b":"b"}}' ); -``` - -should handle undefined. - -```js -var test_template = twig({data: '{{ undef|json_encode }}' }); -test_template.render().should.equal("null" ); -``` - -<a name="twigjs-filters---upper--"></a> -## upper -> -should convert text to uppercase. - -```js -var test_template = twig({data: '{{ "hello"|upper }}' }); -test_template.render().should.equal("HELLO" ); -``` - -should handle undefined. - -```js -var test_template = twig({data: '{{ undef|upper }}' }); -test_template.render().should.equal("" ); -``` - -<a name="twigjs-filters---lower--"></a> -## lower -> -should convert text to lowercase. - -```js -var test_template = twig({data: '{{ "HELLO"|lower }}' }); -test_template.render().should.equal("hello" ); -``` - -should handle undefined. - -```js -var test_template = twig({data: '{{ undef|lower }}' }); -test_template.render().should.equal("" ); -``` - -<a name="twigjs-filters---capitalize--"></a> -## capitalize -> -should capitalize the first word in a string. - -```js -var test_template = twig({data: '{{ "hello world"|capitalize }}' }); -test_template.render().should.equal("Hello world" ); -var test_template2 = twig({data: '{{ "HELLO WORLD"|capitalize }}' }); -test_template2.render().should.equal("Hello world" ); -``` - -should handle undefined. - -```js -var test_template = twig({data: '{{ undef|capitalize }}' }); -test_template.render().should.equal("" ); -``` - -<a name="twigjs-filters---title--"></a> -## title -> -should capitalize all the words in a string. - -```js -var test_template = twig({data: '{{ "hello world"|title }}' }); -test_template.render().should.equal("Hello World" ); -var test_template2 = twig({data: '{{ "HELLO WORLD"|title }}' }); -test_template2.render().should.equal("Hello World" ); -``` - -should handle undefined. - -```js -var test_template = twig({data: '{{ undef|title }}' }); -test_template.render().should.equal("" ); -``` - -<a name="twigjs-filters---length--"></a> -## length -> -should determine the length of a string. - -```js -var test_template = twig({data: '{{ "test"|length }}' }); -test_template.render().should.equal("4"); -``` - -should determine the length of an array. - -```js -var test_template = twig({data: '{{ [1,2,4,76,"tesrt"]|length }}' }); -test_template.render().should.equal("5"); -``` - -should determine the length of an object. - -```js -var test_template = twig({data: '{{ {"a": "b", "c": "1", "test": "test"}|length }}' }); -test_template.render().should.equal("3"); -``` - -should handle undefined. - -```js -var test_template = twig({data: '{{ undef|length }}' }); -test_template.render().should.equal("0" ); -``` - -<a name="twigjs-filters---sort--"></a> -## sort -> -should sort an array. - -```js -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. - -```js -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 " ); -test_template = twig({data: "{% set obj = {'z':'abc','a':2,'y':7,'m':'test'} %}{% for key,value in obj|sort %}{{key}}:{{value}} {%endfor %}" }); -test_template.render().should.equal("a:2 y:7 z:abc m:test " ); -``` - -should handle undefined. - -```js -var test_template = twig({data: '{% set obj = undef|sort %}{% for key, value in obj|sort %}{{key}}:{{value}}{%endfor%}' }); -test_template.render().should.equal("" ); -``` - -<a name="twigjs-filters---reverse--"></a> -## reverse -> -should reverse an array. - -```js -var test_template = twig({data: '{{ ["a", "b", "c"]|reverse }}' }); -test_template.render().should.equal("c,b,a" ); -``` - -should reverse an object. - -```js - -``` - -should handle undefined. - -```js -var test_template = twig({data: '{{ undef|reverse }}' }); -test_template.render().should.equal("" ); -``` - -<a name="twigjs-filters---keys--"></a> -## keys -> -should return the keys of an array. - -```js -var test_template = twig({data: '{{ ["a", "b", "c"]|keys }}' }); -test_template.render().should.equal("0,1,2" ); -``` - -should return the keys of an object. - -```js -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" ); -``` - -should handle undefined. - -```js -var test_template = twig({data: '{{ undef|keys }}' }); -test_template.render().should.equal("" ); -``` - -<a name="twigjs-filters---merge--"></a> -## merge -> -should merge two objects into an object. - -```js -// 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. - -```js -// 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. - -```js -// 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 ' ); -``` - -<a name="twigjs-filters---join--"></a> -## join -> -should join all values in an object. - -```js -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. - -```js -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" ); -``` - -should handle undefined. - -```js -var test_template = twig({data: '{{ undef|join }}' }); -test_template.render().should.equal("" ); -``` - -<a name="twigjs-filters---default--"></a> -## default -> -should not provide the default value if a key is defined and not empty. - -```js -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. - -```js -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. - -```js -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" ); -``` - -should provide a default value of '' if no parameters are passed and a default key is not defined. - -```js -var test_template = twig({data: '{{ var|default }}' }); -test_template.render().should.equal(""); -``` - -should provide a default value of '' if no parameters are passed and a value is empty. - -```js -var test_template = twig({data: '{{ ""|default }}' }); -test_template.render().should.equal(""); -test_template = twig({data: '{{ var.key|default }}' }); -test_template.render({'var':{}}).should.equal(""); -``` - -<a name="twigjs-filters---date--"></a> -## date -> -should recognize timestamps. - -```js -var template = twig({data: '{{ 27571323556|date("d/m/Y @ H:i:s") }}'}) - , date = new Date(27571323556000); // 13/09/2843 @ 08:59:16 EST -template.render().should.equal( stringDate(date) ); -``` - -should recognize timestamps, when they are passed as string. - -```js -var template = twig({data: '{{ "27571323556"|date("d/m/Y @ H:i:s") }}'}) - , date = new Date(27571323556000); // 13/09/2843 @ 08:59:16 EST -template.render().should.equal( stringDate(date) ); -``` - -should recognize string date formats. - -```js -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) ); -``` - -should handle undefined. - -```js -var test_template = twig({data: '{{ undef|date("d/m/Y @ H:i:s") }}' }); -var date = new Date(); -test_template.render().should.equal(stringDate(date)); -``` - -should work with no parameters. - -```js -var test_template = twig({data: '{{ 27571323556|date }}' }); -test_template.render().should.equal(twig({data: '{{ 27571323556|date("F j, Y H:i") }}'}).render()); -``` - -<a name="twigjs-filters---replace--"></a> -## replace -> -should replace strings provided in a map. - -```js -var template = twig({data: '{{ "I like %this% and %that%. Seriously, I like %this% and %that%."|replace({"%this%": foo, "%that%": "bar"}) }}'}); -template.render({foo: "foo"}).should.equal("I like foo and bar. Seriously, I like foo and bar." ); -``` - -should handle undefined. - -```js -var test_template = twig({data: '{{ undef|replace }}' }); -test_template.render().should.equal("" ); -``` - -<a name="twigjs-filters---format--"></a> -## format -> -should replace formatting tags with parameters. - -```js -var template = twig({data: '{{ "I like %s and %s."|format(foo, "bar") }}'}); -template.render({foo: "foo"}).should.equal("I like foo and bar." ); -``` - -should handle undefined. - -```js -var test_template = twig({data: '{{ undef|format }}' }); -test_template.render().should.equal("" ); -``` - -should handle positive leading sign without padding. - -```js -var template = twig({data: '{{ "I like positive numbers like %+d."|format(123) }}'}); -template.render({foo: "foo"}).should.equal("I like positive numbers like +123." ); -``` - -should handle negative leading sign without padding. - -```js -var template = twig({data: '{{ "I like negative numbers like %+d."|format(-123) }}'}); -template.render({foo: "foo"}).should.equal("I like negative numbers like -123." ); -``` - -should handle positive leading sign with padding zero. - -```js -var template = twig({data: '{{ "I like positive numbers like %+05d."|format(123) }}'}); -template.render({foo: "foo"}).should.equal("I like positive numbers like +0123." ); -``` - -should handle negative leading sign with padding zero. - -```js -var template = twig({data: '{{ "I like negative numbers like %+05d."|format(-123) }}'}); -template.render({foo: "foo"}).should.equal("I like negative numbers like -0123." ); -``` - -should handle positive leading sign with padding space. - -```js -var template = twig({data: '{{ "I like positive numbers like %+5d."|format(123) }}'}); -template.render({foo: "foo"}).should.equal("I like positive numbers like +123." ); -``` - -should handle negative leading sign with padding space. - -```js -var template = twig({data: '{{ "I like negative numbers like %+5d."|format(-123) }}'}); -template.render({foo: "foo"}).should.equal("I like negative numbers like -123." ); -``` - -<a name="twigjs-filters---striptags--"></a> -## striptags -> -should remove tags from a value. - -```js -var template = twig({data: '{{ "<p>Test paragraph.</p><!-- Comment --> <a href=\\"#fragment\\">Other text</a>"|striptags }}'}); -template.render().should.equal("Test paragraph. Other text" ); -``` - -should handle undefined. - -```js -var test_template = twig({data: '{{ undef|striptags }}' }); -test_template.render().should.equal("" ); -``` - -<a name="twigjs-filters---escape--"></a> -## escape -> -should convert unsafe characters to HTML entities. - -```js -var template = twig({data: '{{ "<p>Test paragraph.</p><!-- Comment --> <a href=\'#fragment\'>Other text</a>"|escape }}'}); -template.render().should.equal("<p>Test paragraph.</p><!-- Comment --> <a href='#fragment\'>Other text</a>" ); -``` - -should handle undefined. - -```js -var test_template = twig({data: '{{ undef|escape }}' }); -test_template.render().should.equal("" ); -``` - -should not escape twice if autoescape is on. - -```js -twig({ - autoescape: true, - data: '{{ value|escape }}' -}).render({ - value: "<test>&</test>" -}).should.equal('<test>&</test>'); -``` - -should handle the strategy parameter. - -```js -var data = { "foo": "<foo> \\&\"'.,-_?/Ķä€台北[]{}\t\r\n\b\x80" }; -var test_template = twig({data: 'Default: {{ foo|escape }}' }); -test_template.render(data).should.equal("Default: <foo> \\&"'.,-_?/Ķä€台北[]{}\t\r\n\b\x80" ); -var test_template = twig({data: 'html: {{ foo|escape("html") }}' }); -test_template.render(data).should.equal("html: <foo> \\&"'.,-_?/Ķä€台北[]{}\t\r\n\b\x80" ); -var test_template = twig({data: 'js: {{ foo|escape("js") }}' }); -test_template.render(data).should.equal("js: \\x3Cfoo\\x3E\\x20\\x5C\\x26\\x22\\x27.,\\x2D_\\x3F\\x2F\\u0136\\u00E4\\u20AC\\u53F0\\u5317\\x5B\\x5D\\x7B\\x7D\\x9\\xD\\xA\\x8\\u0080" ); -var test_template = twig({data: 'css: {{ foo|escape("css") }}' }); -test_template.render(data).should.equal("css: \\3C foo\\3E \\20 \\5C \\26 \\22 \\27 \\2E \\2C \\2D \\5F \\3F \\2F \\136 \\E4 \\20AC \\53F0 \\5317 \\5B \\5D \\7B \\7D \\9 \\D \\A \\8 \\80 " ); -var test_template = twig({data: 'url: {{ foo|escape("url") }}' }); -test_template.render(data).should.equal("url: %3Cfoo%3E%20%5C%26%22%27.%2C-_%3F%2F%C4%B6%C3%A4%E2%82%AC%E5%8F%B0%E5%8C%97%5B%5D%7B%7D%09%0D%0A%08%C2%80" ); -var test_template = twig({data: 'html_attr: {{ foo|escape("html_attr") }}' }); -test_template.render(data).should.equal("html_attr: <foo> \&"'.,-_?/Ķä€台北[]{}	
�€" ); -``` - -should escape strategy != 'html' if autoescape is on. - -```js -twig({ - autoescape: true, - data: '{{ value|escape("js") }}' -}).render({ - value: "<test>&</test>" -}).should.equal('\\x3Ctest\\x3E\\x26\\x3C\\x2Ftest\\x3E'); -``` - -should not escape twice if autoescape is not html. - -```js -twig({ - autoescape: 'js', - data: '{{ value|escape("js") }}' -}).render({ - value: "<test>&</test>" -}).should.equal('\\x3Ctest\\x3E\\x26\\x3C\\x2Ftest\\x3E'); -``` - -should escape twice if escape strategy is different from autoescape option. - -```js -twig({ - autoescape: 'css', - data: '{{ value|escape("js") }}\n{{ value|escape }}' -}).render({ - value: "<test>&</test>" -}).should.equal('\\5C x3Ctest\\5C x3E\\5C x26\\5C x3C\\5C x2Ftest\\5C x3E\n\\26 lt\\3B test\\26 gt\\3B \\26 amp\\3B \\26 lt\\3B \\2F test\\26 gt\\3B '); -``` - -<a name="twigjs-filters---e--"></a> -## e -> -should alias escape function with e. - -```js -var template = twig({data: '{{ "<p>Test paragraph.</p><!-- Comment --> <a href=\'#fragment\'>Other text</a>"|e }}'}); -template.render().should.equal("<p>Test paragraph.</p><!-- Comment --> <a href='#fragment\'>Other text</a>" ); -``` - -should handle undefined. - -```js -var test_template = twig({data: '{{ undef|e }}' }); -test_template.render().should.equal("" ); -``` - -should not escape twice if autoescape is on. - -```js -var template = twig({ - autoescape: true, - data: '{{ value|e }}' -}); -template.render({ - value: "<test>&</test>" -}).should.equal('<test>&</test>'); -``` - -<a name="twigjs-filters---nl2br--"></a> -## nl2br -> -should convert newlines into html breaks. - -```js -var template = twig({data: '{{ test|nl2br }}'}); -template.render({ test: 'Line 1\r\nLine 2\nLine 3\rLine 4\n\n' }) - .should.equal("Line 1<br />\nLine 2<br />\nLine 3<br />\nLine 4<br />\n<br />\n"); -``` - -should handle undefined. - -```js -var test_template = twig({data: '{{ undef|nl2br }}' }); -test_template.render().should.equal("" ); -``` - -should not escape br tags if autoescape is on. - -```js -twig({ - autoescape: true, - data: '{{ test|nl2br }}' -}).render({ - test: '<test>Line 1\nLine2</test>' -}).should.equal("<test>Line 1<br />\nLine2</test>"); -``` - -<a name="twigjs-filters---truncate--"></a> -## truncate -> -should truncate string to default size(20) and add default separator. - -```js -var template = twig({data: '{{ test|truncate }}'}); -template.render({test: '01234567890123456789012345678901234567890123456789'}).should.equal("012345678901234567890123456789..."); -``` - -should truncate string to custom size(10) and add default separator. - -```js -var template = twig({data: '{{ test|truncate(10) }}'}); -template.render({test: '01234567890123456789012345678901234567890123456789'}).should.equal("0123456789..."); -``` - -should truncate string to custom size(15) with preserve and add default separator. - -```js -var template = twig({data: '{{ test|truncate(15, true) }}'}); -template.render({test: '0123456789 0123456789 0123456789 0123456789 0123456789'}).should.equal("0123456789 0123456789..."); -``` - -should truncate string to custom size(15) with preserve and add custom(*) separator. - -```js -var template = twig({data: '{{ test|truncate(15, true, "*") }}'}); -template.render({test: '0123456789 0123456789 0123456789 0123456789 0123456789'}).should.equal("0123456789 0123456789*"); -``` - -<a name="twigjs-filters---trim--"></a> -## trim -> -should trim whitespace from strings. - -```js -var template = twig({data: '{{ test|trim }}'}); -template.render({ test: '\r\n Test\n ' }).should.equal("Test"); -``` - -should handle undefined. - -```js -var test_template = twig({data: '{{ undef|trim }}' }); -test_template.render().should.equal("" ); -``` - -<a name="twigjs-filters---number_format--"></a> -## number_format -> -should round to nearest integer if no parameters. - -```js -var template = twig({data: '{{ 1234.56|number_format }}'}); -template.render().should.equal("1,235"); -``` - -should have customizable precision. - -```js -var template = twig({data: '{{ 1234.567890123|number_format(4) }}'}); -template.render().should.equal("1,234.5679"); -``` - -should have a customizable decimal seperator. - -```js -var template = twig({data: '{{ 1234.567890123|number_format(2,",") }}'}); -template.render().should.equal("1,234,57"); -``` - -should have a customizable thousands seperator. - -```js -var template = twig({data: '{{ 1234.5678|number_format(2,","," ") }}'}); -template.render().should.equal("1 234,57"); -``` - -should handle blank seperators. - -```js -var template = twig({data: '{{ 1234.5678|number_format(2,"","") }}'}); -template.render().should.equal("123457"); -``` - -should handle undefined. - -```js -var test_template = twig({data: '{{ undef|number_format }}' }); -test_template.render().should.equal("0"); -``` - -<a name="twigjs-filters---slice--"></a> -## slice -> -should slice a string. - -```js -var test_template = twig({data: "{{ '12345'|slice(1, 2) }}" }); -test_template.render().should.equal("23"); -``` - -should slice a string to the end. - -```js -var test_template = twig({data: "{{ '12345'|slice(2) }}" }); -test_template.render().should.equal("345"); -``` - -should slice a string from the start. - -```js -var test_template = twig({data: "{{ '12345'|slice(null, 2) }}" }); -test_template.render().should.equal("12"); -``` - -should slice a string from a negative offset. - -```js -var test_template = twig({data: "{{ '12345'|slice(-2, 1) }}" }); -test_template.render().should.equal("4"); -``` - -should slice a string from a negative offset to end of string. - -```js -var test_template = twig({data: "{{ '12345'|slice(-2) }}" }); -test_template.render().should.equal("45"); -``` - -should slice an array. - -```js -var test_template = twig({data: "{{ [1, 2, 3, 4, 5]|slice(1, 2)|join(',') }}" }); -test_template.render().should.equal("2,3"); -``` - -should slice an array to the end. - -```js -var test_template = twig({data: "{{ [1, 2, 3, 4, 5]|slice(2)|join(',') }}" }); -test_template.render().should.equal("3,4,5"); -``` - -should slice an array from the start. - -```js -var test_template = twig({data: "{{ [1, 2, 3, 4, 5]|slice(null, 2)|join(',') }}" }); -test_template.render().should.equal("1,2"); -``` - -should slice an array from a negative offset. - -```js -var test_template = twig({data: "{{ [1, 2, 3, 4, 5]|slice(-2, 1)|join(',') }}" }); -test_template.render().should.equal("4"); -``` - -should slice an array from a negative offset to the end of the array. - -```js -var test_template = twig({data: "{{ [1, 2, 3, 4, 5]|slice(-4)|join(',') }}" }); -test_template.render().should.equal("2,3,4,5"); -``` - -<a name="twigjs-filters---abs--"></a> -## abs -> -should convert negative numbers to its absolute value. - -```js -var test_template = twig({data: "{{ '-7.365'|abs }}"}); -test_template.render().should.equal("7.365"); -``` - -should not alter absolute numbers. - -```js -var test_template = twig({data: "{{ 95|abs }}"}); -test_template.render().should.equal("95"); -``` - -<a name="twigjs-filters---first--"></a> -## first -> -should return first item in array. - -```js -var test_template = twig({data: "{{ ['a', 'b', 'c', 'd']|first }}"}); -test_template.render().should.equal("a"); -``` - -should return first member of object. - -```js -var test_template = twig({data: "{{ { item1: 'a', item2: 'b', item3: 'c', item4: 'd'}|first }}"}); -test_template.render().should.equal("a"); -``` - -should not fail when passed empty obj, arr or str. - -```js -var test_template = twig({data: "{{ {}|first }}"}); -test_template.render().should.equal(""); -var test_template = twig({data: "{{ []|first }}"}); -test_template.render().should.equal(""); -var test_template = twig({data: "{{ myemptystr|first }}"}); -test_template.render({myemptystr: ""}).should.equal(""); -``` - -should return first character in string. - -```js -var test_template = twig({data: "{{ 'abcde'|first }}"}); -test_template.render().should.equal("a"); -``` - -<a name="twigjs-filters---split--"></a> -## split -> -should split string with a separator. - -```js -var test_template = twig({data: "{{ 'one-two-three'|split('-') }}"}); -test_template.render().should.equal("one,two,three"); -``` - -should split string with a separator and positive limit. - -```js -var test_template = twig({data: "{{ 'one-two-three-four-five'|split('-', 3) }}"}); -test_template.render().should.equal("one,two,three-four-five"); -``` - -should split string with a separator and negative limit. - -```js -var test_template = twig({data: "{{ 'one-two-three-four-five'|split('-', -2) }}"}); -test_template.render().should.equal("one,two,three"); -``` - -should split with empty separator. - -```js -var test_template = twig({data: "{{ '123'|split('') }}"}); -test_template.render().should.equal("1,2,3"); -``` - -should split with empty separator and limit. - -```js -var test_template = twig({data: "{{ 'aabbcc'|split('', 2) }}"}); -test_template.render().should.equal("aa,bb,cc"); -``` - -<a name="twigjs-filters---batch--"></a> -## batch -> -should work with arrays that require filling (with fill specified). - -```js -var test_template = twig({data: "{{ ['a', 'b', 'c', 'd', 'e', 'f', 'g']|batch(3, 'x') }}"}); -test_template.render().should.equal("a,b,c,d,e,f,g,x,x"); -``` - -should work with arrays that require filling (without fill specified). - -```js -var test_template = twig({data: "{{ ['a', 'b', 'c', 'd', 'e', 'f', 'g']|batch(3) }}"}); -test_template.render().should.equal("a,b,c,d,e,f,g"); -``` - -should work with arrays that do not require filling (with fill specified). - -```js -var test_template = twig({data: "{{ ['a', 'b', 'c', 'd', 'e', 'f']|batch(3, 'x') }}"}); -test_template.render().should.equal("a,b,c,d,e,f"); -``` - -should work with arrays that do not require filling (without fill specified). - -```js -var test_template = twig({data: "{{ ['a', 'b', 'c', 'd', 'e', 'f']|batch(3) }}"}); -test_template.render().should.equal("a,b,c,d,e,f"); -``` - -should return an empty result for an empty array. - -```js -var test_template = twig({data: "{{ []|batch(3, 'x') }}"}); -test_template.render().should.equal(""); -``` - -<a name="twigjs-filters---last--"></a> -## last -> -should return last character in string. - -```js -var test_template = twig({data: "{{ 'abcd'|last }}"}); -test_template.render().should.equal("d"); -``` - -should return last item in array. - -```js -var test_template = twig({data: "{{ ['a', 'b', 'c', 'd']|last }}"}); -test_template.render().should.equal("d"); -``` - -should return last item in a sorted object. - -```js -var test_template = twig({data: "{{ {'m':1, 'z':5, 'a':3}|sort|last }}" }); -test_template.render().should.equal("5"); -``` - -<a name="twigjs-filters---raw--"></a> -## raw -> -should output the raw value if autoescape is on. - -```js -var template = twig({ - autoescape: true, - data: '{{ value|raw }}' -}); -template.render({ - value: "<test>&</test>" -}).should.equal('<test>&</test>'); -``` - -should output the raw value if autoescape is off. - -```js -var template = twig({ - autoescape: false, - data: '{{ value|raw }}' -}); -template.render({ - value: "<test>&</test>" -}).should.equal('<test>&</test>'); -``` - -<a name="twigjs-filters---round--"></a> -## round -> -should round up (common). - -```js -var test_template = twig({data: "{{ 2.7|round }}"}); -test_template.render().should.equal("3"); -``` - -should round down (common). - -```js -var test_template = twig({data: "{{ 2.1|round }}"}); -test_template.render().should.equal("2"); -``` - -should truncate input when input decimal places exceeds precision (floor). - -```js -var test_template = twig({data: "{{ 2.1234|round(3, 'floor') }}" }); -test_template.render().should.equal("2.123"); -``` - -should round up (ceil). - -```js -var test_template = twig({data: "{{ 2.1|round(0, 'ceil') }}" }); -test_template.render().should.equal("3"); -``` - -should truncate precision when a negative precision is passed (common). - -```js -var test_template = twig({data: "{{ 21.3|round(-1)}}" }); -test_template.render().should.equal("20"); -``` - -should round up and truncate precision when a negative precision is passed (ceil). - -```js -var test_template = twig({data: "{{ 21.3|round(-1, 'ceil')}}" }); -test_template.render().should.equal("30"); -``` - -should round down and truncate precision when a negative precision is passed (floor). - -```js -var test_template = twig({data: "{{ 21.3|round(-1, 'ceil')}}" }); -test_template.render().should.equal("30"); -``` - -<a name="twigjs-loader--"></a> -# Twig.js Loader -> -should load a template from the filesystem asynchronously. - -```js -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. - -```js -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!"); -``` - -<a name="twigjs-loader---source--"></a> -## source -> -should load the non-compiled template source code. - -```js -twig({data: '{{ source("test/templates/source.twig") }}'}) - .render() - .should - .equal('{% if isUserNew == true %}\n Hello {{ name }}\n{% else %}\n Welcome back {{ name }}\n{% endif %}\n') -; -``` - -should indicate if there was a problem loading the template if 'ignore_missing' is false. - -```js -twig({data: '{{ source("test/templates/non-existing-source.twig", false) }}'}) - .render() - .should - .equal('Template "test/templates/non-existing-source.twig" is not defined.') -; -``` - -should NOT indicate if there was a problem loading the template if 'ignore_missing' is true. - -```js -twig({data: '{{ source("test/templates/non-existing-source.twig", true) }}'}) - .render() - .should - .equal('') -; -``` - -<a name="twigjs-include--"></a> -# Twig.js Include -> -should load an included template with no context. - -```js -twig({ - id: 'include', - path: 'test/templates/include.twig', - async: false -}); -// Load the template -twig({ref: 'include'}).render({test: 'tst'}).should.equal( "BeforeTest template = tst\n\nAfter" ); -``` - -should load an included template with additional context. - -```js -twig({ - id: 'include-with', - path: 'test/templates/include-with.twig', - async: false -}); -// Load the template -twig({ref: 'include-with'}).render({test: 'tst'}).should.equal( "template: before,tst-mid-template: after,tst" ); -``` - -should load an included template with only additional context. - -```js -twig({ - id: 'include-only', - path: 'test/templates/include-only.twig', - async: false -}); -// Load the template -twig({ref: 'include-only'}).render({test: 'tst'}).should.equal( "template: before,-mid-template: after," ); -``` - -<a name="twigjs-functions--"></a> -# Twig.js Functions -> -should allow you to define a function. - -```js -twig({data: '{{ square(a) }}'}).render({a:4}).should.equal("16"); -``` - -should chain with other expressions. - -```js -twig({data: '{{ square(a) + 4 }}'}).render({a:4}).should.equal("20"); -``` - -should chain with filters. - -```js -twig({data: '{{ echo(a)|default("foo") }}'}).render().should.equal("foo"); -``` - -should work in for loop expressions. - -```js -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. - -```js -twig({data: '{{ square ( square ) + square }}'}).render({square: 2}).should.equal("6"); -``` - -should work with boolean operations. - -```js -twig({data: '{% if echo(true) or echo(false) %}yes{% endif %}'}).render().should.equal("yes"); -``` - -should execute functions passed as context values. - -```js -twig({ - data: '{{ value }}' -}).render({ - value: function() { - return "test"; - } -}).should.equal("test"); -``` - -should execute functions passed as context values with this mapped to the context. - -```js -twig({ - data: '{{ value }}' -}).render({ - test: "value", - value: function() { - return this.test; - } -}).should.equal("value"); -``` - -should execute functions passed as context values with arguments. - -```js -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. - -```js -twig({ - data: '{{ value }}' -}).render({ - test: "value", - value: function() { - return this.test; - } -}).should.equal("value"); -``` - -should execute functions passed as context object parameters. - -```js -twig({ - data: '{{ obj.value }}' -}).render({ - obj: { - value: function() { - return "test"; - } - } -}).should.equal("test"); -``` - -should execute functions passed as context object parameters with arguments. - -```js -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. - -```js -twig({ - data: '{{ obj["value"] }}' -}).render({ - obj: { - value: function() { - return "test"; - } - } -}).should.equal("test"); -``` - -should execute functions passed as context object parameters with arguments. - -```js -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"); -``` - -<a name="twigjs-functions---built-in-functions--"></a> -## Built-in Functions -> -<a name="twigjs-functions---built-in-functions---range--"></a> -### range -> -should work over a range of numbers. - -```js -twig({data: '{% for i in range(0, 3) %}{{ i }},{% endfor %}'}).render().should.equal("0,1,2,3,"); -``` - -should work over a range of letters. - -```js -twig({data: '{% for i in range("a", "c") %}{{ i }},{% endfor %}'}).render().should.equal("a,b,c,"); -``` - -should work with an interval. - -```js -twig({data: '{% for i in range(1, 15, 3) %}{{ i }},{% endfor %}'}).render().should.equal("1,4,7,10,13,"); -``` - -should work with .. invocation. - -```js -twig({data: '{% for i in 0..3 %}{{ i }},{% endfor %}'}).render().should.equal("0,1,2,3,"); -twig({data: '{% for i in "a" .. "c" %}{{ i }},{% endfor %}'}).render().should.equal("a,b,c,"); -``` - -<a name="twigjs-functions---built-in-functions---cycle--"></a> -### cycle -> -should cycle through an array of values. - -```js -twig({data: '{% for i in range(0, 3) %}{{ cycle(["odd", "even"], i) }};{% endfor %}'}).render().should.equal("odd;even;odd;even;"); -``` - -<a name="twigjs-functions---built-in-functions---date--"></a> -### date -> -should understand timestamps. - -```js -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. - -```js -twig({data: '{{ date("+1 day") > date() }}'}).render().should.equal("true"); -twig({data: '{{ date("-1 day") > date() }}'}).render().should.equal("false"); -``` - -should support 'now' as a date parameter. - -```js -twig({data: '{{ date("now") }}' }).render().should.equal(new Date().toString()); -``` - -should understand exact dates. - -```js -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)); -``` - -<a name="twigjs-functions---built-in-functions---dump--"></a> -### dump -> -should output formatted number. - -```js -twig({data: '{{ dump(test) }}' }).render({ test: 5 }).should.equal('number(5)' + EOL); -``` - -should output formatted string. - -```js -twig({data: '{{ dump(test) }}' }).render({ test: "String" }).should.equal('string(6) "String"' + EOL); -``` - -should output formatted boolean. - -```js -twig({data: '{{ dump(test) }}' }).render({ test: true }).should.equal('bool(true)' + EOL); -``` - -should output formatted null. - -```js -twig({data: '{{ dump(test) }}' }).render({ test: null }).should.equal('NULL' + EOL); -``` - -should output formatted object. - -```js -twig({data: '{{ dump(test) }}' }).render({ test: {} }).should.equal('object(0) {' + EOL + '}' + EOL); -``` - -should output formatted array. - -```js -twig({data: '{{ dump(test) }}' }).render({ test: [] }).should.equal('object(0) {' + EOL + '}' + EOL); -``` - -should output formatted undefined. - -```js -twig({data: '{{ dump(test) }}' }).render({ test: undefined }).should.equal('undefined' + EOL); -``` - -<a name="twigjs-functions---built-in-functions---block--"></a> -### block -> -should render the content of blocks. - -```js -twig({data: '{% block title %}Content - {{ val }}{% endblock %} Title: {{ block("title") }}'}).render({ val: "test" }) - .should.equal("Content - test Title: Content - test"); -``` - -shouldn't escape the content of blocks twice. - -```js -twig({ - autoescape: true, - data: '{% block test %}{{ val }}{% endblock %} {{ block("test") }}' -}).render({ - val: "te&st" -}).should.equal("te&st te&st"); -``` - -<a name="twigjs-functions---built-in-functions---attribute--"></a> -### attribute -> -should access attribute of an object. - -```js -twig({data: '{{ attribute(obj, key) }}' }).render({ - obj: { name: "Twig.js"}, - key: "name" -}) -.should.equal("Twig.js"); -``` - -should call function of attribute of an object. - -```js -twig({data: '{{ attribute(obj, key, params) }}' }).render({ - obj: { - name: function(first, last) { - return first+'.'+last; - } - }, - key: "name", - params: ['Twig', 'js'] - }) - .should.equal("Twig.js"); -``` - -should return undefined for missing attribute of an object. - -```js -twig({data: '{{ attribute(obj, key, params) }}' }).render({ - obj: { - name: function(first, last) { - return first+'.'+last; - } - }, - key: "missing", - params: ['Twig', 'js'] - }) - .should.equal(""); -``` - -should return element of an array. - -```js -twig({data: '{{ attribute(arr, 0) }}' }).render({ - arr: ['Twig', 'js'] - }) - .should.equal("Twig"); -``` - -should return undef for array beyond index size. - -```js -twig({data: '{{ attribute(arr, 100) }}' }).render({ - arr: ['Twig', 'js'] - }) - .should.equal(""); -``` - -<a name="twigjs-functions---built-in-functions---template_from_string--"></a> -### template_from_string -> -should load a template from a string. - -```js -twig({data: '{% include template_from_string("{{ value }}") %}'}).render({ - value: 'test' -}) -.should.equal('test'); -``` - -should load a template from a variable. - -```js -twig({data: '{% include template_from_string(template) %}'}).render({ - template: '{{ value }}', - value: 'test' -}) -.should.equal('test'); -``` - -<a name="twigjs-functions---built-in-functions---random--"></a> -### random -> -should return a random item from a traversable or array. - -```js -var arr = "bcdefghij".split(""); -for (var i = 1; i <= 1000; i++) { - arr.should.containEql(twig({data: '{{ random(arr) }}'}).render({arr: arr})); -} -``` - -should return a random character from a string. - -```js -var str = "abcdefghij"; -for (var i = 1; i <= 1000; i++) { - str.should.containEql(twig({data: '{{ random(str) }}'}).render({str: str})); -} -``` - -should return a random integer between 0 and the integer parameter. - -```js -for (var i = 1; i <= 1000; i++) { - twig({data: '{{ random(10) }}'}).render().should.be.within(0, 10); -} -``` - -should return a random integer between 0 and 2147483647 when no parameters are passed. - -```js -for (var i = 1; i <= 1000; i++) { - twig({data: '{{ random() }}'}).render().should.be.within(0, 2147483647); -} -``` - -<a name="twigjs-functions---built-in-functions---min-max--"></a> -### min, max -> -should support the 'min' function. - -```js -twig({data: '{{ min(2, 1, 3, 5, 4) }}'}).render().should.equal('1'); -twig({data: '{{ min([2, 1, 3, 5, 4]) }}'}).render().should.equal('1'); -twig({data: '{{ min({2:"two", 1:"one", 3:"three", 5:"five", 4:"four"}) }}'}).render().should.equal('five'); -``` - -should support the 'max' function. - -```js -twig({data: '{{ max([2, 1, 3, 5, 4]) }}'}).render().should.equal('5'); -twig({data: '{{ max(2, 1, 3, 5, 4) }}'}).render().should.equal('5'); -twig({data: '{{ max({2:"two", 1:"one", 3:"three", 5:"five", 4:"four"}) }}'}).render().should.equal('two'); -``` - -<a name="twigjs-loaders--"></a> -# Twig.js Loaders -> -<a name="twigjs-loaders---custom-loader--"></a> -## custom loader -> -should define a custom loader. - -```js -Twig.extend(function(Twig) { - var obj = { - templates: { - 'custom_loader_block': '{% block main %}This lets you {% block data %}use blocks{% endblock data %}{% endblock main %}', - 'custom_loader_simple': 'the value is: {{ value }}', - 'custom_loader_include': 'include others from the same loader method - {% include "custom_loader_simple" %}', - 'custom_loader_complex': '{% extends "custom_loader_block" %} {% block data %}extend other templates and {% include "custom_loader_include" %}{% endblock data %}' - }, - loader: function(location, params, callback, error_callback) { - params.data = this.templates[location]; - params.allowInlineIncludes = true; - var template = new Twig.Template(params); - if (typeof callback === 'function') { - callback(template); - } - return template; - } - }; - Twig.Templates.registerLoader('custom', obj.loader, obj); - Twig.Templates.loaders.should.have.property('custom'); -}); -``` - -should load a simple template from a custom loader. - -```js -twig({ - method: 'custom', - name: 'custom_loader_simple' -}).render({value: 'test succeeded'}).should.equal('the value is: test succeeded'); -``` - -should load a template that includes another from a custom loader. - -```js -twig({ - method: 'custom', - name: 'custom_loader_include' -}).render({value: 'test succeeded'}).should.equal('include others from the same loader method - the value is: test succeeded'); -``` - -should load a template that extends another from a custom loader. - -```js -twig({ - method: 'custom', - name: 'custom_loader_complex' -}).render({value: 'test succeeded'}).should.equal('This lets you extend other templates and include others from the same loader method - the value is: test succeeded'); -``` - -should remove a registered loader. - -```js -Twig.extend(function(Twig) { - Twig.Templates.unRegisterLoader('custom'); - Twig.Templates.loaders.should.not.have.property('custom'); -}); -``` - -<a name="twigjs-macro--"></a> -# Twig.js Macro -> -it should load macro. - -```js -twig({ - id: 'macro', - path: 'test/templates/macro.twig', - async: false -}); -// Load the template -twig({ref: 'macro'}).render({ }).should.equal( '' ); -``` - -it should import macro. - -```js -twig({ - id: 'import-macro', - path: 'test/templates/import.twig', - async: false -}); -// Load the template -twig({ref: 'import-macro'}).render({ }).trim().should.equal( "Hello World" ); -``` - -it should run macro with self reference. - -```js -twig({ - id: 'import-macro-self', - path: 'test/templates/macro-self.twig', - async: false -}); -// Load the template -twig({ref: 'import-macro-self'}).render({ }).trim().should.equal( '<p><input type="text" name="username" value="" size="20" /></p>' ); -``` - -it should run wrapped macro with self reference. - -```js -twig({ - id: 'import-wrapped-macro-self', - path: 'test/templates/macro-wrapped.twig', - async: false -}); -// Load the template -twig({ref: 'import-wrapped-macro-self'}).render({ }).trim().should.equal( '<p><div class="field"><input type="text" name="username" value="" size="20" /></div></p>' ); -``` - -it should run wrapped macro with context and self reference. - -```js -twig({ - id: 'import-macro-context-self', - path: 'test/templates/macro-context.twig', - async: false -}); -// Load the template -twig({ref: 'import-macro-context-self'}).render({ 'greetings': 'Howdy' }).trim().should.equal( 'Howdy Twigjs' ); -``` - -it should run wrapped macro inside blocks. - -```js -twig({ - id: 'import-macro-inside-block', - path: 'test/templates/macro-blocks.twig', - async: false -}); -// Load the template -twig({ref: 'import-macro-inside-block'}).render({ }).trim().should.equal( 'Welcome <div class="name">Twig Js</div>' ); -``` - -it should import selected macros from template. - -```js -twig({ - id: 'from-macro-import', - path: 'test/templates/from.twig', - async: false -}); -// Load the template -twig({ref: 'from-macro-import'}).render({ }).trim().should.equal( 'Twig.js<div class="field"><input type="text" name="text" value="" size="20" /></div><div class="field red"><input type="text" name="password" value="" size="20" /></div>' ); -``` - -should support inline includes by ID. - -```js -twig({ - id: 'hello', - data: '{% macro echo(name) %}Hello {{ name }}{% endmacro %}' -}); -var template = twig({ - allowInlineIncludes: true, - data: 'template with {% from "hello" import echo %}{{ echo("Twig.js") }}' - }), - output = template.render() -output.should.equal("template with Twig.js"); -``` - -<a name="twigjs-namespaces--"></a> -# Twig.js Namespaces -> -should support namespaces defined with ::. - -```js -twig({ - namespaces: { 'test': 'test/templates/namespaces/' }, - path: 'test/templates/namespaces_::.twig', - load: function(template) { - // Render the template - template.render({ - test: "yes", - flag: true - }).should.equal("namespaces"); - - done(); - } - }); -``` - -should support namespaces defined with @. - -```js -twig({ - namespaces: { 'test': 'test/templates/namespaces/' }, - path: 'test/templates/namespaces_@.twig', - load: function(template) { - // Render the template - template.render({ - test: "yes", - flag: true - }).should.equal("namespaces"); - - done(); - } - }); -``` - -<a name="twigjs-optional-functionality--"></a> -# Twig.js Optional Functionality -> -should support inline includes by ID. - -```js -twig({ - id: 'other', - data: 'another template' -}); -var template = twig({ - allowInlineIncludes: true, - data: 'template with {% include "other" %}' - }), - output = template.render() -output.should.equal("template with another template"); -``` - -<a name="twigjs-parsers--"></a> -# Twig.js Parsers -> -<a name="twigjs-parsers---custom-parser--"></a> -## custom parser -> -should define a custom parser. - -```js -Twig.extend(function(Twig) { - var parser = function(params) { - return '[CUSTOM PARSER] ' + params.data; - }; - Twig.Templates.registerParser('custom', parser); - Twig.Templates.parsers.should.have.property('custom'); -}); -``` - -should run the data through the custom parser. - -```js -Twig.extend(function(Twig) { - var params = { - data: 'This is a test template.' - }; - var template = Twig.Templates.parsers.custom(params); - template.should.equal('[CUSTOM PARSER] This is a test template.'); -}); -``` - -should remove a registered parser. - -```js -Twig.extend(function(Twig) { - Twig.Templates.unRegisterParser('custom'); - Twig.Templates.parsers.should.not.have.property('custom'); -}); -``` - -<a name="twigjs-path--"></a> -# Twig.js Path -> -<a name="twigjs-path---relativepath--"></a> -## relativePath -> -should throw an error if trying to get a relative path in an inline template. - -```js -(function () { - relativePath({}); -}).should.throw("Cannot extend an inline template."); -``` - -should give the full path to a file when file is passed. - -```js -relativePath({ url: "http://www.test.com/test.twig"}, "templates/myFile.twig").should.equal("http://www.test.com/templates/myFile.twig"); -relativePath({ path: "test/test.twig"}, "templates/myFile.twig").should.equal("test/templates/myFile.twig"); -``` - -should ascend directories. - -```js -relativePath({ url: "http://www.test.com/templates/../test.twig"}, "myFile.twig").should.equal("http://www.test.com/myFile.twig"); -relativePath({ path: "test/templates/../test.twig"}, "myFile.twig").should.equal("test/myFile.twig"); -``` - -should respect relative directories. - -```js -relativePath({ url: "http://www.test.com/templates/./test.twig"}, "myFile.twig").should.equal("http://www.test.com/templates/myFile.twig"); -relativePath({ path: "test/templates/./test.twig"}, "myFile.twig").should.equal("test/templates/myFile.twig"); -``` - -<a name="twigjs-path---relativepath---url--"></a> -### url -> -should use the url if no base is specified. - -```js -relativePath({ url: "http://www.test.com/test.twig"}).should.equal("http://www.test.com/"); -``` - -should use the base if base is specified. - -```js -relativePath({ url: "http://www.test.com/test.twig", base: "myTest" }).should.equal("myTest/"); -``` - -<a name="twigjs-path---relativepath---path--"></a> -### path -> -should use the path if no base is specified. - -```js -relativePath({ path: "test/test.twig"}).should.equal("test/"); -``` - -should use the base if base is specified. - -```js -relativePath({ path: "test/test.twig", base: "myTest" }).should.equal("myTest/"); -``` - -<a name="twigjs-path---parsepath--"></a> -## parsePath -> -should fall back to relativePath if the template has no namespaces defined. - -```js -var relativePathStub = sinon.stub(Twig.path, "relativePath"); -parsePath({ options: {} }); -relativePathStub.should.have.been.called; -``` - -<a name="twigjs-regression-tests--"></a> -# Twig.js Regression Tests -> -#47 should not match variables starting with not. - -```js -// Define and save a template -twig({data: '{% for note in notes %}{{note}}{% endfor %}'}).render({notes:['a', 'b', 'c']}).should.equal("abc"); -``` - -#56 functions work inside parentheses. - -```js -// Define and save a template -Twig.extendFunction('custom', function(value) { - return true; -}); -twig({data: '{% if (custom("val") and custom("val")) %}out{% endif %}'}).render({}).should.equal("out"); -``` - -#83 Support for trailing commas in arrays. - -```js -twig({data: '{{ [1,2,3,4,] }}'}).render().should.equal("1,2,3,4"); -``` - -#83 Support for trailing commas in objects. - -```js -twig({data: '{{ {a:1, b:2, c:3, } }}'}).render(); -``` - -#283 should support quotes between raw tags. - -```js -twig({data: '{% raw %}\n"\n{% endraw %}'}).render().should.equal('"'); -twig({data: "{% raw %}\n'\n{% endraw %}"}).render().should.equal("'"); -``` - -<a name="twigjs-tags--"></a> -# Twig.js Tags -> -should support spaceless. - -```js -twig({ - data: "{% spaceless %}<div>\n <b>b</b> <i>i</i>\n</div>{% endspaceless %}" -}).render().should.equal( - "<div><b>b</b><i>i</i></div>" -); -``` - -<a name="twigjs-tests--"></a> -# Twig.js Tests -> -<a name="twigjs-tests---empty-test--"></a> -## empty test -> -should identify numbers as not empty. - -```js -// number -twig({data: '{{ 1 is empty }}'}).render().should.equal("false" ); -twig({data: '{{ 0 is empty }}'}).render().should.equal("false" ); -``` - -should identify empty strings. - -```js -// String -twig({data: '{{ "" is empty }}'}).render().should.equal("true" ); -twig({data: '{{ "test" is empty }}'}).render().should.equal("false" ); -``` - -should identify empty arrays. - -```js -// Array -twig({data: '{{ [] is empty }}'}).render().should.equal("true" ); -twig({data: '{{ ["1"] is empty }}'}).render().should.equal("false" ); -``` - -should identify empty objects. - -```js -// 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" ); -``` - -<a name="twigjs-tests---odd-test--"></a> -## odd test -> -should identify a number as odd. - -```js -twig({data: '{{ (1 + 4) is odd }}'}).render().should.equal("true" ); -twig({data: '{{ 6 is odd }}'}).render().should.equal("false" ); -``` - -<a name="twigjs-tests---even-test--"></a> -## even test -> -should identify a number as even. - -```js -twig({data: '{{ (1 + 4) is even }}'}).render().should.equal("false" ); -twig({data: '{{ 6 is even }}'}).render().should.equal("true" ); -``` - -<a name="twigjs-tests---divisibleby-test--"></a> -## divisibleby test -> -should determine if a number is divisible by the given number. - -```js -twig({data: '{{ 5 is divisibleby(3) }}'}).render().should.equal("false" ); -twig({data: '{{ 6 is divisibleby(3) }}'}).render().should.equal("true" ); -``` - -<a name="twigjs-tests---defined-test--"></a> -## defined test -> -should identify a key as defined if it exists in the render context. - -```js -twig({data: '{{ key is defined }}'}).render().should.equal("false" ); -twig({data: '{{ key is defined }}'}).render({key: "test"}).should.equal( "true" ); -var context = { - key: { - foo: "bar", - nothing: null - }, - nothing: null -}; -twig({data: '{{ key.foo is defined }}'}).render(context).should.equal( "true" ); -twig({data: '{{ key.bar is defined }}'}).render(context).should.equal( "false" ); -twig({data: '{{ key.foo.bar is defined }}'}).render(context).should.equal( "false" ); -twig({data: '{{ foo.bar is defined }}'}).render(context).should.equal( "false" ); -twig({data: '{{ nothing is defined }}'}).render(context).should.equal( "true" ); -twig({data: '{{ key.nothing is defined }}'}).render(context).should.equal( "true" ); -``` - -<a name="twigjs-tests---none-test--"></a> -## none test -> -should identify a key as none if it exists in the render context and is null. - -```js -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"); -twig({data: '{{ key is null }}'}).render({key: null}).should.equal("true"); -``` - -<a name="twigjs-tests---sameas-test--"></a> -## sameas test -> -should identify the exact same type as true. - -```js -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. - -```js -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"); -``` - -<a name="twigjs-tests---iterable-test--"></a> -## iterable test -> -should fail on non-iterable data types. - -```js -twig({data: "{{ val is iterable ? 'ok' : 'ko' }}"}).render(data).should.equal("ko"); -twig({data: "{{ val is iterable ? 'ok' : 'ko' }}"}).render({val: null}).should.equal("ko"); -twig({data: "{{ val is iterable ? 'ok' : 'ko' }}"}).render({}).should.equal("ko"); -``` - -should pass on iterable data types. - -```js -twig({data: "{{ foo is iterable ? 'ok' : 'ko' }}"}).render(data).should.equal("ok"); -twig({data: "{{ obj is iterable ? 'ok' : 'ko' }}"}).render(data).should.equal("ok"); -``` - |