Не могу понять как реализовать функцию attributes {"one" to "two"}
open class Tag(val name: String, val value: String)
{
var children: MutableList<Tag> = mutableListOf()
fun add(tag: Tag) = children.add(tag)
override fun toString(): String = "<${name}>${value}${children.joinToString (separator = " ")}</${name}>"
}
class TABLE(value: String) : Tag("TABLE", value)
class TR(value: String) : Tag("TR", value)
class TD(value: String) : Tag("TD", value)
open class TagBuilder {
var value: String = ""
var tags: MutableList<Tag> = mutableListOf()
operator fun String.unaryPlus()
{
value = this
}
}
class TDBuilder : TagBuilder()
{
fun build() : TD = TD(value).apply {
tags.forEach{ add (it) }
}
}
class TRBuilder : TagBuilder()
{
fun td(block: TDBuilder.() -> Unit)
{
val t = TDBuilder().apply(block).build()
tags.add(t)
}
fun build() : TR = TR(value).apply {
tags.forEach{ add (it) }
}
}
class TableBuilder : TagBuilder() {
fun tr(block: TRBuilder.() -> Unit)
{
val t = TRBuilder().apply(block).build()
tags.add(t)
}
fun build() : TABLE = TABLE(value).apply {
tags.forEach{ add (it) }
}
}
fun table(block: TableBuilder.() -> Unit) : TABLE = TableBuilder().apply(block).build()
fun main()
{
val html = table {
tr {
attributes {
"one" to "two"
"name" to "anders"
}
td {
+"1"
}
}
}
println(html)
}
Вывод должен быть таким
<table><tr one='two' name='anders'><td>1</td></tr></table>
Пытался разными способами и через отдельный класс и через список, но кажется чего то не понимаю.
Ответы (1 шт):
Автор решения: insolor
→ Ссылка
Вкратце:
- Нужна функция
attributesдля билдера тэга (чтобы можно было вызывать ее внутри блоков тегов) - Нужен новый класс-контекст (билдер) для этой функции (чтобы внутри него можно было вызвать будущую функцию
to) - В этом контексте нужно переопределить инфиксную функцию
to, чтобы она добавляла свои аргументы в контекст - При вызове
buildбилдера атрибутов собирать их в одну строку в виде"tag='value1' tag2='value2'". - Ну и вызывать
buildиз функцииattributesиз первого пункта. - Сами атрибуты в виде строки нужно передать в конструктор тэга и его потомков, и потом в его методе
toStringотобразить после имени.
Примерная реализация, все более-менее по аналогии с тем что у вас уже есть:
open class Tag(val name: String, val attributes: String, val value: String)
{
var children: MutableList<Tag> = mutableListOf()
fun add(tag: Tag) = children.add(tag)
override fun toString(): String = "<${name}${attributes}>${value}${children.joinToString (separator = " ")}</${name}>"
}
class TABLE(attributes: String, value: String) : Tag("TABLE", attributes, value)
class TR(attributes: String, value: String) : Tag("TR", attributes, value)
class TD(attributes: String, value: String) : Tag("TD", attributes, value)
open class TagBuilder {
var value: String = ""
var attributes: String = ""
var tags: MutableList<Tag> = mutableListOf()
operator fun String.unaryPlus()
{
value = this
}
fun attributes(block: AttributesBuilder.() -> Unit) {
attributes = AttributesBuilder().apply(block).build()
}
}
class AttributesBuilder {
private val attributes: MutableList<Pair<String, String>> = mutableListOf()
infix fun String.to(that: String): Pair<String, String> {
val pair = Pair(this, that)
attributes.add(pair)
return pair
}
fun build(): String = attributes.joinToString(separator = "") {
" ${it.first}='${it.second}'"
}
}
class TDBuilder : TagBuilder()
{
fun build() : TD = TD(attributes, value).apply {
tags.forEach{ add (it) }
}
}
class TRBuilder : TagBuilder()
{
fun td(block: TDBuilder.() -> Unit)
{
val t = TDBuilder().apply(block).build()
tags.add(t)
}
fun build() : TR = TR(attributes, value).apply {
tags.forEach{ add (it) }
}
}
class TableBuilder : TagBuilder() {
fun tr(block: TRBuilder.() -> Unit)
{
val t = TRBuilder().apply(block).build()
tags.add(t)
}
fun build() : TABLE = TABLE(attributes, value).apply {
tags.forEach{ add (it) }
}
}
fun table(block: TableBuilder.() -> Unit) : TABLE = TableBuilder().apply(block).build()
fun main()
{
val html = table {
tr {
attributes {
"one" to "two"
"name" to "anders"
}
td {
+"1"
}
}
}
println(html)
}
Вывод:
<TABLE><TR one='two' name='anders'><TD>1</TD></TR></TABLE>