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

Kotlin DSLs

Kotlin DSLs

Talk held at Android Makers, Paris (https://androidmakers.fr/)

Wolfram Rittmeyer

April 24, 2018
Tweet

More Decks by Wolfram Rittmeyer

Other Decks in Technology

Transcript

  1. 4 DSLs • External DSLs – Use any language to

    implement it • Internal DSLs – Uses host language – Uses normal language constructs – Can use language constructs within DSL
  2. 6 kotlintest should("verify names in map") { //... name should

    (startWith("test") or endWith("Name")) name shouldBe "testName" ageMap should contain("testName") }
  3. 7 Koin val appModule = applicationContext { val db =

    SomeDatabase.getInstance(applicationContext) bean { db.entryDao } bean { SomeApi.create(BuildConfig.DEBUG) } bean("MainScheduler") { AndroidSchedulers.mainThread() as Scheduler } factory { AndroidNotifBuilder(applicationContext) as NotificationBuilder } }
  4. 8 Anko constraintLayout { val title = textView { id

    = R.id.txtTitle textAppearance = R.style.TextAppearance_AppCompat_Large textColor = R.color.titleText } applyConstraintSet { title { connect( TOP to TOP of PARENT_ID margin dip(16), START to START of PARENT_ID margin dip(16) ) } } }
  5. 10 mockK view = mockk<CarDiscoveryView>(relaxed = true) // ... every

    { view.setRemoteVehicles(vehicles = capture(params)) } just runs
  6. 13 mockK /** * Part of DSL. Answer placeholder for

    Unit returning functions. */ infix fun MockKStubScope<Unit>.just(runs: Runs) = answers(ConstantAnswer(Unit))
  7. 18 mockK view = mockk<CarDiscoveryView>(relaxed = true) // ... every

    { view.setRemoteVehicles(vehicles = capture(params)) } just runs
  8. 21 mockK /** * Part of DSL. Object to represent

    phrase "just Runs" */ object Runs typealias runs = Runs
  9. 25 kotlintest fun should(name: String, test: () -> Unit): TestCase

    { val testCase = TestCase( suite = current, name = "should $name", test = test, config = defaultTestCaseConfig) current.addTestCase(testCase) return testCase }
  10. 29 Concepts covered so far • Infix calls • Empty

    object • Type aliases • Trailing lambdas
  11. 33 kotlintest operator fun String.invoke(test: () -> Unit): TestCase {

    val tc = TestCase(suite = rootTestSuite, name = this, test = test, config = defaultTestCaseConfig) rootTestSuite.addTestCase(tc) return tc }
  12. 35 Concepts covered so far • Infix calls • Empty

    object • Type aliases • Trailing lambdas • Extension functions • Conventions
  13. 36 kotlinx.html val html = buildString { appendHTML().html { body

    { div { +"Some text inside the div" } } } }
  14. 38 kotlinx.html @kotlinx.html.HtmlTagMarker public interface Tag { // ... public

    open operator fun kotlin.String.unaryPlus(): kotlin.Unit { /* ... */ } // ... }
  15. 40 Concepts covered so far • Infix calls • Empty

    object • Type aliases • Trailing lambdas • Conventions • Extension functions • Operator overloading
  16. 41 Koin val appModule = applicationContext { val db =

    SomeDatabase.getInstance(applicationContext) bean { db.entryDao } bean { SomeApi.create(BuildConfig.DEBUG) } bean("MainScheduler") { AndroidSchedulers.mainThread() as Scheduler } factory { AndroidNotifBuilder(applicationContext) as NotificationBuilder } }
  17. 43 Koin fun applicationContext(init: Context.() -> Unit): Module = {

    Context(Scope.ROOT, StandAloneContext.koinContext as KoinContext).apply(init) }
  18. 45 Koin fun applicationContext(init: Context.() -> Unit): Module = {

    Context(Scope.ROOT, StandAloneContext.koinContext as KoinContext).apply(init) }
  19. 46 Koin fun applicationContext(init: Context.() -> Unit): Module = {

    val ctx = Context(Scope.ROOT, StandAloneContext.koinContext as KoinContext) ctx.init() }
  20. 50 Lambda vs. Lambda with receivers // slightly simplified public

    inline fun <T> T.also(block: (T) -> Unit): T { block(this) return this } // slightly simplified public inline fun <T> T.apply(block: T.() -> Unit): T { block() return this }
  21. 53 Lambda with receivers in DSLs fun applicationContext(init: Context.() ->

    Unit): Module = { val ctx = Context(Scope.ROOT, StandAloneContext.koinContext as KoinContext) ctx.init() }
  22. 54 Concepts covered so far • Infix calls • Empty

    object • Type aliases • Trailing lambdas • Conventions • Extension functions • Operator overloading • Lambda with Receivers
  23. 55 Anko constraintLayout { val title = textView { id

    = R.id.txtTitle textAppearance = R.style.TextAppearance_AppCompat_Large textColor = R.color.titleText } applyConstraintSet { title { connect( TOP to TOP of PARENT_ID margin dip(16), START to START of PARENT_ID margin dip(16) ) } } }
  24. 60 Concepts • Infix calls • Empty object • Type

    aliases • Trailing lambdas • Conventions • Extension functions • Operator overloading • Lambda with Receivers • Scope limiting
  25. 62 Concepts covered so far • Infix calls • Empty

    object • Type aliases • Trailing lambdas • Conventions • Extension functions • Operator overloading • Lambda with Receivers • Scope limiting
  26. 63 Designing DSLs • Consider deviating from naming conventions •

    As per usual: Don’t go overboard • An interesting discussion of approaches: https:/ /github.com/zsmb13/VillageDSL
  27. 65 General libs • DI / Service Locating: – Koin

    – Kodein • Testing – MockK – Spek – kotlintest
  28. 67 Libs • Spring Router Config • Spring Bean Config

    • Gradle Kotlin DSL • kotlinx.HTML • Exposed