Upgrade to Pro — share decks privately, control downloads, hide ads and more …

GeekOut_2019_-_Building_DSLs_in_Kotlin.pdf

 GeekOut_2019_-_Building_DSLs_in_Kotlin.pdf

As Kotlin programming language is getting more popular, the creators of the libraries are starting to provide Kotlin API for their frameworks. The number of libraries that provide a nice little DSL grows constantly. The session introduces you to some of those libraries and explains, how Kotlin makes creating the DSL so simple. Lambdas, extension methods, lambdas with the receiver, and other syntactic sugar make it easy to implement DSL in Kotlin. In a live coding demo, we will create a simple DSL for the existing Java classes that could be used from a Kotlin code.

Anton Arhipov

September 27, 2019
Tweet

More Decks by Anton Arhipov

Other Decks in Programming

Transcript

  1. createHTML().html { head { +"Hello!" } body { ul {

    p { +"This is my awesome text!" } } } } kotlinx.html https://github.com/Kotlin/kotlinx.html
  2. Anko https://github.com/Kotlin/anko verticalLayout { padding = dip(30) val name =

    editText { hint = "Name" textSize = 24f } val pwd = editText { hint = "Password" textSize = 24f } button("Login") { textSize = 26f onClick { toast("Hello, ${name.text}!") } }
  3. Gradle Kotlin DSL https://github.com/gradle/kotlin-dsl plugins { java kotlin("jvm") version "1.2.70"

    } group = "org.arhan" version = "1.0-SNAPSHOT" repositories { maven { setUrl("http://dl.bintray.com/kotlin/kotlin-eap") } jcenter() } dependencies { val kotlinx_html_version = "0.6.11" compile(kotlin("stdlib-jdk8")) compile("org.jetbrains.kotlinx:kotlinx-html-jvm:${kotlinx_html_version}") testCompile("junit", "junit", "4.12")
  4. Exposed https://github.com/JetBrains/Exposed object Cities : Table() { val id =

    integer("id").autoIncrement().primaryKey() // Column<Int> val name = varchar("name", 50) // Column<String> } transaction { create (Cities) val tallinnId = Cities.insert { it[name] = "Tallinn" } get Cities.id for (city in Cities.selectAll()) { println("${city[Cities.id]}: ${city[Cities.name]}") } }
  5. https://github.com/nfrankel/kaadin Kaadin theme = "valo" verticalLayout(margin = true, spacing =

    true) { tabSheet { tab("Interactions") { accordion { tab("Button", HAND_O_RIGHT) { horizontalLayout(true, true) { button() button("Label") button("Label", HAND_O_RIGHT) button("Click me", onClick = { show("Clicked") }) button("Click me", HAND_O_RIGHT, { show("Clicked") }) } }
  6. Kotlin DSL in TeamCity project { vcsRoot(ApplicationVcs) buildType { id("Application")

    name = "Application" vcs { root(ApplicationVcs) } artifactRules = "target/*jar" steps { maven { goals = "clean package" } } triggers { vcs {} } dependencies { snapshot(Library) {}
  7. fun main(args: Array<String>) { embeddedServer(Jetty, commandLineEnvironment(args)).start(wait = true) } fun

    Application.main() { install(DefaultHeaders) install(CallLogging) routing { get("/") { call.respondHtml { head { title { +"Ktor App" } } body { p { +"Hello from Ktor!" } } Ktor
  8. fun main(args: Array<String>) { embeddedServer(Jetty, commandLineEnvironment(args)).start(wait = true) } fun

    Application.main() { install(DefaultHeaders) install(CallLogging) routing { get("/") { call.respondHtml { head { title { +"Ktor App" } } body { p { +"Hello from Ktor!" } } Ktor
  9. fun main(args: Array<String>) { embeddedServer(Jetty, commandLineEnvironment(args)).start(wait = true) } fun

    Application.main() { install(DefaultHeaders) install(CallLogging) routing { get("/") { call.respondHtml { head { title { +"Ktor App" } } body { p { +"Hello from Ktor!" } } Ktor
  10. foo { bar { baz = "Hello!" qux = quux

    { corge = "Blah" } } }
  11. foo { bar { baz = "Hello!" qux = quux

    { corge = "Blah" } } }
  12. foo { bar { baz = "Hello!" qux = quux

    { corge = "Blah" } } }
  13. foo { bar { baz = "Hello!" qux = quux

    { corge = "Blah" } } }
  14. foo { bar(grault = 1) { baz = "Hello!" qux

    = quux { corge = "Blah" } } }
  15. foo { bar(grault = 1) { baz = "Hello!" qux

    = quux { corge = Blah() } } }
  16. foo { bar(grault = 1) { baz = "Hello!" qux

    = quux { corge = Blah() } } }
  17. foo { bar(grault = 1) { baz = "Hello!" qux

    = quux { corge = Blah() } } }
  18. final ClientBuilder builder = new ClientBuilder(); builder.setFirstName("Anton"); builder.setLastName("Arhipov"); final TwitterBuilder

    twitterBuilder = new TwitterBuilder(); twitterBuilder.setHandle("@antonarhipov"); builder.setTwitter(twitterBuilder.build()); final CompanyBuilder companyBuilder = new CompanyBuilder(); companyBuilder.setName("JetBrains"); companyBuilder.setCity("Tallinn"); builder.setCompany(companyBuilder.build()); final Client client = builder.build(); System.out.println("Created client is: " + client); val client = createClient { firstName = "Anton" lastName = "Arhipov" twitter { handle = "@antonarhipov" } company { name = "JetBrains" city = "Tallinn" } } println("Created client is: " + client.consoleString)
  19. //extension property val Client.consoleString: String get() = "${twitter.handle} ${company.name}" //extension

    method fun Client.toConsoleString(): String { return "${twitter.handle} ${company.name}" }
  20. fun createClient(c: ClientBuilder.() -> Unit): Client { val builder =

    ClientBuilder() c(builder) return builder.build() } fun ClientBuilder.company(t: CompanyBuilder.() -> Unit) { company = CompanyBuilder().apply(t).build() } fun ClientBuilder.twitter(t: CompanyBuilder.() -> Unit) { twitter = TwitterBuilder().apply(t).build() } Lambda with receiver Extension methods
  21. twitter { handle = "@antonarhipov" company { name = "JetBrains"

    city = "Tallinn" } } @DslMarker annotation class ClientDsl @ClientDsl class CompanyBuilderDsl : CompanyBuilder() @ClientDsl class TwitterBuilderDsl : TwitterBuilder() twitter { handle = "@antonarhipov" company { name = "JetBrains" city = "Tallinn" } } Scope control
  22. dateTime = LocalDateTime.of(2018, Month.DECEMBER, 11, 0, 0) dateTime = 11

    December 2018 at (14 hh 0) infix fun Int.December(n: Int) : LocalDate { return LocalDate.of(n, Month.DECEMBER, this) } infix fun LocalDate.at(n: Pair<Int, Int>): LocalDateTime { return this.atTime(n.first, n.second) } infix fun Int.hh(n: Int): Pair<Int, Int> { return Pair(this, n) }
  23. me { name = "Anton Arhipov" twitter = "@antonarhipov" }

    books { courses { Kotlin { Try = "try.kotlinlang.org" Slack = "slack.kotl.in" }