Открыть боковую панель
Aurora OS
Kotlin Multiplatform
Libraries
ktor
Коммиты
82381e87
Не подтверждена
Коммит
82381e87
создал
Ноя 09, 2018
по автору
Erdle, Tobias
Зафиксировано автором
Sergey Mashkov
Дек 13, 2018
Просмотр файлов
Add Mustache templating feature (#713)
владелец
b93daadb
Изменения
7
Скрыть пробелы
Построчно
Рядом
ktor-features/ktor-mustache/build.gradle
0 → 100644
Просмотр файла @
82381e87
description
=
''
dependencies
{
compile
group:
'com.github.spullara.mustache.java'
,
name:
'compiler'
,
version:
'0.9.5'
}
ktor-features/ktor-mustache/src/io/ktor/mustache/Mustache.kt
0 → 100644
Просмотр файла @
82381e87
package
io.ktor.mustache
import
com.github.mustachejava.DefaultMustacheFactory
import
com.github.mustachejava.MustacheFactory
import
io.ktor.application.ApplicationCallPipeline
import
io.ktor.application.ApplicationFeature
import
io.ktor.http.ContentType
import
io.ktor.http.charset
import
io.ktor.http.content.EntityTagVersion
import
io.ktor.http.content.OutgoingContent
import
io.ktor.http.content.versions
import
io.ktor.http.withCharset
import
io.ktor.response.ApplicationSendPipeline
import
io.ktor.util.AttributeKey
import
io.ktor.util.cio.bufferedWriter
import
kotlinx.coroutines.io.ByteWriteChannel
/**
* Response content which could be used to respond [ApplicationCalls] like `call.respond(MustacheContent(...))
*
* @param template name of the template to be resolved by Mustache
* @param model which is passed into the template
* @param etag value for `E-Tag` header (optional)
* @param contentType response's content type which is set to `text/html;charset=utf-8` by default
*/
class
MustacheContent
(
val
template
:
String
,
val
model
:
Any
?,
val
etag
:
String
?
=
null
,
val
contentType
:
ContentType
=
ContentType
.
Text
.
Html
.
withCharset
(
Charsets
.
UTF_8
)
)
/**
* Feature for providing Mustache templates as [MustacheContent]
*/
class
Mustache
(
private
val
mustacheFactory
:
MustacheFactory
)
{
companion
object
Feature
:
ApplicationFeature
<
ApplicationCallPipeline
,
MustacheFactory
,
Mustache
>
{
override
val
key
=
AttributeKey
<
Mustache
>(
"mustache"
)
override
fun
install
(
pipeline
:
ApplicationCallPipeline
,
configure
:
MustacheFactory
.()
->
Unit
):
Mustache
{
val
mustacheFactory
=
DefaultMustacheFactory
().
apply
(
configure
)
val
feature
=
Mustache
(
mustacheFactory
)
pipeline
.
sendPipeline
.
intercept
(
ApplicationSendPipeline
.
Transform
)
{
value
->
if
(
value
is
MustacheContent
)
{
val
response
=
feature
.
process
(
value
)
proceedWith
(
response
)
}
}
return
feature
}
}
private
fun
process
(
content
:
MustacheContent
):
MustacheOutgoingContent
{
return
MustacheOutgoingContent
(
mustacheFactory
.
compile
(
content
.
template
),
content
.
model
,
content
.
etag
,
content
.
contentType
)
}
/**
* Content which is responded when Mustache templates are rendered.
*
* @param template the compiled [com.github.mustachejava.Mustache] template
* @param model the model provided into the template
* @param etag value for `E-Tag` header (optional)
* @param contentType response's content type which is set to `text/html;charset=utf-8` by default
*/
private
class
MustacheOutgoingContent
(
val
template
:
com
.
github
.
mustachejava
.
Mustache
,
val
model
:
Any
?,
etag
:
String
?,
override
val
contentType
:
ContentType
)
:
OutgoingContent
.
WriteChannelContent
()
{
override
suspend
fun
writeTo
(
channel
:
ByteWriteChannel
)
{
channel
.
bufferedWriter
(
contentType
.
charset
()
?:
Charsets
.
UTF_8
).
use
{
template
.
execute
(
it
,
model
)
}
}
init
{
if
(
etag
!=
null
)
versions
+=
EntityTagVersion
(
etag
)
}
}
}
ktor-features/ktor-mustache/src/io/ktor/mustache/RespondTemplate.kt
0 → 100644
Просмотр файла @
82381e87
package
io.ktor.mustache
import
io.ktor.application.ApplicationCall
import
io.ktor.http.ContentType
import
io.ktor.http.withCharset
import
io.ktor.response.respond
/**
* Respond with the specified [template] passing [model]
*
* @see MustacheContent
*/
suspend
fun
ApplicationCall
.
respondTemplate
(
template
:
String
,
model
:
Any
?
=
null
,
etag
:
String
?
=
null
,
contentType
:
ContentType
=
ContentType
.
Text
.
Html
.
withCharset
(
Charsets
.
UTF_8
)
)
=
respond
(
MustacheContent
(
template
,
model
,
etag
,
contentType
))
ktor-features/ktor-mustache/test-resources/withPlaceholder.mustache
0 → 100644
Просмотр файла @
82381e87
<p>
Hello,
{{
id
}}
</p>
<h1>
{{
title
}}
</h1>
ktor-features/ktor-mustache/test-resources/withoutPlaceholder.mustache
0 → 100644
Просмотр файла @
82381e87
<p>
Hello, Anonymous
</p>
<h1>
Hi!
</h1>
ktor-features/ktor-mustache/test/io/ktor/mustache/MustacheTest.kt
0 → 100644
Просмотр файла @
82381e87
package
io.ktor.mustache
import
com.github.mustachejava.DefaultMustacheFactory
import
io.ktor.application.Application
import
io.ktor.application.call
import
io.ktor.application.install
import
io.ktor.features.Compression
import
io.ktor.features.ConditionalHeaders
import
io.ktor.http.ContentType
import
io.ktor.http.HttpHeaders
import
io.ktor.http.HttpMethod
import
io.ktor.http.withCharset
import
io.ktor.response.respond
import
io.ktor.routing.get
import
io.ktor.routing.routing
import
io.ktor.server.testing.handleRequest
import
io.ktor.server.testing.withTestApplication
import
org.junit.Test
import
java.util.zip.GZIPInputStream
import
kotlin.test.assertEquals
import
kotlin.test.assertNotNull
class
MustacheTest
{
@Test
fun
`Fill
template
and
expect
correct
rendered
content`
()
{
withTestApplication
{
application
.
setupMustache
()
application
.
install
(
ConditionalHeaders
)
application
.
routing
{
get
(
"/"
)
{
call
.
respond
(
MustacheContent
(
TemplateWithPlaceholder
,
DefaultModel
,
"e"
))
}
}
handleRequest
(
HttpMethod
.
Get
,
"/"
).
response
.
let
{
response
->
val
lines
=
response
.
content
!!
.
lines
()
assertEquals
(
"<p>Hello, 1</p>"
,
lines
[
0
])
assertEquals
(
"<h1>Hello World!</h1>"
,
lines
[
1
])
}
}
}
@Test
fun
`Fill
template
and
expect
correct
default
content
type`
()
{
withTestApplication
{
application
.
setupMustache
()
application
.
install
(
ConditionalHeaders
)
application
.
routing
{
get
(
"/"
)
{
call
.
respond
(
MustacheContent
(
TemplateWithPlaceholder
,
DefaultModel
,
"e"
))
}
}
handleRequest
(
HttpMethod
.
Get
,
"/"
).
response
.
let
{
response
->
val
contentTypeText
=
assertNotNull
(
response
.
headers
[
HttpHeaders
.
ContentType
])
assertEquals
(
ContentType
.
Text
.
Html
.
withCharset
(
Charsets
.
UTF_8
),
ContentType
.
parse
(
contentTypeText
))
}
}
}
@Test
fun
`Fill
template
and
expect
eTag
set
when
it
is
provided`
()
{
withTestApplication
{
application
.
setupMustache
()
application
.
install
(
ConditionalHeaders
)
application
.
routing
{
get
(
"/"
)
{
call
.
respond
(
MustacheContent
(
TemplateWithPlaceholder
,
DefaultModel
,
"e"
))
}
}
assertEquals
(
"e"
,
handleRequest
(
HttpMethod
.
Get
,
"/"
).
response
.
headers
[
HttpHeaders
.
ETag
])
}
}
@Test
fun
`Render
empty
model`
()
{
withTestApplication
{
application
.
setupMustache
()
application
.
install
(
ConditionalHeaders
)
application
.
routing
{
get
(
"/"
)
{
call
.
respond
(
MustacheContent
(
TemplateWithoutPlaceholder
,
null
,
"e"
))
}
}
handleRequest
(
HttpMethod
.
Get
,
"/"
).
response
.
let
{
response
->
val
lines
=
response
.
content
!!
.
lines
()
assertEquals
(
"<p>Hello, Anonymous</p>"
,
lines
[
0
])
assertEquals
(
"<h1>Hi!</h1>"
,
lines
[
1
])
}
}
}
@Test
fun
`Render
template
compressed
with
GZIP`
()
{
withTestApplication
{
application
.
setupMustache
()
application
.
install
(
Compression
)
application
.
install
(
ConditionalHeaders
)
application
.
routing
{
get
(
"/"
)
{
call
.
respondTemplate
(
TemplateWithPlaceholder
,
DefaultModel
,
"e"
)
}
}
handleRequest
(
HttpMethod
.
Get
,
"/"
)
{
addHeader
(
HttpHeaders
.
AcceptEncoding
,
"gzip"
)
}.
response
.
let
{
response
->
val
content
=
GZIPInputStream
(
response
.
byteContent
!!
.
inputStream
()).
reader
().
readText
()
val
lines
=
content
.
lines
()
assertEquals
(
"<p>Hello, 1</p>"
,
lines
[
0
])
assertEquals
(
"<h1>Hello World!</h1>"
,
lines
[
1
])
}
}
}
@Test
fun
`Render
template
without
eTag`
()
{
withTestApplication
{
application
.
setupMustache
()
application
.
install
(
ConditionalHeaders
)
application
.
routing
{
get
(
"/"
)
{
call
.
respond
(
MustacheContent
(
TemplateWithPlaceholder
,
DefaultModel
))
}
}
assertEquals
(
null
,
handleRequest
(
HttpMethod
.
Get
,
"/"
).
response
.
headers
[
HttpHeaders
.
ETag
])
}
}
private
fun
Application
.
setupMustache
()
{
install
(
Mustache
)
{
DefaultMustacheFactory
()
}
}
companion
object
{
private
val
DefaultModel
=
mapOf
(
"id"
to
1
,
"title"
to
"Hello World!"
)
private
val
TemplateWithPlaceholder
=
"withPlaceholder.mustache"
private
val
TemplateWithoutPlaceholder
=
"withoutPlaceholder.mustache"
}
}
settings.gradle
Просмотр файла @
82381e87
...
...
@@ -59,6 +59,7 @@ includeEx ':ktor-client:ktor-client-features:ktor-client-logging:ktor-client-log
includeEx
':ktor-client:ktor-client-features:ktor-client-logging:ktor-client-logging-js'
includeEx
':ktor-client:ktor-client-features:ktor-client-logging:ktor-client-logging-ios'
includeEx
':ktor-features:ktor-freemarker'
includeEx
':ktor-features:ktor-mustache'
includeEx
':ktor-features:ktor-velocity'
includeEx
':ktor-features:ktor-gson'
includeEx
':ktor-features:ktor-jackson'
...
...
Редактирование
Предварительный просмотр
Поддерживает Markdown
0%
Попробовать снова
или
прикрепить новый файл
.
Отмена
You are about to add
0
people
to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Отмена
Пожалуйста,
зарегистрируйтесь
или
войдите
чтобы прокомментировать