Giter VIP home page Giter VIP logo

mustache's Introduction

Mustache templates

A Dart library to parse and render mustache templates.

Build Status Coverage Status

See the mustache manual for detailed usage information.

This library passes all mustache specification tests.

Example usage

import 'package:mustache/mustache.dart';

main() {
	var source = '''
	  {{# names }}
            <div>{{ lastname }}, {{ firstname }}</div>
	  {{/ names }}
	  {{^ names }}
	    <div>No names.</div>
	  {{/ names }}
	  {{! I am a comment. }}
	''';

	var template = new Template(source, name: 'template-filename.html');

	var output = template.renderString({'names': [
		{'firstname': 'Greg', 'lastname': 'Lowe'},
		{'firstname': 'Bob', 'lastname': 'Johnson'}
	]});

	print(output);
}

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.

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.

Dart2js

This library uses mirrors. When compiling with dart2js you will need to pass the experimental mirrors flag. You also need to mark any objects which will be rendered with the @mustache annotation. There is also another version of this library available which doesn't use mirrors.

Differences between strict mode and lenient mode.

Strict mode (default)

  • Tag names may only contain the characters a-z, A-Z, 0-9, underscore, period and minus. Other characters in tags will cause a TemplateException to be thrown during parsing.

  • During rendering, if no map key or object member which matches the tag name is found, then a TemplateException will be thrown.

Lenient mode

  • Tag names may use any characters.
  • During rendering, if no map key or object member which matches the tag name is found, then silently ignore and output nothing.

Nested paths

  var t = new Template('{{ author.name }}');
  var output = template.renderString({'author': {'name': 'Greg Lowe'}});

Partials - example usage

var partial = new Template('{{ foo }}', name: 'partial');

var resolver = (String name) {
   if (name == 'partial-name') { // Name of partial tag.
     return partial;
   }
};

var t = new Template('{{> partial-name }}', partialResolver: resolver);

var output = t.renderString({'foo': 'bar'}); // bar

Lambdas - example usage

var t = new Template('{{# foo }}');
var lambda = (_) => 'bar';
t.renderString({'foo': lambda}); // bar
var t = new Template('{{# foo }}hidden{{/ foo }}');
var lambda = (_) => 'shown'};
t.renderString({'foo': lambda); // shown
var t = new Template('{{# foo }}oi{{/ foo }}');
var lambda = (LambdaContext ctx) => '<b>${ctx.renderString().toUpperCase()}</b>';
t.renderString({'foo': lambda}); // <b>OI</b>
var t = new Template('{{# foo }}{{bar}}{{/ foo }}');
var lambda = (LambdaContext ctx) => '<b>${ctx.renderString().toUpperCase()}</b>';
t.renderString({'foo': lambda, 'bar': 'pub'}); // <b>PUB</b>
var t = new Template('{{# foo }}{{bar}}{{/ foo }}');
var lambda = (LambdaContext ctx) => '<b>${ctx.renderString().toUpperCase()}</b>';
t.renderString({'foo': lambda, 'bar': 'pub'}); // <b>PUB</b>

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.

var t = new Template('{{# foo }}{{bar}}{{/ foo }}');
var lambda = (LambdaContext ctx) => ctx.renderSource(ctx.source + ' {{cmd}}')};
t.renderString({'foo': lambda, 'bar': 'pub', 'cmd': 'build'}); // pub build

mustache's People

Contributors

bcko avatar damondouglas avatar greg-montoux avatar jcollins-g avatar jorishermans avatar keertip avatar michaelhixson avatar michaelrfairhurst avatar mkustermann avatar nshahan avatar rodsevich avatar sethladd avatar srawlins avatar stereotype441 avatar timkendrick avatar xxgreg avatar yjbanov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

mustache's Issues

My version is Dart 2.x ready, uses reflectable and is strong_mode compliant

Hi Greg, I forked your version a couple of hours ago and made it D2.x ready, strong_mode compliant. My version uses reflectable 2.x - so no mirrors!

All tests are on green

pub run build_runner test
pub run build_runner test -- -p chrome

Browser-sample works - webdev serve

I trie to make a PR but somehow it fails...
Here is my version: https://github.com/MikeMitterer/mustache

Maybe you can clone it to an extra branch on your side, check it out, and... :-))), if everything is OK on your side, release it to pub

LambdaContext lookup should return null if no property

Let's say i have something like this

{{!index.mustache}}

{{#users}}
...
{{#isBirthday}}
HAPPY BIRTHDAY!!!
{{/isBirthday}}
...
{{/users}}
// app.dart
...

template.render({
  'users': [
    {
      'name': 'guy',
      'age': 18,
      'birthday': {'day': 15, 'month': 5},
    },
    {
      'name': 'gal',
      'age': 22,
    }
  ],
  'isBirthday': (LambdaContext ctx) {
    Map birthday = ctx.lookup('birthday'); // Causes an error because it returns an empty Object on the second person

    if (birthday != null) {
      ...
    }
  }
}, req.response)


...

Wouldn't it make more sense to return null since that's what it actually is?

is mustache deprecated?

I meant to ask about NNBD, but
I see that this repo hasn't been updated in about 2 years

is mustache deprecated?

Not clear where to add @mustache annotation

I really like your package - and it works great in Chromium but after compiling the whole App to JS I get an error message:

I have this class:

@mustache
class Model {
    static Model _model;

    final StreamController _controller = new StreamController<ModelChangedEvent>.broadcast();

    Stream<ModelChangedEvent> onChange;

    int _sliderValue = 20;

    @mustache
    List<int> randomValues = new List<int>();

    factory Model() {
        if(_model == null) {  _model = new Model._internal(); }
        return _model;
    }

    @mustache
    int get sliderValue => _sliderValue;

    set sliderValue(final int value) {
        _sliderValue = value;
        randomValues.clear();
        for(int counter = 0;counter < _sliderValue;counter++) {
            randomValues.add(new Math.Random().nextInt(1000));
        }
        _controller.add(new ModelChangedEvent());
    }

    //- private -----------------------------------------------------------------------------------

    Model._internal() {
        onChange = _controller.stream;
    }
}

After compiling to JS I get the following error:

Uncaught Uncaught Error: Value was missing for variable tag: sliderValue. (1:18)
<div>Slidervalue:{{sliderValue}}<ol>{{#randomValues}}<li>{{.}},</li>{{/rand...
                 ^

Stack Trace:
Value was missing for variable tag: sliderValue. (1:18)
<div>Slidervalue:{{sliderValue}}<ol>{{#randomValues}}<li>{{.}},</li>{{/rand...

Error message on invalid name doesn't specify file

Hi,

Just got this error:

Tag contained invalid characters in name, allowed: 0-9, a-z, A-Z, underscore, and minus, at: 45:13.

But which file? :)

Full stack trace:

Tag contained invalid characters in name, allowed: 0-9, a-z, A-Z, underscore, and minus, at: 45:13.
#0      _checkTagChars (package:mustache/template.dart:53:4)
#1      _parseTokens (package:mustache/template.dart:19:18)
#2      _parse (package:mustache/template.dart:10:24)
#3      parse (package:mustache/mustache.dart:17:48)
#4      NewHtmlGenerator.generatePackage (package:dartdoc/src/new_html_generator.dart:58:24)
#5      NewHtmlGenerator.generate (package:dartdoc/src/new_html_generator.dart:35:20)
#6      DartDoc.generateDocs.<anonymous closure> (package:dartdoc/dartdoc.dart:76:58)
#7      List.forEach (dart:core-patch/growable_array.dart:254)
#8      DartDoc.generateDocs (package:dartdoc/dartdoc.dart:76:24)
#9      main (file:///Users/sethladd/Code/dartdoc/bin/dartdoc.dart:45:19)
#10     _startIsolate (dart:isolate-patch/isolate_patch.dart:237)
#11     _startMainIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:192)
#12     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:130)

Partials API

Given that templates already have names, wouldn't it be easier to resolve partial by template names? You'd have to create the field List<Template> partials. But this example

var partial = new Template('{{ foo }}', name: 'partial');

var resolver = (String name) {
   if (name == 'partial-name') { // Name of partial tag.
     return partial;
   }
};

var t = new Template('{{> partial-name }}', partialResolver: resolver);

var output = t.renderString({'foo': 'bar'});

could be reduced to something like this

var partial = new Template('{{ foo }}', name: 'partial-name');

var t = new Template('{{> partial-name }}', partials: [partial]);

var output = t.renderString({'foo': 'bar'});

“Non-reflection version” in docs should say what and where this is

The docs say:

There is also another version of this library available which doesn't use mirrors.

I have no idea what to do after this. It would be much more useful to specify at least what and where this other way of doing things is (is it another project? somewhere inside this project? available through some flag?).

If it’s otherwise equivalent, the version that doesn’t require mirrors would seem to be strictly better and should be the only version offered.

Support arbitrary getters in templates via reflection

When I first tried this library, I naively expected templates to be able to invoke getter methods on my objects. Like this:

class:

public class Foo {
  String message;
  Foo(this.message);
}

template:

{{#foo}}{{message}}{{/foo}}

rendering code:

var foo = new Foo("hello");
print(template.renderString({"foo": foo}));
// Want this to print "hello", but it throws an error.

mustache4dart and mustache.java both support this. I have a rough working implementation of this feature locally, for this library. It is pretty convenient, but it performs much worse (about 1/3 as fast) than the alternative:

var foo = new Foo("hello");
print(template.renderString({"foo": { "message": foo.message }}));

But I think the ease of use is worth the performance penalty. It's not so clear in this simple example, but I think the "transform everything to Maps" approach would become very ugly the more you have to use it, and the more complicated your objects become. Imagine rendering a list of Foos, and each one has a Bar, and each Bar has a list of Baz, and you want to render properties of all of them in the template. If reflection is supported you get that for free. Without reflection, you have to marshall all that data into Maps yourself.

Would you be interested in including this feature? (If so, I can clean up my code, test it more thoroughly, and share it here.)

Escape curly brackets

Hi, is there really no better way to escape curly brackets than this:
(The output should be: <div>Repeat me {{name}} {{name2}}</div>)

        {{= | | =}}
        <div>Repeat me {{name}} {{name2}}</div>
        |= {{ }} =|

Something like \{{name}} for example...

If this is the only way at the moment - could you please add a note to your README?
Would be cool - it took my quite a while to figure out this workaround...
Thanks!

Executed dart2native report error error: import of dart:mirrors is not supported in the current Dart runtime

import 'package:mustache/mustache.dart' as mustache;
import 'file_system.dart';

void renderTemplate(String absoluteSourcePath, String finalDestinationPath,
    Map<String, dynamic> context) {
  final sourceFile = fs.file(absoluteSourcePath);
  final templateContents = sourceFile.readAsStringSync();
  final renderedContents =
      mustache.Template(templateContents).renderString(context);

  final finalDestinationFile = fs.file(finalDestinationPath);
  finalDestinationFile.writeAsStringSync(renderedContents);
}

remove mustache import , dart2native can output the bin

Support lambdas

Hello. It's me again. :)

I have an implementation of lambdas locally. Are you interested in adding lambda support to this library?

If so, how can they be properly tested in mustache_spec_test? The ~lambdas.yml file seems to include code for various languages as strings, which I take to mean it implicitly relies on the existence of an "eval" function in the language. AFAIK Dart doesn't have eval, so...

Any advice on how to make the tests work? My current thought is to:

  • Add 'dart' entries under each 'lambda' section in ~lambdas.yml.
  • In mustache_spec_test.dart, add something like this at the top of the runTest function:
// Special case: the lambda tests contain source code for various languages.
// Extract out this code and run it in a new isolate.  Then, replace that
// entry with a map with a function that talks to the isolate.
if (data.containsKey('lambda') && data['lambda'].containsKey['dart']) {
    String lambdaSource = data['lambda']['dart'];
    String lambdaUri = 'tmp/lambda.dart';
    File lambdaFile = new File('tmp/lambda.dart');
    IOSink lambdaSink = lambdaFile.openWrite();
    lambdaSink.add(lambdaSource.codeUnits);
    isolate.SendPort port = isolate.spawnUri(lambdaUri);
    data['lambda'] = ??? // I reached the limit of my Dart skills
}

Unicode is not rendered correctly

test('Unicode', () {
  var output = parse('\u{1F634}\n').renderString({});
  expect(output, equals('\u{1F634}\n'));
});

The above test fails with the following error:

Expected: '😴\n'
            ''
  Actual: '😴\n'
            '😴\n'
            ''
   Which: is different. Both strings start the same, but the actual value also has the following trailing characters: 😴\n

package:test_api              expect
test/mustache_test.dart 41:7  main.<fn>.<fn>

Support {{#.}} and Iterable values

See the following commit for a small change that adds support for:

  1. {{#.}} as a section identifier
  2. Iterable values (instead of just List)

https://github.com/michaelhixson/mustache/commit/ce331cc921da62d6aadc3569a890120be682e580

Why? It removes the need for some extra map/list creation in code that uses this library. For instance, in this code, I want to pass a list of simple model objects to my template:

https://github.com/TechEmpower/FrameworkBenchmarks/blob/master/dart/server.dart#L195-L198

Currently I have to insert that as the value in a single-entry map, so that it has a name the template understands (but I'd rather avoid that and use "{{#.}}"). Also, I have to add a "toList()" to turn my Iterable values into a List, or else the template doesn't know how to render it (but I'd rather just avoid doing that -- the template doesn't really need it to be a List).

Stack overflow on recursion

Following test throws stack overflow exception.

test('recursion', () {
  var output = _partialTest({
    'content': "X",
    'nodes': [
      {'content': "Y", 'nodes': [
        {'content': "Y1"},
        {'content': "Y2"},
      ]}
    ]
  }, {
    'root': '{{>node}}',
    'node': '{{content}}<{{#nodes}}{{>node}}{{/nodes}}>'
  }, 'root', lenient: true);
  expect(output, equals('X<Y<Y1Y2>>'));
});

0.2.0 release - feedback please!

I'd like to push a 0.2 release of the mustache package up within the next week or two.

The branch is here
https://github.com/xxgreg/mustache/tree/0.2

These are the changes I've made:

  • Implemented partials
  • Implemented lambdas
  • Tagged dart:mirrors import with MirrorsUsed so this library can be used with dart2js.
    Publish a mustache_io package which makes rendering templates stored in files easy. See:
    https://github.com/xxgreg/mustache_io
  • Will publish a separate mustache_no_mirrors package which provides the same api but with no mirrors support, this is for use in the browser. See: https://github.com/xxgreg/mustache/tree/no_mirrors

If you're using this package, I'd really appreciate if you could have a look and see if these changes work for you, or if you'd like things done differently.

Cheers!

Dart 2 runtime failures in tests

Running the tests on VM with --preview-dart-2, see the following failure

type 'List' is not a subtype of type 'List' of 'function result' where...
type 'List' is not a subtype of type 'List' of 'function result' where
List is from dart:core
List is from dart:core
ParameterMirror is from dart:mirrors
dart:mirrors _LocalMethodMirror.parameters
package:mustache/src/renderer.dart 252:50 Renderer._getNamedProperty

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.