The document discusses Kotlin DSL and provides examples of using Kotlin as a domain-specific language (DSL) to define validation rules. It shows how to build a validation DSL that allows defining validation logic for fields in a concise way using functions like "be" and "not". The validation rules can then be validated against objects to check for errors.
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歳以上で入力"
}
}
•
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
}
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))
}
}
•
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
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歳以上で入力]}
•
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")
}
}
}
•