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

Inheritance : Extending Classes
Inheritance : Extending ClassesInheritance : Extending Classes
Inheritance : Extending ClassesNilesh Dalvi
 
Machine learning ( Part 2 )
Machine learning ( Part 2 )Machine learning ( Part 2 )
Machine learning ( Part 2 )Sunil OS
 
Collection v3
Collection v3Collection v3
Collection v3Sunil OS
 
JavaScript
JavaScriptJavaScript
JavaScriptSunil OS
 
JAVA Variables and Operators
JAVA Variables and OperatorsJAVA Variables and Operators
JAVA Variables and OperatorsSunil OS
 
Java Basics V3
Java Basics V3Java Basics V3
Java Basics V3Sunil OS
 
Inheritance in c++
Inheritance in c++ Inheritance in c++
Inheritance in c++ sandeep54552
 
Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)Scott Wlaschin
 
Object Oriented Solved Practice Programs C++ Exams
Object Oriented Solved Practice Programs C++ ExamsObject Oriented Solved Practice Programs C++ Exams
Object Oriented Solved Practice Programs C++ ExamsMuhammadTalha436
 
JDBC - JPA - Spring Data
JDBC - JPA - Spring DataJDBC - JPA - Spring Data
JDBC - JPA - Spring DataArturs Drozdovs
 
Flutter tutorial for Beginner Step by Step
Flutter tutorial for Beginner Step by StepFlutter tutorial for Beginner Step by Step
Flutter tutorial for Beginner Step by StepChandramouli Biyyala
 

What's hot (20)

Inheritance : Extending Classes
Inheritance : Extending ClassesInheritance : Extending Classes
Inheritance : Extending Classes
 
Machine learning ( Part 2 )
Machine learning ( Part 2 )Machine learning ( Part 2 )
Machine learning ( Part 2 )
 
Collection v3
Collection v3Collection v3
Collection v3
 
PDBC
PDBCPDBC
PDBC
 
JavaScript
JavaScriptJavaScript
JavaScript
 
JAVA Variables and Operators
JAVA Variables and OperatorsJAVA Variables and Operators
JAVA Variables and Operators
 
Java Basics V3
Java Basics V3Java Basics V3
Java Basics V3
 
Introduction to php
Introduction to phpIntroduction to php
Introduction to php
 
Inheritance in c++
Inheritance in c++ Inheritance in c++
Inheritance in c++
 
Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)
 
Object Oriented Solved Practice Programs C++ Exams
Object Oriented Solved Practice Programs C++ ExamsObject Oriented Solved Practice Programs C++ Exams
Object Oriented Solved Practice Programs C++ Exams
 
JDBC - JPA - Spring Data
JDBC - JPA - Spring DataJDBC - JPA - Spring Data
JDBC - JPA - Spring Data
 
Flutter tutorial for Beginner Step by Step
Flutter tutorial for Beginner Step by StepFlutter tutorial for Beginner Step by Step
Flutter tutorial for Beginner Step by Step
 
Java tutorial PPT
Java tutorial PPTJava tutorial PPT
Java tutorial PPT
 
Managing I/O in c++
Managing I/O in c++Managing I/O in c++
Managing I/O in c++
 
JDBC
JDBCJDBC
JDBC
 
Cgi
CgiCgi
Cgi
 
Quiz using C++
Quiz using C++Quiz using C++
Quiz using C++
 
JavaScript Inheritance
JavaScript InheritanceJavaScript Inheritance
JavaScript Inheritance
 
Java Quiz
Java QuizJava Quiz
Java Quiz
 

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

つくってあそぼ Kotlin DSL 第2版
つくってあそぼ Kotlin DSL 第2版つくってあそぼ Kotlin DSL 第2版
つくってあそぼ Kotlin DSL 第2版kamedon39
 
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
 

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

つくってあそぼ Kotlin DSL 第2版
つくってあそぼ Kotlin DSL 第2版つくってあそぼ Kotlin DSL 第2版
つくってあそぼ Kotlin DSL 第2版
 
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
 
Pooya Khaloo Presentation on IWMC 2015
Pooya Khaloo Presentation on IWMC 2015Pooya Khaloo Presentation on IWMC 2015
Pooya Khaloo Presentation on IWMC 2015
 
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 Денис Нелюбин. О сортах кофе
 

Recently uploaded

Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDGMarianaLemus7
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024The Digital Insurer
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 

Recently uploaded (20)

Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDG
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food Manufacturing
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 

つくってあそぼ 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 • /