Upgrade to Pro — share decks privately, control downloads, hide ads and more …

knitで学ぶKotlin入門の次 #Kotlin_Sansan

knitで学ぶKotlin入門の次 #Kotlin_Sansan

第2回Kotlin勉強会 @ Sansan ( http://connpass.com/event/27583/ )で発表したスライドです。

14c9795d267f5b85abb98ca5e8780646?s=128

Taro Nagasawa

March 25, 2016
Tweet

Transcript

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

  2. 自己紹介 • 長澤 太郎 たろーって呼んでね • プログラマー@エムスリー株式会社 ◦ Android, Kotlin,

    Java, Scala, Rubyなど • Kotlinエバンジェリスト(JetBrains黙認) ◦ 日本Kotlinユーザグループ代表 ◦ Kotlin入門書 目下執筆中! • やすべえとディズニーが好き
  3. 1. knitの紹介

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

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

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

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

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

  9. 2. knitの造り

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

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

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

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

  14. Asserter interface Asserter<T> { val target: T infix fun not(matcher:

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

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

    Matcher<in T>) infix fun be(expected: T) infix fun be(matcher: Matcher<in T>) infix fun be(block: () -> T) infix fun notBe(unexpected: T) infix fun notBe(matcher: Matcher<in T>) infix fun notBe(block: () -> T) } infix call
  17. infix call asserter.be(expected) asserter be expected • メソッドを中置演算子っぽく呼び出せる • 標準ライブラリだと

    and や or がinfix指定されている
  18. Asserterオブジェクトの生成 actual.should be expected

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

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

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

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

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

  24. 拡張プロパティ should val <T> T.should: Asserter<T> get() = AsserterImpl(this) Asserterの実装

    オブジェクトを生成
  25. 他の表現も可能 fun <T> should(target: T): Asserter<T> = AsserterImpl(target) fun <T>

    T.should(): Asserter<T> = AsserterImpl(this)
  26. このコードを実現したいがため // 関数 should(actual) be expected // 拡張関数 actual.should() be

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

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

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

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

    actual.should() be expected // 拡張プロパティ 英語の文章としてまぁ自然 actual.should be expected ※DSLだから許される?
  31. 3. 小ネタ

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

    val <T> (()->T).should: Asserter<T> get() = this().should
  33. ファイル名どうするの問題 • クラスやインタフェースはJavaと同じ ◦ いわゆるpascal-case ◦ 例) AsserterImpl.kt • クラスがないファイルは?

    ◦ 特に決まりはないっぽい ◦ 試しにcamel-case ◦ 例) matcherAliases.kt ◦ IDEAさんならアイコンでわかる
  34. 識別子クォート、テストで便利だった 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" } }
  35. Matcherを取るバージョン "knit".should(endWith("it"))

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

  37. Matcherを取るバージョン "knit".should(endWith("it")) fun <T> T.should(matcher: Matcher(in T>) { assertThat(this, matcher)

    } 拡張関数版 should (妥協)
  38. Asserterにinvokeを持たせたかったが... "knit".should(endWith("it")) // NG ("knit".should)(endWith("it")) // OK "knit".should.invoke(endWith("it")) // OK

    interface Asserter<T> { operator fun invoke(matcher: Matcher<in T>) ... なぜか型エラー
  39. Thank you Enjoy Kotlin