-
-
Notifications
You must be signed in to change notification settings - Fork 98
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #671 from hexagonkt/develop
Add jte template adapter
- Loading branch information
Showing
18 changed files
with
323 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
|
||
# Module templates_jte | ||
[jte] template engine adapter for Hexagon. | ||
|
||
For usage instructions, refer to the [Templates Port documentation](/templates/). | ||
|
||
[jte]: https://jte.gg | ||
|
||
### Install the Dependency | ||
|
||
=== "build.gradle" | ||
|
||
```groovy | ||
repositories { | ||
mavenCentral() | ||
} | ||
|
||
implementation("com.hexagonkt:templates_jte:$hexagonVersion") | ||
``` | ||
|
||
=== "pom.xml" | ||
|
||
```xml | ||
<dependency> | ||
<groupId>com.hexagonkt</groupId> | ||
<artifactId>templates_jte</artifactId> | ||
<version>$hexagonVersion</version> | ||
</dependency> | ||
``` | ||
|
||
## Use the Adapter | ||
In order to use this adapter you need to set up a build plugin to compile the templates. To do so in | ||
Gradle, add the following lines to `build.gradle.kts`: | ||
|
||
```kotlin | ||
plugins { | ||
id("gg.jte.gradle") version("3.1.3") | ||
} | ||
|
||
dependencies { | ||
"jteGenerate"("gg.jte:jte-native-resources:$jteVersion") | ||
} | ||
|
||
tasks.named("compileKotlin") { dependsOn("generateJte") } | ||
|
||
jte { | ||
sourceDirectory.set(projectDir.resolve("src/main/resources/templates").toPath()) | ||
contentType.set(gg.jte.ContentType.Html) | ||
|
||
jteExtension("gg.jte.nativeimage.NativeResourcesExtension") | ||
|
||
generate() | ||
} | ||
``` | ||
|
||
# TODO | ||
* Don't create `jte-classes` directory | ||
* Generate template classes only for tests | ||
* Test file loaded templates | ||
* Test plain test templates | ||
|
||
# Package com.hexagonkt.templates.jte | ||
Classes that implement the Templates Port interface with the [jte] engine. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import gg.jte.ContentType.Html | ||
|
||
plugins { | ||
id("java-library") | ||
id("gg.jte.gradle") version("3.1.3") | ||
} | ||
|
||
apply(from = "$rootDir/gradle/kotlin.gradle") | ||
apply(from = "$rootDir/gradle/publish.gradle") | ||
apply(from = "$rootDir/gradle/dokka.gradle") | ||
apply(from = "$rootDir/gradle/native.gradle") | ||
apply(from = "$rootDir/gradle/detekt.gradle") | ||
|
||
description = "Template processor adapter for 'jte'." | ||
|
||
dependencies { | ||
val jteVersion = properties["jteVersion"] | ||
|
||
"api"(project(":templates:templates")) | ||
"api"("gg.jte:jte:$jteVersion") | ||
|
||
"testImplementation"(project(":templates:templates_test")) | ||
"testImplementation"(project(":serialization:serialization_jackson_json")) | ||
|
||
"jteGenerate"("gg.jte:jte-native-resources:$jteVersion") | ||
} | ||
|
||
tasks.named("compileKotlin") { dependsOn("generateJte") } | ||
tasks.named("processResources") { dependsOn("processTestResources") } | ||
tasks.named("detektMain") { dependsOn("compileTestKotlin") } | ||
tasks.named("sourcesJar") { dependsOn("compileTestKotlin") } | ||
|
||
// TODO Remove when settings prevent this directory from being created (check .gitignore also) | ||
tasks.named<Delete>("clean") { | ||
delete("jte-classes") | ||
} | ||
|
||
jte { | ||
sourceDirectory.set(projectDir.resolve("src/test/resources/templates").toPath()) | ||
targetDirectory.set(projectDir.resolve("build/classes/kotlin/test").toPath()) | ||
contentType.set(Html) | ||
|
||
jteExtension("gg.jte.nativeimage.NativeResourcesExtension") | ||
|
||
generate() | ||
} |
70 changes: 70 additions & 0 deletions
70
templates/templates_jte/src/main/kotlin/com/hexagonkt/templates/jte/JteAdapter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package com.hexagonkt.templates.jte | ||
|
||
import com.hexagonkt.core.media.MediaType | ||
import com.hexagonkt.core.media.TEXT_HTML | ||
import com.hexagonkt.core.media.TEXT_PLAIN | ||
import com.hexagonkt.templates.TemplatePort | ||
import gg.jte.CodeResolver | ||
import gg.jte.ContentType | ||
import gg.jte.TemplateEngine | ||
import gg.jte.TemplateOutput | ||
import gg.jte.output.StringOutput | ||
import gg.jte.resolve.DirectoryCodeResolver | ||
import gg.jte.resolve.ResourceCodeResolver | ||
import java.net.URL | ||
import java.nio.file.Path | ||
import java.util.* | ||
|
||
class JteAdapter( | ||
mediaType: MediaType, | ||
resolverBase: URL? = null, | ||
precompiled: Boolean = false | ||
) : TemplatePort { | ||
|
||
private companion object { | ||
val allowedTypes: String = setOf(TEXT_HTML, TEXT_PLAIN).joinToString(", ") { it.fullType } | ||
} | ||
|
||
private val contentType = when (mediaType) { | ||
TEXT_HTML -> ContentType.Html | ||
TEXT_PLAIN -> ContentType.Plain | ||
else -> | ||
error("Unsupported media type not in: $allowedTypes (${mediaType.fullType})") | ||
} | ||
|
||
private val resolver: CodeResolver = | ||
when (resolverBase?.protocol) { | ||
"classpath" -> ResourceCodeResolver(resolverBase.path) | ||
"file" -> DirectoryCodeResolver(Path.of(resolverBase.path)) | ||
null -> ResourceCodeResolver("") | ||
else -> error("Invalid base schema not in: classpath, file (${resolverBase.protocol})") | ||
} | ||
|
||
private val templateEngine: TemplateEngine = | ||
if (precompiled) { | ||
if (resolverBase === null) { | ||
TemplateEngine.createPrecompiled(contentType) | ||
} | ||
else { | ||
val protocol = resolverBase.protocol | ||
check(protocol == "classpath") { | ||
"Precompiled base must be classpath URLs ($protocol)" | ||
} | ||
TemplateEngine.createPrecompiled(Path.of(resolverBase.path), contentType) | ||
} | ||
} | ||
else { | ||
TemplateEngine.create(resolver, contentType) | ||
} | ||
|
||
override fun render(url: URL, context: Map<String, *>, locale: Locale): String { | ||
val output: TemplateOutput = StringOutput() | ||
templateEngine.render(url.path, context, output) | ||
return output.toString() | ||
} | ||
|
||
override fun render( | ||
name: String, templates: Map<String, String>, context: Map<String, *>, locale: Locale | ||
): String = | ||
throw UnsupportedOperationException("jte does not support memory templates") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
|
||
module com.hexagonkt.templates_jte { | ||
|
||
requires transitive kotlin.stdlib; | ||
requires transitive com.hexagonkt.templates; | ||
|
||
requires gg.jte; | ||
requires gg.jte.runtime; | ||
|
||
exports com.hexagonkt.templates.jte; | ||
} |
61 changes: 61 additions & 0 deletions
61
templates/templates_jte/src/test/kotlin/com/hexagonkt/templates/jte/JteAdapterTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package com.hexagonkt.templates.jte | ||
|
||
import com.hexagonkt.core.media.TEXT_CSS | ||
import com.hexagonkt.core.media.TEXT_HTML | ||
import com.hexagonkt.core.urlOf | ||
import org.junit.jupiter.api.Test | ||
import org.junit.jupiter.api.condition.DisabledInNativeImage | ||
import java.time.LocalDateTime | ||
import java.util.Locale | ||
import kotlin.test.assertEquals | ||
import kotlin.test.assertFailsWith | ||
|
||
internal class JteAdapterTest { | ||
|
||
private val locale = Locale.getDefault() | ||
|
||
@Test | ||
@DisabledInNativeImage | ||
fun `Dates are converted properly`() { | ||
val context = mapOf("localDate" to LocalDateTime.of(2000, 12, 31, 23, 45)) | ||
val resource = "classpath:templates/test.jte" | ||
val html = JteAdapter(TEXT_HTML).render(urlOf(resource), context, locale) | ||
assert(html.contains("23:45")) | ||
assert(html.contains("2000")) | ||
assert(html.contains("31")) | ||
} | ||
|
||
@Test fun `Dates are converted properly with precompiled templates`() { | ||
val context = mapOf("localDate" to LocalDateTime.of(2000, 12, 31, 23, 45)) | ||
val resource = "classpath:test.jte" | ||
val adapter = JteAdapter(TEXT_HTML, precompiled = true) | ||
val html = adapter.render(urlOf(resource), context, locale) | ||
assert(html.contains("23:45")) | ||
assert(html.contains("2000")) | ||
assert(html.contains("31")) | ||
} | ||
|
||
@Test fun `Literal templates are not supported`() { | ||
val context = mapOf("localDate" to LocalDateTime.of(2000, 12, 31, 23, 45)) | ||
val e = assertFailsWith<UnsupportedOperationException> { | ||
JteAdapter(TEXT_HTML).render("template code", context, locale) | ||
} | ||
assertEquals("jte does not support memory templates", e.message) | ||
} | ||
|
||
@Test fun `Invalid jte adapters throw exceptions on creation`() { | ||
assertIllegalState("Unsupported media type not in: text/html, text/plain (text/css)") { | ||
JteAdapter(TEXT_CSS) | ||
} | ||
assertIllegalState("Invalid base schema not in: classpath, file (http)") { | ||
JteAdapter(TEXT_HTML, urlOf("http://example.com")) | ||
} | ||
assertIllegalState("Precompiled base must be classpath URLs (file)") { | ||
JteAdapter(TEXT_HTML, urlOf("file://example.com"), true) | ||
} | ||
} | ||
|
||
private inline fun assertIllegalState(message: String, block: () -> Unit) { | ||
assertEquals(message, assertFailsWith(IllegalStateException::class, block).message) | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
..._jte/src/test/kotlin/com/hexagonkt/templates/jte/JteTemplateAdapterPrecompiledBaseTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.hexagonkt.templates.jte | ||
|
||
import com.hexagonkt.core.media.TEXT_HTML | ||
import com.hexagonkt.core.urlOf | ||
import com.hexagonkt.templates.test.TemplateAdapterTest | ||
|
||
internal class JteTemplateAdapterPrecompiledBaseTest : | ||
TemplateAdapterTest( | ||
urlOf("classpath:test.jte"), | ||
JteAdapter(TEXT_HTML, urlOf("classpath:/"), precompiled = true) | ||
) |
8 changes: 8 additions & 0 deletions
8
...ates_jte/src/test/kotlin/com/hexagonkt/templates/jte/JteTemplateAdapterPrecompiledTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.hexagonkt.templates.jte | ||
|
||
import com.hexagonkt.core.media.TEXT_HTML | ||
import com.hexagonkt.core.urlOf | ||
import com.hexagonkt.templates.test.TemplateAdapterTest | ||
|
||
internal class JteTemplateAdapterPrecompiledTest : | ||
TemplateAdapterTest(urlOf("classpath:test.jte"), JteAdapter(TEXT_HTML, precompiled = true)) |
Oops, something went wrong.