Frischling
Frischling

Reputation: 2268

Is there a Kotlin "eval"

I have a bunch of strings like these in my already existing and quit big template file:

Hello $World I say hello to $User, too

I was thinking I could somehow let kotlin parse/search&replace this file as a kotlin string, and I'd just have to set the variables World and User to get an evaluated string... How is this possible?
This is not a kotlin source file, but a file that's beeing read by my kotlin program.

Why I want to do this? I used bash's envsubst before, and had to move away from this, since things were getting too complicated. But now I have no easy way to replace strings in a file anymore...

Thanks

Upvotes: 1

Views: 2953

Answers (2)

Renato
Renato

Reputation: 13690

Warning: Please see my other answer first: you probably don't want to run a full Kotlin script just to parse some text file with variables... use a template engine for that.

It's possible to execute Kotlin scripts, i.e. eval Kotlin code, but it requires that you basically ship the Kotlin compiler with your application.

This GitHub project, KtsRunner, for example, does that, so you can do this:

val scriptContent = "5 + 10"
val fromScript: Int = KtsObjectLoader().load<Int>(scriptContent))
println(fromScript)
// >> 15

It requires some hacking though, is very slow and it uses a bunch of Kotlin "internal" APIs to work.

See the full list of libraries this project uses here:

https://github.com/s1monw1/KtsRunner/blob/master/lib/build.gradle.kts#L21

A "proper" KEEP proposal (discussion here) exists to add first-class support for this in Kotlin, but it's not finalized yet.

Currently, it looks something like this:

fun evalFile(scriptFile: File): ResultWithDiagnostics<EvaluationResult> {

    val compilationConfiguration = createJvmCompilationConfigurationFromTemplate<MainKtsScript>()
    val evaluationConfiguration = createJvmEvaluationConfigurationFromTemplate<MainKtsScript>()

    return BasicJvmScriptingHost().eval(scriptFile.toScriptSource(), compilationConfiguration, evaluationConfiguration)
}

But it'll probably change before being released.

Upvotes: 0

Renato
Renato

Reputation: 13690

What you want is called a template engine.

You don't really need an eval (which would allow running a full Kotlin application from a String) in this case.

For example, FreeMarker templates use a syntax that's similar to Kotlin template Strings, so a template may look like this:

<h1>Welcome ${user}!</h1>

Then, from Kotlin, you can evaluate the template with a Map holding the template bindings (variables the template can use) like this:

val user = "joe"
val bindings = mapOf("user" to user)

val cfg = new Configuration(Configuration.VERSION_2_3_29)
cfg.directoryForTemplateLoading = File("/where/you/store/templates")

val template = cfg.getTemplate("test.ftlh")

// write the resolved template to stdout
val out = OutputStreamWriter(System.out)
template.process(bindings, out)

See a Java example here: https://freemarker.apache.org/docs/pgui_quickstart_all.html

There are many other template engines, and the KTor site lists a few:

https://ktor.io/docs/working-with-views.html

If you're using KTor, BTW, it makes it much easier to use template engines... your framework may even have similar.

Upvotes: 1

Related Questions