SlideShare a Scribd company logo
1 of 80
Download to read offline
Kotlin DSL
~ ~
11/2 2 Android
Kamedon
•
• Kotlin
•
•
• DSL
• DSL
• DSL
•
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
• 

• 

[ ]

5 10 

[ ]

20
• 

•
•
•
•
DSL
DSL (1)
•
• 5
•
• X be Y
DSL (2)
•
• 5 

• X be Y 

not
• X be Y 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歳以上で入力"
}
}
•
DSL
• : operator invoke
• {} : lambda lambda
• ()
• : (Extensions Functions or
Properties)
• : infix)
• var val : Builder
be
be not
be not
DSL
be not
be not
be not
be not
be not
be not
be not
be not
be not
operator invoke + lambda
Validation<User> {
"name"{
be { name.isNotBlank() } not "入力してください"
be { name.length >= 5 } not "5文字以上入力"
be { name.length <= 10 } not "10文字以下で入力"
}
}
•
class Validation<T> {
companion object {
operator fun <T>
invoke(init: Validation<T>.() -> Unit): Validation<T> {
return Validation<T>().apply(init)
}
}
}
+ lambda
Validation<User> {
"name"{
be { name.isNotBlank() } not "入力してください"
be { name.length >= 5 } not "5文字以上入力"
be { name.length <= 10 } not "10文字以下で入力"
}
}
•
class Validation<T> {
val validations = mutableMapOf<String, ChildValidation<T>>()
operator fun String.invoke(
init: ChildValidation<T>.() -> Unit
) {
validations.put(this, ChildValidation<T>().apply(init))
}
}
infix( )
Validation<User> {
"name"{
be { name.isNotBlank() } not "入力してください"
be { name.length >= 5 } not "5文字以上入力"
be { name.length <= 10 } not "10文字以下で入力"
}
}
•
class ChildValidation<T> {
fun be(f: T.() -> Boolean) = f
infix fun (T.() -> Boolean).not(message: String)
}
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 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()
}
}
}
DSL
DSL
•
•
•
• 

• DSL inline
0
inline
class Sample {
fun run(f: () -> Unit) {
f()
}
inline fun inlineRun(f: () -> Unit) {
f()
}
fun main() {
run { print("run") }
inlineRun { print("inlineRun") }
}
}
public final class Sample {
public final void run(@NotNull Function0 f) {
Intrinsics.checkParameterIsNotNull(f, "f");
f.invoke();
}
public final void inlineRun(@NotNull Function0 f) {
Intrinsics.checkParameterIsNotNull(f, "f");
f.invoke();
}
public final void main() {
this.run((Function0)null.INSTANCE);
String var2 = "inlineRun";
System.out.print(var2);
}
}
Inline
public final class Sample {
public final void run(@NotNull Function0 f) {
Intrinsics.checkParameterIsNotNull(f, "f");
f.invoke();
}
public final void inlineRun(@NotNull Function0 f) {
Intrinsics.checkParameterIsNotNull(f, "f");
f.invoke();
}
public final void main() {
this.run((Function0)null.INSTANCE);
String var2 = "inlineRun";
System.out.print(var2);
}
}
• X be Y not error_message
• not
• not 

error message
• be 20 

not error message “20 ”
Validation<User> {
"name"{
be { name.length >= 5 } not "5文字以下"
be { name.length <= 10 } not "10文字以下"
}
"age"{
be { age >= 20 } not error message "20歳以上"
}
}
•
fun be(f: T.() -> Boolean) = f
infix fun (T.() -> Boolean).not(???) : ???
be { age >= 20 } not error message "20歳以上"
• error message 

•
Syntax object
object error
infix fun (T.() -> Boolean).not(syntax: error) = this
infix fun (T.() -> Boolean).message(message: String) {
validations.add(Pair(this, message))
}
be { age >= 20 } not error message "20歳以上"
• object error this
• not message
Syntax object
object error
infix fun (T.() -> Boolean).not(syntax: error) = this
infix fun (T.() -> Boolean).message(message: String) {
validations.add(Pair(this, message))
}
be { age >= 20 } not error message “20歳以上"
• object error this
• not message
IDE
be { age >= 0 } not error not error not error …
•
• not error
•
•
• not error message
IDE
class ErrorMessageSyntax<T>(val validation: T.() -> Boolean)
infix fun (T.() -> Boolean).not(syntax: error) =
ErrorMessageSyntax(this)
infix fun ErrorMessageSyntax<T>.message(message: String) {
validations.add(Pair(this.validation, message))
}
•
•
•
IDE
be { age >= 0 } not error
•
•
be { age >= 20 } not with callback "20歳以上入力"{
print("debug log")
}
class WithCallbackSyntax<T>(val validation: T.() -> Boolean)
infix fun (T.() -> Boolean).not(syntax: with) =
WithCallbackSyntax(this)
•
• error with 

•
• GitHub
•
•
•
• User Todo
• 

DSL
• User 5 …
• Todo …
•
• Validations { define<T> } 

DSL
define
define
Validations {
define<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歳以上で入力"
}
}
define<Todo> {
"body"{
be { body.isNotBlank() } not "入力してください"
}
}
}
define
define
Validations {
}
object Validations {
val map = mutableMapOf<String, Any>()
operator fun invoke(init: Validations.() -> Unit) {
init()
}
}
define Validation<T>
Validations {
define<User> {
}
}
object Validations {
inline fun <reified T>
define(init: ValidationBuilder<T>.() -> Unit) {
val validation = ValidationBuilder<T>().apply(init).build()
val key = (T::class.java).run {
"${`package`.name}.$simpleName"
}
map[key] = validation
}
}
Validations {
define<User> {
"name"{
be { name.length >= 5 } not "5文字以上入力"
be { name.length <= 10 } not "10文字以下で入力"
}
"age"{
be { age >= 0 } not "入力してください"
be { age >= 20 } not "20歳以上で入力"
}
}
define<Todo> {
"body"{
be { body.isNotBlank() } not "入力してください"
}
}
}
//{name=[5文字以上入力], age=[20歳以上で入力]}
Validations.validate(User("k",1).validate())
//{body=[入力してください]}
Validations.validate(Todo("").validate())
•
•
•
•
•
inline fun <reified T> T.validate() = 

Validations.validate(this)
•
•
Validations {
define<User> {
"name"{
be { name.length >= 5 } not "5文字以上入力"
be { name.length <= 10 } not "10文字以下で入力"
}
"age"{
be { age >= 0 } not "入力してください"
be { age >= 20 } not "20歳以上で入力"
}
}
define<Todo> {
"body"{
be { body.isNotBlank() } not "入力してください"
}
}
}
//{name=[5文字以上入力], age=[20歳以上で入力]}
User("k",1).validate()
//{body=[入力してください]}
Todo("").validate()
• 

• validate
• define
• interface
• interface
interface Validable
inline fun <reified T : Validable> T.validate()
= Validations.validate(this)
• Validable
validate
• validate
class User(val name: String, val age: Int) : Validable
class Todo(val body: String) : Validable
Validations {
define<User> {
"name"{
be { name.length >= 5 } not "5文字以上入力"
be { name.length <= 10 } not "10文字以下で入力"
}
"age"{
be { age >= 0 } not "入力してください"
be { age >= 20 } not "20歳以上で入力"
}
}
define<Todo> {
"body"{
be { body.isNotBlank() } not "入力してください"
}
}
}
User("k",1).validate()
Todo("").validate()
interface Validable<T> {
val key: String
fun validate(): Map<String, List<String>> =
(Validations.get(key) as Validation<T>).validate(this as T)
}
}
inline fun <reified T> Validable<T>.key() = 

Validations.key<T>()
class User(val name: String, val age: Int) : Validable<User> {
override val key: String = key()
}
User("k", 3).validate()
/
•
• 

get,setter
(Delegated Properties)
class Delegate : ReadWriteProperty<Hoge, String> {
var value = ""
override fun getValue(thisRef: Hoge, property: KProperty<*>): String {
return "value:" + value
}
override fun setValue(thisRef: Hoge, property: KProperty<*>, value: String) {
this.value = value
}
}
class Hoge {
var x by Delegate()
}
fun main() {
val hoge = Hoge()
hoge.x = "test"
print(hoge.x) // value: test
}
(Delegated Properties)
object ValidableDelegate {
class Validable<T>(private val key: String)
: ReadOnlyProperty<Any, Validation<T>> {
override fun getValue(thisRef: Any, property: KProperty<*>)
: Validation<T> {
return Validations.get(key) as Validation<T>
}
}
inline fun <reified T> get() = Validable<T>(Validations.key<T>())
}
class Todo(val body: String) {
private val validation by ValidableDelegate.get<Todo>()
fun validate() = validation.validate(this)
}
Todo("").validate()
• inline
• syntax object
• Interface
• interface
• /
つくってあそぼ Kotlin DSL ~拡張編~

More Related Content

What's hot

Introduction to Gremlin
Introduction to GremlinIntroduction to Gremlin
Introduction to GremlinMax De Marzi
 
Let the type system be your friend
Let the type system be your friendLet the type system be your friend
Let the type system be your friendThe Software House
 
JDD 2016 - Pawel Byszewski - Kotlin, why?
JDD 2016 - Pawel Byszewski - Kotlin, why?JDD 2016 - Pawel Byszewski - Kotlin, why?
JDD 2016 - Pawel Byszewski - Kotlin, why?PROIDEA
 
Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)Jonas Bonér
 
Error Management: Future vs ZIO
Error Management: Future vs ZIOError Management: Future vs ZIO
Error Management: Future vs ZIOJohn De Goes
 
#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"
#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"
#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"epamspb
 
How to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftHow to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftGiordano Scalzo
 
The Ring programming language version 1.5.2 book - Part 33 of 181
The Ring programming language version 1.5.2 book - Part 33 of 181The Ring programming language version 1.5.2 book - Part 33 of 181
The Ring programming language version 1.5.2 book - Part 33 of 181Mahmoud Samir Fayed
 
Parsing with Perl6 Grammars
Parsing with Perl6 GrammarsParsing with Perl6 Grammars
Parsing with Perl6 Grammarsabrummett
 
Developer Experience i TypeScript. Najbardziej ikoniczne duo
Developer Experience i TypeScript. Najbardziej ikoniczne duoDeveloper Experience i TypeScript. Najbardziej ikoniczne duo
Developer Experience i TypeScript. Najbardziej ikoniczne duoThe Software House
 
Expression trees in c#, Алексей Голубь (Svitla Systems)
Expression trees in c#, Алексей Голубь (Svitla Systems)Expression trees in c#, Алексей Голубь (Svitla Systems)
Expression trees in c#, Алексей Голубь (Svitla Systems)Alina Vilk
 
Software architecture2008 ejbql-quickref
Software architecture2008 ejbql-quickrefSoftware architecture2008 ejbql-quickref
Software architecture2008 ejbql-quickrefjaiverlh
 
The Ring programming language version 1.5.4 book - Part 44 of 185
The Ring programming language version 1.5.4 book - Part 44 of 185The Ring programming language version 1.5.4 book - Part 44 of 185
The Ring programming language version 1.5.4 book - Part 44 of 185Mahmoud Samir Fayed
 
The Ring programming language version 1.9 book - Part 42 of 210
The Ring programming language version 1.9 book - Part 42 of 210The Ring programming language version 1.9 book - Part 42 of 210
The Ring programming language version 1.9 book - Part 42 of 210Mahmoud Samir Fayed
 
BDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
BDD - Behavior Driven Development Webapps mit Groovy Spock und GebBDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
BDD - Behavior Driven Development Webapps mit Groovy Spock und GebChristian Baranowski
 
Beyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCodeBeyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCodeAijaz Ansari
 
Expression trees in c#
Expression trees in c#Expression trees in c#
Expression trees in c#Oleksii Holub
 

What's hot (18)

Introduction to Gremlin
Introduction to GremlinIntroduction to Gremlin
Introduction to Gremlin
 
Let the type system be your friend
Let the type system be your friendLet the type system be your friend
Let the type system be your friend
 
JDD 2016 - Pawel Byszewski - Kotlin, why?
JDD 2016 - Pawel Byszewski - Kotlin, why?JDD 2016 - Pawel Byszewski - Kotlin, why?
JDD 2016 - Pawel Byszewski - Kotlin, why?
 
Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)
 
Error Management: Future vs ZIO
Error Management: Future vs ZIOError Management: Future vs ZIO
Error Management: Future vs ZIO
 
#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"
#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"
#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"
 
How to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftHow to Clone Flappy Bird in Swift
How to Clone Flappy Bird in Swift
 
The Ring programming language version 1.5.2 book - Part 33 of 181
The Ring programming language version 1.5.2 book - Part 33 of 181The Ring programming language version 1.5.2 book - Part 33 of 181
The Ring programming language version 1.5.2 book - Part 33 of 181
 
Parsing with Perl6 Grammars
Parsing with Perl6 GrammarsParsing with Perl6 Grammars
Parsing with Perl6 Grammars
 
Developer Experience i TypeScript. Najbardziej ikoniczne duo
Developer Experience i TypeScript. Najbardziej ikoniczne duoDeveloper Experience i TypeScript. Najbardziej ikoniczne duo
Developer Experience i TypeScript. Najbardziej ikoniczne duo
 
Expression trees in c#, Алексей Голубь (Svitla Systems)
Expression trees in c#, Алексей Голубь (Svitla Systems)Expression trees in c#, Алексей Голубь (Svitla Systems)
Expression trees in c#, Алексей Голубь (Svitla Systems)
 
Software architecture2008 ejbql-quickref
Software architecture2008 ejbql-quickrefSoftware architecture2008 ejbql-quickref
Software architecture2008 ejbql-quickref
 
The Ring programming language version 1.5.4 book - Part 44 of 185
The Ring programming language version 1.5.4 book - Part 44 of 185The Ring programming language version 1.5.4 book - Part 44 of 185
The Ring programming language version 1.5.4 book - Part 44 of 185
 
The Ring programming language version 1.9 book - Part 42 of 210
The Ring programming language version 1.9 book - Part 42 of 210The Ring programming language version 1.9 book - Part 42 of 210
The Ring programming language version 1.9 book - Part 42 of 210
 
Scala in practice
Scala in practiceScala in practice
Scala in practice
 
BDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
BDD - Behavior Driven Development Webapps mit Groovy Spock und GebBDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
BDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
 
Beyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCodeBeyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCode
 
Expression trees in c#
Expression trees in c#Expression trees in c#
Expression trees in c#
 

Similar to つくってあそぼ Kotlin DSL ~拡張編~

Kotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan SoaresKotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan SoaresiMasters
 
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
TDC218SP | Trilha Kotlin - DSLs in a Kotlin WayTDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Waytdc-globalcode
 
From java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+kFrom java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+kFabio Collini
 
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Tsuyoshi Yamamoto
 
Scala in practice
Scala in practiceScala in practice
Scala in practicepatforna
 
Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018
Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018
Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018Codemotion
 
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf MilanFrom Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf MilanFabio Collini
 
Greach, GroovyFx Workshop
Greach, GroovyFx WorkshopGreach, GroovyFx Workshop
Greach, GroovyFx WorkshopDierk König
 
Kotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projectsKotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projectsBartosz Kosarzycki
 
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016STX Next
 
A swift introduction to Swift
A swift introduction to SwiftA swift introduction to Swift
A swift introduction to SwiftGiordano Scalzo
 
JJUG CCC 2011 Spring
JJUG CCC 2011 SpringJJUG CCC 2011 Spring
JJUG CCC 2011 SpringKiyotaka Oku
 
Android & Kotlin - The code awakens #03
Android & Kotlin - The code awakens #03Android & Kotlin - The code awakens #03
Android & Kotlin - The code awakens #03Omar Miatello
 
Persisting Data on SQLite using Room
Persisting Data on SQLite using RoomPersisting Data on SQLite using Room
Persisting Data on SQLite using RoomNelson Glauber Leal
 

Similar to つくってあそぼ Kotlin DSL ~拡張編~ (20)

Kotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan SoaresKotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan Soares
 
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
TDC218SP | Trilha Kotlin - DSLs in a Kotlin WayTDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
 
Introduction kot iin
Introduction kot iinIntroduction kot iin
Introduction kot iin
 
Kotlin Generation
Kotlin GenerationKotlin Generation
Kotlin Generation
 
From java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+kFrom java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+k
 
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
 
Kotlin
KotlinKotlin
Kotlin
 
Scala in practice
Scala in practiceScala in practice
Scala in practice
 
Scala on Your Phone
Scala on Your PhoneScala on Your Phone
Scala on Your Phone
 
Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018
Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018
Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018
 
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf MilanFrom Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
 
Greach, GroovyFx Workshop
Greach, GroovyFx WorkshopGreach, GroovyFx Workshop
Greach, GroovyFx Workshop
 
Kotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projectsKotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projects
 
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
 
Griffon @ Svwjug
Griffon @ SvwjugGriffon @ Svwjug
Griffon @ Svwjug
 
A swift introduction to Swift
A swift introduction to SwiftA swift introduction to Swift
A swift introduction to Swift
 
JJUG CCC 2011 Spring
JJUG CCC 2011 SpringJJUG CCC 2011 Spring
JJUG CCC 2011 Spring
 
2014-11-01 01 Денис Нелюбин. О сортах кофе
2014-11-01 01 Денис Нелюбин. О сортах кофе2014-11-01 01 Денис Нелюбин. О сортах кофе
2014-11-01 01 Денис Нелюбин. О сортах кофе
 
Android & Kotlin - The code awakens #03
Android & Kotlin - The code awakens #03Android & Kotlin - The code awakens #03
Android & Kotlin - The code awakens #03
 
Persisting Data on SQLite using Room
Persisting Data on SQLite using RoomPersisting Data on SQLite using Room
Persisting Data on SQLite using Room
 

Recently uploaded

Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...HostedbyConfluent
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...gurkirankumar98700
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxOnBoard
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 

Recently uploaded (20)

Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptx
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 

つくってあそぼ Kotlin DSL ~拡張編~

  • 1. Kotlin DSL ~ ~ 11/2 2 Android Kamedon
  • 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
  • 15.
  • 16. • 
 • 
 [ ]
 5 10 
 [ ]
 20 • 

  • 17.
  • 19. DSL
  • 21. DSL (2) • • 5 
 • X be Y 
 not • X be Y 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歳以上で入力" } } •
  • 25. DSL
  • 26. • : operator invoke • {} : lambda lambda • () • : (Extensions Functions or Properties) • : infix) • var val : Builder
  • 28. DSL be not be not be not be not be not
  • 29. be not be not be not be not
  • 30. operator invoke + lambda Validation<User> { "name"{ be { name.isNotBlank() } not "入力してください" be { name.length >= 5 } not "5文字以上入力" be { name.length <= 10 } not "10文字以下で入力" } } • class Validation<T> { companion object { operator fun <T> invoke(init: Validation<T>.() -> Unit): Validation<T> { return Validation<T>().apply(init) } } }
  • 31. + lambda Validation<User> { "name"{ be { name.isNotBlank() } not "入力してください" be { name.length >= 5 } not "5文字以上入力" be { name.length <= 10 } not "10文字以下で入力" } } • class Validation<T> { val validations = mutableMapOf<String, ChildValidation<T>>() operator fun String.invoke( init: ChildValidation<T>.() -> Unit ) { validations.put(this, ChildValidation<T>().apply(init)) } }
  • 32. infix( ) Validation<User> { "name"{ be { name.isNotBlank() } not "入力してください" be { name.length >= 5 } not "5文字以上入力" be { name.length <= 10 } not "10文字以下で入力" } } • class ChildValidation<T> { fun be(f: T.() -> Boolean) = f infix fun (T.() -> Boolean).not(message: String) }
  • 33. 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) } } }
  • 34. 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)) } } •
  • 35. 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
  • 36. 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 } }
  • 37. 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>> }
  • 38. 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() } } }
  • 39. DSL
  • 41.
  • 42. • 
 • DSL inline 0
  • 43. inline class Sample { fun run(f: () -> Unit) { f() } inline fun inlineRun(f: () -> Unit) { f() } fun main() { run { print("run") } inlineRun { print("inlineRun") } } }
  • 44. public final class Sample { public final void run(@NotNull Function0 f) { Intrinsics.checkParameterIsNotNull(f, "f"); f.invoke(); } public final void inlineRun(@NotNull Function0 f) { Intrinsics.checkParameterIsNotNull(f, "f"); f.invoke(); } public final void main() { this.run((Function0)null.INSTANCE); String var2 = "inlineRun"; System.out.print(var2); } }
  • 45. Inline public final class Sample { public final void run(@NotNull Function0 f) { Intrinsics.checkParameterIsNotNull(f, "f"); f.invoke(); } public final void inlineRun(@NotNull Function0 f) { Intrinsics.checkParameterIsNotNull(f, "f"); f.invoke(); } public final void main() { this.run((Function0)null.INSTANCE); String var2 = "inlineRun"; System.out.print(var2); } }
  • 46.
  • 47. • X be Y not error_message • not • not 
 error message • be 20 
 not error message “20 ”
  • 48. Validation<User> { "name"{ be { name.length >= 5 } not "5文字以下" be { name.length <= 10 } not "10文字以下" } "age"{ be { age >= 20 } not error message "20歳以上" } } •
  • 49. fun be(f: T.() -> Boolean) = f infix fun (T.() -> Boolean).not(???) : ??? be { age >= 20 } not error message "20歳以上" • error message 
 •
  • 50. Syntax object object error infix fun (T.() -> Boolean).not(syntax: error) = this infix fun (T.() -> Boolean).message(message: String) { validations.add(Pair(this, message)) } be { age >= 20 } not error message "20歳以上" • object error this • not message
  • 51. Syntax object object error infix fun (T.() -> Boolean).not(syntax: error) = this infix fun (T.() -> Boolean).message(message: String) { validations.add(Pair(this, message)) } be { age >= 20 } not error message “20歳以上" • object error this • not message
  • 52. IDE be { age >= 0 } not error not error not error … • • not error • • • not error message
  • 53. IDE class ErrorMessageSyntax<T>(val validation: T.() -> Boolean) infix fun (T.() -> Boolean).not(syntax: error) = ErrorMessageSyntax(this) infix fun ErrorMessageSyntax<T>.message(message: String) { validations.add(Pair(this.validation, message)) } • • •
  • 54. IDE be { age >= 0 } not error • •
  • 55. be { age >= 20 } not with callback "20歳以上入力"{ print("debug log") } class WithCallbackSyntax<T>(val validation: T.() -> Boolean) infix fun (T.() -> Boolean).not(syntax: with) = WithCallbackSyntax(this) • • error with 
 • • GitHub
  • 57.
  • 59.
  • 60. DSL • User 5 … • Todo … • • Validations { define<T> } 
 DSL
  • 62. Validations { define<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歳以上で入力" } } define<Todo> { "body"{ be { body.isNotBlank() } not "入力してください" } } }
  • 64. Validations { } object Validations { val map = mutableMapOf<String, Any>() operator fun invoke(init: Validations.() -> Unit) { init() } }
  • 65. define Validation<T> Validations { define<User> { } } object Validations { inline fun <reified T> define(init: ValidationBuilder<T>.() -> Unit) { val validation = ValidationBuilder<T>().apply(init).build() val key = (T::class.java).run { "${`package`.name}.$simpleName" } map[key] = validation } }
  • 66. Validations { define<User> { "name"{ be { name.length >= 5 } not "5文字以上入力" be { name.length <= 10 } not "10文字以下で入力" } "age"{ be { age >= 0 } not "入力してください" be { age >= 20 } not "20歳以上で入力" } } define<Todo> { "body"{ be { body.isNotBlank() } not "入力してください" } } } //{name=[5文字以上入力], age=[20歳以上で入力]} Validations.validate(User("k",1).validate()) //{body=[入力してください]} Validations.validate(Todo("").validate())
  • 67.
  • 69. inline fun <reified T> T.validate() = 
 Validations.validate(this) • •
  • 70. Validations { define<User> { "name"{ be { name.length >= 5 } not "5文字以上入力" be { name.length <= 10 } not "10文字以下で入力" } "age"{ be { age >= 0 } not "入力してください" be { age >= 20 } not "20歳以上で入力" } } define<Todo> { "body"{ be { body.isNotBlank() } not "入力してください" } } } //{name=[5文字以上入力], age=[20歳以上で入力]} User("k",1).validate() //{body=[入力してください]} Todo("").validate()
  • 73. interface Validable inline fun <reified T : Validable> T.validate() = Validations.validate(this) • Validable validate • validate
  • 74. class User(val name: String, val age: Int) : Validable class Todo(val body: String) : Validable Validations { define<User> { "name"{ be { name.length >= 5 } not "5文字以上入力" be { name.length <= 10 } not "10文字以下で入力" } "age"{ be { age >= 0 } not "入力してください" be { age >= 20 } not "20歳以上で入力" } } define<Todo> { "body"{ be { body.isNotBlank() } not "入力してください" } } } User("k",1).validate() Todo("").validate()
  • 75. interface Validable<T> { val key: String fun validate(): Map<String, List<String>> = (Validations.get(key) as Validation<T>).validate(this as T) } } inline fun <reified T> Validable<T>.key() = 
 Validations.key<T>() class User(val name: String, val age: Int) : Validable<User> { override val key: String = key() } User("k", 3).validate()
  • 77. (Delegated Properties) class Delegate : ReadWriteProperty<Hoge, String> { var value = "" override fun getValue(thisRef: Hoge, property: KProperty<*>): String { return "value:" + value } override fun setValue(thisRef: Hoge, property: KProperty<*>, value: String) { this.value = value } } class Hoge { var x by Delegate() } fun main() { val hoge = Hoge() hoge.x = "test" print(hoge.x) // value: test }
  • 78. (Delegated Properties) object ValidableDelegate { class Validable<T>(private val key: String) : ReadOnlyProperty<Any, Validation<T>> { override fun getValue(thisRef: Any, property: KProperty<*>) : Validation<T> { return Validations.get(key) as Validation<T> } } inline fun <reified T> get() = Validable<T>(Validations.key<T>()) } class Todo(val body: String) { private val validation by ValidableDelegate.get<Todo>() fun validate() = validation.validate(this) } Todo("").validate()
  • 79. • inline • syntax object • Interface • interface • /