SlideShare a Scribd company logo
Kotlin DSL
2018 10/12
Kamedon
•
• Kotlin
•
•
• DSL
•
• DSL Kotlin
DSL
DSL
• domain-specific language/ )
• DSL
(wikipedia )
• 

• DSL 

Builder
//Java
Human human= new Human.Builder()
.setName("Kamedon")
.setAge(30)
.build();
//Kotlin
class Human(val name: String, val age: Int)
Human(age = 30, name = "Kamedon")
if(human.isAdult()){
//成人だったらなにかする
}
Build DSL
buildscript {
ext.kotlin_version = '1.2.70'
repositories {
google()
jcenter()
maven {
url 'http://kamedon.github.com/Validation/repository'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.4'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:
$kotlin_version"
}
}
•
Layout Anko)
verticalLayout {
val name = editText()
button("Say Hello") {
onClick { toast("Hello, ${name.text}!") }
}
}
•
• LinearLayout
DI DSL(Kodein)
Kodein {
bind<Presenter>() with singleton {
Presenter(instance(), inetance())
}
}
val presenter: Presenter by instance()
•
•
DSL
•
•
• IDE
• Sansan Kotlin DSL
DSL
•
•
• Kotlin 

Java DSL
• DSL Kotlin
DSL
• Validation DSL
• DSL
• Validation 

https://github.com/kamedon/Validation
Step1.
• 

• 

[ ]

5 10 

[ ]

20
つくってあそぼ Kotlin DSL 第2版
•
•
•
•
Step2. DSL
DSL (1)
•
• 5
•
• A be B
DSL (2)
•
• 5 

• A be B 

not
• A be B not Message
DSL
be not
be not
be not
be not
be not
DSL
be not
be not
be not
be not
be not
Validation<User> {
"name"{
be { name.isNotBlank() } not "入力してください"
be { name.length >= 5 } not "5文字以上入力"
be { name.length <= 10 } not "10文字以下で入力"
}
"age"{
be { age >= 0 } not "入力してください"
be { age >= 20 } not "20歳以上で入力"
}
}
•
Step3.
be
be not
be not
•
• Pair Triple 

Build
• 

DSL
• DSL
data class User(val name: String, val age: Int)
class ValidationTest {
@Test
fun dslTest() {
Validation<User> {}
}
}
Validation<User> {}
• operator invoke companion object 

• companion object Java static
•
•
operator invoke
• Kotlin +,-, a..b , a in b, 

• invoke
class K {
operator fun invoke(value: Int) = value * 1000
}
val k = K()
k.invoke(1)
k(1) // invokeは省略可能
fun Int.k() = this * 1000
val kg = 1.k() //1000
public static final int k(int $receiver) {
return $receiver * 1000;
}
}
•
• static
• 

+ operator invoke
• operator invoke
operator fun String.invoke(){}
"name"()

operator fun String.invoke(f: ()->Unit){}
"name"({})
"name"{}
• Lambda)
• Syntax Suger
val kg: (Int) -> Int = fun(value: Int): Int {
return value * 1000
}
val kg = { value: Int -> value * 1000 }
kg.invoke(1) //invokeメソッドが作られる
kg(1) //invokeは省略可能
class Sample {
fun task(f: (String) -> Unit) {
//taskする
f("Hello")
}
fun task2(f: String.() -> Unit) {
//taskする
"Hello".f()
}
}
class Test {
fun task() {
val sample = Sample()
sample.task {
print(this::class.java.name)
print(it.length)
}
sample.task2 {
print(this::class.java.name)
print(length)
}
}
}


// f: String.() -> Unit)
public static final String f(@NotNull String $receiver)
// f: (String) -> Unit)
public static final String f($receiver: Test, @NotNull String it)
•
• {} this
Validation{}
class Validation<T> {
companion object {
operator fun <T>
invoke(init: Validation<T>.() -> Unit): Validation<T> {
return Validation<T>().apply(init)
}
}
}
public inline fun <T> T.apply(block: T.() -> Unit): T {
block()
return this
}
@Test
fun dslTest() {
Validation<User> {
"name"{}
}
}
•
• {}
• +
{}
class Validation<T> {
operator fun String.invoke(init: () -> Unit)
}
• Validation 

Validation
•
{}
•
• ChildValidation
• {} ChildValidation
• ChildValidation
• ChildValidation Validation
be not
be not
be not
be not
{}
class Validation<T> {
val validations = mutableMapOf<String, ChildValidation<T>>()
operator fun String.invoke(
init: ChildValidation<T>.() -> Unit
) {
validations.put(this, ChildValidation<T>().apply(init))
}
}
•
• String.invoke ChildValidation
• ChildValidation Validations 

be {}
@Test
fun dslTest() {
Validation<User> {
"name"{
be { name.isNotBlank() }
}
}
}
•
be
• name
"name"{
be { name.isNotBlank() }
this.be { name.isNotBlank() }
this.be({ name.isNotBlank() })
this.be({ this.name.isNotBlank() })
}
• 

ßbe
class Validation<T> {
operator fun String.invoke(init: ChildValidation<T>.() -> Unit)
}
class ChildValidation<T> {
fun be(f: T.() -> Boolean) {}
}
•
• String{} ChildValidation
• be ChildValidation
• User(T)
• T boolean
(infix)
infix fun Int.k(str: String): String {
return "${this * 1000}$str"
}
val kg = 1.k("g") //1000g
val kg = 1 k "g" //1000g
•
• 1 infix
•
be {} not message
@Test
fun dslTest() {
Validation<User> {
"name"{
be { name.isNotBlank() } not "入力してください"
}
}
}
•
be not
not
val validation = be { name.isNotBlank() } not "入力してください"
if(!validation(user)) {
return errorMessage
}
• 

1
• {} not
• be {} /
class ChildValidation<T> {
fun be(f: T.() -> Boolean) = f
infix fun (T.() -> Boolean).not(message: String)
}
•
• be
• not
DSL
Validation<User> {
"name"{
be { name.isNotBlank() } not "入力してください"
be { name.length >= 5 } not "5文字以上入力"
be { name.length <= 10 } not "10文字以下で入力"
}
"age"{
be { age >= 0 } not "入力してください"
be { age >= 20 } not "20歳以上で入力"
}
}
•
class Validation<T>
(val validations: Map<String, ChildValidation<T>>)
class ChildValidation<T> {
val validations: MutableList<Pair<T.() -> Boolean, String>>
= mutableListOf()
}
• ChildValidation Validation
• <Pair<T.() -> Boolean, String> ChildValidation
ChildValidation
"name"{
be { name.isNotBlank() } not "入力してください"
be { name.length >= 0 } not "5文字以上で入力"
}
class ChildValidation<T> {
val validations =
mutableListOf<Pair<T.() -> Boolean, String>>()
infix fun be(f: T.() -> Boolean) = f
infix fun (T.() -> Boolean).not(message: String) {
validations.add(Pair(this, message))
}
}
Validation
ChildValidation
Validation<User> {
"name"{
be { name.isNotBlank() } not "入力してください"
}
}
class Validation<T> {
val validations = mutableMapOf<String, ChildValidation<T>>()
operator fun String.invoke(init: ChildValidation<T>.() -> Unit) {
validations.put(this, ChildValidation<T>().apply(init))
}
}
•
DSL
Validation<User> {
"name"{
}
}
class Validation<T> {
val validations = mutableMapOf<String, ChildValidation<T>>()
operator fun String.invoke(init: ChildValidation<T>.() -> Unit) {
validations.put(this, ChildValidation<T>().apply(init))
}
companion object {
inline operator fun <T> invoke(
init: Validation<T>.() -> Unit): Validation<T> {
return Validation<T>().apply(init)
}
}
}
DSL
be { name.isNotBlank() } not "入力してください"
class ChildValidation<T> {
val validations = mutableListOf<Pair<T.() -> Boolean, String>>()
infix fun be(f: T.() -> Boolean) = f
infix fun (T.() -> Boolean).not(message: String) {
validations.add(Pair(this, message))
}
}
•
DSL
Validation<User> {
"name"{
be { name.isNotBlank() } not "入力してください"
be { name.length >= 5 } not "5文字以上入力"
be { name.length <= 10 } not "10文字以下で入力"
}
"age"{
be { age >= 0 } not "入力してください"
be { age >= 20 } not "20歳以上で入力"
}
}
•
validate
Validate
class Validation<T> {
val validations = mutableMapOf<String, ChildValidation<T>>()
fun validate(value: T): Map<String, List<String>> {
val messages = mutableMapOf<String, List<String>>()
validations.forEach { map ->
val errors = map.value.validations.asSequence()
.filter { !it.first.invoke(value) }
.map { it.second }
.filter { it.isNotEmpty() }
.toList()
if(errors.isNotEmpty()){
messages.put(map.key, errors)
}
}
return messages
}
}
DSL OK
val user = User("kamedon", 30)
val v = Validation<User> {
"name"{
be { name.isNotBlank() } not "入力してください"
be { name.length >= 5 } not "5文字以上入力"
be { name.length <= 10 } not "10文字以下で入力"
}
"age"{
be { age >= 0 } not "入力してください"
be { age >= 20 } not "20歳以上で入力"
}
}
v.validate(user)
•
DSL NG
val user = User("k", 10)
val v = Validation<User> {
"name"{
be { name.isNotBlank() } not "入力してください"
be { name.length >= 5 } not "5文字以上入力"
be { name.length <= 10 } not "10文字以下で入力"
}
"age"{
be { age >= 0 } not "入力してください"
be { age >= 20 } not "20歳以上で入力"
}
}
v.validate(user)
{name=[5文字以上入力], age=[20歳以上で入力]}
•
Step4.
• Pair
• Builder var build val
• mutable immutable
• DSL 

DSL Builder
class Validation<T> {
val validations = mutableMapOf<String, ChildValidation<T>>()
operator fun String.invoke(init: ChildValidation<T>.() -> Unit) {
validations.put(this, ChildValidation<T>().apply(init))
}
companion object {
inline operator fun <T> invoke(
init: Validation<T>.() -> Unit): Validation<T> {
return Validation<T>().apply(init)
}
}
fun validate(value: T): Map<String, List<String>>
}
DSL Builder
class ValidationBuilder<T> {
val validations = mutableMapOf<String, ChildValidation<T>>()
operator fun String.invoke(init: ChildValidation<T>.() -> Unit) {
validations.put(this, ChildValidation<T>().apply(init))
}
fun build(): Validation<T> {
return Validation(validations)
}
}
class Validation<T>(val validations: Map<String, ChildValidation<T>>) {
companion object {
inline operator fun <T> invoke(
init: ValidationBuilder<T>.() -> Unit): Validation<T> {
val builder = ValidationBuilder<T>().apply(init)
return builder.build()
}
}
}
Step5.
• object DSL
• inline GC
•
• interface
Validation<User> {
"name"{
be { name.length >= 5 } not "5文字以下"
be { name.length <= 10 } not "10文字以下"
}
"age"{
be { age >= 20 } not error message { "20歳以上" }
be { age <= 150 } not with callback ("150歳以下"){
print("callback")
}
}
}
•
11/2 

• Java
• DSL
• IDE DSL
• DSL
• var val : Builder
• {} : lambda lambda
• ()
• : operator invoke
• : (Extensions Functions or
Properties)
• : infix)
• DSL
•
• 

Validation GitHub 

11/2
つくってあそぼ Kotlin DSL 第2版

More Related Content

PDF
つくってあそぼ Kotlin DSL ~拡張編~
PDF
The Ring programming language version 1.5.1 book - Part 32 of 180
PDF
The Ring programming language version 1.9 book - Part 39 of 210
PDF
The Ring programming language version 1.6 book - Part 40 of 189
PDF
Pragmatic Real-World Scala (short version)
PDF
Nik Graf - Get started with Reason and ReasonReact
PPTX
TDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDB
PDF
Functional Programming with Groovy
つくってあそぼ Kotlin DSL ~拡張編~
The Ring programming language version 1.5.1 book - Part 32 of 180
The Ring programming language version 1.9 book - Part 39 of 210
The Ring programming language version 1.6 book - Part 40 of 189
Pragmatic Real-World Scala (short version)
Nik Graf - Get started with Reason and ReasonReact
TDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDB
Functional Programming with Groovy

What's hot (18)

PDF
JDD 2016 - Pawel Byszewski - Kotlin, why?
PPTX
TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de pro...
PDF
Pooya Khaloo Presentation on IWMC 2015
PDF
Error Management: Future vs ZIO
PDF
The Ring programming language version 1.5.2 book - Part 33 of 181
PDF
Software architecture2008 ejbql-quickref
ODP
Parsing with Perl6 Grammars
PDF
The Ring programming language version 1.5.4 book - Part 44 of 185
PPTX
Expression trees in c#, Алексей Голубь (Svitla Systems)
PDF
The Ring programming language version 1.9 book - Part 42 of 210
PDF
Scala in practice
PDF
BDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
PDF
Expression trees in c#
PDF
Beyond Breakpoints: Advanced Debugging with XCode
PDF
The Ring programming language version 1.10 book - Part 40 of 212
PDF
PDF
The Ring programming language version 1.10 book - Part 47 of 212
PPTX
Understanding Async/Await in Javascript
JDD 2016 - Pawel Byszewski - Kotlin, why?
TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de pro...
Pooya Khaloo Presentation on IWMC 2015
Error Management: Future vs ZIO
The Ring programming language version 1.5.2 book - Part 33 of 181
Software architecture2008 ejbql-quickref
Parsing with Perl6 Grammars
The Ring programming language version 1.5.4 book - Part 44 of 185
Expression trees in c#, Алексей Голубь (Svitla Systems)
The Ring programming language version 1.9 book - Part 42 of 210
Scala in practice
BDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
Expression trees in c#
Beyond Breakpoints: Advanced Debugging with XCode
The Ring programming language version 1.10 book - Part 40 of 212
The Ring programming language version 1.10 book - Part 47 of 212
Understanding Async/Await in Javascript
Ad

Recently uploaded (20)

PDF
NewMind AI Weekly Chronicles - August'25-Week II
PDF
gpt5_lecture_notes_comprehensive_20250812015547.pdf
PDF
Machine learning based COVID-19 study performance prediction
PDF
Electronic commerce courselecture one. Pdf
PDF
Empathic Computing: Creating Shared Understanding
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
Encapsulation theory and applications.pdf
PPTX
SOPHOS-XG Firewall Administrator PPT.pptx
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PPTX
Big Data Technologies - Introduction.pptx
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
Approach and Philosophy of On baking technology
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PPTX
A Presentation on Artificial Intelligence
PDF
Spectral efficient network and resource selection model in 5G networks
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
NewMind AI Weekly Chronicles - August'25-Week II
gpt5_lecture_notes_comprehensive_20250812015547.pdf
Machine learning based COVID-19 study performance prediction
Electronic commerce courselecture one. Pdf
Empathic Computing: Creating Shared Understanding
Per capita expenditure prediction using model stacking based on satellite ima...
Encapsulation theory and applications.pdf
SOPHOS-XG Firewall Administrator PPT.pptx
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
Big Data Technologies - Introduction.pptx
Agricultural_Statistics_at_a_Glance_2022_0.pdf
“AI and Expert System Decision Support & Business Intelligence Systems”
Approach and Philosophy of On baking technology
Programs and apps: productivity, graphics, security and other tools
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
A Presentation on Artificial Intelligence
Spectral efficient network and resource selection model in 5G networks
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
Ad

つくってあそぼ Kotlin DSL 第2版

  • 4. DSL
  • 5. DSL • domain-specific language/ ) • DSL (wikipedia ) • 

  • 7. Builder //Java Human human= new Human.Builder() .setName("Kamedon") .setAge(30) .build(); //Kotlin class Human(val name: String, val age: Int) Human(age = 30, name = "Kamedon") if(human.isAdult()){ //成人だったらなにかする }
  • 8. Build DSL buildscript { ext.kotlin_version = '1.2.70' repositories { google() jcenter() maven { url 'http://kamedon.github.com/Validation/repository' } } dependencies { classpath 'com.android.tools.build:gradle:3.1.4' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin: $kotlin_version" } } •
  • 9. Layout Anko) verticalLayout { val name = editText() button("Say Hello") { onClick { toast("Hello, ${name.text}!") } } } • • LinearLayout
  • 10. DI DSL(Kodein) Kodein { bind<Presenter>() with singleton { Presenter(instance(), inetance()) } } val presenter: Presenter by instance() • •
  • 12. DSL • • • Kotlin 
 Java DSL • DSL Kotlin
  • 13. DSL
  • 14. • Validation DSL • DSL • Validation 
 https://github.com/kamedon/Validation
  • 16. • 
 • 
 [ ]
 5 10 
 [ ]
 20
  • 21. DSL (2) • • 5 
 • A be B 
 not • A be B not Message
  • 22. DSL be not be not be not be not be not
  • 23. DSL be not be not be not be not be not
  • 24. Validation<User> { "name"{ be { name.isNotBlank() } not "入力してください" be { name.length >= 5 } not "5文字以上入力" be { name.length <= 10 } not "10文字以下で入力" } "age"{ be { age >= 0 } not "入力してください" be { age >= 20 } not "20歳以上で入力" } } •
  • 27. • • Pair Triple 
 Build • 
 DSL • DSL
  • 28. data class User(val name: String, val age: Int) class ValidationTest { @Test fun dslTest() { Validation<User> {} } }
  • 29. Validation<User> {} • operator invoke companion object 
 • companion object Java static • •
  • 30. operator invoke • Kotlin +,-, a..b , a in b, 
 • invoke class K { operator fun invoke(value: Int) = value * 1000 } val k = K() k.invoke(1) k(1) // invokeは省略可能
  • 31. fun Int.k() = this * 1000 val kg = 1.k() //1000 public static final int k(int $receiver) { return $receiver * 1000; } } • • static • 

  • 32. + operator invoke • operator invoke operator fun String.invoke(){} "name"()
 operator fun String.invoke(f: ()->Unit){} "name"({}) "name"{}
  • 33. • Lambda) • Syntax Suger val kg: (Int) -> Int = fun(value: Int): Int { return value * 1000 } val kg = { value: Int -> value * 1000 } kg.invoke(1) //invokeメソッドが作られる kg(1) //invokeは省略可能
  • 34. class Sample { fun task(f: (String) -> Unit) { //taskする f("Hello") } fun task2(f: String.() -> Unit) { //taskする "Hello".f() } }
  • 35. class Test { fun task() { val sample = Sample() sample.task { print(this::class.java.name) print(it.length) } sample.task2 { print(this::class.java.name) print(length) } } }
  • 36. 
 // f: String.() -> Unit) public static final String f(@NotNull String $receiver) // f: (String) -> Unit) public static final String f($receiver: Test, @NotNull String it) • • {} this
  • 37. Validation{} class Validation<T> { companion object { operator fun <T> invoke(init: Validation<T>.() -> Unit): Validation<T> { return Validation<T>().apply(init) } } } public inline fun <T> T.apply(block: T.() -> Unit): T { block() return this }
  • 38. @Test fun dslTest() { Validation<User> { "name"{} } } • • {} • +
  • 39. {} class Validation<T> { operator fun String.invoke(init: () -> Unit) } • Validation 
 Validation •
  • 40. {} • • ChildValidation • {} ChildValidation • ChildValidation • ChildValidation Validation
  • 41. be not be not be not be not
  • 42. {} class Validation<T> { val validations = mutableMapOf<String, ChildValidation<T>>() operator fun String.invoke( init: ChildValidation<T>.() -> Unit ) { validations.put(this, ChildValidation<T>().apply(init)) } } • • String.invoke ChildValidation • ChildValidation Validations 

  • 43. be {} @Test fun dslTest() { Validation<User> { "name"{ be { name.isNotBlank() } } } } • be • name
  • 44. "name"{ be { name.isNotBlank() } this.be { name.isNotBlank() } this.be({ name.isNotBlank() }) this.be({ this.name.isNotBlank() }) } • 
 ßbe
  • 45. class Validation<T> { operator fun String.invoke(init: ChildValidation<T>.() -> Unit) } class ChildValidation<T> { fun be(f: T.() -> Boolean) {} } • • String{} ChildValidation • be ChildValidation • User(T) • T boolean
  • 46. (infix) infix fun Int.k(str: String): String { return "${this * 1000}$str" } val kg = 1.k("g") //1000g val kg = 1 k "g" //1000g • • 1 infix •
  • 47. be {} not message @Test fun dslTest() { Validation<User> { "name"{ be { name.isNotBlank() } not "入力してください" } } } • be not not
  • 48. val validation = be { name.isNotBlank() } not "入力してください" if(!validation(user)) { return errorMessage } • 
 1 • {} not • be {} /
  • 49. class ChildValidation<T> { fun be(f: T.() -> Boolean) = f infix fun (T.() -> Boolean).not(message: String) } • • be • not DSL
  • 50. Validation<User> { "name"{ be { name.isNotBlank() } not "入力してください" be { name.length >= 5 } not "5文字以上入力" be { name.length <= 10 } not "10文字以下で入力" } "age"{ be { age >= 0 } not "入力してください" be { age >= 20 } not "20歳以上で入力" } } •
  • 51. class Validation<T> (val validations: Map<String, ChildValidation<T>>) class ChildValidation<T> { val validations: MutableList<Pair<T.() -> Boolean, String>> = mutableListOf() } • ChildValidation Validation • <Pair<T.() -> Boolean, String> ChildValidation
  • 52. ChildValidation "name"{ be { name.isNotBlank() } not "入力してください" be { name.length >= 0 } not "5文字以上で入力" } class ChildValidation<T> { val validations = mutableListOf<Pair<T.() -> Boolean, String>>() infix fun be(f: T.() -> Boolean) = f infix fun (T.() -> Boolean).not(message: String) { validations.add(Pair(this, message)) } }
  • 53. Validation ChildValidation Validation<User> { "name"{ be { name.isNotBlank() } not "入力してください" } } class Validation<T> { val validations = mutableMapOf<String, ChildValidation<T>>() operator fun String.invoke(init: ChildValidation<T>.() -> Unit) { validations.put(this, ChildValidation<T>().apply(init)) } } •
  • 54. DSL Validation<User> { "name"{ } } class Validation<T> { val validations = mutableMapOf<String, ChildValidation<T>>() operator fun String.invoke(init: ChildValidation<T>.() -> Unit) { validations.put(this, ChildValidation<T>().apply(init)) } companion object { inline operator fun <T> invoke( init: Validation<T>.() -> Unit): Validation<T> { return Validation<T>().apply(init) } } }
  • 55. DSL be { name.isNotBlank() } not "入力してください" class ChildValidation<T> { val validations = mutableListOf<Pair<T.() -> Boolean, String>>() infix fun be(f: T.() -> Boolean) = f infix fun (T.() -> Boolean).not(message: String) { validations.add(Pair(this, message)) } } •
  • 56. DSL Validation<User> { "name"{ be { name.isNotBlank() } not "入力してください" be { name.length >= 5 } not "5文字以上入力" be { name.length <= 10 } not "10文字以下で入力" } "age"{ be { age >= 0 } not "入力してください" be { age >= 20 } not "20歳以上で入力" } } • validate
  • 57. Validate class Validation<T> { val validations = mutableMapOf<String, ChildValidation<T>>() fun validate(value: T): Map<String, List<String>> { val messages = mutableMapOf<String, List<String>>() validations.forEach { map -> val errors = map.value.validations.asSequence() .filter { !it.first.invoke(value) } .map { it.second } .filter { it.isNotEmpty() } .toList() if(errors.isNotEmpty()){ messages.put(map.key, errors) } } return messages } }
  • 58. DSL OK val user = User("kamedon", 30) val v = Validation<User> { "name"{ be { name.isNotBlank() } not "入力してください" be { name.length >= 5 } not "5文字以上入力" be { name.length <= 10 } not "10文字以下で入力" } "age"{ be { age >= 0 } not "入力してください" be { age >= 20 } not "20歳以上で入力" } } v.validate(user) •
  • 59. DSL NG val user = User("k", 10) val v = Validation<User> { "name"{ be { name.isNotBlank() } not "入力してください" be { name.length >= 5 } not "5文字以上入力" be { name.length <= 10 } not "10文字以下で入力" } "age"{ be { age >= 0 } not "入力してください" be { age >= 20 } not "20歳以上で入力" } } v.validate(user) {name=[5文字以上入力], age=[20歳以上で入力]} •
  • 61. • Pair • Builder var build val • mutable immutable • DSL 

  • 62. DSL Builder class Validation<T> { val validations = mutableMapOf<String, ChildValidation<T>>() operator fun String.invoke(init: ChildValidation<T>.() -> Unit) { validations.put(this, ChildValidation<T>().apply(init)) } companion object { inline operator fun <T> invoke( init: Validation<T>.() -> Unit): Validation<T> { return Validation<T>().apply(init) } } fun validate(value: T): Map<String, List<String>> }
  • 63. DSL Builder class ValidationBuilder<T> { val validations = mutableMapOf<String, ChildValidation<T>>() operator fun String.invoke(init: ChildValidation<T>.() -> Unit) { validations.put(this, ChildValidation<T>().apply(init)) } fun build(): Validation<T> { return Validation(validations) } } class Validation<T>(val validations: Map<String, ChildValidation<T>>) { companion object { inline operator fun <T> invoke( init: ValidationBuilder<T>.() -> Unit): Validation<T> { val builder = ValidationBuilder<T>().apply(init) return builder.build() } } }
  • 65. • object DSL • inline GC • • interface
  • 66. Validation<User> { "name"{ be { name.length >= 5 } not "5文字以下" be { name.length <= 10 } not "10文字以下" } "age"{ be { age >= 20 } not error message { "20歳以上" } be { age <= 150 } not with callback ("150歳以下"){ print("callback") } } } •
  • 68. • Java • DSL • IDE DSL • DSL
  • 69. • var val : Builder • {} : lambda lambda • () • : operator invoke • : (Extensions Functions or Properties) • : infix)