Slide 1

Slide 1 text

knitで学ぶ Kotlin入門の次 2016-03-24 第2回Kotlin勉強会@Sansan 長澤 太郎 @ngsw_taro

Slide 2

Slide 2 text

自己紹介 ● 長澤 太郎 たろーって呼んでね ● プログラマー@エムスリー株式会社 ○ Android, Kotlin, Java, Scala, Rubyなど ● Kotlinエバンジェリスト(JetBrains黙認) ○ 日本Kotlinユーザグループ代表 ○ Kotlin入門書 目下執筆中! ● やすべえとディズニーが好き

Slide 3

Slide 3 text

1. knitの紹介

Slide 4

Slide 4 text

knitとは ● JUnitの薄いラッパー ● 1ヶ月くらい前につくった ● 今すぐダウンロード github.com/ntaro/knit

Slide 5

Slide 5 text

なぜつくったか // JUnit assertThat(actual, `is`(expected))

Slide 6

Slide 6 text

なぜつくったか // JUnit assertThat(actual, `is`(expected)) ダサい

Slide 7

Slide 7 text

knitを使うと // knit actual.should be expected

Slide 8

Slide 8 text

やってることは単純 actual.should be expected assertThat(actual, `is`(expected))

Slide 9

Slide 9 text

2. knitの造り

Slide 10

Slide 10 text

構成要素を分解 actual.should be expected (actual.should).be(expected)

Slide 11

Slide 11 text

構成要素を分解 actual.should be expected (actual.should).be(expected) オブジェクトへの参照

Slide 12

Slide 12 text

構成要素を分解 actual.should be expected (actual.should).be(expected) メソッド呼び出し

Slide 13

Slide 13 text

構成要素を分解 actual.should be expected asserter .be(expected) オブジェクトへの参照 →インタフェース Asserter

Slide 14

Slide 14 text

Asserter interface Asserter { val target: T infix fun not(matcher: Matcher) infix fun be(expected: T) infix fun be(matcher: Matcher) infix fun be(block: () -> T) infix fun notBe(unexpected: T) infix fun notBe(matcher: Matcher) infix fun notBe(block: () -> T) }

Slide 15

Slide 15 text

Asserter interface Asserter { val target: T infix fun not(matcher: Matcher) infix fun be(expected: T) infix fun be(matcher: Matcher) infix fun be(block: () -> T) infix fun notBe(unexpected: T) infix fun notBe(matcher: Matcher) infix fun notBe(block: () -> T) }

Slide 16

Slide 16 text

Asserter interface Asserter { val target: T infix fun not(matcher: Matcher) infix fun be(expected: T) infix fun be(matcher: Matcher) infix fun be(block: () -> T) infix fun notBe(unexpected: T) infix fun notBe(matcher: Matcher) infix fun notBe(block: () -> T) } infix call

Slide 17

Slide 17 text

infix call asserter.be(expected) asserter be expected ● メソッドを中置演算子っぽく呼び出せる ● 標準ライブラリだと and や or がinfix指定されている

Slide 18

Slide 18 text

Asserterオブジェクトの生成 actual.should be expected

Slide 19

Slide 19 text

Asserterオブジェクトの生成 actual.should be expected 任意の型のプロパティ

Slide 20

Slide 20 text

拡張プロパティ should val T.should: Asserter get() = AsserterImpl(this)

Slide 21

Slide 21 text

拡張プロパティ should val T.should: Asserter get() = AsserterImpl(this) 型パラメータ

Slide 22

Slide 22 text

拡張プロパティ should val T.should: Asserter get() = AsserterImpl(this) 拡張プロパティ

Slide 23

Slide 23 text

拡張プロパティ should val T.should: Asserter get() = AsserterImpl(this) 型

Slide 24

Slide 24 text

拡張プロパティ should val T.should: Asserter get() = AsserterImpl(this) Asserterの実装 オブジェクトを生成

Slide 25

Slide 25 text

他の表現も可能 fun should(target: T): Asserter = AsserterImpl(target) fun T.should(): Asserter = AsserterImpl(this)

Slide 26

Slide 26 text

このコードを実現したいがため // 関数 should(actual) be expected // 拡張関数 actual.should() be expected // 拡張プロパティ actual.should be expected

Slide 27

Slide 27 text

このコードを実現したいがため // 関数 疑問文みたいな語順 should(actual) be expected // 拡張関数 actual.should() be expected // 拡張プロパティ actual.should be expected

Slide 28

Slide 28 text

このコードを実現したいがため // 関数 疑問文みたいな語順 should(actual) be expected // 拡張関数 カッコが邪魔 actual.should() be expected // 拡張プロパティ actual.should be expected

Slide 29

Slide 29 text

このコードを実現したいがため // 関数 疑問文みたいな語順 should(actual) be expected // 拡張関数 カッコが邪魔 actual.should() be expected // 拡張プロパティ 英語の文章としてまぁ自然 actual.should be expected

Slide 30

Slide 30 text

このコードを実現したいがため // 関数 疑問文みたいな語順 should(actual) be expected // 拡張関数 カッコが邪魔 actual.should() be expected // 拡張プロパティ 英語の文章としてまぁ自然 actual.should be expected ※DSLだから許される?

Slide 31

Slide 31 text

3. 小ネタ

Slide 32

Slide 32 text

トップレベルに関数やプロパティをおける package com.taroid.knit val T.should: Asserter get() = AsserterImpl(this) val (()->T).should: Asserter get() = this().should

Slide 33

Slide 33 text

ファイル名どうするの問題 ● クラスやインタフェースはJavaと同じ ○ いわゆるpascal-case ○ 例) AsserterImpl.kt ● クラスがないファイルは? ○ 特に決まりはないっぽい ○ 試しにcamel-case ○ 例) matcherAliases.kt ○ IDEAさんならアイコンでわかる

Slide 34

Slide 34 text

識別子クォート、テストで便利だった class `be - expected` { @Test fun `does nothing when target equals expected`() { sut be java.lang.String("Kotlin").toString() } @Test(expected = AssertionError::class) fun `throws error when target does not equal expected`() { sut be "kotlin" } }

Slide 35

Slide 35 text

Matcherを取るバージョン "knit".should(endWith("it"))

Slide 36

Slide 36 text

Matcherを取るバージョン "knit".should(endWith("it")) fun endWith(suffix: String): Matcher = CoreMatchers.endsWith(suffix) 三単現のsを除く地味な工夫...

Slide 37

Slide 37 text

Matcherを取るバージョン "knit".should(endWith("it")) fun T.should(matcher: Matcher(in T>) { assertThat(this, matcher) } 拡張関数版 should (妥協)

Slide 38

Slide 38 text

Asserterにinvokeを持たせたかったが... "knit".should(endWith("it")) // NG ("knit".should)(endWith("it")) // OK "knit".should.invoke(endWith("it")) // OK interface Asserter { operator fun invoke(matcher: Matcher) ... なぜか型エラー

Slide 39

Slide 39 text

Thank you Enjoy Kotlin