Can I apply Dart's string interpolation dynamically?

(posted by Bill Hesse)

By wrapping the string literal in a function that takes the context as a parameter, you can have a Function : context -> String that you can pass around instead of a String. If you need to use some String operations, like concat, on these objects, you can implement these operations on a class encapsulating this type ("lifting" them). This seems like a straightforward way to give the string literal in one place, and give the data you want to interpolate in another.

String interpolation always happens dynamically, each time the literal is used, and the data can easily come from a parameter to a function rather than from the lexical context.

For example:

Function MyTemplate() {
   return (Context context) {
     return "<table><tr><td class=${context.leftColumnClass}>Red Sox</td><td>${context.data}</td></tr></table>";
   }
}

...

var templateHere = MyTemplate();

...

var output = templateHere(context);

You could also skip a level of indirection and just create

String FillMyTemplate(Context context) => '''
    <html><head><title>$context.title</title></head>
''';

and use FillMyTemplate where you need the template.


(posted by Sam McCall)

There's a trick involving noSuchMethod():

class Template {
  var _context;

  noSuchMethod(method, args) {
    if (!method.startsWith("get:")) return super.noSuchMethod(method, args);
    return _context[method.substring(4)];
  }

  abstract String template();

  String evaluate(context) {
    _context = context;
    try {
      return template();
    } finally { _context = null; }
  }
}

And then create a subclass:

class MyTemplate extends Template { template() => """
  <title>$title</title>
  <h1>$title</h1>
""";}

Finally, use it!

final renderedText = new MyTemplate().evaluate({"title": "Hello, world"})