Template engine?


#1

Is there any current project working on a Kotlin template engine? Something along the lines of Scala Templates that are used in Play?


#2

Sounds fun, but I've to read up on those Scala templates first.

What is your plan? :slight_smile:


#3

Rather ambitious project I'd say: https://github.com/playframework/Play20/wiki/ScalaTemplates


#4

I've been working on a Kotlin web framework that does html and css templates using Kotlin's builder-style syntax. Not really the same as Scala's templates, but I think they're more powerful since they leverage the language features to make very concise markup. I should have something out on github shortly if you're interested.


#5

Check out http://kool.io


#6

I'd looked at that, but would prefer a more traditional template solution.

It seems like Kotlin’s built in template support isn’t that far off. It would need to add some control structures, but that’s about it. It can already do variable substitution.

val s = """ <html> <body>   $if (x == 0) {   <h1>X is Zero!</h1>

  }
  $for (y in items) {
  <li>$y.name</li>

  }
</body>
</html>
"""

This doesn’t seem too far from where we’re at with the template engine. I haven’t looked at the code for the current string template support. What kind of effort would this sort of thing require, and is it desirable?


#7

There are control structures available now in string templates:

``

println("""
  Foo: ${if (bar) “bar” else “bar1”}
  Bar
""")


To be convenient, loops need some library support:

``

""“sdfsdf ${buildString { for (i in 1…10) it.append(i)} } sdfsadfg”""


Where buildString() is defined as follows:

``

fun buildString(body: (StringBuilder) -> ()): String {
  val sb = StringBuilder()
  body(sb)
  return sb.toString()
}


#8

Wow, that's great. I didn't see that documented anywhere. We're much further along than I thought! :)

I do think it’s important to have a native Kotlin template engine (type and null safe, etc.), so I’ll be watching as things evolve, contributing if possible. Can’t wait to see how this evolves.


#9

I took a slightly different approach, creating some standard iterators:

fun For(iterator: Iterator<Any?>, out: (v:Any?)->String): String {   val sb = StringBuilder()   iterator.forEach {   sb.append(out(it))   }   return sb.toString() }

Allowing you to do something like:

return """   <html>   <head>   </head>   <body>   <ul>   ${For(1..10) {"<li>$it</li>"}}   </ul></body>   </html>   """

I also made a version of While.

This is all good, but Kotlin does not, as of yet, support language injection, which would make this all the better. There was an existing issue related to this:

http://youtrack.jetbrains.com/issue/KT-2428

Once that’s implemented, my Kotlin web development dreams would be realized.


#10

For HTML, check out Kara.


#11

Yes, I'd looked at that before. While I can see some use cases, for the work I do, I often get html pages sent to me, and the workflow that works best is just to modify that html.


#12

Are there any generic XML builders in Koltin like the ones that exist in Groovy ?


#13
fun <T> forEach(iterable: Iterable<T>, out: (v: T) -> String): String {
    val sb = StringBuilder()
    iterable.forEach {
        sb.append(out(it))
    }
    return sb.toString()
}
fun <T> forEachIndexed(iterable: Iterable<T>, out: (i: Int, v: T) -> String): String {
    val sb = StringBuilder()
    iterable.forEachIndexed { i, it ->
        sb.append(out(i + 1, it))
    }
    return sb.toString()
}

#14

If you are not searching for a specific syntax. I have a project for templates compatibles with twig/django/liquid syntax: https://github.com/soywiz/korte


#15

The easiest out-of-the-box way of using loops in Kotlin string templates I found so far is to replace loops with equivalent joinToString calls:

"<ol>${list.joinToString("") { "<li>$it" }}</ol>"

or

"""
<ol>${list.indices.joinToString("") {
    """
    <li id="item${it + 1}">${list[it]}"""
}}
</ol>""".trimIndent()

Crossposted this here: https://stackoverflow.com/questions/44554781/how-to-embed-for-loops-in-kotlin-string-templates


#16

Look at the other parameters to joinToString, there are prefix and postfix parameters which would fit very well with your usecase.