From 6918a8ca3e3489ad81d2d73500b2b16ff43267e1 Mon Sep 17 00:00:00 2001 From: Timm Friebe Date: Sat, 14 Oct 2023 12:06:46 +0200 Subject: [PATCH 1/7] Template namespaces --- .../php/web/frontend/WithNamespaces.class.php | 50 +++++++++++++++++++ .../unittest/WithNamespacesTest.class.php | 49 ++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100755 src/main/php/web/frontend/WithNamespaces.class.php create mode 100755 src/test/php/web/frontend/unittest/WithNamespacesTest.class.php diff --git a/src/main/php/web/frontend/WithNamespaces.class.php b/src/main/php/web/frontend/WithNamespaces.class.php new file mode 100755 index 0000000..0f5e296 --- /dev/null +++ b/src/main/php/web/frontend/WithNamespaces.class.php @@ -0,0 +1,50 @@ +default= $default; + $this->namespaced= $namespaced; + } + + /** + * Load a template by a given name + * + * @param string $name The template name, not including the file extension + * @return com.github.mustache.templates.Input + * @throws util.NoSuchElementException + */ + public function source($name) { + if (false === ($p= strpos($name, ':'))) return $this->default->source($name); + + $ns= substr($name, 0, $p); + if ($t= ($this->namespaced[$ns] ?? null)) return $t->source(substr($name, $p + 1)); + + throw new NoSuchElementException('Unknown namespace "'.$ns.'"'); + } + + /** + * Returns available templates + * + * @return com.github.mustache.TemplateListing + */ + public function listing() { + return $this->default->listing(); // FIXME + } +} \ No newline at end of file diff --git a/src/test/php/web/frontend/unittest/WithNamespacesTest.class.php b/src/test/php/web/frontend/unittest/WithNamespacesTest.class.php new file mode 100755 index 0000000..a0c0e17 --- /dev/null +++ b/src/test/php/web/frontend/unittest/WithNamespacesTest.class.php @@ -0,0 +1,49 @@ +templates, []); + } + + #[Test, Expect(class: NoSuchElementException::class, message: 'Unknown namespace "nonexistant"')] + public function errors_for_non_existant_namespaces() { + (new WithNamespaces($this->templates, []))->source('nonexistant:name'); + } + + #[Test] + public function render_directly() { + $fixture= new Handlebars(new WithNamespaces( + $this->templates, + ['layout' => (new InMemory())->add('content', '

{{title}}

')] + )); + + Assert::equals('

Test

', $fixture->render('layout:content', ['title' => 'Test'])); + } + + #[Test] + public function referenced_as_partial() { + $fixture= new Handlebars(new WithNamespaces( + $this->templates->add('fixture', '{{> layout:content}}'), + ['layout' => (new InMemory())->add('content', '

{{title}}

')] + )); + + Assert::equals('

Test

', $fixture->render('fixture', ['title' => 'Test'])); + } + + #[Test] + public function passing_variables_to_partial() { + $fixture= new Handlebars(new WithNamespaces( + $this->templates->add('fixture', '{{> layout:content title="Test"}}'), + ['layout' => (new InMemory())->add('content', '

{{title}}

')] + )); + + Assert::equals('

Test

', $fixture->render('fixture', [])); + } +} \ No newline at end of file From 353f08749cf85bf06a7c2130d53ba78412242854 Mon Sep 17 00:00:00 2001 From: Timm Friebe Date: Sat, 14 Oct 2023 12:52:21 +0200 Subject: [PATCH 2/7] Use TemplatesFrom --- ...amespaces.class.php => TemplatesFrom.class.php} | 6 +++--- ...sTest.class.php => TemplatesFromTest.class.php} | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) rename src/main/php/web/frontend/{WithNamespaces.class.php => TemplatesFrom.class.php} (92%) rename src/test/php/web/frontend/unittest/{WithNamespacesTest.class.php => TemplatesFromTest.class.php} (76%) diff --git a/src/main/php/web/frontend/WithNamespaces.class.php b/src/main/php/web/frontend/TemplatesFrom.class.php similarity index 92% rename from src/main/php/web/frontend/WithNamespaces.class.php rename to src/main/php/web/frontend/TemplatesFrom.class.php index 0f5e296..b376c01 100755 --- a/src/main/php/web/frontend/WithNamespaces.class.php +++ b/src/main/php/web/frontend/TemplatesFrom.class.php @@ -7,9 +7,9 @@ * Adds support for loading namespaced templates (`namespace:name`) from * a given map of namespaces and template loaders. * - * @test web.frontend.unittest.WithNamespacesTest + * @test web.frontend.unittest.TemplatesFromTest */ -class WithNamespaces extends Templates { +class TemplatesFrom extends Templates { private $default, $namespaced; /** @@ -18,7 +18,7 @@ class WithNamespaces extends Templates { * @param parent $default * @param [:parent] $namespaced */ - public function __construct(parent $default, array $namespaced) { + public function __construct(parent $default, array $namespaced= []) { $this->default= $default; $this->namespaced= $namespaced; } diff --git a/src/test/php/web/frontend/unittest/WithNamespacesTest.class.php b/src/test/php/web/frontend/unittest/TemplatesFromTest.class.php similarity index 76% rename from src/test/php/web/frontend/unittest/WithNamespacesTest.class.php rename to src/test/php/web/frontend/unittest/TemplatesFromTest.class.php index a0c0e17..1716d06 100755 --- a/src/test/php/web/frontend/unittest/WithNamespacesTest.class.php +++ b/src/test/php/web/frontend/unittest/TemplatesFromTest.class.php @@ -3,23 +3,23 @@ use com\github\mustache\InMemory; use test\{Assert, Expect, Test}; use util\NoSuchElementException; -use web\frontend\{Handlebars, WithNamespaces}; +use web\frontend\{Handlebars, TemplatesFrom}; -class WithNamespacesTest extends HandlebarsTest { +class TemplatesFromTest extends HandlebarsTest { #[Test] public function can_create() { - new WithNamespaces($this->templates, []); + new TemplatesFrom($this->templates); } #[Test, Expect(class: NoSuchElementException::class, message: 'Unknown namespace "nonexistant"')] public function errors_for_non_existant_namespaces() { - (new WithNamespaces($this->templates, []))->source('nonexistant:name'); + (new TemplatesFrom($this->templates))->source('nonexistant:name'); } #[Test] public function render_directly() { - $fixture= new Handlebars(new WithNamespaces( + $fixture= new Handlebars(new TemplatesFrom( $this->templates, ['layout' => (new InMemory())->add('content', '

{{title}}

')] )); @@ -29,7 +29,7 @@ public function render_directly() { #[Test] public function referenced_as_partial() { - $fixture= new Handlebars(new WithNamespaces( + $fixture= new Handlebars(new TemplatesFrom( $this->templates->add('fixture', '{{> layout:content}}'), ['layout' => (new InMemory())->add('content', '

{{title}}

')] )); @@ -39,7 +39,7 @@ public function referenced_as_partial() { #[Test] public function passing_variables_to_partial() { - $fixture= new Handlebars(new WithNamespaces( + $fixture= new Handlebars(new TemplatesFrom( $this->templates->add('fixture', '{{> layout:content title="Test"}}'), ['layout' => (new InMemory())->add('content', '

{{title}}

')] )); From 1ffb53ece19cec10300147d0d16fc86ba788ddbc Mon Sep 17 00:00:00 2001 From: Timm Friebe Date: Sat, 14 Oct 2023 12:59:09 +0200 Subject: [PATCH 3/7] Support strings, io.Path and io.Folder instances --- .../php/web/frontend/TemplatesFrom.class.php | 31 ++++++++++++++----- .../unittest/TemplatesFromTest.class.php | 7 ++++- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/main/php/web/frontend/TemplatesFrom.class.php b/src/main/php/web/frontend/TemplatesFrom.class.php index b376c01..d2593be 100755 --- a/src/main/php/web/frontend/TemplatesFrom.class.php +++ b/src/main/php/web/frontend/TemplatesFrom.class.php @@ -1,26 +1,41 @@ default= $default; - $this->namespaced= $namespaced; + public function __construct($default, array $namespaced= []) { + $this->default= $this->asTemplates($default); + foreach ($namespaced as $namespace => $templates) { + $this->namespaced[$namespace]= $this->asTemplates($templates); + } + } + + /** + * Casts given argument to a `Templates` instance. + * + * @param string|io.Path|io.Folder|parent $arg + * @return parent + */ + private function asTemplates($arg) { + return $arg instanceof parent ? $arg : new FilesIn($arg); } /** diff --git a/src/test/php/web/frontend/unittest/TemplatesFromTest.class.php b/src/test/php/web/frontend/unittest/TemplatesFromTest.class.php index 1716d06..5418e8d 100755 --- a/src/test/php/web/frontend/unittest/TemplatesFromTest.class.php +++ b/src/test/php/web/frontend/unittest/TemplatesFromTest.class.php @@ -8,10 +8,15 @@ class TemplatesFromTest extends HandlebarsTest { #[Test] - public function can_create() { + public function can_create_with_templates() { new TemplatesFrom($this->templates); } + #[Test] + public function can_create_with_path() { + new TemplatesFrom('src/main/handlebars'); + } + #[Test, Expect(class: NoSuchElementException::class, message: 'Unknown namespace "nonexistant"')] public function errors_for_non_existant_namespaces() { (new TemplatesFrom($this->templates))->source('nonexistant:name'); From ad51368043258232adcf96dd0c6a3e8523ae56eb Mon Sep 17 00:00:00 2001 From: Timm Friebe Date: Sat, 14 Oct 2023 13:01:24 +0200 Subject: [PATCH 4/7] QA: Consistently use variable names --- src/main/php/web/frontend/TemplatesFrom.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/php/web/frontend/TemplatesFrom.class.php b/src/main/php/web/frontend/TemplatesFrom.class.php index d2593be..1515308 100755 --- a/src/main/php/web/frontend/TemplatesFrom.class.php +++ b/src/main/php/web/frontend/TemplatesFrom.class.php @@ -23,8 +23,8 @@ class TemplatesFrom extends Templates { */ public function __construct($default, array $namespaced= []) { $this->default= $this->asTemplates($default); - foreach ($namespaced as $namespace => $templates) { - $this->namespaced[$namespace]= $this->asTemplates($templates); + foreach ($namespaced as $ns => $t) { + $this->namespaced[$ns]= $this->asTemplates($t); } } From 005079e8fcdcf0fdb7c1e0673eb5f1507622af6b Mon Sep 17 00:00:00 2001 From: Timm Friebe Date: Sat, 14 Oct 2023 13:05:13 +0200 Subject: [PATCH 5/7] Add test for partial blocks with namespaced templates --- .../web/frontend/unittest/TemplatesFromTest.class.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/test/php/web/frontend/unittest/TemplatesFromTest.class.php b/src/test/php/web/frontend/unittest/TemplatesFromTest.class.php index 5418e8d..c2346de 100755 --- a/src/test/php/web/frontend/unittest/TemplatesFromTest.class.php +++ b/src/test/php/web/frontend/unittest/TemplatesFromTest.class.php @@ -51,4 +51,15 @@ public function passing_variables_to_partial() { Assert::equals('

Test

', $fixture->render('fixture', [])); } + + #[Test] + public function partial_blocks() { + $template= '{{#> layout:content}}{{#*inline "title"}}Test{{/inline}}{{/layout:content}}'; + $fixture= new Handlebars(new TemplatesFrom( + $this->templates->add('fixture', $template), + ['layout' => (new InMemory())->add('content', '

{{> title}}

')] + )); + + Assert::equals('

Test

', $fixture->render('fixture', [])); + } } \ No newline at end of file From 4b4668587374b0340eca882a08c33b05f5110b97 Mon Sep 17 00:00:00 2001 From: Timm Friebe Date: Sat, 14 Oct 2023 18:47:44 +0200 Subject: [PATCH 6/7] Verify names with "/" work --- .../web/frontend/unittest/TemplatesFromTest.class.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/php/web/frontend/unittest/TemplatesFromTest.class.php b/src/test/php/web/frontend/unittest/TemplatesFromTest.class.php index c2346de..9f47736 100755 --- a/src/test/php/web/frontend/unittest/TemplatesFromTest.class.php +++ b/src/test/php/web/frontend/unittest/TemplatesFromTest.class.php @@ -1,7 +1,7 @@ Test', $fixture->render('fixture', [])); } - #[Test] - public function partial_blocks() { - $template= '{{#> layout:content}}{{#*inline "title"}}Test{{/inline}}{{/layout:content}}'; + #[Test, Values(['layout', 'example/layout-lib'])] + public function partial_blocks($ns) { + $template= "{{#> {$ns}:content}}{{#*inline 'title'}}Test{{/inline}}{{/{$ns}:content}}"; $fixture= new Handlebars(new TemplatesFrom( $this->templates->add('fixture', $template), - ['layout' => (new InMemory())->add('content', '

{{> title}}

')] + [$ns => (new InMemory())->add('content', '

{{> title}}

')] )); Assert::equals('

Test

', $fixture->render('fixture', [])); From 6c256958f6fe10f78d7e22c3f307c2c629128374 Mon Sep 17 00:00:00 2001 From: Timm Friebe Date: Sat, 14 Oct 2023 20:00:47 +0200 Subject: [PATCH 7/7] Ensure we use ".handlebars" file extension --- src/main/php/web/frontend/TemplatesFrom.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/php/web/frontend/TemplatesFrom.class.php b/src/main/php/web/frontend/TemplatesFrom.class.php index 1515308..24214bd 100755 --- a/src/main/php/web/frontend/TemplatesFrom.class.php +++ b/src/main/php/web/frontend/TemplatesFrom.class.php @@ -1,7 +1,7 @@