summaryrefslogtreecommitdiff
path: root/vendor/zordius
diff options
context:
space:
mode:
authorPierre Schmitz <pierre@archlinux.de>2015-12-20 09:00:55 +0100
committerPierre Schmitz <pierre@archlinux.de>2015-12-20 09:00:55 +0100
commita2190ac74dd4d7080b12bab90e552d7aa81209ef (patch)
tree8b31f38de9882d18df54cf8d9e0de74167a094eb /vendor/zordius
parent15e69f7b20b6596b9148030acce5b59993b95a45 (diff)
parent257401d8b2cf661adf36c84b0e3fd1cf85e33c22 (diff)
Merge branch 'mw-1.26'
Diffstat (limited to 'vendor/zordius')
-rw-r--r--vendor/zordius/lightncandy/HISTORY.md180
-rw-r--r--vendor/zordius/lightncandy/LICENSE.txt2
-rw-r--r--vendor/zordius/lightncandy/README.md91
-rw-r--r--vendor/zordius/lightncandy/UPGRADE.md4
-rwxr-xr-xvendor/zordius/lightncandy/build/gen_doc6
-rw-r--r--vendor/zordius/lightncandy/build/gen_test.php64
-rwxr-xr-xvendor/zordius/lightncandy/build/push_ghpage12
-rwxr-xr-xvendor/zordius/lightncandy/build/runphp2
-rwxr-xr-xvendor/zordius/lightncandy/build/travis_push60
-rw-r--r--vendor/zordius/lightncandy/src/lightncandy.php540
-rw-r--r--vendor/zordius/lightncandy/tests/LCRun3Test.php18
-rw-r--r--vendor/zordius/lightncandy/tests/LightnCandyTest.php159
-rw-r--r--vendor/zordius/lightncandy/tests/contextTest.php300
-rw-r--r--vendor/zordius/lightncandy/tests/errorTest.php23
-rwxr-xr-x[-rw-r--r--]vendor/zordius/lightncandy/tests/example_helpers.php0
-rw-r--r--vendor/zordius/lightncandy/tests/helpers_for_test.php12
-rw-r--r--vendor/zordius/lightncandy/tests/regressionTest.php609
17 files changed, 1733 insertions, 349 deletions
diff --git a/vendor/zordius/lightncandy/HISTORY.md b/vendor/zordius/lightncandy/HISTORY.md
index 577f953d..60237bbb 100644
--- a/vendor/zordius/lightncandy/HISTORY.md
+++ b/vendor/zordius/lightncandy/HISTORY.md
@@ -4,106 +4,145 @@ HISTORY
master current trunk
* align with handlebars.js master
-v0.17 https://github.com/zordius/lightncandy/tree/v0.17
- * 7bcce4c1a7 support {{@last}} for {{#each}} on both object and array.
+v0.21 https://github.com/zordius/lightncandy/tree/v0.21
+ * align with handlebars.js 3.0.3
+ * 9f24268d57 support FLAG_BARE to remove PHP start/end tags
+ * 60d5a46c55 handle object/propery merge when deal with partial
+ * d0130bf7e5 support undefined `{{helper undefined}}`
+ * 8d228606f7 support `lcrun` to use customized render library when compile()
+ * d0bad115f0 remove tmp PHP file when prepare() now
+ * d84bbb4519 support keeping tmp PHP file when prepare()
+ * ee833ae2f8 fix syntax validator bug on `{{helper "foo[]"}}`
+ * 30b891ab28 fix syntax validator bug on `{{helper 'foo[]'}}`
+ * 1867f1cc37 now count subexpression usage correctly
+ * 78ef9b8a89 new syntax validator on handlebars variable name
+
+v0.20 https://github.com/zordius/lightncandy/tree/v0.20
+ * align with handlebars.js 3.0.0
+ * 3d9a557af9 fix `{{foo (bar ../abc)}}` compile bug
+ * 7dc16ac255 refine custom helper error detection logic
+ * 72d32dc299 fix subexpression parsing bug inside `{{#each}}`
+ * d1f1b93130 support context access inside a hbhelper by `$options['_this']`
+
+v0.19 https://github.com/zordius/lightncandy/tree/v0.19
+ * align with handlebars.js 3.0.0
+ * 5703851e49 fix `{{foo bar=['abc=123']}}` parsing bug
+ * 7b4e36a1e3 fix `{{foo bar=["abc=123"]}}` parsing bug
+ * c710c8349b fix `{{foo bar=(helper a b c)}}` parsing bug
+ * 4bda1c6f41 fix subexpression+builtin block helper (EX: `{{#if (foo bar)}}`) parsing bug
+ * 6fdba10fc6 fix `{{foo ( bar) or " car" or ' cat' or [ cage]}}` pasing bug
+ * 0cd5f2d5e2 fix indent issue when custom helper inside a partial
+ * 296ea89267 support dynamic partial `{{> (foo)}}`
+ * f491d04bd5 fix `{{../foo}}` look up inside root scope issue
+ * 38fba8a5a5 fix scope issue for hbhelpers
+ * a24a0473e2 change internal variable structure and fix for `{{number}}`
+ * 7ae8289b7e fix escape in double quoted string bug
+ * 90adb5531b fix `{{#if 0.0}}` logic to behave as false
+ * 004a6ddffe fix `{{../foo}}` double usage count bug
+ * 9d55f12c5a fix subexpression parsing bug when line change inside it
+
+v0.18 https://github.com/zordius/lightncandy/tree/v0.18
+ * align with handlebars.js 2.0.0
+ * 7bcce4c1a7 support `{{@last}}` for `{{#each}}` on both object and array
* b0c44c3b40 remove ending \n in lightncandy.php
- * e130875d5a support single quoted string input: {{foo 'bar'}}.
- * c603aa39d8 support `renderex` to extend anything in render function.
- * f063e5302c now render function debug constants works well in standalone mode.
- * 53f6a6816d fix parsing bug when there is a `=` inside single quoted string.
- * 2f16c0c393 now really autoload when installed with composer.
- * c4da1f576c supports {{^myHelper}}.
+ * e130875d5a support single quoted string input: `{{foo 'bar'}}`
+ * c603aa39d8 support `renderex` to extend anything in render function
+ * f063e5302c now render function debug constants works well in standalone mode
+ * 53f6a6816d fix parsing bug when there is a `=` inside single quoted string
+ * 2f16c0c393 now really autoload when installed with composer
+ * c4da1f576c supports `{{^myHelper}}`
v0.17 https://github.com/zordius/lightncandy/tree/v0.17
+ * align with handlebars.js 2.0.0
* 3b48a0acf7 fix parsing bug when FLAG_NOESCAPE enabled
* 5c774b1b08 fix hbhelpers response error with options['fn'] when FLAG_BESTPERFORMANCE enabled
* c60fe70bdb fix hbhelpers response error with options['inverse'] when FLAG_BESTPERFORMANCE enabled
* e19b3e3426 provide options['root'] and options['_parent'] to hbhelpers
- * d8a288e83b refine variable parsing logic to support {{@../index}}, {{@../key}}, etc.
+ * d8a288e83b refine variable parsing logic to support `{{@../index}}`, `{{@../key}}`, etc.
v0.16 https://github.com/zordius/lightncandy/tree/v0.16
* align with handlebars.js 2.0.0
- * 4f036aff62 better error message for named arguments.
- * 0b462a387b support {{#with var}} ... {{else}} ... {{/with}}.
- * 4ca624f651 fix 1 ANSI code error.
- * 01ea3e9f42 support instances with PHP __call magic funciton.
- * 38059036a7 support {{#foo}} or {{#each foo}} on PHP Traversable instance.
- * 366f5ec0ac add FLAG_MUSTACHESP and FLAG_MUSTACHEPAIN into FLAG_HANDLEBARS and FLAG_HANDLEBARSJS now.
- * b61d7b4a81 align with handlebars.js standalone tags behavior.
- * b211e1742e now render false as 'false'.
- * 655a2485be fix bug for {{helper "==="}}
+ * 4f036aff62 better error message for named arguments
+ * 0b462a387b support `{{#with var}}` ... `{{else}}` ... `{{/with}}`
+ * 4ca624f651 fix 1 ANSI code error
+ * 01ea3e9f42 support instances with PHP __call magic funciton
+ * 38059036a7 support `{{#foo}}` or `{{#each foo}}` on PHP Traversable instance
+ * 366f5ec0ac add FLAG_MUSTACHESP and FLAG_MUSTACHEPAIN into FLAG_HANDLEBARS and FLAG_HANDLEBARSJS now
+ * b61d7b4a81 align with handlebars.js standalone tags behavior
+ * b211e1742e now render false as 'false'
+ * 655a2485be fix bug for `{{helper "==="}}`
* bb58669162 support FLAG_NOESCAPE
v0.15 https://github.com/zordius/lightncandy/tree/v0.15
* align with handlebars.js 2.0.0
- * 4c750806e8 fix for \ in template
- * 12ab6626d6 support escape. \{{foo}} will be rendered as is. ( handlebars spec , require FLAG_SLASH )
+ * 4c750806e8 fix for `\` in template
+ * 12ab6626d6 support escape. `\{{foo}}` will be rendered as is. ( handlebars spec , require FLAG_SLASH )
* 876bd44d9c escape &#x60; to &amp;#x60; ( require FLAG_JSQUOTE )
- * f1f388ed79 support {{^}} as {{else}} ( require FLAG_ELSE )
- * d5e17204b6 support {{#each}} == {{#each .}} now.
- * 742126b440 fix {{>foo/bar}} partial not found bug.
- * d62c261ff9 support numbers as helper input {{helper 0.1 -1.2}}
- * d40c76b84f support escape in string arguments {{helper "test \" double quote"}}
- * ecb57a2348 fix for missing partial in partial bug.
- * 1adad5dbfa fix {{#with}} error when FLAG_WITH not used.
- * ffd5e35c2d fix error when rendering array value as {{.}} without FLAG_JSOBJECT.
- * bd4987adbd support changing context on partial {{>foo bar}} ( require FLAG_RUNTIMEPARTIAL )
- * f5decaa7e3 support name sarguments on partial {{>foo bar name=tee}} . fix {{..}} bug.
- * c20bb36457 support `partials` in options.
- * e8779dbe8c change default `basedir` hehavior, stop partial files lookup when do not prodive `basedir` in options.
- * c4e3401fe4 fix {{>"test"}} or {{>[test]}} or {{>1234}} bug.
- * e59f62ea9b fix seciton behavior when input is object, and add one new flag: FLAG_MUSTACHESEC.
- * 80eaf8e007 use static::method not self::method for subclass.
+ * f1f388ed79 support `{{^}}` as `{{else}}` ( require FLAG_ELSE )
+ * d5e17204b6 support `{{#each}}` == `{{#each .}}` now
+ * 742126b440 fix `{{>foo/bar}} partial not found bug
+ * d62c261ff9 support numbers as helper input `{{helper 0.1 -1.2}}`
+ * d40c76b84f support escape in string arguments `{{helper "test \" double quote"}}`
+ * ecb57a2348 fix for missing partial in partial bug
+ * 1adad5dbfa fix `{{#with}}` error when FLAG_WITH not used
+ * ffd5e35c2d fix error when rendering array value as `{{.}}` without FLAG_JSOBJECT
+ * bd4987adbd support changing context on partial `{{>foo bar}}` ( require FLAG_RUNTIMEPARTIAL )
+ * f5decaa7e3 support name sarguments on partial `{{>foo bar name=tee}}` . fix `{{..}}` bug
+ * c20bb36457 support `partials` in options
+ * e8779dbe8c change default `basedir` hehavior, stop partial files lookup when do not prodive `basedir` in options
+ * c4e3401fe4 fix `{{>"test"}}` or `{{>[test]}}` or `{{>1234}}` bug
+ * e59f62ea9b fix seciton behavior when input is object, and add one new flag: FLAG_MUSTACHESEC
+ * 80eaf8e007 use static::method not self::method for subclass
* 0bad5c8f20 fix usedFeature generation bugs
v0.14 https://github.com/zordius/lightncandy/tree/v0.14
* align with handlebars.js 2.0.0-alpha.4
* fa6225f278 support boolen value in named arguments for cusotm helper
- * 160743e1c8 better error message when unmatch {{/foo}} tag detected
- * d9a9416907 support {{&foo}}
- * 8797485cfa fix {{^foo}} logic when foo is empty list
+ * 160743e1c8 better error message when unmatch `{{/foo}}` tag detected
+ * d9a9416907 support `{{&foo}}`
+ * 8797485cfa fix `{{^foo}}` logic when foo is empty list
* 523b1373c4 fix handlebars custom helper interface
* a744a2d522 fix bad syntax when FLAG_RENDER_DEBUG + helpers
* 0044f7bd10 change FLAG_THIS behavoir
* b5b0739b68 support recursive context lookup now ( mustache spec , require FLAG_MUSTACHELOOKUP )
* 096c241fce support standalone tag detection now ( mustache spec , require FLAG_MUSTACHESP )
- * cea46c9a67 support {{=<% %>=}} to set delimiter
- * 131696af11 support subexpression {{helper (helper2 foo) bar}}
+ * cea46c9a67 support `{{=<% %>=}}` to set delimiter
+ * 131696af11 support subexpression `{{helper (helper2 foo) bar}}`
* 5184d41be6 support runtime/recursive partial ( require FLAG_RUNTIMEPARTIAL )
* 6408917f76 support partial indent ( mustache spec , require FLAG_MUSTACHEPAIN )
v0.13 https://github.com/zordius/lightncandy/tree/v0.13
* align with handlebars.js 2.0.0-alpha.4
- * e5a8fe3833 fix issue #46 ( error with {{this.foo.bar}} )
+ * e5a8fe3833 fix issue #46 ( error with `{{this.foo.bar}}` )
* ea131512f9 fix issue #44 ( error with some helper inline function PHP code syntax )
* 522591a0c6 fix issue #49 ( error with some helper user function PHP code syntax )
- * c4f7e1eaac support {{foo.bar}} lookup on instance foo then property/method bar ( flagd FLAG_PROPERTY or FLAG_METHOD required )
+ * c4f7e1eaac support `{{foo.bar}} lookup on instance foo then property/method bar ( flagd FLAG_PROPERTY or FLAG_METHOD required )
* 0f4c0daa4b stop simulate Javascript output for array when pass input to custom helpers
* 22d07e5f0f BIG CHANGE of custom helper interface
v0.12 https://github.com/zordius/lightncandy/tree/v0.12
* align with handlebars.js 2.0.0-alpha.2
- * 64db34cf65 support {{@first}} and {{@last}}
+ * 64db34cf65 support `{{@first}}` and `{{@last}}`
* bfa1fbef97 add new flag FLAG_SPVARS
* 10a4623dc1 remove json schema support
* 240d9fa290 only export used LCRun2 functions when compile() with FLAG_STANDALONE now
- * 3fa897c98c rename LCRun2 to LCRun3 for interface changed, old none standalone templates will error with newer version.
+ * 3fa897c98c rename LCRun2 to LCRun3 for interface changed, old none standalone templates will error with newer version
* e0838c7418 now can output debug template map with ANSI color
* 80dbeab63d fix php warning when compile with custom helper or block custom helper
* 8ce6268b64 support Handlebars.js style custom helper
v0.11 https://github.com/zordius/lightncandy/tree/v0.11
* align with handlebars.js 2.0.0-alpha.2
- * a275d52c97 use php array, remove val().
+ * a275d52c97 use php array, remove val()
* 8834914c2a only export used custom helper into render function now
* eb6d82d871 refine option flag consts
* fc437295ed refine comments for phpdoc
* fbf116c3e2 fix for tailing ; after helper functions
- * f47a2d5014 fix for wrong param when new Exception
+ * f47a2d5014 fix for wrong param when new Exception
* 94e71ebcbd add isset() check for input value
- * a826b8a1ab support {{else}} in {{#each}} now
- * 25dac11bb7 support {{!-- comments --}} now (this extension allow }} apperas in the comments)
- * e142b6e116 support {{@root}} or {{@root.foo.bar}} now
+ * a826b8a1ab support `{{else}}` in `{{#each}}` now
+ * 25dac11bb7 support `{{!-- comments --}}` now (this handlebars.js extension allow `}}` apperas in the comments)
+ * e142b6e116 support `{{@root}}` or `{{@root.foo.bar}}` now
* 58c8d84aa2 custom helper can return extra flag to change html encoded behavior now
v0.10 https://github.com/zordius/lightncandy/tree/v0.10
@@ -111,10 +150,10 @@ v0.10 https://github.com/zordius/lightncandy/tree/v0.10
* 4c9f681080 file name changed: lightncandy.inc => lightncandy.php
* e3de01081c some minor fix for json schema
* 1feec458c7 new variable handling logic, save variable name parsing time when render() . rendering performance improved 10~30%!
- * 3fa897c98c rename LCRun to LCRun2 for interface changed, old none standalone templates will error with newer version.
- * 43a6d33717 fix for {{../}} php warning message
+ * 3fa897c98c rename LCRun to LCRun2 for interface changed, old none standalone templates will error with newer version
+ * 43a6d33717 fix for `{{../}}` php warning message
* 9189ebc1e4 now auto push documents from Travis CI
- * e077d0b631 support named arguments for custom helpers {{helper name=value}}
+ * e077d0b631 support named arguments for custom helpers `{{helper name=value}}`
* 2331b6fe55 support block custom helpers
* 4fedaa25f7 support number value as named arguments
* 6a91ab93d2 fix for default options and php warnings
@@ -122,13 +161,13 @@ v0.10 https://github.com/zordius/lightncandy/tree/v0.10
v0.9 https://github.com/zordius/lightncandy/tree/v0.9
* align with handlebars.js 1.3
- * a55f2dd067 support both {{@index}} and {{@key}} when {{#each an_object}}
+ * a55f2dd067 support both `{{@index}}` and `{{@key}}` when `{{#each an_object}}`
* e59f931ea7 add FLAG_JSQUOTE support
* 92b3cf58af report more than 1 error when compile()
* 93cc121bcf test for wrong variable name format in test/error.php
- * 41c1b431b4 support advanced variable naming {{foo.[bar].10}} now
+ * 41c1b431b4 support advanced variable naming `{{foo.[bar].10}}` now
* 15ce1a00a8 add FLAG_EXTHELPER option
- * f51337bde2 support space control {{~sometag}} or {{sometag~}}
+ * f51337bde2 support space control `{{~sometag}}` or `{{sometag~}}`
* fe3d67802e add FLAG_SPACECTL option
* 920fbb3039 support custom helper
* 07ae71a1bf migrate into Travis CI
@@ -141,30 +180,31 @@ v0.9 https://github.com/zordius/lightncandy/tree/v0.9
v0.8 https://github.com/zordius/lightncandy/tree/v0.8
* align with handlebars.js 1.0.12
* aaec049 fix partial in partial not works bug
- * 52706cc fix for {{#var}} and {{^var}} , now when var === 0 means true
- * 4f7f816 support {{@key}} and {{@index}} in {{#each var}}
- * 63aef2a prevent array_diff_key() PHP warning when {{#each}} on none array value
- * 10f3d73 add more is_array() check when {{#each}} and {{#var}}
- * 367247b fix {{#if}} and {{#unless}} when value is an empty array
+ * 52706cc fix for `{{#var}}` and `{{^var}}` , now when var === 0 means true
+ * 4f7f816 support `{{@key}}` and `{{@index}}` in `{{#each var}}`
+ * 63aef2a prevent array_diff_key() PHP warning when `{{#each}}` on none array value
+ * 10f3d73 add more is_array() check when `{{#each}}` and `{{#var}}`
+ * 367247b fix `{{#if}}` and `{{#unless}}` when value is an empty array
* c76c0bb returns null if var is not exist in a template [contributed by dtelyukh@github.com]
* d18bb6d add FLAG_ECHO support
- * aec2b2b fix {{#if}} and {{#unless}} when value is an empty string
+ * aec2b2b fix `{{#if}}` and `{{#unless}}` when value is an empty string
* 8924604 fix variable output when false in an array
* e82c324 fix for ifv and ifvar logic difference
- * 1e38e47 better logic on var name checking. now support {{0}} in the loop, but it is not handlebars.js standard
+ * 1e38e47 better logic on var name checking. now support `{{0}}` in the loop, but it is not handlebars.js standard
v0.7 https://github.com/zordius/lightncandy/tree/v0.7
+ * align with handlebarsjs 1.0.11
* add HISTORY.md
* 777304c change compile format to include in val, isec, ifvar
- * 55de127 support {{../}} in {{#each}}
+ * 55de127 support `{{../}}` in `{{#each}}`
* 57e90af fix parent levels detection bug
- * 96bb4d7 fix bugs for {{#.}} and {{#this}}
+ * 96bb4d7 fix bugs for `{{#.}}` and `{{#this}}`
* f4217d1 add ifv and unl 2 new methods for LCRun
- * 3f1014c fix {{#this}} and {{#.}} bug when used with {{../var}}
- * cbf0b28 fix {{#if}} logic error when using {{../}}
- * 2b20ef8 fix {{#with}} + {{../}} bug
+ * 3f1014c fix `{{#this}}` and `{{#.}}` bug when used with `{{../var}}`
+ * cbf0b28 fix `{{#if}}` logic error when using `{{../}}`
+ * 2b20ef8 fix `{{#with}}` + `{{../}}` bug
* 540cd44 now support FLAG_STANDALONE
- * 67ac5ff support {{>partial}}
+ * 67ac5ff support `{{>partial}}`
* 98c7bb1 detect unclosed token now
v0.6 https://github.com/zordius/lightncandy/tree/v0.6
@@ -174,8 +214,8 @@ v0.6 https://github.com/zordius/lightncandy/tree/v0.6
* fdc753b fix #each and section logic for 018-hb-withwith-006
* e6cc95a add FLAG_PARENT, detect template error when scan()
* 1980691 make new LCRun::val() method to normal path.val logic
- * 110d24f {{#if path.var}} bug fixed
- * d6ae2e6 fix {{#with path.val}} when input value is null
+ * 110d24f `{{#if path.var}}` bug fixed
+ * d6ae2e6 fix `{{#with path.val}}` when input value is null
* 71cf074 fix for 020-hb-doteach testcase
v0.5 https://github.com/zordius/lightncandy/tree/v0.5
diff --git a/vendor/zordius/lightncandy/LICENSE.txt b/vendor/zordius/lightncandy/LICENSE.txt
index 3df560d4..069e6cef 100644
--- a/vendor/zordius/lightncandy/LICENSE.txt
+++ b/vendor/zordius/lightncandy/LICENSE.txt
@@ -1,7 +1,7 @@
Copyrights for code authored by Yahoo! Inc. is licensed under the following
terms:
MIT License
-Copyright (c) 2013, 2014 Yahoo! Inc. All Rights Reserved.
+Copyright (c) 2013-2015 Yahoo! Inc. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
diff --git a/vendor/zordius/lightncandy/README.md b/vendor/zordius/lightncandy/README.md
index 2afd6b9c..d5a3a5bc 100644
--- a/vendor/zordius/lightncandy/README.md
+++ b/vendor/zordius/lightncandy/README.md
@@ -7,7 +7,7 @@ Travis CI status: [![Unit testing](https://travis-ci.org/zordius/lightncandy.svg
Scrutinizer CI status: [![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/zordius/lightncandy.svg)](https://scrutinizer-ci.com/g/zordius/lightncandy/)
-Package on packagist: [![Latest Stable Version](https://poser.pugx.org/zordius/lightncandy/v/stable.svg)](https://packagist.org/packages/zordius/lightncandy) [![License](https://poser.pugx.org/zordius/lightncandy/license.svg)](https://github.com/zordius/lightncandy/blob/master/LICENSE.txt) [![Total Downloads](https://poser.pugx.org/zordius/lightncandy/downloads.svg)](https://packagist.org/packages/zordius/lightncandy) [![HHVM Status](http://hhvm.h4cc.de/badge/zordius/lightncandy.svg)](http://hhvm.h4cc.de/package/zordius/lightncandy)
+Package on packagist: [![Latest Stable Version](https://poser.pugx.org/zordius/lightncandy/v/stable.svg)](https://packagist.org/packages/zordius/lightncandy) [![License](https://poser.pugx.org/zordius/lightncandy/license.svg)](https://github.com/zordius/lightncandy/blob/master/LICENSE.txt) [![Total Downloads](https://poser.pugx.org/zordius/lightncandy/downloads)](https://packagist.org/packages/zordius/lightncandy) [![HHVM Status](http://hhvm.h4cc.de/badge/zordius/lightncandy.svg)](http://hhvm.h4cc.de/package/zordius/lightncandy)
Features
--------
@@ -21,7 +21,7 @@ Features
* Runs 4~10 times faster than <a href="https://github.com/dingram/mustache-php">mustache-php</a>.
* Runs 10~30 times faster than <a href="https://github.com/XaminProject/handlebars.php">handlebars.php</a>.
* Detail performance test reports can be found <a href="https://github.com/zordius/HandlebarsTest">here</a>, go http://zordius.github.io/HandlebarsTest/ to see charts.
-* **SMALL!** single PHP file, only 110K!
+* **SMALL!** single PHP file, only 120K!
* **ROBUST!**
* 100% support <a href="https://github.com/mustache/spec">mustache spec v1.1.2</a> (without lambda module)
* Supports almost all <a href="https://github.com/kasperisager/handlebars-spec">handlebars.js spec</a>
@@ -133,8 +133,8 @@ Default is to compile the template as PHP, which can be run as fast as possible
* `FLAG_RUNTIMEPARTIAL` : compile partial as runtime function, This enables recursive partials or context change for partials.
* `FLAG_SLASH` : Skip a delimiter when it behind `\` .
* `FLAG_ELSE` : support `{{else}}` or `{{^}}` as handlebars specification. Otherwise, `{{else}}` will be resolved as normal variable , and {{^}} will cause template error.
-* `FLAG_PROPERTY` : support object instance attribute access.
-* `FLAG_METHOD` : support object instance method access.
+* `FLAG_PROPERTY` : support object instance attribute access. You MUST apply this if your data contains object. And, the rendering performance will be worse.
+* `FLAG_METHOD` : support object instance method access. You MUST apply this if your data contains object. And, the rendering performance will be worse.
* `FLAG_INSTANCE` : same with `FLAG_PROPERTY` + `FLAG_METHOD`
* `FLAG_SPACECTL` : support space control `{{~ }}` or `{{ ~}}` in template. Otherwise, `{{~ }}` or `{{ ~}}` will cause template error.
* `FLAG_SPVARS` : support special variables include @root, @index, @key, @first, @last. Otherwise, compile these variable names with default parsing logic.
@@ -142,13 +142,13 @@ Default is to compile the template as PHP, which can be run as fast as possible
* `FLAG_HANDLEBARS` : support all handlebars extensions (which mustache do not supports) , same with `FLAG_THIS` + `FLAG_WITH` + `FLAG_PARENT` + `FLAG_JSQUOTE` + `FLAG_ADVARNAME` + `FLAG_NAMEDARG` + `FLAG_SLASH` + `FLAG_ELSE` + `FLAG_MUSTACHESP` + `FLAG_MUSTACHEPAIN`.
* `FLAG_HANDLEBARSJS` : align with handlebars.js behaviors, same with `FLAG_JS` + `FLAG_HANDLEBARS`.
* `FLAG_MUSTACHESP` : align line change and spacing behaviors with mustache specification.
-* `FLAG_MUSTACHELOOKUP` : align recursive lookup up behaviors with mustache specification.
+* `FLAG_MUSTACHELOOKUP` : align recursive lookup up behaviors with mustache specification. And, the rendering performance will be worse.
* `FLAG_MUSTACHEPAIN` : align partial indent behavior with mustache specification.
-* `FLAG_MUSTACHESEC` : align section `{{#foo}}` context behavior with mustache specification.
-* `FLAG_MUSTACHE` : support all mustache specification, same with `FLAG_ERROR_SKIPPARTIAL` + `FLAG_MUSTACHESP` + `FLAG_MUSTACHELOOKUP` + `FLAG_MUSTACHEPAIN` + `FLAG_MUSTACHESEC`.
+* `FLAG_MUSTACHE` : support all mustache specification, same with `FLAG_ERROR_SKIPPARTIAL` + `FLAG_MUSTACHESP` + `FLAG_MUSTACHELOOKUP` + `FLAG_MUSTACHEPAIN`.
* `FLAG_ECHO` : compile to `echo 'a', $b, 'c';` to improve performance. This will slow down rendering when the template and data are simple, but will improve 1% ~ 7% when the data is big and looping in the template.
* `FLAG_BESTPERFORMANCE` : same with `FLAG_ECHO` now. This flag may be changed base on performance testing result in the future.
* `FLAG_RENDER_DEBUG` : generate debug template to show error when rendering. With this flag, the performance of rendering may be slowed.
+* `FLAG_BARE`: generate PHP code without PHP tags `<?php` and `?>`
Partial Support
---------------
@@ -205,8 +205,13 @@ By default, partial uses the same context with original template. If you want to
{{>partial_name .}} // Same as {{>partial_name}}
{{>partial_name foo}} // Change input context to foo, FLAG_RUNTIMEPARTIAL required
{{>partial_name ..}} // use {{..}} as new input context, FLAG_RUNTIMEPARTIAL required
+
+{{>partial_name .. key=bar}} // use {{..}} as new input context, FLAG_RUNTIMEPARTIAL required
+ // also merge key into new context.
```
+You can use dynamic partial name by passing a custom helper as subexpression syntax, for example: `{{> (foo)}}` . the return value of custom helper `foo` will be the partial name. When you using dynamic partial, LightnCandy will compile all partial inside the `partials` option into template. (**TODO: add an example to show how to provide partials across templates to reduce size**)
+
Custom Helper
-------------
@@ -321,6 +326,19 @@ return Array('Not&Same output \' " Ya!', 'enc');
return Array('Not&Same output \' " Ya!', 'encq');
```
+In most case, a custom helper should always return a string. If you design a custom helper to be executed inside a subexpression, you can return an object or an array by this way:
+
+```php
+// return an object
+return Array($anObject, 'asis');
+
+// in another way
+return Array($anObject, 'raw');
+
+// return Array(1, 3, 5)
+return Array(Array(1, 3, 5), 'any_string_but_not_enc_nor_encq');
+```
+
Block Custom Helper
-------------------
@@ -400,7 +418,7 @@ The mission of a block custom helper is only focus on providing different contex
Handlebars.js' Custom Helper
----------------------------
-You can implement helpers more like Handlebars.js way with `hbhelpers` option, all matched single custom helper and block custom helper will be handled. In Handlebars.js, a block custom helper can rendener child block by executing options->fn, and change context by send new context as first parameter. Here are some examples to explain the behavior of `hbhelpers` custom helper:
+You can implement helpers more like Handlebars.js way with `hbhelpers` option, all matched single custom helper and block custom helper will be handled. In Handlebars.js, a block custom helper can rendener child block by executing `options.fn`; or change context by send new context as first parameter. Here are some examples to explain the behavior of `hbhelpers` custom helper:
**#mywith (context change)**
* LightnCandy
@@ -504,6 +522,30 @@ Handlebars.registerHelper('sample', function(arg1, arg2, options) {
});
```
+**Data variables and context**
+
+You can get special data variables from `$options['data']`. Using `$options['_this']` to receive current context.
+
+```php
+$php = LightnCandy::compile($template, Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'getRoot' => function ($options) {
+ print_($options['_this']); // dump current context
+ return $options['data']['root']; // same as {{@root}}
+ }
+ )
+));
+```
+
+* Handlebars.js
+```javascript
+Handlebars.registerHelper('getRoot', function(options) {
+ console.log(this); // dump current context
+ return options.data.root; // same as {{@root}}
+});
+```
+
**Escaping**
When a Handlebars.js style custom helper be used as block tags, LightnCandy will not escape the result. When it is a single {{...}} tag, LightnCandy will escape the result. To change the escape behavior, you can return extended information by Array(), please read <a href="#custom-helper-escaping">Custom Helper Escaping</a> for more.
@@ -589,10 +631,32 @@ function ($in) {$
Please make sure the passed in `renderex` is valid PHP, LightnCandy will not check it.
+Customize Rendering Runtime Class
+---------------------------------
+
+If you want to extend `LCRun3` class and replace default rendering runtime library, you may use `lcrun` when `compile()` . For example, this sample will generate render function based on your extended `MyLCRunClass`:
+
+```php
+// Customized rendering runtime library to debug {{{foo}}}
+class MyLCRunClass extends LCRun3 {
+ public static function raw($cx, $v) {
+ return '[[DEBUG:raw()=>' . var_export($v, true) . ']]';
+ }
+}
+
+// Use MyLCRunClass as rendering runtime library
+$php = LightnCandy::compile($template, Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'lcrun' => 'MyLCRunClass'
+));
+```
+
+Please make sure `MyLCRunClass` exists when compile() or rendering based on your `FLAG_STANDALONE` .
+
Unsupported Feature (so far)
----------------------------
-* [NEVER] `{{foo/bar}}` style variable name, it is deprecated in official handlebars.js document.
+* [NEVER] `{{foo/bar}}` style variable name, it is deprecated in official handlebars.js document, please use this style: `{{foo.bar}}`.
* [maybe] mustache lambda : runtime time compile based on input value is far from lightncandy nature, not in the plan now.
Suggested Handlebars Template Practices
@@ -651,6 +715,8 @@ Go http://handlebarsjs.com/ to see more feature description about handlebars.js.
* `{{../var}}` : parent template scope. (require `FLAG_PARENT`)
* `{{>file}}` : partial; include another template inside a template.
* `{{>file foo}}` : partial with new context (require `FLAG_RUNTIMEPARTIAL`)
+* `{{>file foo bar=another}}` : partial with new context which mixed with followed key value (require `FLAG_RUNTIMEPARTIAL`)
+* `{{>(helper) foo}}` : include dynamic partial by name provided from a helper (require `FLAG_RUNTIMEPARTIAL`)
* `{{@index}}` : references to current index in a `{{#each}}` loop on an array. (require `FLAG_SPVARS`)
* `{{@key}}` : references to current key in a `{{#each}}` loop on an object. (require `FLAG_SPVARS`)
* `{{@root}}` : references to root context. (require `FLAG_SPVARS`)
@@ -665,6 +731,13 @@ Go http://handlebarsjs.com/ to see more feature description about handlebars.js.
* `{{{helper var}}}` : Execute custom helper then render the result
* `{{helper var}}` : Execute custom helper then render the HTML escaped result
* `{{helper "str"}}` or `{{helper 'str'}}` : Execute custom helper with string arguments (require `FLAG_ADVARNAME`)
+* `{{helper 123 null true false undefined}}` : Pass number, true, false, null or undefined into helper
* `{{helper name1=var name2=var2}}` : Execute custom helper with named arguments (require `FLAG_NAMEDARG`)
* `{{#helper ...}}...{{/helper}}` : Execute block custom helper
* `{{helper (helper2 foo) bar}}` : Execute custom helpers as subexpression (require `FLAG_ADVARNAME`)
+
+Framework Integration
+---------------------
+
+- [Slim 3.0.x](https://github.com/endel/slim-lightncandy-view)
+- [Laravel 4](https://github.com/samwalshnz/lightncandy-l4)
diff --git a/vendor/zordius/lightncandy/UPGRADE.md b/vendor/zordius/lightncandy/UPGRADE.md
index 01f4c15b..680137be 100644
--- a/vendor/zordius/lightncandy/UPGRADE.md
+++ b/vendor/zordius/lightncandy/UPGRADE.md
@@ -5,6 +5,10 @@ Upgrade Notice
* Recompile your none standalone templates when you upgrade LightnCandy.
+CURRENT MASTER
+--------------
+* Option FLAG_MUSTACHESEC removed, no need to use this flag anymore.
+
Version v0.13
-------------
* The interface of custom helpers was changed from v0.13 . if you use this feature you may need to modify your custom helper functions.
diff --git a/vendor/zordius/lightncandy/build/gen_doc b/vendor/zordius/lightncandy/build/gen_doc
new file mode 100755
index 00000000..807bc21a
--- /dev/null
+++ b/vendor/zordius/lightncandy/build/gen_doc
@@ -0,0 +1,6 @@
+#!/bin/sh
+curl -O https://cloud.github.com/downloads/ApiGen/ApiGen/ApiGen-2.8.0-standalone.zip
+unzip -oq ApiGen-2.8.0-standalone.zip
+rm ApiGen-2.8.0-standalone.zip
+php -dopen_basedir=/ apigen/apigen.php --source src/ --destination build/result/docs/ --template-config apigen/templates/bootstrap/config.neon --deprecated yes
+rm -rf apigen
diff --git a/vendor/zordius/lightncandy/build/gen_test.php b/vendor/zordius/lightncandy/build/gen_test.php
new file mode 100644
index 00000000..97d49489
--- /dev/null
+++ b/vendor/zordius/lightncandy/build/gen_test.php
@@ -0,0 +1,64 @@
+<?php
+
+foreach (Array(
+ 'vendor/phpunit/phpunit/PHPUnitPHPUnit/Autoload.php',
+ 'PHPUnit/Autoload.php',
+ 'src/lightncandy.php'
+) as $inc) {
+ if (file_exists($inc)) {
+ include_once($inc);
+ break;
+ }
+}
+
+genTestForClass('LightnCandy');
+genTestForClass('LCRun3');
+
+function genTestForClass($classname) {
+ ob_start();
+
+ echo <<<VAR
+<?php
+/**
+ * Generated by build/gen_test
+ */
+require_once('src/lightncandy.php');
+
+class {$classname}Test extends PHPUnit_Framework_TestCase
+{
+
+VAR
+ ;
+
+ $class = new ReflectionClass($classname);
+ foreach ($class->getMethods() as $method) {
+ if (preg_match_all('/@expect (.+) when input (.+)( after (.+))?/', $method->getDocComment(), $matched)) {
+ echo <<<VAR
+ /**
+ * @covers {$classname}::{$method->name}
+ */
+ public function testOn_{$method->name}() {
+ \$method = new ReflectionMethod('$classname', '{$method->name}');
+
+VAR
+ ;
+ if ($method->isPrivate() || $method->isProtected()) {
+ echo " \$method->setAccessible(true);\n";
+ }
+ foreach ($matched[1] as $idx => $expect) {
+ if ($matched[3][$idx]) {
+ echo " {$matched[3][$idx]}\n";
+ }
+ echo " \$this->assertEquals($expect, \$method->invoke(null,\n {$matched[2][$idx]}\n ));\n";
+ }
+ echo " }\n";
+ }
+ }
+ echo "}\n?>";
+
+ $fn = "tests/{$classname}Test.php";
+ if (!file_put_contents($fn, ob_get_clean())) {
+ die("Can not generate tests into file $fn !!\n");
+ }
+}
+?>
diff --git a/vendor/zordius/lightncandy/build/push_ghpage b/vendor/zordius/lightncandy/build/push_ghpage
new file mode 100755
index 00000000..de64e2b9
--- /dev/null
+++ b/vendor/zordius/lightncandy/build/push_ghpage
@@ -0,0 +1,12 @@
+#!/bin/sh
+git checkout -B gh-pages
+git pull origin gh-pages
+rm *
+rm -rf src
+rm -rf test
+cp -r build/result/docs/* .
+rm -rf build
+rm .travis.yml
+git add .
+git commit -a -m "New documents on github"
+git push origin gh-pages
diff --git a/vendor/zordius/lightncandy/build/runphp b/vendor/zordius/lightncandy/build/runphp
new file mode 100755
index 00000000..aa694de3
--- /dev/null
+++ b/vendor/zordius/lightncandy/build/runphp
@@ -0,0 +1,2 @@
+#!/bin/sh
+php -dopen_basedir=/ $1 $2
diff --git a/vendor/zordius/lightncandy/build/travis_push b/vendor/zordius/lightncandy/build/travis_push
new file mode 100755
index 00000000..b51e4dcc
--- /dev/null
+++ b/vendor/zordius/lightncandy/build/travis_push
@@ -0,0 +1,60 @@
+#!/bin/sh
+echo "DEBUG ENV: ${TRAVIS_JOB_NUMBER} , ${TRAVIS_BUILD_NUMBER} , ${TRAVIS_PULL_REQUEST} ..."
+
+if [ "${TRAVIS_PULL_REQUEST}" != "false" ]; then
+ echo "This is a PR, skip push."
+ exit 0
+fi
+
+if [ "${TRAVIS_BUILD_NUMBER}.1" != "${TRAVIS_JOB_NUMBER}" ]; then
+ echo "Only push documents 1 time... quit."
+ exit 0
+fi
+
+# Push coverage report
+wget https://scrutinizer-ci.com/ocular.phar
+php ocular.phar code-coverage:upload --format=php-clover coverage.clover
+
+# Set for all push in this script.
+git config --global user.name "Travis-CI"
+git config --global user.email "zordius@yahoo-inc.com"
+
+# Generate ANSI sample
+git clone https://github.com/fcambus/ansilove
+php tests/example_debug.php > example_debug
+php ansilove/ansilove example_debug
+git add example_debug.png
+
+# Push new tests back to this branch
+git commit -a -m "Auto generated tests from Travis [ci skip]"
+git push "https://${GHTK}@github.com/zordius/lightncandy.git" HEAD:${TRAVIS_BRANCH} > /dev/null 2>&1
+
+# Update hash in HandlebarsTest and push back, trigger new tests there.
+git clone https://github.com/zordius/HandlebarsTest
+cd HandlebarsTest
+echo ${TRAVIS_COMMIT} > lightncandy
+git add lightncandy
+git commit -a -m "Auto test on zordius/lightncandy@${TRAVIS_COMMIT}"
+git push "https://${GHTK}@github.com/zordius/HandlebarsTest.git" > /dev/null 2>&1
+cd ..
+
+# Generate documents for this branch
+build/gen_doc
+cd build/result/docs
+
+if [ "${TRAVIS_BRANCH}" != "master" ]; then
+ echo "Document will be pushed here: http://zordius.github.io/lightncandy/${TRAVIS_BRANCH}/"
+ cd ..
+ git init
+ git pull --quiet "https://${GHTK}@github.com/zordius/lightncandy.git" gh-pages:master > /dev/null 2>&1
+ rm -rf $TRAVIS_BRANCH
+ mv docs $TRAVIS_BRANCH
+ git add $TRAVIS_BRANCH
+else
+ echo "Document will be pushed here: http://zordius.github.io/lightncandy/"
+ git init
+ git add .
+fi
+
+git commit -m "Auto deployed to Github Pages from branch ${TRAVIS_BRANCH} @${TRAVIS_COMMIT} [ci skip]"
+git push --force --quiet "https://${GHTK}@github.com/zordius/lightncandy.git" master:gh-pages > /dev/null 2>&1
diff --git a/vendor/zordius/lightncandy/src/lightncandy.php b/vendor/zordius/lightncandy/src/lightncandy.php
index d7a62e57..bc62781c 100644
--- a/vendor/zordius/lightncandy/src/lightncandy.php
+++ b/vendor/zordius/lightncandy/src/lightncandy.php
@@ -3,7 +3,7 @@
Copyrights for code authored by Yahoo! Inc. is licensed under the following terms:
MIT License
-Copyright (c) 2013 Yahoo! Inc. All Rights Reserved.
+Copyright (c) 2013-2015 Yahoo! Inc. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -29,6 +29,7 @@ class LightnCandy {
// Compile the template as standalone PHP code which can execute without including LightnCandy
const FLAG_STANDALONE = 4;
+ const FLAG_BARE = 33554432;
const FLAG_NOESCAPE = 67108864;
// JavaScript compatibility
@@ -58,7 +59,6 @@ class LightnCandy {
const FLAG_MUSTACHESP = 131072;
const FLAG_MUSTACHELOOKUP = 262144;
const FLAG_MUSTACHEPAIN = 2097152;
- const FLAG_MUSTACHESEC = 33554432;
// Template rendering time debug flags
const FLAG_RENDER_DEBUG = 524288;
@@ -66,7 +66,7 @@ class LightnCandy {
// alias flags
const FLAG_BESTPERFORMANCE = 16384; // FLAG_ECHO
const FLAG_JS = 24; // FLAG_JSTRUE + FLAG_JSOBJECT
- const FLAG_MUSTACHE = 40239104; // FLAG_ERROR_SKIPPARTIAL + FLAG_MUSTACHESP + FLAG_MUSTACHELOOKUP + FLAG_MUSTACHEPAIN + FLAG_MUSTACHESEC
+ const FLAG_MUSTACHE = 6684672; // FLAG_ERROR_SKIPPARTIAL + FLAG_MUSTACHESP + FLAG_MUSTACHELOOKUP + FLAG_MUSTACHEPAIN
const FLAG_HANDLEBARS = 27402208; // FLAG_THIS + FLAG_WITH + FLAG_PARENT + FLAG_JSQUOTE + FLAG_ADVARNAME + FLAG_SPACECTL + FLAG_NAMEDARG + FLAG_SPVARS + FLAG_SLASH + FLAG_ELSE + FLAG_MUSTACHESP + FLAG_MUSTACHEPAIN
const FLAG_HANDLEBARSJS = 27402232; // FLAG_JS + FLAG_HANDLEBARS
const FLAG_INSTANCE = 98304; // FLAG_PROPERTY + FLAG_METHOD
@@ -74,6 +74,7 @@ class LightnCandy {
// RegExps
const VARNAME_SEARCH = '/(\\[[^\\]]+\\]|[^\\[\\]\\.]+)/';
const EXTENDED_COMMENT_SEARCH = '/{{!--.*?--}}/s';
+ const IS_SUBEXP_SEARCH = '/^\(.+\)$/s';
// Positions of matched token
const POS_LOTHER = 1;
@@ -105,7 +106,7 @@ class LightnCandy {
}
// Strip extended comments
- $template = preg_replace(static::EXTENDED_COMMENT_SEARCH, '{{!*}}', $template);
+ $template = preg_replace(static::EXTENDED_COMMENT_SEARCH, '{{! }}', $template);
// Do first time scan to find out used feature, detect template error.
static::setupToken($context);
@@ -115,8 +116,14 @@ class LightnCandy {
return false;
}
+ $context['scan'] = false;
+
// Do PHP code generation.
static::setupToken($context);
+
+ // Handle dynamic partials
+ static::handleDynamicPartial($context);
+
$code = static::compileTemplate($context, static::escapeTemplate($template));
// return false when fatal error
@@ -128,7 +135,20 @@ class LightnCandy {
return static::composePHPRender($context, $code);
}
- /*
+ /**
+ * Include all partials when using dynamic partials
+ */
+ protected static function handleDynamicPartial(&$context) {
+ if ($context['usedFeature']['dynpartial'] == 0) {
+ return;
+ }
+
+ foreach ($context['partials'] as $name => $code) {
+ static::readPartial($name, $context);
+ }
+ }
+
+ /**
* Escape template
*
* @param string $template handlebars template string
@@ -136,7 +156,7 @@ class LightnCandy {
* @return string Escaped template
*
* @expect 'abc' when input 'abc'
- * @expect 'a\\bc' when input 'a\bc'
+ * @expect 'a\\\\bc' when input 'a\bc'
* @expect 'a\\\'bc' when input 'a\'bc'
*/
protected static function escapeTemplate($template) {
@@ -255,7 +275,6 @@ class LightnCandy {
$flagProp = static::getBoolStr($context['flags']['prop']);
$flagMethod = static::getBoolStr($context['flags']['method']);
$flagMustlok = static::getBoolStr($context['flags']['mustlok']);
- $flagMustsec = static::getBoolStr($context['flags']['mustsec']);
$flagEcho = static::getBoolStr($context['flags']['echo']);
$libstr = static::exportLCRun($context);
@@ -264,9 +283,11 @@ class LightnCandy {
$bhelpers = static::exportHelper($context, 'blockhelpers');
$hbhelpers = static::exportHelper($context, 'hbhelpers');
$debug = LCRun3::DEBUG_ERROR_LOG;
+ $phpstart = $context['flags']['bare'] ? '' : '<?php ';
+ $phpend = $context['flags']['bare'] ? '' : "\n?>";
// Return generated PHP code string.
- return "<?php return function (\$in, \$debugopt = $debug) {
+ return "{$phpstart}return function (\$in, \$debugopt = $debug) {
\$cx = array(
'flags' => array(
'jstrue' => $flagJStrue,
@@ -275,7 +296,6 @@ class LightnCandy {
'prop' => $flagProp,
'method' => $flagMethod,
'mustlok' => $flagMustlok,
- 'mustsec' => $flagMustsec,
'echo' => $flagEcho,
'debug' => \$debugopt,
),
@@ -284,14 +304,14 @@ class LightnCandy {
'blockhelpers' => $bhelpers,
'hbhelpers' => $hbhelpers,
'partials' => array({$context['partialCode']}),
- 'scopes' => array(\$in),
+ 'scopes' => array(),
'sp_vars' => array('root' => \$in),
+ 'lcrun' => '{$context['lcrun']}',
$libstr
);
{$context['renderex']}
{$context['ops']['op_start']}'$code'{$context['ops']['op_end']}
-}
-?>";
+}$phpend";
}
/**
@@ -314,6 +334,7 @@ $libstr
'exception' => $flags & self::FLAG_ERROR_EXCEPTION,
'skippartial' => $flags & self::FLAG_ERROR_SKIPPARTIAL,
'standalone' => $flags & self::FLAG_STANDALONE,
+ 'bare' => $flags & self::FLAG_BARE,
'noesc' => $flags & self::FLAG_NOESCAPE,
'jstrue' => $flags & self::FLAG_JSTRUE,
'jsobj' => $flags & self::FLAG_JSOBJECT,
@@ -331,13 +352,13 @@ $libstr
'mustsp' => $flags & self::FLAG_MUSTACHESP,
'mustlok' => $flags & self::FLAG_MUSTACHELOOKUP,
'mustpi' => $flags & self::FLAG_MUSTACHEPAIN,
- 'mustsec' => $flags & self::FLAG_MUSTACHESEC,
'debug' => $flags & self::FLAG_RENDER_DEBUG,
'prop' => $flags & self::FLAG_PROPERTY,
'method' => $flags & self::FLAG_METHOD,
'runpart' => $flags & self::FLAG_RUNTIMEPARTIAL,
),
'level' => 0,
+ 'scan' => true,
'stack' => array(),
'error' => array(),
'basedir' => static::buildCXBasedir($options),
@@ -365,13 +386,14 @@ $libstr
'this' => 0,
'parent' => 0,
'with' => 0,
- 'dot' => 0,
'comment' => 0,
'partial' => 0,
+ 'dynpartial' => 0,
'helper' => 0,
'bhelper' => 0,
'hbhelper' => 0,
'delimiter' => 0,
+ 'subexp' => 0,
),
'usedCount' => array(
'var' => array(),
@@ -385,6 +407,7 @@ $libstr
'blockhelpers' => array(),
'hbhelpers' => array(),
'renderex' => isset($options['renderex']) ? $options['renderex'] : '',
+ 'lcrun' => isset($options['lcrun']) ? $options['lcrun'] : 'LCRun3',
);
$context['ops'] = $context['flags']['echo'] ? array(
@@ -470,6 +493,16 @@ $libstr
return static::compilePartial($name, $context, $cnt);
}
+ if (preg_match(static::IS_SUBEXP_SEARCH, $name)) {
+ if ($context['flags']['runpart']) {
+ $context['usedFeature']['dynpartial']++;
+ return;
+ } else {
+ $context['error'][] = "You use dynamic partial name as '$name', this only works with option FLAG_RUNTIMEPARTIAL enabled";
+ return;
+ }
+ }
+
if (!$context['flags']['skippartial']) {
$context['error'][] = "Can not find partial file for '$name', you should set correct basedir and fileext in options";
}
@@ -525,6 +558,8 @@ $libstr
if ($context['flags']['mustpi']) {
$sp = ', $sp';
$code = preg_replace('/^/m', "'{$context['ops']['seperator']}\$sp{$context['ops']['seperator']}'", $code);
+ // callbacks inside partial should be aware of $sp
+ $code = preg_replace('/\bfunction\s*\((.*?)\)\s*{/', 'function(\\1)use($sp){', $code);
} else {
$sp = '';
}
@@ -640,7 +675,7 @@ $libstr
return '';
}
- $class = new ReflectionClass('LCRun3');
+ $class = new ReflectionClass($context['lcrun']);
$fname = $class->getFileName();
$lines = file_get_contents($fname);
$file = new SplFileObject($fname);
@@ -693,7 +728,7 @@ $libstr
return 'array()';
}
- $class = new ReflectionClass('LCRun3');
+ $class = new ReflectionClass($context['lcrun']);
$constants = $class->getConstants();
$ret = " array(\n";
foreach($constants as $name => $value) {
@@ -790,19 +825,20 @@ $libstr
*
* @param string $php PHP code
* @param string|null $tmpDir Optional, change temp directory for php include file saved by prepare() when cannot include PHP code with data:// format.
+ * @param boolean $delete Optional, delete temp php file when set to tru. Default is true, set it to false for debug propose
*
* @return Closure|false result of include()
*
* @deprecated
*/
- public static function prepare($php, $tmpDir = null) {
+ public static function prepare($php, $tmpDir = null, $delete = true) {
if (!ini_get('allow_url_include') || !ini_get('allow_url_fopen')) {
- if (!$tmpDir || !is_dir($tmpDir)) {
+ if (!is_string($tmpDir) || !is_dir($tmpDir)) {
$tmpDir = sys_get_temp_dir();
}
}
- if ($tmpDir) {
+ if (is_dir($tmpDir)) {
$fn = tempnam($tmpDir, 'lci_');
if (!$fn) {
error_log("Can not generate tmp file under $tmpDir!!\n");
@@ -812,7 +848,14 @@ $libstr
error_log("Can not include saved temp php code from $fn, you should add $tmpDir into open_basedir!!\n");
return false;
}
- return include($fn);
+
+ $phpfunc = include($fn);
+
+ if ($delete) {
+ unlink($fn);
+ }
+
+ return $phpfunc;
}
return include('data://text/plain,' . urlencode($php));
@@ -827,10 +870,10 @@ $libstr
*
* @return string compiled Function name
*
- * @expect 'LCRun3::test(' when input array('flags' => array('standalone' => 0, 'debug' => 0)), 'test', ''
- * @expect 'LCRun3::test2(' when input array('flags' => array('standalone' => 0, 'debug' => 0)), 'test2', ''
- * @expect "\$cx['funcs']['test3'](" when input array('flags' => array('standalone' => 1, 'debug' => 0)), 'test3', ''
- * @expect 'LCRun3::debug(\'abc\', \'test\', ' when input array('flags' => array('standalone' => 0, 'debug' => 1)), 'test', 'abc'
+ * @expect 'LCRun3::test(' when input array('flags' => array('standalone' => 0, 'debug' => 0), 'lcrun' => 'LCRun3'), 'test', ''
+ * @expect 'LCRun3::test2(' when input array('flags' => array('standalone' => 0, 'debug' => 0), 'lcrun' => 'LCRun3'), 'test2', ''
+ * @expect "\$cx['funcs']['test3'](" when input array('flags' => array('standalone' => 1, 'debug' => 0), 'lcrun' => 'LCRun3'), 'test3', ''
+ * @expect 'LCRun3::debug(\'abc\', \'test\', ' when input array('flags' => array('standalone' => 0, 'debug' => 1), 'lcrun' => 'LCRun3'), 'test', 'abc'
*/
protected static function getFuncName(&$context, $name, $tag) {
static::addUsageCount($context, 'lcrun', $name);
@@ -843,7 +886,7 @@ $libstr
$dbg = '';
}
- return $context['flags']['standalone'] ? "\$cx['funcs']['$name']($dbg" : "LCRun3::$name($dbg";
+ return $context['flags']['standalone'] ? "\$cx['funcs']['$name']($dbg" : "{$context['lcrun']}::$name($dbg";
}
/**
@@ -883,7 +926,6 @@ $libstr
*
* @param array<array> $vn variable name array.
* @param array<string,array|string|integer> $context current compile context
- * @param boolean $ishelper true when compile for helper
*
* @return array<string|array> variable names
*
@@ -891,15 +933,11 @@ $libstr
* @expect array('array(array($in,$in),array())', array('this', 'this')) when input array(null, null), array('flags'=>array('spvar'=>true))
* @expect array('array(array(),array(\'a\'=>$in))', array('this')) when input array('a' => null), array('flags'=>array('spvar'=>true))
*/
- protected static function getVariableNames($vn, &$context, $ishelper = false) {
+ protected static function getVariableNames($vn, &$context) {
$vars = array(array(), array());
$exps = array();
foreach ($vn as $i => $v) {
- if (isset($v[0]) && preg_match('/^\(.+\)$/', $v[0])) {
- $V = static::compileSubExpression($v[0], $context);
- } else {
- $V = static::getVariableName($v, $context, $ishelper);
- }
+ $V = static::getVariableNameOrSubExpression($v, $context);
if (is_string($i)) {
$vars[1][] = "'$i'=>{$V[0]}";
} else {
@@ -915,16 +953,17 @@ $libstr
*
* @param string $subExpression subExpression to compile
* @param array<string,array|string|integer> $context current compile context
+ * @param boolean $keepCount keep original usage count
*
* @return array<string> code representing passed expression
*/
- protected static function compileSubExpression($subExpression, &$context) {
+ protected static function compileSubExpression($subExpression, &$context, $keepCount = false) {
// mock up a token for this expression
$token = array_fill(self::POS_LOTHER, self::POS_ROTHER, '');
// strip outer ( ) from subexpression
$token[self::POS_INNERTAG] = substr($subExpression, 1, -1);
-
+ $oldCount = $context['usedFeature'];
list(, $vars) = static::parseTokenArgs($token, $context);
// no separator is needed, this code will be used as a function argument
@@ -934,6 +973,21 @@ $libstr
$ret = static::compileCustomHelper($context, $vars, true, true);
$context['ops']['seperator'] = $origSeperator;
+ if ($keepCount) {
+ $context['usedFeature'] = $oldCount;
+ } else {
+ $context['usedFeature']['subexp']++;
+ // detect handlebars custom helpers.
+ if (isset($context['hbhelpers'][$vars[0][0]])) {
+ $context['usedFeature']['hbhelper']++;
+ } else {
+ // detect custom helpers.
+ if (isset($context['helpers'][$vars[0][0]])) {
+ $context['usedFeature']['helper']++;
+ }
+ }
+ }
+
return array($ret ? $ret : '', $subExpression);
}
@@ -942,47 +996,47 @@ $libstr
*
* @param array<array|string|integer> $var variable parsed path
* @param array<array|string|integer> $context current compile context
- * @param boolean $ishelper true when compile for helper$
+ *
+ * @return array<string> variable names
+ */
+ protected static function getVariableNameOrSubExpression($var, &$context) {
+ if (isset($var[0]) && preg_match(static::IS_SUBEXP_SEARCH, $var[0])) {
+ return static::compileSubExpression($var[0], $context, true);
+ }
+ return static::getVariableName($var, $context);
+ }
+
+ /**
+ * Internal method used by compile().
+ *
+ * @param array<array|string|integer> $var variable parsed path
+ * @param array<array|string|integer> $context current compile context
*
* @return array<string> variable names
*
* @expect array('$in', 'this') when input array(null), array('flags'=>array('spvar'=>true,'debug'=>0))
- * @expect array('true', 'true') when input array('true'), array('flags'=>array('spvar'=>true,'debug'=>0)), true
- * @expect array('false', 'false') when input array('false'), array('flags'=>array('spvar'=>true,'debug'=>0)), true
- * @expect array(2, '2') when input array('2'), array('flags'=>array('spvar'=>true,'debug'=>0)), true
+ * @expect array('((isset($in[\'true\']) && is_array($in)) ? $in[\'true\'] : null)', '[true]') when input array('true'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ * @expect array('((isset($in[\'false\']) && is_array($in)) ? $in[\'false\'] : null)', '[false]') when input array('false'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ * @expect array('true', 'true') when input array(0, 'true'), array('flags'=>array('spvar'=>true,'debug'=>0))
+ * @expect array('false', 'false') when input array(0, 'false'), array('flags'=>array('spvar'=>true,'debug'=>0))
+ * @expect array('((isset($in[\'2\']) && is_array($in)) ? $in[\'2\'] : null)', '[2]') when input array('2'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ * @expect array('2', '2') when input array(0, '2'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0))
* @expect array('((isset($in[\'@index\']) && is_array($in)) ? $in[\'@index\'] : null)', '[@index]') when input array('@index'), array('flags'=>array('spvar'=>false,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
- * @expect array("((isset(\$cx['sp_vars']['index']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['index'] : null)", '@[index]') when input array('@index'), array('flags'=>array('spvar'=>true,'debug'=>0))
- * @expect array("((isset(\$cx['sp_vars']['key']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['key'] : null)", '@[key]') when input array('@key'), array('flags'=>array('spvar'=>true,'debug'=>0))
- * @expect array("((isset(\$cx['sp_vars']['first']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['first'] : null)", '@[first]') when input array('@first'), array('flags'=>array('spvar'=>true,'debug'=>0))
- * @expect array("((isset(\$cx['sp_vars']['last']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['last'] : null)", '@[last]') when input array('@last'), array('flags'=>array('spvar'=>true,'debug'=>0))
- * @expect array('\'a\'', '"a"') when input array('"a"'), array('flags'=>array('spvar'=>true,'debug'=>0))
+ * @expect array("((isset(\$cx['sp_vars']['index']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['index'] : null)", '@[index]') when input array('@index'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ * @expect array("((isset(\$cx['sp_vars']['key']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['key'] : null)", '@[key]') when input array('@key'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ * @expect array("((isset(\$cx['sp_vars']['first']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['first'] : null)", '@[first]') when input array('@first'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ * @expect array("((isset(\$cx['sp_vars']['last']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['last'] : null)", '@[last]') when input array('@last'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ * @expect array('((isset($in[\'"a"\']) && is_array($in)) ? $in[\'"a"\'] : null)', '["a"]') when input array('"a"'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ * @expect array('"a"', '"a"') when input array(0, '"a"'), array('flags'=>array('spvar'=>true,'debug'=>0))
* @expect array('((isset($in[\'a\']) && is_array($in)) ? $in[\'a\'] : null)', '[a]') when input array('a'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
* @expect array('((isset($cx[\'scopes\'][count($cx[\'scopes\'])-1][\'a\']) && is_array($cx[\'scopes\'][count($cx[\'scopes\'])-1])) ? $cx[\'scopes\'][count($cx[\'scopes\'])-1][\'a\'] : null)', '../[a]') when input array(1,'a'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
* @expect array('((isset($cx[\'scopes\'][count($cx[\'scopes\'])-3][\'a\']) && is_array($cx[\'scopes\'][count($cx[\'scopes\'])-3])) ? $cx[\'scopes\'][count($cx[\'scopes\'])-3][\'a\'] : null)', '../../../[a]') when input array(3,'a'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
* @expect array('((isset($in[\'id\']) && is_array($in)) ? $in[\'id\'] : null)', 'this.[id]') when input array(null, 'id'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
- * @expect array('LCRun3::v($cx, $in, array(\'id\'))', 'this.[id]') when input array(null, 'id'), array('flags'=>array('prop'=>true,'spvar'=>true,'debug'=>0,'method'=>0,'mustlok'=>0,'standalone'=>0))
+ * @expect array('LCRun3::v($cx, $in, array(\'id\'))', 'this.[id]') when input array(null, 'id'), array('flags'=>array('prop'=>true,'spvar'=>true,'debug'=>0,'method'=>0,'mustlok'=>0,'standalone'=>0), 'lcrun' => 'LCRun3')
*/
- protected static function getVariableName($var, &$context, $ishelper = false) {
- if (isset($var[0])) {
- // Handle language constants or number , only for helpers
- if ($ishelper) {
- if ((count($var) == 1) && is_numeric($var[0])) {
- // convert 0x00 or 0b00 numbers to decimal
- return array((string) 1 * $var[0], $var[0]);
- }
- switch ($var[0]) {
- case 'true':
- return array('true', 'true');
- case 'false':
- return array('false', 'false');
- }
- }
-
- // Handle double quoted string
- if (preg_match('/^"(.*)"$/', $var[0], $matched)) {
- $t = addcslashes(stripslashes(preg_replace('/\\\\\\\\/', '\\', $matched[1])), "'");
- return array("'{$t}'", "\"{$t}\"");
- }
+ protected static function getVariableName($var, &$context) {
+ if (isset($var[0]) && ($var[0] === 0)) {
+ return array($var[1], preg_replace('/\'(.*)\'/', '$1', $var[1]));
}
$levels = 0;
@@ -994,7 +1048,9 @@ $libstr
if (!is_string($var[0]) && is_int($var[0])) {
$levels = array_shift($var);
}
+ }
+ if (isset($var[0])) {
// handle @root, @index, @key, @last, etc
if ($context['flags']['spvar']) {
if (substr($var[0], 0, 1) === '@') {
@@ -1003,14 +1059,14 @@ $libstr
$var[0] = substr($var[0], 1);
}
}
+ }
- // change base when trace to parent
- if ($levels > 0) {
- if ($spvar) {
- $base .= str_repeat("['_parent']", $levels);
- } else {
- $base = "\$cx['scopes'][count(\$cx['scopes'])-$levels]";
- }
+ // change base when trace to parent
+ if ($levels > 0) {
+ if ($spvar) {
+ $base .= str_repeat("['_parent']", $levels);
+ } else {
+ $base = "\$cx['scopes'][count(\$cx['scopes'])-$levels]";
}
}
@@ -1073,31 +1129,44 @@ $libstr
* @return array<integer,string> Return variable name array
*
* @expect array('this') when input 'this', array('flags' => array('advar' => 0, 'this' => 0))
- * @expect array(null) when input 'this', array('flags' => array('advar' => 0, 'this' => 1))
- * @expect array(1, null) when input '../', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
- * @expect array(1, null) when input '../.', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
- * @expect array(1, null) when input '../this', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
- * @expect array(1, 'a') when input '../a', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
- * @expect array(2, 'a', 'b') when input '../../a.b', array('flags' => array('advar' => 0, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
- * @expect array(2, '[a]', 'b') when input '../../[a].b', array('flags' => array('advar' => 0, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
- * @expect array(2, 'a', 'b') when input '../../[a].b', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
- * @expect array('"a.b"') when input '"a.b"', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
- * @expect array(null, 'id') when input 'this.id', array('flags' => array('advar' => 1, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ * @expect array() when input 'this', array('flags' => array('advar' => 0, 'this' => 1))
+ * @expect array(1) when input '../', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
+ * @expect array(1) when input '../.', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
+ * @expect array(1) when input '../this', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
+ * @expect array(1, 'a') when input '../a', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
+ * @expect array(2, 'a', 'b') when input '../../a.b', array('flags' => array('advar' => 0, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
+ * @expect array(2, '[a]', 'b') when input '../../[a].b', array('flags' => array('advar' => 0, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
+ * @expect array(2, 'a', 'b') when input '../../[a].b', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
+ * @expect array('id') when input 'this.id', array('flags' => array('advar' => 1, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ * @expect array(0, '\'a.b\'') when input '"a.b"', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ * @expect array(0, '123') when input '123', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ * @expect array(0, 'null') when input 'null', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
*/
protected static function fixVariable($v, &$context) {
- $ret = array();
- $levels = 0;
+ // handle number
+ if (is_numeric($v)) {
+ // convert 0x00 or 0b00 numbers to decimal
+ return array(0, (string) 1 * $v);
+ }
// handle double quoted string
if (preg_match('/^"(.*)"$/', $v, $matched)) {
- return array($v);
+ return array(0, "'" . preg_replace('/([^\\\\])\\\\\\\\"/', '$1"', preg_replace('/^\\\\\\\\"/', '"', $matched[1])) . "'");
}
// handle single quoted string
if (preg_match('/^\\\\\'(.*)\\\\\'$/', $v, $matched)) {
- return array("\"{$matched[1]}\"");
+ return array(0, "'$matched[1]'");
}
+ // handle boolean, null and undefined
+ if (preg_match('/^(true|false|null|undefined)$/', $v)) {
+ return array(0, ($v === 'undefined') ? 'null' : $v);
+ }
+
+ $ret = array();
+ $levels = 0;
+
// handle ..
if ($v === '..') {
$v = '../';
@@ -1114,7 +1183,7 @@ $libstr
if (!$context['flags']['parent']) {
$context['error'][] = 'Do not support {{../var}}, you should do compile with LightnCandy::FLAG_PARENT flag';
}
- $context['usedFeature']['parent']++;
+ $context['usedFeature']['parent'] += ($context['scan'] ? 1 : 0);
}
if ($context['flags']['advar'] && preg_match('/\\]/', $v)) {
@@ -1123,15 +1192,11 @@ $libstr
preg_match_all('/([^\\.\\/]+)/', $v, $matchedall);
}
- if (($v === '.') || ($v === '')) {
- $matchedall = array(array('.'), array('.'));
- }
-
foreach ($matchedall[1] as $m) {
if ($context['flags']['advar'] && substr($m, 0, 1) === '[') {
$ret[] = substr($m, 1, -1);
- } else {
- $ret[] = (($context['flags']['this'] && ($m === 'this')) || ($m === '.')) ? null : $m;
+ } else if ((!$context['flags']['this'] || ($m !== 'this')) && ($m !== '.')) {
+ $ret[] = $m;
}
}
@@ -1146,24 +1211,31 @@ $libstr
*
* @return array<boolean|array> Return parsed result
*
- * @expect array(false, array(array(null))) when input array(0,0,0,0,0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
- * @expect array(true, array(array(null))) when input array(0,0,0,'{{{',0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
- * @expect array(true, array(array(null))) when input array(0,0,0,0,0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 1))
- * @expect array(false, array(array('a'))) when input array(0,0,0,0,0,0,'a'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
- * @expect array(false, array(array('a'), array('b'))) when input array(0,0,0,0,0,0,'a b'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
- * @expect array(false, array(array('a'), array('"b'), array('c"'))) when input array(0,0,0,0,0,0,'a "b c"'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
- * @expect array(false, array(array('a'), array('"b c"'))) when input array(0,0,0,0,0,0,'a "b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0))
- * @expect array(false, array(array('a'), array('[b'), array('c]'))) when input array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
- * @expect array(false, array(array('a'), array('[b'), array('c]'))) when input array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0))
- * @expect array(false, array(array('a'), array('b c'))) when input array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0))
- * @expect array(false, array(array('a'), array('b c'))) when input array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0))
- * @expect array(false, array(array('a'), 'q' => array('b c'))) when input array(0,0,0,0,0,0,'a q=[b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0))
- * @expect array(false, array(array('a'), array('q=[b c'))) when input array(0,0,0,0,0,0,'a [q=[b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0))
- * @expect array(false, array(array('a'), 'q' => array('[b'), array('c]'))) when input array(0,0,0,0,0,0,'a q=[b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0))
- * @expect array(false, array(array('a'), 'q' => array('b'), array('c'))) when input array(0,0,0,0,0,0,'a [q]=b c'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0))
- * @expect array(false, array(array('a'), 'q' => array('"b c"'))) when input array(0,0,0,0,0,0,'a q="b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0))
- * @expect array(false, array(array('(foo bar)'))) when input array(0,0,0,0,0,0,'(foo bar)'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0))
- * @expect array(false, array(array('foo'), array("'=='"), array('bar'))) when input array(0,0,0,0,0,0,"foo '==' bar"), array('flags' => array('advar' => 1, 'namev' => 1))
+ * @expect array(false, array(array())) when input array(0,0,0,0,0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
+ * @expect array(true, array(array())) when input array(0,0,0,'{{{',0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
+ * @expect array(true, array(array())) when input array(0,0,0,0,0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 1), 'scan' => false)
+ * @expect array(false, array(array('a'))) when input array(0,0,0,0,0,0,'a'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), array('b'))) when input array(0,0,0,0,0,0,'a b'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), array('"b'), array('c"'))) when input array(0,0,0,0,0,0,'a "b c"'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), array(0, '\'b c\''))) when input array(0,0,0,0,0,0,'a "b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), array('[b'), array('c]'))) when input array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), array('[b'), array('c]'))) when input array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), array('b c'))) when input array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), array('b c'))) when input array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), 'q' => array('b c'))) when input array(0,0,0,0,0,0,'a q=[b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), array('q=[b c'))) when input array(0,0,0,0,0,0,'a [q=[b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), 'q' => array('[b'), array('c]'))) when input array(0,0,0,0,0,0,'a q=[b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), 'q' => array('b'), array('c'))) when input array(0,0,0,0,0,0,'a [q]=b c'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), 'q' => array(0, '\'b c\''))) when input array(0,0,0,0,0,0,'a q="b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('(foo bar)'))) when input array(0,0,0,0,0,0,'(foo bar)'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0, 'exhlp' => 1), 'ops' => array('seperator' => ''), 'usedFeature' => array('subexp' => 0), 'scan' => false)
+ * @expect array(false, array(array('foo'), array("'=='"), array('bar'))) when input array(0,0,0,0,0,0,"foo '==' bar"), array('flags' => array('advar' => 1, 'namev' => 1, 'noesc' => 0, 'this' => 0), 'scan' => false)
+ * @expect array(false, array(array('( foo bar)'))) when input array(0,0,0,0,0,0,'( foo bar)'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0, 'exhlp' => 1), 'ops' => array('seperator' => ''), 'usedFeature' => array('subexp' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), array(0, '\' b c\''))) when input array(0,0,0,0,0,0,'a " b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), 'q' => array(0, '\' b c\''))) when input array(0,0,0,0,0,0,'a q=" b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('foo'), array(0, "' =='"), array('bar'))) when input array(0,0,0,0,0,0,"foo \' ==\' bar"), array('flags' => array('advar' => 1, 'namev' => 1, 'noesc' => 0, 'this' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), array(' b c'))) when input array(0,0,0,0,0,0,'a [ b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), 'q' => array(0, "' d e'"))) when input array(0,0,0,0,0,0,"a q=\' d e\'"), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array('q' => array('( foo bar)'))) when input array(0,0,0,0,0,0,'q=( foo bar)'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
*/
protected static function parseTokenArgs(&$token, &$context) {
trim($token[self::POS_INNERTAG]);
@@ -1175,6 +1247,11 @@ $libstr
return array(false, array());
}
+ // Skip validation on comments
+ if ($token[self::POS_OP] === '!') {
+ return array(false, array());
+ }
+
$vars = array();
$count = preg_match_all('/(\s*)([^\s]+)/', $token[self::POS_INNERTAG], $matchedall);
@@ -1196,46 +1273,54 @@ $libstr
}
// continue to next match when begin with '(' without ending ')'
- if (preg_match('/^\([^\)]+$/', $t)) {
+ if (preg_match('/^\([^\)]*$/', $t)) {
$prev = $t;
$expect = ')';
continue;
}
// continue to next match when begin with '"' without ending '"'
- if (preg_match('/^"[^"]+$/', $t)) {
+ if (preg_match('/^"[^"]*$/', $t)) {
$prev = $t;
$expect = '"';
continue;
}
+ // continue to next match when begin with \' without ending '
+ if (preg_match('/^\\\\\'[^\']*$/', $t)) {
+ $prev = $t;
+ $expect = '\'';
+ continue;
+ }
+
// continue to next match when '="' exists without ending '"'
- if (preg_match('/="[^"]+$/', $t)) {
+ if (preg_match('/^[^"]*="[^"]*$/', $t)) {
$prev = $t;
$expect = '"';
continue;
}
- // continue to next match when begin with \' without ending '
- if (preg_match('/^\\\\\'[^\']+$/', $t)) {
+ // continue to next match when '[' exists without ending ']'
+ if (preg_match('/\\[[^\\]]*$/', $t)) {
$prev = $t;
- $expect = '\'';
+ $expect = ']';
continue;
}
// continue to next match when =\' exists without ending '
- if (preg_match('/=\\\\\'[^\']+$/', $t)) {
+ if (preg_match('/^[^\']*=\\\\\'[^\']*$/', $t)) {
$prev = $t;
$expect = '\'';
continue;
}
- // continue to next match when '[' exists without ending ']'
- if (preg_match('/\\[[^\\]]+$/', $t)) {
+ // continue to next match when =( exists without ending )
+ if (preg_match('/.+\([^\)]*$/', $t)) {
$prev = $t;
- $expect = ']';
+ $expect = ')';
continue;
}
+
$vars[] = $t;
}
} else {
@@ -1247,7 +1332,8 @@ $libstr
$i = 0;
foreach ($vars as $idx => $var) {
// Skip advanced processing for subexpressions
- if (preg_match('/^\(.+\)$/', $var)) {
+ if (preg_match(static::IS_SUBEXP_SEARCH, $var)) {
+ static::compileSubExpression($var, $context, !$context['scan']);
$ret[$i] = array($var);
$i++;
continue;
@@ -1262,7 +1348,9 @@ $libstr
$var = $m[5];
}
}
- if ($context['flags']['advar']) {
+
+ $esc = $context['scan'] ? '' : '\\\\';
+ if ($context['flags']['advar'] && !preg_match("/^(\"|$esc')(.*)(\"|$esc')$/", $var)) {
// foo] Rule 1: no starting [ or [ not start from head
if (preg_match('/^[^\\[\\.]+[\\]\\[]/', $var)
// [bar Rule 2: no ending ] or ] not in the end
@@ -1273,13 +1361,22 @@ $libstr
|| preg_match('/\\.[^\\]\\[\\.]+\\[/', preg_replace('/^(..\\/)+/', '', preg_replace('/\\[[^\\]]+\\]/', '[XXX]', $var)))
) {
$context['error'][] = "Wrong variable naming as '$var' in " . static::tokenString($token) . ' !';
+ } else {
+ if (!$context['scan']) {
+ $name = preg_replace('/(\\[.+?\\])/', '', $var);
+ // Scan for invalid charactors which not be protected by [ ]
+ // now make ( and ) pass, later fix
+ if (preg_match('/[!"#%\'*+,;<=>{|}~]/', $name)) {
+ $context['error'][] = "Wrong variable naming as '$var' in " . static::tokenString($token) . ' ! You should wrap ! " # % & \' * + , ; < = > { | } ~ into [ ]';
+ }
+ }
}
}
if (($idx === 0) && ($token[self::POS_OP] === '>')) {
$var = array(preg_replace('/^("(.+)")|(\\[(.+)\\])$/', '$2$4', $var));
- } else if (is_numeric($var)) {
- $var = array('"' . $var . '"');
+ } else if (preg_match('/^\(.+\)$/', $var)) {
+ $var = array($var);
} else {
$var = static::fixVariable($var, $context);
}
@@ -1368,7 +1465,7 @@ $libstr
return ++$context['usedFeature']['delimiter'];
case '^':
- if ($vars[0][0]) {
+ if (isset($vars[0][0])) {
$context['stack'][] = $token[self::POS_INNERTAG];
$context['level']++;
return ++$context['usedFeature']['isec'];
@@ -1391,14 +1488,20 @@ $libstr
$context['stack'][] = $token[self::POS_INNERTAG];
$context['level']++;
- // detect handlebars custom helpers.
- if (isset($context['hbhelpers'][$vars[0][0]])) {
- return ++$context['usedFeature']['hbhelper'];
+ if (!isset($vars[0][0])) {
+ return;
}
- // detect block custom helpers.
- if (isset($context['blockhelpers'][$vars[0][0]])) {
- return ++$context['usedFeature']['bhelper'];
+ if (is_string($vars[0][0])) {
+ // detect handlebars custom helpers.
+ if (isset($context['hbhelpers'][$vars[0][0]])) {
+ return ++$context['usedFeature']['hbhelper'];
+ }
+
+ // detect block custom helpers.
+ if (isset($context['blockhelpers'][$vars[0][0]])) {
+ return ++$context['usedFeature']['bhelper'];
+ }
}
switch ($vars[0][0]) {
@@ -1457,20 +1560,23 @@ $libstr
$context['usedFeature'][$raw ? 'raw' : 'enc']++;
}
- // validate else and this.
- switch ($vars[0][0]) {
- case 'else':
- if ($context['flags']['else']) {
- return $context['usedFeature']['else']++;
- }
- break;
-
- case 'this':
- case '.':
+ foreach ($vars as $var) {
+ if (!isset($var[0])) {
if ($context['level'] == 0) {
$context['usedFeature']['rootthis']++;
}
- return $context['usedFeature'][($vars[0] == '.') ? 'dot' : 'this']++;
+ $context['usedFeature']['this']++;
+ }
+ }
+
+ if (!isset($vars[0][0])) {
+ return;
+ }
+
+ if ($vars[0][0] === 'else') {
+ if ($context['flags']['else']) {
+ return $context['usedFeature']['else']++;
+ }
}
// detect handlebars custom helpers.
@@ -1592,12 +1698,13 @@ $libstr
return $ret;
}
- if ($ret = static::compileCustomHelper($context, $vars, $raw)) {
- return $ret;
- }
-
- if ($ret = static::compileElse($context, $vars)) {
- return $ret;
+ if (isset($vars[0][0])) {
+ if ($ret = static::compileCustomHelper($context, $vars, $raw)) {
+ return $ret;
+ }
+ if ($ret = static::compileElse($context, $vars)) {
+ return $ret;
+ }
}
static::noNamedArguments($token, $context, $named, ', maybe you missing the custom helper?');
@@ -1619,27 +1726,31 @@ $libstr
switch ($token[self::POS_OP]) {
case '>':
// mustache spec: ignore missing partial
- if (!isset($context['usedPartial'][$vars[0][0]])) {
+ if (($context['usedFeature']['dynpartial'] === 0) && !isset($context['usedPartial'][$vars[0][0]])) {
return $context['ops']['seperator'];
}
$p = array_shift($vars);
if (!isset($vars[0])) {
$vars[0] = array();
}
- $v = static::getVariableNames($vars, $context, true);
+ $v = static::getVariableNames($vars, $context);
$tag = ">$p[0] " .implode(' ', $v[1]);
if ($context['flags']['runpart']) {
- $sp = $context['tokens']['partialind'] ? ", '{$context['tokens']['partialind']}'" : '';
- return $context['ops']['seperator'] . static::getFuncName($context, 'p', $tag) . "\$cx, '$p[0]', $v[0]$sp){$context['ops']['seperator']}";
- } else {
- if ($named || $v[0] !== 'array(array($in),array())') {
- $context['error'][] = "Do not support {{{$tag}}}, you should do compile with LightnCandy::FLAG_RUNTIMEPARTIAL flag";
+ if (preg_match(static::IS_SUBEXP_SEARCH, $p[0])) {
+ list($p) = static::compileSubExpression($p[0], $context);
+ } else {
+ $p = "'$p[0]'";
}
- return "{$context['ops']['seperator']}'" . static::compileTemplate($context, preg_replace('/^/m', $context['tokens']['partialind'], $context['usedPartial'][$p[0]]), $p[0]) . "'{$context['ops']['seperator']}";
+ $sp = $context['tokens']['partialind'] ? ", '{$context['tokens']['partialind']}'" : '';
+ return $context['ops']['seperator'] . static::getFuncName($context, 'p', $tag) . "\$cx, $p, $v[0]$sp){$context['ops']['seperator']}";
}
+ if ($named || $v[0] !== 'array(array($in),array())') {
+ $context['error'][] = "Do not support {{{$tag}}}, you should do compile with LightnCandy::FLAG_RUNTIMEPARTIAL flag";
+ }
+ return "{$context['ops']['seperator']}'" . static::compileTemplate($context, preg_replace('/^/m', $context['tokens']['partialind'], $context['usedPartial'][$p[0]]), $p[0]) . "'{$context['ops']['seperator']}";
case '^':
// {{^}} means {{else}}
- if (!$vars[0][0]) {
+ if (!isset($vars[0][0])) {
$vars[0][0] = 'else';
$token[self::POS_OP] = '';
return;
@@ -1647,7 +1758,7 @@ $libstr
// Try to compile as custom helper {{^myHelper}}
$r = static::compileBlockCustomHelper($context, $vars, true);
- if ($r) {
+ if ($r !== null) {
return $r;
}
@@ -1665,7 +1776,7 @@ $libstr
case '#':
// Try to compile as custom helper {{#myHelper}}
$r = static::compileBlockCustomHelper($context, $vars);
- if ($r) {
+ if ($r !== null) {
return $r;
}
static::noNamedArguments($token, $context, $named, ', maybe you missing the block custom helper?');
@@ -1684,6 +1795,9 @@ $libstr
* @return string|null Return compiled code segment for the token
*/
protected static function compileBlockCustomHelper(&$context, $vars, $inverted = false) {
+ if (!isset($vars[0][0])) {
+ return;
+ }
$notHBCH = !isset($context['hbhelpers'][$vars[0][0]]);
if (!isset($context['blockhelpers'][$vars[0][0]]) && $notHBCH) {
@@ -1697,7 +1811,7 @@ $libstr
$inverted = $inverted ? 'true' : 'false';
static::addUsageCount($context, $notHBCH ? 'blockhelpers' : 'hbhelpers', $ch[0]);
- $v = static::getVariableNames($vars, $context, true);
+ $v = static::getVariableNames($vars, $context);
return $context['ops']['seperator'] . static::getFuncName($context, $notHBCH ? 'bch' : 'hbch', ($inverted ? '^' : '#') . implode(' ', $v[1])) . "\$cx, '$ch[0]', {$v[0]}, \$in, $inverted, function(\$cx, \$in) {{$context['ops']['f_start']}";
}
@@ -1763,8 +1877,8 @@ $libstr
*/
protected static function compileBlockBegin(&$context, $vars) {
$each = 'false';
- $v = isset($vars[1]) ? static::getVariableName($vars[1], $context, true) : array(null, array());
- switch ($vars[0][0]) {
+ $v = isset($vars[1]) ? static::getVariableNameOrSubExpression($vars[1], $context) : array(null, array());
+ switch (isset($vars[0][0]) ? $vars[0][0] : null) {
case 'if':
$context['stack'][] = 'if';
return $context['usedFeature']['parent']
@@ -1789,7 +1903,7 @@ $libstr
}
}
- $v = static::getVariableName($vars[0], $context);
+ $v = static::getVariableNameOrSubExpression($vars[0], $context);
$context['stack'][] = $v[1];
$context['stack'][] = '#';
return $context['ops']['seperator'] . static::getFuncName($context, 'sec', (($each == 'true') ? 'each ' : '') . $v[1]) . "\$cx, {$v[0]}, \$in, $each, function(\$cx, \$in) {{$context['ops']['f_start']}";
@@ -1805,20 +1919,22 @@ $libstr
*
* @return string|null Return compiled code segment for the token when the token is custom helper
*/
- protected static function compileCustomHelper(&$context, &$vars, $raw, $err = false) {
+ protected static function compileCustomHelper(&$context, $vars, $raw, $err = false) {
$notHH = !isset($context['hbhelpers'][$vars[0][0]]);
if (!isset($context['helpers'][$vars[0][0]]) && $notHH) {
if ($err) {
- $context['error'][] = "Custom helper '{$vars[0][0]}' not found!";
+ if (!$context['flags']['exhlp']) {
+ $context['error'][] = "Can not find custom helper function defination {$vars[0][0]}() !";
+ }
}
return;
}
$fn = $raw ? 'raw' : $context['ops']['enc'];
$ch = array_shift($vars);
- $v = static::getVariableNames($vars, $context, true);
+ $v = static::getVariableNames($vars, $context);
static::addUsageCount($context, $notHH ? 'helpers' : 'hbhelpers', $ch[0]);
- return $context['ops']['seperator'] . static::getFuncName($context, $notHH ? 'ch' : 'hbch', "$ch[0] " . implode(' ', $v[1])) . "\$cx, '$ch[0]', {$v[0]}, '$fn'" . ($notHH ? '' : ', \'$in\'') . "){$context['ops']['seperator']}";
+ return $context['ops']['seperator'] . static::getFuncName($context, $notHH ? 'ch' : 'hbch', "$ch[0] " . implode(' ', $v[1])) . "\$cx, '$ch[0]', {$v[0]}, '$fn'" . ($notHH ? '' : ', $in') . "){$context['ops']['seperator']}";
}
/**
@@ -1842,6 +1958,7 @@ $libstr
case 'each':
case '#':
return "{$context['ops']['f_end']}}, function(\$cx, \$in) {{$context['ops']['f_start']}";
+ default:
}
}
$context['error'][] = '{{else}} only valid in if, unless, each, and #section context';
@@ -1903,12 +2020,12 @@ class LCRun3 {
* @param string $f runtime function name
* @param array<string,array|string|integer> $cx render time context
*
- * @expect '{{123}}' when input '123', 'miss', array('flags' => array('debug' => LCRun3::DEBUG_TAGS)), ''
- * @expect '<!--MISSED((-->{{#123}}<!--))--><!--SKIPPED--><!--MISSED((-->{{/123}}<!--))-->' when input '123', 'wi', array('flags' => array('debug' => LCRun3::DEBUG_TAGS_HTML)), false, false, function () {return 'A';}
+ * @expect '{{123}}' when input '123', 'miss', array('flags' => array('debug' => LCRun3::DEBUG_TAGS), 'lcrun' => 'LCRun3'), ''
+ * @expect '<!--MISSED((-->{{#123}}<!--))--><!--SKIPPED--><!--MISSED((-->{{/123}}<!--))-->' when input '123', 'wi', array('flags' => array('debug' => LCRun3::DEBUG_TAGS_HTML), 'lcrun' => 'LCRun3'), false, false, function () {return 'A';}
*/
public static function debug($v, $f, $cx) {
$params = array_slice(func_get_args(), 2);
- $r = call_user_func_array((isset($cx['funcs'][$f]) ? $cx['funcs'][$f] : "LCRun3::$f"), $params);
+ $r = call_user_func_array((isset($cx['funcs'][$f]) ? $cx['funcs'][$f] : "{$cx['lcrun']}::$f"), $params);
if ($cx['flags']['debug'] & self::DEBUG_TAGS) {
$ansi = $cx['flags']['debug'] & (self::DEBUG_TAGS_ANSI - self::DEBUG_TAGS);
@@ -1999,10 +2116,14 @@ class LCRun3 {
return $v;
}
$count--;
- if ($count >= 0) {
- $base = $cx['scopes'][$count];
- } else {
- return null;
+ switch ($count) {
+ case -1:
+ $base = $cx['sp_vars']['root'];
+ break;
+ case -2:
+ return null;
+ default:
+ $base = $cx['scopes'][$count];
}
}
}
@@ -2026,7 +2147,7 @@ class LCRun3 {
* @expect true when input array(), array(0)
*/
public static function ifvar($cx, $v) {
- return !is_null($v) && ($v !== false) && ($v !== 0) && ($v !== '') && (is_array($v) ? (count($v) > 0) : true);
+ return !is_null($v) && ($v !== false) && ($v !== 0) && ($v !== 0.0) && ($v !== '') && (is_array($v) ? (count($v) > 0) : true);
}
/**
@@ -2149,6 +2270,8 @@ class LCRun3 {
}
return join(',', $ret);
}
+ } else {
+ return 'Array';
}
}
@@ -2207,11 +2330,11 @@ class LCRun3 {
* @expect '-a=' when input array('flags' => array('spvar' => 0)), array('a'), array('a'), false, function ($c, $i) {return "-$i=";}
* @expect '-a=-b=' when input array('flags' => array('spvar' => 0)), array('a','b'), array('a','b'), false, function ($c, $i) {return "-$i=";}
* @expect '' when input array('flags' => array('spvar' => 0)), 'abc', 'abc', true, function ($c, $i) {return "-$i=";}
- * @expect '-b=' when input array('flags' => array('spvar' => 0, 'mustsec' => 0)), array('a' => 'b'), array('a' => 'b'), true, function ($c, $i) {return "-$i=";}
+ * @expect '-b=' when input array('flags' => array('spvar' => 0)), array('a' => 'b'), array('a' => 'b'), true, function ($c, $i) {return "-$i=";}
* @expect '1' when input array('flags' => array('spvar' => 0)), 'b', 'b', false, function ($c, $i) {return count($i);}
* @expect '1' when input array('flags' => array('spvar' => 0)), 1, 1, false, function ($c, $i) {return print_r($i, true);}
* @expect '0' when input array('flags' => array('spvar' => 0)), 0, 0, false, function ($c, $i) {return print_r($i, true);}
- * @expect '{"b":"c"}' when input array('flags' => array('spvar' => 0, 'mustsec' => 0)), array('b' => 'c'), array('b' => 'c'), false, function ($c, $i) {return json_encode($i);}
+ * @expect '{"b":"c"}' when input array('flags' => array('spvar' => 0)), array('b' => 'c'), array('b' => 'c'), false, function ($c, $i) {return json_encode($i);}
* @expect 'inv' when input array('flags' => array('spvar' => 0)), array(), 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'inv' when input array('flags' => array('spvar' => 0)), array(), 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'inv' when input array('flags' => array('spvar' => 0)), false, 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
@@ -2222,8 +2345,8 @@ class LCRun3 {
* @expect 'cb' when input array('flags' => array('spvar' => 0)), 0, 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'inv' when input array('flags' => array('spvar' => 0)), new stdClass, 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'cb' when input array('flags' => array('spvar' => 0)), new stdClass, 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
- * @expect '268' when input array('flags' => array('spvar' => 1)), array(1,3,4), 0, false, function ($c, $i) {return $i * 2;}
- * @expect '038' when input array('flags' => array('spvar' => 1), 'sp_vars'=>array()), array(1,3,'a'=>4), 0, true, function ($c, $i) {return $i * $c['sp_vars']['index'];}
+ * @expect '268' when input array('flags' => array('spvar' => 1), 'sp_vars'=>array('root' => 0)), array(1,3,4), 0, false, function ($c, $i) {return $i * 2;}
+ * @expect '038' when input array('flags' => array('spvar' => 1), 'sp_vars'=>array('root' => 0)), array(1,3,'a'=>4), 0, true, function ($c, $i) {return $i * $c['sp_vars']['index'];}
*/
public static function sec($cx, $v, $in, $each, $cb, $else = null) {
$isAry = is_array($v);
@@ -2234,7 +2357,10 @@ class LCRun3 {
$isObj = false;
if ($isAry && $else !== null && count($v) === 0) {
- return $else($cx, $in);
+ $cx['scopes'][] = $in;
+ $ret = $else($cx, $in);
+ array_pop($cx['scopes']);
+ return $ret;
}
// #var, detect input type is object or not
@@ -2298,13 +2424,9 @@ class LCRun3 {
return '';
}
if ($isAry) {
- if ($cx['flags']['mustsec']) {
- $cx['scopes'][] = $v;
- }
+ $cx['scopes'][] = $in;
$ret = $cb($cx, $v);
- if ($cx['flags']['mustsec']) {
- array_pop($cx['scopes']);
- }
+ array_pop($cx['scopes']);
return $ret;
}
@@ -2317,7 +2439,10 @@ class LCRun3 {
}
if ($else !== null) {
- return $else($cx, $in);
+ $cx['scopes'][] = $in;
+ $ret = $else($cx, $in);
+ array_pop($cx['scopes']);
+ return $ret;
}
return '';
@@ -2336,8 +2461,8 @@ class LCRun3 {
*
* @expect '' when input array(), false, false, function () {return 'A';}
* @expect '' when input array(), null, null, function () {return 'A';}
- * @expect '-Array=' when input array(), array('a'=>'b'), array('a' => 'b'), function ($c, $i) {return "-$i=";}
- * @expect '-b=' when input array(), 'b', array('a' => 'b'), function ($c, $i) {return "-$i=";}
+ * @expect '{"a":"b"}' when input array(), array('a'=>'b'), array('a'=>'c'), function ($c, $i) {return json_encode($i);}
+ * @expect '-b=' when input array(), 'b', array('a'=>'b'), function ($c, $i) {return "-$i=";}
*/
public static function wi($cx, $v, $in, $cb, $else = null) {
if (($v === false) || ($v === null)) {
@@ -2360,7 +2485,19 @@ class LCRun3 {
*
*/
public static function p($cx, $p, $v, $sp = '') {
- return call_user_func($cx['partials'][$p], $cx, is_array($v[0][0]) ? array_merge($v[0][0], $v[1]) : $v[0][0], $sp);
+ $param = $v[0][0];
+
+ if (is_array($v[1])) {
+ if (is_array($v[0][0])) {
+ $param = array_merge($v[0][0], $v[1]);
+ } else if (($cx['flags']['method'] || $cx['flags']['prop']) && is_object($v[0][0])) {
+ foreach ($v[1] as $i => $v) {
+ $param->$i = $v;
+ }
+ }
+ }
+
+ return call_user_func($cx['partials'][$p], $cx, $param, $sp);
}
/**
@@ -2425,17 +2562,18 @@ class LCRun3 {
* @param array<array|string|integer>|string|integer|null $vars variables for the helper
* @param string $op the name of variable resolver. should be one of: 'raw', 'enc', or 'encq'.
* @param boolean $inverted the logic will be inverted
- * @param Closure $cb callback function to render child context
+ * @param Closure|null $cb callback function to render child context
* @param Closure|null $else callback function to render child context when {{else}}
*
* @return string The rendered string of the token
*/
- public static function hbch($cx, $ch, $vars, $op, $inverted, $cb = false, $else = false) {
+ public static function hbch($cx, $ch, $vars, $op, $inverted, $cb = null, $else = null) {
$isBlock = (is_object($cb) && ($cb instanceof Closure));
$args = $vars[0];
$options = array(
'name' => $ch,
- 'hash' => $vars[1]
+ 'hash' => $vars[1],
+ '_this' => $isBlock ? $op : $inverted,
);
// $invert the logic
@@ -2451,12 +2589,13 @@ class LCRun3 {
ob_start();
}
if ($context === '_NO_INPUT_HERE_') {
+ $cx['scopes'][] = $op;
$ret = $cb($cx, $op);
} else {
$cx['scopes'][] = $op;
$ret = $cb($cx, $context);
- array_pop($cx['scopes']);
}
+ array_pop($cx['scopes']);
return $cx['flags']['echo'] ? ob_get_clean() : $ret;
};
}
@@ -2480,7 +2619,6 @@ class LCRun3 {
// prepare $options['data']
if ($cx['flags']['spvar']) {
$options['data'] = $cx['sp_vars'];
- $options['data']['root'] = $cx['scopes'][0];
}
$args[] = $options;
@@ -2493,12 +2631,6 @@ class LCRun3 {
$e = "LCRun3: call custom helper '$ch' error: " . $E->getMessage();
}
- if ($r === false) {
- if ($e === null) {
- $e = "LCRun3: call custom helper '$ch' error";
- }
- }
-
if($e !== null) {
if ($cx['flags']['debug'] & self::DEBUG_ERROR_LOG) {
error_log($e);
@@ -2528,7 +2660,7 @@ class LCRun3 {
* @expect '2.6.5' when input array('blockhelpers' => array('a' => function ($cx,$in) {return array($cx,$in[0],5);})), 'a', array('6', 0), 2, false, function($cx, $i) {return implode('.', $i);}
* @expect '' when input array('blockhelpers' => array('a' => function ($cx,$in) {})), 'a', array('6', 0), 2, false, function($cx, $i) {return implode('.', $i);}
*/
- public static function bch($cx, $ch, $vars, $in, $inverted, $cb, $else = false) {
+ public static function bch($cx, $ch, $vars, $in, $inverted, $cb, $else = null) {
$r = call_user_func($cx['blockhelpers'][$ch], $in, $vars[0], $vars[1]);
// $invert the logic
@@ -2556,5 +2688,3 @@ class LCRun3 {
return $ret;
}
}
-
-?> \ No newline at end of file
diff --git a/vendor/zordius/lightncandy/tests/LCRun3Test.php b/vendor/zordius/lightncandy/tests/LCRun3Test.php
index 63d6348e..03595298 100644
--- a/vendor/zordius/lightncandy/tests/LCRun3Test.php
+++ b/vendor/zordius/lightncandy/tests/LCRun3Test.php
@@ -12,10 +12,10 @@ class LCRun3Test extends PHPUnit_Framework_TestCase
public function testOn_debug() {
$method = new ReflectionMethod('LCRun3', 'debug');
$this->assertEquals('{{123}}', $method->invoke(null,
- '123', 'miss', array('flags' => array('debug' => LCRun3::DEBUG_TAGS)), ''
+ '123', 'miss', array('flags' => array('debug' => LCRun3::DEBUG_TAGS), 'lcrun' => 'LCRun3'), ''
));
$this->assertEquals('<!--MISSED((-->{{#123}}<!--))--><!--SKIPPED--><!--MISSED((-->{{/123}}<!--))-->', $method->invoke(null,
- '123', 'wi', array('flags' => array('debug' => LCRun3::DEBUG_TAGS_HTML)), false, false, function () {return 'A';}
+ '123', 'wi', array('flags' => array('debug' => LCRun3::DEBUG_TAGS_HTML), 'lcrun' => 'LCRun3'), false, false, function () {return 'A';}
));
}
/**
@@ -237,7 +237,7 @@ class LCRun3Test extends PHPUnit_Framework_TestCase
array('flags' => array('spvar' => 0)), 'abc', 'abc', true, function ($c, $i) {return "-$i=";}
));
$this->assertEquals('-b=', $method->invoke(null,
- array('flags' => array('spvar' => 0, 'mustsec' => 0)), array('a' => 'b'), array('a' => 'b'), true, function ($c, $i) {return "-$i=";}
+ array('flags' => array('spvar' => 0)), array('a' => 'b'), array('a' => 'b'), true, function ($c, $i) {return "-$i=";}
));
$this->assertEquals('1', $method->invoke(null,
array('flags' => array('spvar' => 0)), 'b', 'b', false, function ($c, $i) {return count($i);}
@@ -249,7 +249,7 @@ class LCRun3Test extends PHPUnit_Framework_TestCase
array('flags' => array('spvar' => 0)), 0, 0, false, function ($c, $i) {return print_r($i, true);}
));
$this->assertEquals('{"b":"c"}', $method->invoke(null,
- array('flags' => array('spvar' => 0, 'mustsec' => 0)), array('b' => 'c'), array('b' => 'c'), false, function ($c, $i) {return json_encode($i);}
+ array('flags' => array('spvar' => 0)), array('b' => 'c'), array('b' => 'c'), false, function ($c, $i) {return json_encode($i);}
));
$this->assertEquals('inv', $method->invoke(null,
array('flags' => array('spvar' => 0)), array(), 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
@@ -282,10 +282,10 @@ class LCRun3Test extends PHPUnit_Framework_TestCase
array('flags' => array('spvar' => 0)), new stdClass, 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
));
$this->assertEquals('268', $method->invoke(null,
- array('flags' => array('spvar' => 1)), array(1,3,4), 0, false, function ($c, $i) {return $i * 2;}
+ array('flags' => array('spvar' => 1), 'sp_vars'=>array('root' => 0)), array(1,3,4), 0, false, function ($c, $i) {return $i * 2;}
));
$this->assertEquals('038', $method->invoke(null,
- array('flags' => array('spvar' => 1), 'sp_vars'=>array()), array(1,3,'a'=>4), 0, true, function ($c, $i) {return $i * $c['sp_vars']['index'];}
+ array('flags' => array('spvar' => 1), 'sp_vars'=>array('root' => 0)), array(1,3,'a'=>4), 0, true, function ($c, $i) {return $i * $c['sp_vars']['index'];}
));
}
/**
@@ -299,11 +299,11 @@ class LCRun3Test extends PHPUnit_Framework_TestCase
$this->assertEquals('', $method->invoke(null,
array(), null, null, function () {return 'A';}
));
- $this->assertEquals('-Array=', $method->invoke(null,
- array(), array('a'=>'b'), array('a' => 'b'), function ($c, $i) {return "-$i=";}
+ $this->assertEquals('{"a":"b"}', $method->invoke(null,
+ array(), array('a'=>'b'), array('a'=>'c'), function ($c, $i) {return json_encode($i);}
));
$this->assertEquals('-b=', $method->invoke(null,
- array(), 'b', array('a' => 'b'), function ($c, $i) {return "-$i=";}
+ array(), 'b', array('a'=>'b'), function ($c, $i) {return "-$i=";}
));
}
/**
diff --git a/vendor/zordius/lightncandy/tests/LightnCandyTest.php b/vendor/zordius/lightncandy/tests/LightnCandyTest.php
index 6f82f2bd..9c82aac3 100644
--- a/vendor/zordius/lightncandy/tests/LightnCandyTest.php
+++ b/vendor/zordius/lightncandy/tests/LightnCandyTest.php
@@ -7,6 +7,22 @@ require_once('src/lightncandy.php');
class LightnCandyTest extends PHPUnit_Framework_TestCase
{
/**
+ * @covers LightnCandy::escapeTemplate
+ */
+ public function testOn_escapeTemplate() {
+ $method = new ReflectionMethod('LightnCandy', 'escapeTemplate');
+ $method->setAccessible(true);
+ $this->assertEquals('abc', $method->invoke(null,
+ 'abc'
+ ));
+ $this->assertEquals('a\\\\bc', $method->invoke(null,
+ 'a\bc'
+ ));
+ $this->assertEquals('a\\\'bc', $method->invoke(null,
+ 'a\'bc'
+ ));
+ }
+ /**
* @covers LightnCandy::buildHelperTable
*/
public function testOn_buildHelperTable() {
@@ -124,16 +140,16 @@ class LightnCandyTest extends PHPUnit_Framework_TestCase
$method = new ReflectionMethod('LightnCandy', 'getFuncName');
$method->setAccessible(true);
$this->assertEquals('LCRun3::test(', $method->invoke(null,
- array('flags' => array('standalone' => 0, 'debug' => 0)), 'test', ''
+ array('flags' => array('standalone' => 0, 'debug' => 0), 'lcrun' => 'LCRun3'), 'test', ''
));
$this->assertEquals('LCRun3::test2(', $method->invoke(null,
- array('flags' => array('standalone' => 0, 'debug' => 0)), 'test2', ''
+ array('flags' => array('standalone' => 0, 'debug' => 0), 'lcrun' => 'LCRun3'), 'test2', ''
));
$this->assertEquals("\$cx['funcs']['test3'](", $method->invoke(null,
- array('flags' => array('standalone' => 1, 'debug' => 0)), 'test3', ''
+ array('flags' => array('standalone' => 1, 'debug' => 0), 'lcrun' => 'LCRun3'), 'test3', ''
));
$this->assertEquals('LCRun3::debug(\'abc\', \'test\', ', $method->invoke(null,
- array('flags' => array('standalone' => 0, 'debug' => 1)), 'test', 'abc'
+ array('flags' => array('standalone' => 0, 'debug' => 1), 'lcrun' => 'LCRun3'), 'test', 'abc'
));
}
/**
@@ -193,32 +209,44 @@ class LightnCandyTest extends PHPUnit_Framework_TestCase
$this->assertEquals(array('$in', 'this'), $method->invoke(null,
array(null), array('flags'=>array('spvar'=>true,'debug'=>0))
));
+ $this->assertEquals(array('((isset($in[\'true\']) && is_array($in)) ? $in[\'true\'] : null)', '[true]'), $method->invoke(null,
+ array('true'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ ));
+ $this->assertEquals(array('((isset($in[\'false\']) && is_array($in)) ? $in[\'false\'] : null)', '[false]'), $method->invoke(null,
+ array('false'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ ));
$this->assertEquals(array('true', 'true'), $method->invoke(null,
- array('true'), array('flags'=>array('spvar'=>true,'debug'=>0)), true
+ array(0, 'true'), array('flags'=>array('spvar'=>true,'debug'=>0))
));
$this->assertEquals(array('false', 'false'), $method->invoke(null,
- array('false'), array('flags'=>array('spvar'=>true,'debug'=>0)), true
+ array(0, 'false'), array('flags'=>array('spvar'=>true,'debug'=>0))
));
- $this->assertEquals(array(2, '2'), $method->invoke(null,
- array('2'), array('flags'=>array('spvar'=>true,'debug'=>0)), true
+ $this->assertEquals(array('((isset($in[\'2\']) && is_array($in)) ? $in[\'2\'] : null)', '[2]'), $method->invoke(null,
+ array('2'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ ));
+ $this->assertEquals(array('2', '2'), $method->invoke(null,
+ array(0, '2'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0))
));
$this->assertEquals(array('((isset($in[\'@index\']) && is_array($in)) ? $in[\'@index\'] : null)', '[@index]'), $method->invoke(null,
array('@index'), array('flags'=>array('spvar'=>false,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
));
$this->assertEquals(array("((isset(\$cx['sp_vars']['index']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['index'] : null)", '@[index]'), $method->invoke(null,
- array('@index'), array('flags'=>array('spvar'=>true,'debug'=>0))
+ array('@index'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
));
$this->assertEquals(array("((isset(\$cx['sp_vars']['key']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['key'] : null)", '@[key]'), $method->invoke(null,
- array('@key'), array('flags'=>array('spvar'=>true,'debug'=>0))
+ array('@key'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
));
$this->assertEquals(array("((isset(\$cx['sp_vars']['first']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['first'] : null)", '@[first]'), $method->invoke(null,
- array('@first'), array('flags'=>array('spvar'=>true,'debug'=>0))
+ array('@first'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
));
$this->assertEquals(array("((isset(\$cx['sp_vars']['last']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['last'] : null)", '@[last]'), $method->invoke(null,
- array('@last'), array('flags'=>array('spvar'=>true,'debug'=>0))
+ array('@last'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ ));
+ $this->assertEquals(array('((isset($in[\'"a"\']) && is_array($in)) ? $in[\'"a"\'] : null)', '["a"]'), $method->invoke(null,
+ array('"a"'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
));
- $this->assertEquals(array('\'a\'', '"a"'), $method->invoke(null,
- array('"a"'), array('flags'=>array('spvar'=>true,'debug'=>0))
+ $this->assertEquals(array('"a"', '"a"'), $method->invoke(null,
+ array(0, '"a"'), array('flags'=>array('spvar'=>true,'debug'=>0))
));
$this->assertEquals(array('((isset($in[\'a\']) && is_array($in)) ? $in[\'a\'] : null)', '[a]'), $method->invoke(null,
array('a'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
@@ -233,7 +261,7 @@ class LightnCandyTest extends PHPUnit_Framework_TestCase
array(null, 'id'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
));
$this->assertEquals(array('LCRun3::v($cx, $in, array(\'id\'))', 'this.[id]'), $method->invoke(null,
- array(null, 'id'), array('flags'=>array('prop'=>true,'spvar'=>true,'debug'=>0,'method'=>0,'mustlok'=>0,'standalone'=>0))
+ array(null, 'id'), array('flags'=>array('prop'=>true,'spvar'=>true,'debug'=>0,'method'=>0,'mustlok'=>0,'standalone'=>0), 'lcrun' => 'LCRun3')
));
}
/**
@@ -273,35 +301,41 @@ class LightnCandyTest extends PHPUnit_Framework_TestCase
$this->assertEquals(array('this'), $method->invoke(null,
'this', array('flags' => array('advar' => 0, 'this' => 0))
));
- $this->assertEquals(array(null), $method->invoke(null,
+ $this->assertEquals(array(), $method->invoke(null,
'this', array('flags' => array('advar' => 0, 'this' => 1))
));
- $this->assertEquals(array(1, null), $method->invoke(null,
- '../', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ $this->assertEquals(array(1), $method->invoke(null,
+ '../', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
));
- $this->assertEquals(array(1, null), $method->invoke(null,
- '../.', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ $this->assertEquals(array(1), $method->invoke(null,
+ '../.', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
));
- $this->assertEquals(array(1, null), $method->invoke(null,
- '../this', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ $this->assertEquals(array(1), $method->invoke(null,
+ '../this', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
));
$this->assertEquals(array(1, 'a'), $method->invoke(null,
- '../a', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ '../a', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
));
$this->assertEquals(array(2, 'a', 'b'), $method->invoke(null,
- '../../a.b', array('flags' => array('advar' => 0, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ '../../a.b', array('flags' => array('advar' => 0, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
));
$this->assertEquals(array(2, '[a]', 'b'), $method->invoke(null,
- '../../[a].b', array('flags' => array('advar' => 0, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ '../../[a].b', array('flags' => array('advar' => 0, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
));
$this->assertEquals(array(2, 'a', 'b'), $method->invoke(null,
- '../../[a].b', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ '../../[a].b', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
));
- $this->assertEquals(array('"a.b"'), $method->invoke(null,
+ $this->assertEquals(array('id'), $method->invoke(null,
+ 'this.id', array('flags' => array('advar' => 1, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ ));
+ $this->assertEquals(array(0, '\'a.b\''), $method->invoke(null,
'"a.b"', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
));
- $this->assertEquals(array(null, 'id'), $method->invoke(null,
- 'this.id', array('flags' => array('advar' => 1, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ $this->assertEquals(array(0, '123'), $method->invoke(null,
+ '123', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ ));
+ $this->assertEquals(array(0, 'null'), $method->invoke(null,
+ 'null', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
));
}
/**
@@ -310,59 +344,80 @@ class LightnCandyTest extends PHPUnit_Framework_TestCase
public function testOn_parseTokenArgs() {
$method = new ReflectionMethod('LightnCandy', 'parseTokenArgs');
$method->setAccessible(true);
- $this->assertEquals(array(false, array(array(null))), $method->invoke(null,
- array(0,0,0,0,0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
+ $this->assertEquals(array(false, array(array())), $method->invoke(null,
+ array(0,0,0,0,0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
));
- $this->assertEquals(array(true, array(array(null))), $method->invoke(null,
- array(0,0,0,'{{{',0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
+ $this->assertEquals(array(true, array(array())), $method->invoke(null,
+ array(0,0,0,'{{{',0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
));
- $this->assertEquals(array(true, array(array(null))), $method->invoke(null,
- array(0,0,0,0,0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 1))
+ $this->assertEquals(array(true, array(array())), $method->invoke(null,
+ array(0,0,0,0,0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 1), 'scan' => false)
));
$this->assertEquals(array(false, array(array('a'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
+ array(0,0,0,0,0,0,'a'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('a'), array('b'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a b'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
+ array(0,0,0,0,0,0,'a b'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('a'), array('"b'), array('c"'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a "b c"'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
+ array(0,0,0,0,0,0,'a "b c"'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
));
- $this->assertEquals(array(false, array(array('a'), array('"b c"'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a "b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0))
+ $this->assertEquals(array(false, array(array('a'), array(0, '\'b c\''))), $method->invoke(null,
+ array(0,0,0,0,0,0,'a "b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('a'), array('[b'), array('c]'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
+ array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('a'), array('[b'), array('c]'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0))
+ array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('a'), array('b c'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0))
+ array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('a'), array('b c'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0))
+ array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('a'), 'q' => array('b c'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a q=[b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0))
+ array(0,0,0,0,0,0,'a q=[b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('a'), array('q=[b c'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a [q=[b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0))
+ array(0,0,0,0,0,0,'a [q=[b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('a'), 'q' => array('[b'), array('c]'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a q=[b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0))
+ array(0,0,0,0,0,0,'a q=[b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('a'), 'q' => array('b'), array('c'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a [q]=b c'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0))
+ array(0,0,0,0,0,0,'a [q]=b c'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
));
- $this->assertEquals(array(false, array(array('a'), 'q' => array('"b c"'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a q="b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0))
+ $this->assertEquals(array(false, array(array('a'), 'q' => array(0, '\'b c\''))), $method->invoke(null,
+ array(0,0,0,0,0,0,'a q="b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('(foo bar)'))), $method->invoke(null,
- array(0,0,0,0,0,0,'(foo bar)'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0))
+ array(0,0,0,0,0,0,'(foo bar)'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0, 'exhlp' => 1), 'ops' => array('seperator' => ''), 'usedFeature' => array('subexp' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('foo'), array("'=='"), array('bar'))), $method->invoke(null,
- array(0,0,0,0,0,0,"foo '==' bar"), array('flags' => array('advar' => 1, 'namev' => 1))
+ array(0,0,0,0,0,0,"foo '==' bar"), array('flags' => array('advar' => 1, 'namev' => 1, 'noesc' => 0, 'this' => 0), 'scan' => false)
+ ));
+ $this->assertEquals(array(false, array(array('( foo bar)'))), $method->invoke(null,
+ array(0,0,0,0,0,0,'( foo bar)'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0, 'exhlp' => 1), 'ops' => array('seperator' => ''), 'usedFeature' => array('subexp' => 0), 'scan' => false)
+ ));
+ $this->assertEquals(array(false, array(array('a'), array(0, '\' b c\''))), $method->invoke(null,
+ array(0,0,0,0,0,0,'a " b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
+ ));
+ $this->assertEquals(array(false, array(array('a'), 'q' => array(0, '\' b c\''))), $method->invoke(null,
+ array(0,0,0,0,0,0,'a q=" b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ ));
+ $this->assertEquals(array(false, array(array('foo'), array(0, "' =='"), array('bar'))), $method->invoke(null,
+ array(0,0,0,0,0,0,"foo \' ==\' bar"), array('flags' => array('advar' => 1, 'namev' => 1, 'noesc' => 0, 'this' => 0), 'scan' => false)
+ ));
+ $this->assertEquals(array(false, array(array('a'), array(' b c'))), $method->invoke(null,
+ array(0,0,0,0,0,0,'a [ b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ ));
+ $this->assertEquals(array(false, array(array('a'), 'q' => array(0, "' d e'"))), $method->invoke(null,
+ array(0,0,0,0,0,0,"a q=\' d e\'"), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ ));
+ $this->assertEquals(array(false, array('q' => array('( foo bar)'))), $method->invoke(null,
+ array(0,0,0,0,0,0,'q=( foo bar)'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
));
}
/**
diff --git a/vendor/zordius/lightncandy/tests/contextTest.php b/vendor/zordius/lightncandy/tests/contextTest.php
new file mode 100644
index 00000000..8fa88d88
--- /dev/null
+++ b/vendor/zordius/lightncandy/tests/contextTest.php
@@ -0,0 +1,300 @@
+<?php
+
+require_once('src/lightncandy.php');
+require_once('tests/helpers_for_test.php');
+
+class contextTest extends PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider compileProvider
+ */
+ public function testUsedFeature($test)
+ {
+ LightnCandy::compile($test['template'], $test['options']);
+ $context = LightnCandy::getContext();
+ $this->assertEquals($test['expected'], $context['usedFeature']);
+ }
+
+ public function compileProvider()
+ {
+ $default = Array(
+ 'rootthis' => 0,
+ 'enc' => 0,
+ 'raw' => 0,
+ 'sec' => 0,
+ 'isec' => 0,
+ 'if' => 0,
+ 'else' => 0,
+ 'unless' => 0,
+ 'each' => 0,
+ 'this' => 0,
+ 'parent' => 0,
+ 'with' => 0,
+ 'comment' => 0,
+ 'partial' => 0,
+ 'dynpartial' => 0,
+ 'helper' => 0,
+ 'bhelper' => 0,
+ 'hbhelper' => 0,
+ 'delimiter' => 0,
+ 'subexp' => 0,
+ );
+
+ $compileCases = Array(
+ Array(
+ 'template' => 'abc',
+ ),
+
+ Array(
+ 'template' => 'abc{{def',
+ ),
+
+ Array(
+ 'template' => 'abc{{def}}',
+ 'expected' => Array(
+ 'enc' => 1
+ ),
+ ),
+
+ Array(
+ 'template' => 'abc{{{def}}}',
+ 'expected' => Array(
+ 'raw' => 1
+ ),
+ ),
+
+ Array(
+ 'template' => 'abc{{&def}}',
+ 'expected' => Array(
+ 'raw' => 1
+ ),
+ ),
+
+ Array(
+ 'template' => 'abc{{this}}',
+ 'expected' => Array(
+ 'enc' => 1
+ ),
+ ),
+
+ Array(
+ 'template' => 'abc{{this}}',
+ 'options' => Array('flags' => LightnCandy::FLAG_THIS),
+ 'expected' => Array(
+ 'enc' => 1,
+ 'this' => 1,
+ 'rootthis' => 1,
+ ),
+ ),
+
+ Array(
+ 'template' => '{{#if abc}}OK!{{/if}}',
+ 'expected' => Array(
+ 'if' => 1
+ ),
+ ),
+
+ Array(
+ 'template' => '{{#unless abc}}OK!{{/unless}}',
+ 'expected' => Array(
+ 'unless' => 1
+ ),
+ ),
+
+ Array(
+ 'template' => '{{#with abc}}OK!{{/with}}',
+ 'expected' => Array(
+ 'with' => 1
+ ),
+ ),
+
+ Array(
+ 'template' => '{{#abc}}OK!{{/abc}}',
+ 'expected' => Array(
+ 'sec' => 1
+ ),
+ ),
+
+ Array(
+ 'template' => '{{^abc}}OK!{{/abc}}',
+ 'expected' => Array(
+ 'isec' => 1
+ ),
+ ),
+
+ Array(
+ 'template' => '{{#each abc}}OK!{{/each}}',
+ 'expected' => Array(
+ 'each' => 1
+ ),
+ ),
+
+ Array(
+ 'template' => '{{! test}}OK!{{! done}}',
+ 'expected' => Array(
+ 'comment' => 2
+ ),
+ ),
+
+ Array(
+ 'template' => '{{../OK}}',
+ 'expected' => Array(
+ 'parent' => 1,
+ 'enc' => 1,
+ ),
+ ),
+
+ Array(
+ 'template' => '{{&../../OK}}',
+ 'expected' => Array(
+ 'parent' => 1,
+ 'raw' => 1,
+ ),
+ ),
+
+ Array(
+ 'template' => '{{&../../../OK}} {{../OK}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'mytest' => function ($context) {
+ return $context;
+ }
+ )
+ ),
+ 'expected' => Array(
+ 'parent' => 2,
+ 'enc' => 1,
+ 'raw' => 1,
+ ),
+ ),
+
+ Array(
+ 'template' => '{{mytest ../../../OK}} {{../OK}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'mytest' => function ($context) {
+ return $context;
+ }
+ )
+ ),
+ 'expected' => Array(
+ 'parent' => 2,
+ 'enc' => 2,
+ 'hbhelper' => 1,
+ ),
+ ),
+
+ Array(
+ 'template' => '{{mytest . .}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'mytest' => function ($a, $b) {
+ return '';
+ }
+ )
+ ),
+ 'expected' => Array(
+ 'rootthis' => 2,
+ 'this' => 2,
+ 'enc' => 1,
+ 'hbhelper' => 1,
+ ),
+ ),
+
+ Array(
+ 'template' => '{{mytest (mytest ..)}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'mytest' => function ($context) {
+ return $context;
+ }
+ )
+ ),
+ 'expected' => Array(
+ 'parent' => 1,
+ 'enc' => 1,
+ 'hbhelper' => 2,
+ 'subexp' => 1,
+ ),
+ ),
+
+ Array(
+ 'template' => '{{mytest (mytest ..) .}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'mytest' => function ($context) {
+ return $context;
+ }
+ )
+ ),
+ 'expected' => Array(
+ 'parent' => 1,
+ 'rootthis' => 1,
+ 'this' => 1,
+ 'enc' => 1,
+ 'hbhelper' => 2,
+ 'subexp' => 1,
+ ),
+ ),
+
+ Array(
+ 'template' => '{{mytest (mytest (mytest ..)) .}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'mytest' => function ($context) {
+ return $context;
+ }
+ )
+ ),
+ 'expected' => Array(
+ 'parent' => 1,
+ 'rootthis' => 1,
+ 'this' => 1,
+ 'enc' => 1,
+ 'hbhelper' => 3,
+ 'subexp' => 2,
+ ),
+ ),
+
+ Array(
+ 'id' => '134',
+ 'template' => '{{#if 1}}{{keys (keys ../names)}}{{/if}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'keys' => function ($context) {
+ return $context;
+ }
+ )
+ ),
+ 'expected' => Array(
+ 'parent' => 1,
+ 'enc' => 1,
+ 'if' => 1,
+ 'hbhelper' => 2,
+ 'subexp' => 1,
+ ),
+ ),
+ );
+
+ return array_map(function($i) use ($default) {
+ if (!isset($i['options'])) {
+ $i['options'] = Array('flags' => 0);
+ }
+ if (!isset($i['options']['flags'])) {
+ $i['options']['flags'] = 0;
+ }
+ $i['expected'] = array_merge($default, isset($i['expected']) ? $i['expected'] : array());
+ return Array($i);
+ }, $compileCases);
+ }
+}
+
+
+?>
diff --git a/vendor/zordius/lightncandy/tests/errorTest.php b/vendor/zordius/lightncandy/tests/errorTest.php
index 30ecd97d..8c1cbbf1 100644
--- a/vendor/zordius/lightncandy/tests/errorTest.php
+++ b/vendor/zordius/lightncandy/tests/errorTest.php
@@ -197,7 +197,7 @@ class errorTest extends PHPUnit_Framework_TestCase
Array(
'template' => '{{testA[}}',
'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
- 'expected' => 'Wrong variable naming as \'testA[\' in {{testA[}} !',
+ 'expected' => 'Wrong variable naming in {{testA[}}',
),
Array(
'template' => '{{[testB}}',
@@ -387,8 +387,27 @@ class errorTest extends PHPUnit_Framework_TestCase
'flags' => LightnCandy::FLAG_ADVARNAME,
'helpers' => Array('test_join'),
),
- 'expected' => "Custom helper 'foo' not found!",
+ 'expected' => "Can not find custom helper function defination foo() !",
),
+ Array(
+ 'template' => '{{1 + 2}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array('test_join'),
+ ),
+ 'expected' => "Wrong variable naming as '+' in {{1 + 2}} ! You should wrap ! \" # % & ' * + , ; < = > { | } ~ into [ ]",
+ ),
+ Array(
+ 'template' => '{{> (foo) bar}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'basedir' => '.',
+ ),
+ 'expected' => Array(
+ "Can not find custom helper function defination foo() !",
+ "You use dynamic partial name as '(foo)', this only works with option FLAG_RUNTIMEPARTIAL enabled",
+ )
+ ),
);
return array_map(function($i) {
diff --git a/vendor/zordius/lightncandy/tests/example_helpers.php b/vendor/zordius/lightncandy/tests/example_helpers.php
index f5e67d6f..f5e67d6f 100644..100755
--- a/vendor/zordius/lightncandy/tests/example_helpers.php
+++ b/vendor/zordius/lightncandy/tests/example_helpers.php
diff --git a/vendor/zordius/lightncandy/tests/helpers_for_test.php b/vendor/zordius/lightncandy/tests/helpers_for_test.php
index 93a1dbc7..80c3e860 100644
--- a/vendor/zordius/lightncandy/tests/helpers_for_test.php
+++ b/vendor/zordius/lightncandy/tests/helpers_for_test.php
@@ -1,5 +1,12 @@
<?php
+// Class for customized LCRun
+class MyLCRunClass extends LCRun3 {
+ public static function raw($cx, $v) {
+ return '[[DEBUG:raw()=>' . var_export($v, true) . ']]';
+ }
+}
+
// Classes for inputs or helpers
class myClass {
function test() {
@@ -7,7 +14,7 @@ class myClass {
}
function helper2($arg) {
- return "=$arg=";
+ return is_array($arg) ? '=Array=' : "=$arg=";
}
function __call($method, $args) {
@@ -63,9 +70,12 @@ class twoDimensionIterator implements Iterator {
// Custom helpers
function helper1($arg) {
+ $arg = is_array($arg) ? 'Array' : $arg;
return "-$arg-";
}
function alink($u, $t) {
+ $u = is_array($u) ? 'Array' : $u;
+ $t = is_array($t) ? 'Array' : $t;
return "<a href=\"$u\">$t</a>";
}
diff --git a/vendor/zordius/lightncandy/tests/regressionTest.php b/vendor/zordius/lightncandy/tests/regressionTest.php
index bf591536..d7b6b96d 100644
--- a/vendor/zordius/lightncandy/tests/regressionTest.php
+++ b/vendor/zordius/lightncandy/tests/regressionTest.php
@@ -282,6 +282,612 @@ class regressionTest extends PHPUnit_Framework_TestCase
),
Array(
+ 'id' => 114,
+ 'template' => '{{^myeach .}}OK:{{.}},{{else}}NOT GOOD{{/myeach}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS | LightnCandy::FLAG_BESTPERFORMANCE,
+ 'blockhelpers' => Array(
+ 'myeach' => function ($input) {
+ return $input;
+ }
+ ),
+ ),
+ 'data' => Array(1, 'foo', 3, 'bar'),
+ 'expected' => 'NOT GOOD',
+ ),
+
+ Array(
+ 'id' => 114,
+ 'template' => '{{^myeach .}}OK:{{.}},{{else}}NOT GOOD{{/myeach}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS | LightnCandy::FLAG_BESTPERFORMANCE,
+ 'blockhelpers' => Array(
+ 'myeach' => function ($input) {
+ return;
+ }
+ ),
+ ),
+ 'data' => Array(1, 'foo', 3, 'bar'),
+ 'expected' => 'OK:,',
+ ),
+
+ Array(
+ 'id' => 124,
+ 'template' => '{{list foo bar abc=(lt 10 3) def=(lt 3 10)}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'lt' => function ($a, $b) {
+ return ($a > $b) ? Array("$a>$b", 'raw') : '';
+ },
+ 'list' => function () {
+ $out = 'List:';
+ $args = func_get_args();
+ $opts = array_pop($args);
+
+ foreach ($args as $v) {
+ if ($v) {
+ $out .= ")$v , ";
+ }
+ }
+
+ foreach ($opts['hash'] as $k => $v) {
+ if ($v) {
+ $out .= "]$k=$v , ";
+ }
+ }
+ return array($out, 'raw');
+ }
+ ),
+ ),
+ 'data' => Array('foo' => 'OK!', 'bar' => 'OK2', 'abc' => false, 'def' => 123),
+ 'expected' => 'List:)OK! , )OK2 , ]abc=10>3 , ',
+ ),
+
+ Array(
+ 'id' => 124,
+ 'template' => '{{#if (equal \'OK\' cde)}}YES!{{/if}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'equal' => function ($a, $b) {
+ return $a === $b;
+ }
+ ),
+ ),
+ 'data' => Array('cde' => 'OK'),
+ 'expected' => 'YES!'
+ ),
+
+ Array(
+ 'id' => 124,
+ 'template' => '{{#if (equal true (equal \'OK\' cde))}}YES!{{/if}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'equal' => function ($a, $b) {
+ return $a === $b;
+ }
+ ),
+ ),
+ 'data' => Array('cde' => 'OK'),
+ 'expected' => 'YES!'
+ ),
+
+ Array(
+ 'id' => 125,
+ 'template' => '{{#if (equal true ( equal \'OK\' cde))}}YES!{{/if}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'equal' => function ($a, $b) {
+ return $a === $b;
+ }
+ ),
+ ),
+ 'data' => Array('cde' => 'OK'),
+ 'expected' => 'YES!'
+ ),
+
+ Array(
+ 'id' => 125,
+ 'template' => '{{#if (equal true (equal \' OK\' cde))}}YES!{{/if}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'equal' => function ($a, $b) {
+ return $a === $b;
+ }
+ ),
+ ),
+ 'data' => Array('cde' => ' OK'),
+ 'expected' => 'YES!'
+ ),
+
+ Array(
+ 'id' => 125,
+ 'template' => '{{#if (equal true (equal \' ==\' cde))}}YES!{{/if}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'equal' => function ($a, $b) {
+ return $a === $b;
+ }
+ ),
+ ),
+ 'data' => Array('cde' => ' =='),
+ 'expected' => 'YES!'
+ ),
+
+ Array(
+ 'id' => 125,
+ 'template' => '{{#if (equal true (equal " ==" cde))}}YES!{{/if}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'equal' => function ($a, $b) {
+ return $a === $b;
+ }
+ ),
+ ),
+ 'data' => Array('cde' => ' =='),
+ 'expected' => 'YES!'
+ ),
+
+ Array(
+ 'id' => 125,
+ 'template' => '{{[ abc]}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'equal' => function ($a, $b) {
+ return $a === $b;
+ }
+ ),
+ ),
+ 'data' => Array(' abc' => 'YES!'),
+ 'expected' => 'YES!'
+ ),
+
+ Array(
+ 'id' => 125,
+ 'template' => '{{list [ abc] " xyz" \' def\' "==" \'==\' "OK"}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'list' => function ($a, $b) {
+ $out = 'List:';
+ $args = func_get_args();
+ $opts = array_pop($args);
+ foreach ($args as $v) {
+ if ($v) {
+ $out .= ")$v , ";
+ }
+ }
+ return $out;
+ }
+ ),
+ ),
+ 'data' => Array(' abc' => 'YES!'),
+ 'expected' => 'List:)YES! , ) xyz , ) def , )== , )== , )OK , '
+ ),
+
+ Array(
+ 'id' => 127,
+ 'template' => '{{#each array}}#{{#if true}}{{name}}-{{../name}}-{{../../name}}-{{../../../name}}{{/if}}##{{#myif true}}{{name}}={{../name}}={{../../name}}={{../../../name}}{{/myif}}###{{#mywith true}}{{name}}~{{../name}}~{{../../name}}~{{../../../name}}{{/mywith}}{{/each}}',
+ 'data' => Array('name' => 'john', 'array' => Array(1,2,3)),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array('myif', 'mywith'),
+ ),
+ 'expected' => '#--john-##==john=###~~john~#--john-##==john=###~~john~#--john-##==john=###~~john~',
+ ),
+
+ Array(
+ 'id' => 128,
+ 'template' => 'foo: {{foo}} , parent foo: {{../foo}}',
+ 'data' => Array('foo' => 'OK'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ ),
+ 'expected' => 'foo: OK , parent foo: ',
+ ),
+
+ Array(
+ 'id' => 132,
+ 'template' => '{{list (keys .)}}',
+ 'data' => Array('foo' => 'bar', 'test' => 'ok'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'keys' => function($arg) {
+ return Array(array_keys($arg[0]), 'asis');
+ },
+ 'list' => function($arg) {
+ return join(',', $arg[0]);
+ }
+ ),
+ ),
+ 'expected' => 'foo,test',
+ ),
+
+ Array(
+ 'id' => 133,
+ 'template' => "{{list (keys\n .\n ) \n}}",
+ 'data' => Array('foo' => 'bar', 'test' => 'ok'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'keys' => function($arg) {
+ return Array(array_keys($arg[0]), 'asis');
+ },
+ 'list' => function($arg) {
+ return join(',', $arg[0]);
+ }
+ ),
+ ),
+ 'expected' => 'foo,test',
+ ),
+
+ Array(
+ 'id' => 133,
+ 'template' => "{{list\n .\n \n \n}}",
+ 'data' => Array('foo', 'bar', 'test'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'list' => function($arg) {
+ return join(',', $arg[0]);
+ }
+ ),
+ ),
+ 'expected' => 'foo,bar,test',
+ ),
+
+ Array(
+ 'id' => 134,
+ 'template' => "{{#if 1}}{{list (keys ../names)}}{{/if}}",
+ 'data' => Array('names' => Array('foo' => 'bar', 'test' => 'ok')),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'keys' => function($arg) {
+ return Array(array_keys($arg[0]), 'asis');
+ },
+ 'list' => function($arg) {
+ return join(',', $arg[0]);
+ }
+ ),
+ ),
+ 'expected' => 'foo,test',
+ ),
+
+ Array(
+ 'id' => 138,
+ 'template' => "{{#each (keys .)}}={{.}}{{/each}}",
+ 'data' => Array('foo' => 'bar', 'test' => 'ok', 'Haha'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'keys' => function($arg) {
+ return Array(array_keys($arg[0]), 'asis');
+ }
+ ),
+ ),
+ 'expected' => '=foo=test=0',
+ ),
+
+ Array(
+ 'id' => 140,
+ 'template' => "{{[a.good.helper] .}}",
+ 'data' => Array('ha', 'hey', 'ho'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'a.good.helper' => function($arg) {
+ return join(',', $arg[0]);
+ }
+ ),
+ ),
+ 'expected' => 'ha,hey,ho',
+ ),
+
+ Array(
+ 'id' => 141,
+ 'template' => "{{#with foo}}{{#getThis bar}}{{/getThis}}{{/with}}",
+ 'data' => Array('foo' => Array('bar' => 'Good!')),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'getThis' => function($input, $options) {
+ return $input . '-' . $options['_this']['bar'];
+ }
+ ),
+ ),
+ 'expected' => 'Good!-Good!',
+ ),
+
+ Array(
+ 'id' => 141,
+ 'template' => "{{#with foo}}{{getThis bar}}{{/with}}",
+ 'data' => Array('foo' => Array('bar' => 'Good!')),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'getThis' => function($input, $options) {
+ return $input . '-' . $options['_this']['bar'];
+ }
+ ),
+ ),
+ 'expected' => 'Good!-Good!',
+ ),
+
+ Array(
+ 'id' => 143,
+ 'template' => "{{testString foo bar=\" \"}}",
+ 'data' => Array('foo' => 'good!'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'testString' => function($args, $named) {
+ return $args[0] . '-' . $named['bar'];
+ }
+ ),
+ ),
+ 'expected' => 'good!- ',
+ ),
+
+ Array(
+ 'id' => 143,
+ 'template' => "{{testString foo bar=\"\"}}",
+ 'data' => Array('foo' => 'good!'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'testString' => function($args, $named) {
+ return $args[0] . '-' . $named['bar'];
+ }
+ ),
+ ),
+ 'expected' => 'good!-',
+ ),
+
+ Array(
+ 'id' => 143,
+ 'template' => "{{testString foo bar=' '}}",
+ 'data' => Array('foo' => 'good!'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'testString' => function($args, $named) {
+ return $args[0] . '-' . $named['bar'];
+ }
+ ),
+ ),
+ 'expected' => 'good!- ',
+ ),
+
+ Array(
+ 'id' => 143,
+ 'template' => "{{testString foo bar=''}}",
+ 'data' => Array('foo' => 'good!'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'testString' => function($args, $named) {
+ return $args[0] . '-' . $named['bar'];
+ }
+ ),
+ ),
+ 'expected' => 'good!-',
+ ),
+
+ Array(
+ 'id' => 143,
+ 'template' => "{{testString foo bar=\" \"}}",
+ 'data' => Array('foo' => 'good!'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'testString' => function($arg1, $options) {
+ return $arg1 . '-' . $options['hash']['bar'];
+ }
+ ),
+ ),
+ 'expected' => 'good!- ',
+ ),
+
+ Array(
+ 'id' => 147,
+ 'template' => '{{> test/test3 foo="bar"}}',
+ 'data' => Array('test' => 'OK!', 'foo' => 'error'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS | LightnCandy::FLAG_RUNTIMEPARTIAL,
+ 'partials' => Array('test/test3' => '{{test}}, {{foo}}'),
+ ),
+ 'expected' => 'OK!, bar'
+ ),
+
+ Array(
+ 'id' => 147,
+ 'template' => '{{> test/test3 foo="bar"}}',
+ 'data' => new foo(),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS | LightnCandy::FLAG_RUNTIMEPARTIAL | LightnCandy::FLAG_INSTANCE,
+ 'partials' => Array('test/test3' => '{{bar}}, {{foo}}'),
+ ),
+ 'expected' => 'OK!, bar'
+ ),
+
+ Array(
+ 'id' => 150,
+ 'template' => '{{{.}}}',
+ 'data' => Array('hello' => 'world'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'lcrun' => 'MyLCRunClass',
+ ),
+ 'expected' => "[[DEBUG:raw()=>array (\n 'hello' => 'world',\n)]]",
+ ),
+
+ Array(
+ 'id' => 153,
+ 'template' => '{{echo "test[]"}}',
+ 'data' => null,
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'echo' => function ($in) {
+ return "-$in[0]-";
+ }
+ )
+ ),
+ 'expected' => "-test[]-",
+ ),
+
+ Array(
+ 'id' => 153,
+ 'template' => '{{echo \'test[]\'}}',
+ 'data' => null,
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'echo' => function ($in) {
+ return "-$in[0]-";
+ }
+ )
+ ),
+ 'expected' => "-test[]-",
+ ),
+
+ Array(
+ 'id' => 154,
+ 'template' => 'O{{! this is comment ! ... }}K!',
+ 'data' => null,
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ ),
+ 'expected' => "OK!"
+ ),
+
+ Array(
+ 'template' => '{{testNull null undefined 1}}',
+ 'data' => 'test',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'testNull' => function($arg1, $arg2) {
+ return (($arg1 === null) && ($arg2 === null)) ? 'YES!' : 'no';
+ }
+ )
+ ),
+ 'expected' => 'YES!'
+ ),
+
+ Array(
+ 'template' => '{{> (pname foo) bar}}',
+ 'data' => Array('bar' => 'OK! SUBEXP+PARTIAL!', 'foo' => Array('test/test3')),
+ 'options' => Array(
+ 'helpers' => Array(
+ 'pname' => function($arg) {
+ return $arg[0];
+ }
+ ),
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS | LightnCandy::FLAG_RUNTIMEPARTIAL,
+ 'partials' => Array('test/test3' => '{{.}}'),
+ ),
+ 'expected' => 'OK! SUBEXP+PARTIAL!'
+ ),
+
+ Array(
+ 'template' => '{{> testpartial newcontext mixed=foo}}',
+ 'data' => Array('foo' => 'OK!', 'newcontext' => Array('bar' => 'test')),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS | LightnCandy::FLAG_RUNTIMEPARTIAL,
+ 'partials' => Array('testpartial' => '{{bar}}-{{mixed}}'),
+ ),
+ 'expected' => 'test-OK!'
+ ),
+
+ Array(
+ 'template' => '{{[helper]}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'helper' => function () {
+ return 'DEF';
+ }
+ )
+ ),
+ 'data' => Array(),
+ 'expected' => 'DEF'
+ ),
+
+ Array(
+ 'template' => '{{#[helper3]}}ABC{{/[helper3]}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'helper3' => function () {
+ return 'DEF';
+ }
+ )
+ ),
+ 'data' => Array(),
+ 'expected' => 'DEF'
+ ),
+
+ Array(
+ 'template' => '{{#[helper3]}}ABC{{/[helper3]}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'blockhelpers' => Array(
+ 'helper3' => function () {
+ return Array('a', 'b', 'c');
+ }
+ )
+ ),
+ 'data' => Array(),
+ 'expected' => 'ABC'
+ ),
+
+ Array(
+ 'template' => '{{hash abc=["def=123"]}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS | LightnCandy::FLAG_BESTPERFORMANCE,
+ 'hbhelpers' => Array(
+ 'hash' => function ($options) {
+ $ret = '';
+ foreach ($options['hash'] as $k => $v) {
+ $ret .= "$k : $v,";
+ }
+ return $ret;
+ }
+ ),
+ ),
+ 'data' => Array('"def=123"' => 'La!'),
+ 'expected' => 'abc : La!,',
+ ),
+
+ Array(
+ 'template' => '{{hash abc=[\'def=123\']}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS | LightnCandy::FLAG_BESTPERFORMANCE,
+ 'hbhelpers' => Array(
+ 'hash' => function ($options) {
+ $ret = '';
+ foreach ($options['hash'] as $k => $v) {
+ $ret .= "$k : $v,";
+ }
+ return $ret;
+ }
+ ),
+ ),
+ 'data' => Array("'def=123'" => 'La!'),
+ 'expected' => 'abc : La!,',
+ ),
+
+ Array(
'template' => 'ABC{{#block "YES!"}}DEF{{foo}}GHI{{else}}NO~{{/block}}JKL',
'options' => Array(
'flags' => LightnCandy::FLAG_HANDLEBARSJS | LightnCandy::FLAG_BESTPERFORMANCE,
@@ -558,6 +1164,9 @@ VAREND
'he' => 'helper1',
'h2' => 'myClass::helper2',
'link' => function ($arg) {
+ if (is_array($arg)) {
+ $arg = 'Array';
+ }
return "<a href=\"{$arg}\">click here</a>";
},
'alink',