-
Notifications
You must be signed in to change notification settings - Fork 9
[mustache_template] Add example app #36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
eeb1b88
97bb613
4f8e4ac
98925c5
2bb2389
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -60,3 +60,6 @@ gradlew.bat | |
| .project | ||
| .classpath | ||
| .settings | ||
|
|
||
| # FVM Version Cache | ||
| .fvm/ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,34 +7,47 @@ See the [mustache manual](https://mustache.github.io/mustache.5.html) for detail | |
| This library passes all [mustache specification](https://github.com/mustache/spec/tree/master/specs) tests. | ||
|
|
||
| ## Example usage | ||
|
|
||
| <?code-excerpt "main.dart (example_usage)"?> | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This reference is not correct. Did you run the excerpting tool, or did you manually copy everything between the files? |
||
| ```dart | ||
| import 'package:mustache_template/mustache_template.dart'; | ||
|
|
||
| main() { | ||
| var source = ''' | ||
| {{# names }} | ||
| <div>{{ lastname }}, {{ firstname }}</div> | ||
| {{/ names }} | ||
| {{^ names }} | ||
| <div>No names.</div> | ||
| {{/ names }} | ||
| {{! I am a comment. }} | ||
| '''; | ||
|
|
||
| var template = Template(source, name: 'template-filename.html'); | ||
|
|
||
| var output = template.renderString({'names': [ | ||
| {'firstname': 'Greg', 'lastname': 'Lowe'}, | ||
| {'firstname': 'Bob', 'lastname': 'Johnson'} | ||
| ]}); | ||
| /// The main entrypoint for the example app. | ||
| void main() { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. None of this is relevant to the example; just the original code, omitting the |
||
| exampleUsage(); | ||
| nestedPaths(); | ||
| partialsExample(); | ||
| lambdasExample(); | ||
| } | ||
|
|
||
| print(output); | ||
| /// Demonstrates basic usage of mustache templates. | ||
| void exampleUsage() { | ||
| const String source = ''' | ||
| {{# names }} | ||
| <div>{{ lastname }}, {{ firstname }}</div> | ||
| {{/ names }} | ||
| {{^ names }} | ||
| <div>No names.</div> | ||
| {{/ names }} | ||
| {{! I am a comment. }} | ||
| '''; | ||
|
|
||
| final Template template = Template(source, name: 'template-filename.html'); | ||
|
|
||
| final String output = template.renderString(<String, dynamic>{ | ||
| 'names': <Map<String, String>>[ | ||
| <String, String>{'firstname': 'Greg', 'lastname': 'Lowe'}, | ||
| <String, String>{'firstname': 'Bob', 'lastname': 'Johnson'}, | ||
| ], | ||
| }); | ||
|
|
||
| print(output); | ||
| } | ||
|
princesoni18 marked this conversation as resolved.
|
||
| ``` | ||
|
|
||
| A template is parsed when it is created, after parsing it can be rendered any number of times with different values. A TemplateException is thrown if there is a problem parsing or rendering the template. | ||
|
|
||
| The Template contstructor allows passing a name, this name will be used in error messages. When working with a number of templates, it is important to pass a name so that the error messages specify which template caused the error. | ||
| The Template constructor allows passing a name, this name will be used in error messages. When working with a number of templates, it is important to pass a name so that the error messages specify which template caused the error. | ||
|
|
||
| By default all output from `{{variable}}` tags is html escaped, this behaviour can be changed by passing htmlEscapeValues : false to the Template constructor. You can also use a `{{{triple mustache}}}` tag, or a unescaped variable tag `{{&unescaped}}`, the output from these tags is not escaped. | ||
|
|
||
|
|
@@ -53,65 +66,80 @@ By default all output from `{{variable}}` tags is html escaped, this behaviour c | |
|
|
||
| ## Nested paths | ||
|
|
||
| <?code-excerpt "main.dart (nested_paths)"?> | ||
| ```dart | ||
| var t = Template('{{ author.name }}'); | ||
| var output = template.renderString({'author': {'name': 'Greg Lowe'}}); | ||
| /// Demonstrates how to access nested map properties. | ||
| void nestedPaths() { | ||
| final Template template = Template('The author is {{ author.name }}'); | ||
| final String output = template.renderString(<String, dynamic>{ | ||
| 'author': <String, String>{'name': 'Greg Lowe'}, | ||
| }); | ||
| print(output); | ||
| } | ||
|
princesoni18 marked this conversation as resolved.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And then more generally, you've significantly changed the structure of all of these examples, making them longer by adding unnecessary boilerplate. The code being excerpted should be structurally the same as it was, with the changes being those necessary to follow style rules. |
||
| ``` | ||
|
|
||
| ## Partials - example usage | ||
|
|
||
| <?code-excerpt "main.dart (partials)"?> | ||
| ```dart | ||
|
|
||
| var partial = Template('{{ foo }}', name: 'partial'); | ||
|
|
||
| var resolver = (String name) { | ||
| if (name == 'partial-name') { // Name of partial tag. | ||
| return partial; | ||
| } | ||
| }; | ||
|
|
||
| var t = Template('{{> partial-name }}', partialResolver: resolver); | ||
|
|
||
| var output = t.renderString({'foo': 'bar'}); // bar | ||
|
|
||
| /// Demonstrates the usage of partials with a custom resolver. | ||
| void partialsExample() { | ||
| final Template partial = Template('{{ foo }}', name: 'partial'); | ||
|
|
||
| Template? resolver(String name) { | ||
| if (name == 'partial-name') { | ||
| // Name of partial tag. | ||
| return partial; | ||
| } | ||
| return null; | ||
| } | ||
|
|
||
| final Template t = Template('{{> partial-name }}', partialResolver: resolver); | ||
|
|
||
| final String output = t.renderString(<String, dynamic>{'foo': 'bar'}); | ||
| print(output); // bar | ||
| } | ||
| ``` | ||
|
|
||
| ## Lambdas - example usage | ||
|
|
||
| <?code-excerpt "main.dart (lambdas)"?> | ||
| ```dart | ||
| var t = Template('{{# foo }}'); | ||
| var lambda = (_) => 'bar'; | ||
| t.renderString({'foo': lambda}); // bar | ||
| ``` | ||
|
|
||
| ```dart | ||
| var t = Template('{{# foo }}hidden{{/ foo }}'); | ||
| var lambda = (_) => 'shown'; | ||
| t.renderString('foo': lambda); // shown | ||
| ``` | ||
|
|
||
| ```dart | ||
| var t = Template('{{# foo }}oi{{/ foo }}'); | ||
| var lambda = (LambdaContext ctx) => '<b>${ctx.renderString().toUpperCase()}</b>'; | ||
| t.renderString({'foo': lambda}); // <b>OI</b> | ||
| ``` | ||
|
|
||
| ```dart | ||
| var t = Template('{{# foo }}{{bar}}{{/ foo }}'); | ||
| var lambda = (LambdaContext ctx) => '<b>${ctx.renderString().toUpperCase()}</b>'; | ||
| t.renderString({'foo': lambda, 'bar': 'pub'}); // <b>PUB</b> | ||
| ``` | ||
|
|
||
| ```dart | ||
| var t = Template('{{# foo }}{{bar}}{{/ foo }}'); | ||
| var lambda = (LambdaContext ctx) => '<b>${ctx.renderString().toUpperCase()}</b>'; | ||
| t.renderString({'foo': lambda, 'bar': 'pub'}); // <b>PUB</b> | ||
| /// Demonstrates various usages of lambdas, including hidden sections and lambda contexts. | ||
| void lambdasExample() { | ||
| // Simple lambda | ||
| final Template t1 = Template('{{# foo }}inner{{/ foo }}'); | ||
| Object lambda1(Object? _) => 'bar'; | ||
| print(t1.renderString(<String, dynamic>{'foo': lambda1})); // bar | ||
|
|
||
| // Lambda returning text for a hidden section | ||
| final Template t2 = Template('{{# foo }}hidden{{/ foo }}'); | ||
| Object lambda2(Object? _) => 'shown'; | ||
| print(t2.renderString(<String, dynamic>{'foo': lambda2})); // shown | ||
|
|
||
| // Lambda Context | ||
| final Template t3 = Template('{{# foo }}oi{{/ foo }}'); | ||
| Object lambda3(LambdaContext ctx) => | ||
| '<b>${ctx.renderString().toUpperCase()}</b>'; | ||
| print(t3.renderString(<String, dynamic>{'foo': lambda3})); // <b>OI</b> | ||
|
|
||
| // Lambda Context with variables | ||
| final Template t4 = Template('{{# foo }}{{bar}}{{/ foo }}'); | ||
| Object lambda4(LambdaContext ctx) => | ||
| '<b>${ctx.renderString().toUpperCase()}</b>'; | ||
| print(t4.renderString( | ||
| <String, dynamic>{'foo': lambda4, 'bar': 'pub'})); // <b>PUB</b> | ||
|
|
||
| // Lambda Context re-parsing source | ||
| final Template t5 = Template('{{# foo }}{{bar}}{{/ foo }}'); | ||
| Object lambda5(LambdaContext ctx) => | ||
| ctx.renderSource('${ctx.source} {{cmd}}'); | ||
| print(t5.renderString(<String, dynamic>{ | ||
| 'foo': lambda5, | ||
| 'bar': 'pub', | ||
| 'cmd': 'build', | ||
| })); // pub build | ||
| } | ||
|
princesoni18 marked this conversation as resolved.
|
||
| ``` | ||
|
|
||
| In the following example `LambdaContext.renderSource(source)` re-parses the source string in the current context, this is the default behaviour in many mustache implementations. Since re-parsing the content is slow, and often not required, this library makes this step optional. | ||
|
|
||
| ```dart | ||
| var t = Template('{{# foo }}{{bar}}{{/ foo }}'); | ||
| var lambda = (LambdaContext ctx) => ctx.renderSource(ctx.source + ' {{cmd}}'); | ||
| t.renderString({'foo': lambda, 'bar': 'pub', 'cmd': 'build'}); // pub build | ||
| ``` | ||
| In the last lambda example `LambdaContext.renderSource(source)` re-parses the source string in the current context, this is the default behaviour in many mustache implementations. Since re-parsing the content is slow, and often not required, this library makes this step optional. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| // Copyright 2026 The Flutter Authors. All rights reserved. | ||
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
| // ignore_for_file: avoid_print | ||
|
|
||
| // #docregion example_usage | ||
| import 'package:mustache_template/mustache_template.dart'; | ||
|
|
||
| /// The main entrypoint for the example app. | ||
| void main() { | ||
| exampleUsage(); | ||
| nestedPaths(); | ||
| partialsExample(); | ||
| lambdasExample(); | ||
| } | ||
|
|
||
| /// Demonstrates basic usage of mustache templates. | ||
| void exampleUsage() { | ||
| const String source = ''' | ||
| {{# names }} | ||
| <div>{{ lastname }}, {{ firstname }}</div> | ||
| {{/ names }} | ||
| {{^ names }} | ||
| <div>No names.</div> | ||
| {{/ names }} | ||
| {{! I am a comment. }} | ||
| '''; | ||
|
|
||
| final Template template = Template(source, name: 'template-filename.html'); | ||
|
|
||
| final String output = template.renderString(<String, dynamic>{ | ||
| 'names': <Map<String, String>>[ | ||
| <String, String>{'firstname': 'Greg', 'lastname': 'Lowe'}, | ||
| <String, String>{'firstname': 'Bob', 'lastname': 'Johnson'}, | ||
| ], | ||
| }); | ||
|
|
||
| print(output); | ||
| } | ||
| // #enddocregion example_usage | ||
|
|
||
| // #docregion nested_paths | ||
| /// Demonstrates how to access nested map properties. | ||
| void nestedPaths() { | ||
| final Template template = Template('The author is {{ author.name }}'); | ||
| final String output = template.renderString(<String, dynamic>{ | ||
| 'author': <String, String>{'name': 'Greg Lowe'}, | ||
| }); | ||
| print(output); | ||
| } | ||
| // #enddocregion nested_paths | ||
|
|
||
| // #docregion partials | ||
| /// Demonstrates the usage of partials with a custom resolver. | ||
| void partialsExample() { | ||
| final Template partial = Template('{{ foo }}', name: 'partial'); | ||
|
|
||
| Template? resolver(String name) { | ||
| if (name == 'partial-name') { | ||
| // Name of partial tag. | ||
| return partial; | ||
| } | ||
| return null; | ||
| } | ||
|
|
||
| final Template t = Template('{{> partial-name }}', partialResolver: resolver); | ||
|
|
||
| final String output = t.renderString(<String, dynamic>{'foo': 'bar'}); | ||
| print(output); // bar | ||
| } | ||
| // #enddocregion partials | ||
|
|
||
| // #docregion lambdas | ||
| /// Demonstrates various usages of lambdas, including hidden sections and lambda contexts. | ||
| void lambdasExample() { | ||
| // Simple lambda | ||
| final Template t1 = Template('{{# foo }}inner{{/ foo }}'); | ||
| Object lambda1(Object? _) => 'bar'; | ||
| print(t1.renderString(<String, dynamic>{'foo': lambda1})); // bar | ||
|
|
||
| // Lambda returning text for a hidden section | ||
| final Template t2 = Template('{{# foo }}hidden{{/ foo }}'); | ||
| Object lambda2(Object? _) => 'shown'; | ||
| print(t2.renderString(<String, dynamic>{'foo': lambda2})); // shown | ||
|
|
||
| // Lambda Context | ||
| final Template t3 = Template('{{# foo }}oi{{/ foo }}'); | ||
| Object lambda3(LambdaContext ctx) => | ||
| '<b>${ctx.renderString().toUpperCase()}</b>'; | ||
| print(t3.renderString(<String, dynamic>{'foo': lambda3})); // <b>OI</b> | ||
|
|
||
| // Lambda Context with variables | ||
| final Template t4 = Template('{{# foo }}{{bar}}{{/ foo }}'); | ||
| Object lambda4(LambdaContext ctx) => | ||
| '<b>${ctx.renderString().toUpperCase()}</b>'; | ||
| print(t4.renderString( | ||
| <String, dynamic>{'foo': lambda4, 'bar': 'pub'})); // <b>PUB</b> | ||
|
|
||
| // Lambda Context re-parsing source | ||
| final Template t5 = Template('{{# foo }}{{bar}}{{/ foo }}'); | ||
| Object lambda5(LambdaContext ctx) => | ||
| ctx.renderSource('${ctx.source} {{cmd}}'); | ||
| print(t5.renderString(<String, dynamic>{ | ||
| 'foo': lambda5, | ||
| 'bar': 'pub', | ||
| 'cmd': 'build', | ||
| })); // pub build | ||
| } | ||
| // #enddocregion lambdas |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| name: mustache_template_example | ||
| description: Example app for the mustache_template package. | ||
| publish_to: 'none' | ||
|
|
||
| environment: | ||
| sdk: ^3.10.0 | ||
|
|
||
| dependencies: | ||
| mustache_template: | ||
| path: ../ | ||
|
|
||
| dev_dependencies: | ||
| lints: ^3.0.0 | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't use |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ignores for local tools should be done in your user-level git ignore, not added to the repository.