26. class Chainer(…) {
infix fun joinedWith(option: Joiner) =
initials.reduce { previous, letter !"
val next = when (option) {
is noPunctuaction !" letter
is dots !" "$letter."
}
"$previous$next"
}
27. class Chainer(…) {
infix fun joinedWith(option: Joiner) =
initials.reduce { previous, letter !"
val next = when (option) {
is noPunctuaction !" letter
is dots !" "$letter."
}
"$previous$next"
}
28. class Chainer(…) {
infix fun joinedWith(option: Joiner) =
initials.reduce { previous, letter !"
val next = when (option) {
is noPunctuaction !" letter
is dots !" "$letter."
}
"$previous$next"
}
29. class Chainer(…) {
infix fun joinedWith(option: Joiner) =
initials.reduce { previous, letter !"
val next = when (option) {
is noPunctuaction !" letter
is dots !" "$letter."
}
"$previous$next"
}
30. val dsl = acronymn from
"Domain" and
"Specific" and
"Language" joinedWith
noPunctuaction //DSL
31. val dsl = acronymn from
"Domain" and
"Specific" and
"Language" joinedWith
dots //D.S.L
34. val items = mutableListOf(1, 2, 3)
items += 4
/#$
* Adds the specified [element] to this mutable collection.
%&
@kotlin.internal.InlineOnly
public inline operator fun <T> MutableCollection<in T>.plusAssign(element: T) {
this.add(element)
}
35. typealias IntPair = Pair<Int, Int>
val calendar by lazy {
Calendar.getInstance()
}
36. operator fun Date.plus(args: IntPair): Date {
calendar.time = this
calendar.add(args.first, args.second)
return calendar.time
}
operator fun Date.minus(args: IntPair): Date {
calendar.time = this
calendar.add(args.first, -args.second)
return calendar.time
}
37. operator fun Date.plus(args: IntPair): Date {
calendar.time = this
calendar.add(args.first, args.second)
return calendar.time
}
operator fun Date.minus(args: IntPair): Date {
calendar.time = this
calendar.add(args.first, -args.second)
return calendar.time
}
38. fun Int.days() =
Calendar.DAY_OF_YEAR to this
fun Int.months() =
Calendar.MONTH to this
val atPast = Date() - 2.months()
val atFuture = Date() + 15.days()
39. val past = Date() - 2.months
val future = Date() + 15.days
👌
val Int.days: IntPair
get() = Calendar.DAY_OF_YEAR to this
val Int.months: IntPair
get() = Calendar.MONTH to this
41. val toSpan = SpannableStringBuilder()
val start = toSpan.length
toSpan.append("First Part")
toSpan.setSpan(
UnderlineSpan(),
start,
toSpan.length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
toSpan.setSpan(
StyleSpan(android.graphics.Typeface.BOLD),
start,
toSpan.length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
toSpan.append("not bold or underlined")
42. operator fun SpannableString.plus(s: String) =
SpannableString(TextUtils.concat(this, s))
operator fun SpannableString.plus(s: SpannableString) =
SpannableString(TextUtils.concat(this, s))
43. fun span(given: CharSequence, span: Any): SpannableString {
val spannable =
if (given is String) SpannableString(given)
else given as? SpannableString ?: throw CannotBeSpanned
return spannable.apply {
setSpan(span, 0, length, SPAN_EXCLUSIVE_EXCLUSIVE)
}
}
object CannotBeSpanned : IllegalArgumentException(
"Cannot apply span. Should be String or SpannableString"
)
44. // Add more hooks to same span() function
fun italic(given: CharSequence) =
span(given, StyleSpan(Typeface.ITALIC))
fun underline(given: CharSequence) =
span(given, UnderlineSpan())
fun bold(given: CharSequence) =
span(given, StyleSpan(Typeface.BOLD))
47. fun x(lambda: () !" Unit) { lambda() }
fun y(lambda: () !" Int) = lambda()
val x: () !" Int = { TODO() }
val result = x()
48. val add = fun(a: Int, b: Int) = a + b
fun calculate(func: (Int, Int) !" Int) {
func.invoke(2,2)
}
// Trailling Notation
calculate { a, b !" a + b }
// Normal notation
calculate(add)
49. class Receiver(val data: Int)
// Kotlin allows us to add an extension function
// literal to a type. Such lambda acquires the
// properties of non-static method in the context
val addOne: Receiver.() !" Int = {
data + 1
}
val two = addOne(Receiver(1))
val twoAgain = Receiver(1).addOne()
50. fun receive(block: Receiver.() !" Unit) {
val r = Receiver(data = 1)
block(r)
// r.block() is exactly the same
}
receive {
println(data) // 1
}
65. class FilmFiels {
private val picked = mutableListOf<String>()
fun fields() = TODO()
val title: String
get() {
picked.add(TITLE)
return TITLE
}
}
66. class FilmFields {
val title: String
get() { … }
val director: String
get() { … }
private companion object {
const val TITLE = "title"
const val DIRECTOR = "director"
}
}
67. class FilmFields {
fun fields() =
picked.distinct().joinToString(separator = " ")
val title: String
get() { … }
val director: String
get() { … }
private companion object { … }
}
68. class FilmFields {
fun fields() =
picked.distinct().joinToString(separator = " ")
val title: String
get() { … }
val director: String
get() { … }
private companion object { … }
}
69. val starWars = query {
allFilms {
film {
title
director
}
}
}
println(starWars)
70.
71. // Plain old mockWebServer
val server = MockWebServer()
val response = MockResponse().apply {
setResponseCode(503)
setBody("Ops!")
}
server.enqueue(response)
server.start()
72. class MockResponseBuilder(
'( Aliases
var code: Int = 0,
var response: String? = null) {
fun mockResponse() = MockResponse().apply {
setResponseCode(code)
setBody(response)
}
}
73. class QueueBuilder {
val mocks = mutableListOf<MockResponse>()
fun enqueueMock(setup: MockResponseBuilder.() !" Unit) {
val builder = MockResponseBuilder()
builder.setup()
mocks.add(builder.mockResponse())
}
}
74. typealias BuildMock = MockResponseBuilder.() !" Unit
class QueueBuilder {
val mocks = mutableListOf<MockResponse>()
fun enqueueMock(setup: BuildMock) =
MockResponseBuilder().run {
setup()
mocks.add(mockResponse())
}
}
75. typealias BuildMock = MockResponseBuilder.() !" Unit
class QueueBuilder {
val mocks = mutableListOf<MockResponse>()
fun enqueueMock(setup: BuildMock) =
MockResponseBuilder().run {
setup()
mocks.add(mockResponse())
}
}
76. typealias BuildQueue = QueueBuilder.() !" Unit
fun newServer(setup: BuildQueue): MockWebServer =
with(MockWebServer()) {
'( ????
return this
}
77. typealias BuildQueue = QueueBuilder.() !" Unit
fun newServer(setup: BuildQueue): MockWebServer =
with(MockWebServer()) {
QueueBuilder().run {
setup()
mocks.forEach { enqueue(it) }
}
return this
}
78. typealias BuildQueue = QueueBuilder.() !" Unit
fun newServer(setup: BuildQueue): MockWebServer =
with(MockWebServer()) {
QueueBuilder().run {
setup()
mocks.forEach { enqueue(it) }
}
return this
}
79. // DSL based
val server = newServer {
enqueueMock {
code = 200
response = "OK"
}
}
server.start()
// Plain old mockWebServer
val server = MockWebServer()
val response = MockResponse().apply {
setResponseCode(503)
setBody("Ops!")
}
server.enqueue(response)
server.start()
82. CONCLUSIONS
• DSLs are fun (with no pun)
• DSL-building offer great insights over Kotlin features!
• DSLs should work to improve an existing domain, not replace it
• Design your own DSLs for fun and profit !