「⚠ This project uses Gradle Version Catalogs: this tool may not behave as expected.」→ 今現在、Gradle Version Catalog には gradle-versions-plugin が必須では?

使ってみました、Gradle Version Catalog。

こんなのでました。

Gradle Version Catalog

⚠ This project uses Gradle Version Catalogs: this tool may not behave as expected.

どうします? dependencies の 更新。

suggestions も出ないし。

 

👌 ben-manes/gradle-versions-plugin で確認する

現在、スター 3.4k のスーパープラグインを使いましょう。

ben-manes/gradle-versions-plugin: Gradle plugin to discover dependency updates

👉 ben-manes/gradle-versions-plugin: Gradle plugin to discover dependency updates hatena-bookmark

使い方は、プラグインにセットして


# gradle/libs.versions.toml

[plugins]
gradle-versions-plugin = { id = "com.github.ben-manes.versions", version = "0.43.0" }


// app/build.gradle

plugins {
  alias libs.plugins.gradle.versions.plugin
}

実行します。


./gradlew dependencyUpdates

現在利用中のライブラリーのバージョンと各公開されてるリポジトリのバージョンを比較して表示だけ してくれます。

ツールからは gradle/libs.versions.toml の書き換えは行ないません。安心です。

gradlew dependencyUpdates

しかし、これ何ですかね。


The following dependencies have later milestone versions:
 - org.jacoco:org.jacoco.ant [0.8.3 -> 0.8.7]
     http://jacoco.org

👉 org.jacoco:org.jacoco.ant dependency not found? · Issue #534 · ben-manes/gradle-versions-plugin hatena-bookmark

無視で良さそうです。

👉 Gradle Version Catalog への書き換えツールを作る【python】 hatena-bookmark
👉 【Gradle Version Catalog】libs.versions.toml キー名の形式 camelCase vs kebab-case hatena-bookmark
👉 Jetpack Compose Samples でも使われている「Version catalog update plugin」で libs.versions.toml を書き出してみる hatena-bookmark


Gradle Version Catalog への書き換えツールを作る【python】

素晴らしいツールを公開されています。

👉 takahirom/gradle-version-catalog-converter: Convert `implementation 'androidx.core:core-ktx:1.7.0'` into `androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidxCore" }` hatena-bookmark

結果は以下。

gradle-version-catalog-converter


implementation "com.google.accompanist:accompanist-systemuicontroller:0.17.0"
implementation 'com.google.accompanist:accompanist-swiperefresh:0.26.5-rc'


[versions]
comGoogleAccompanist = "0.17.0"

[libraries]
com-google-accompanist-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "comGoogleAccompanist" }
com-google-accompanist-swiperefresh = { module = "com.google.accompanist:accompanist-swiperefresh", version.ref = "comGoogleAccompanist" }

build.gradle
implementation libs.com.google.accompanist.systemuicontroller
implementation libs.com.google.accompanist.swiperefresh

build.gradle.kts
implementation(libs.com.google.accompanist.systemuicontroller)
implementation(libs.com.google.accompanist.swiperefresh)

高機能で便利です。

作った動機はだれもが同感できるでしょう。

ということで、

私も python の勉強がてら雑魚ツールを作ります。

クリップボードにコピーした


implementation "com.google.accompanist:accompanist-systemuicontroller:0.17.0"
implementation 'com.google.accompanist:accompanist-swiperefresh:0.26.5-rc'

を python スクリプト実行後すると


* source
  implementation "com.google.accompanist:accompanist-systemuicontroller:0.17.0"
  implementation 'com.google.accompanist:accompanist-swiperefresh:0.26.5-rc'

* gradle/libs.versions.toml
[libraries]
accompanist-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version = "0.17.0"" }
accompanist-swiperefresh = { module = "com.google.accompanist:accompanist-swiperefresh", version = "0.26.5-rc" }

* build.gradle
implementation libs.accompanist.systemuicontroller
implementation libs.accompanist.swiperefresh

と表示します。

まずは、ただそれだけです。

[versions] を設定するのもだるい implementation 単独バージョンのライブラリ用。

幼稚なスクリプトなので拡張や変更、削除しやすいです。

重複に注意です。

このへんの変換処理は、

きっと、Android Studio プラグインが登場して、

そのあと、Android Studio に取り込まれいく

のだろうと妄想しています。

それまでのつなぎで。

※ このページは gist を更新しながら更新していきます。

※ 追記: こんなのあったんですね!


👉 「⚠ This project uses Gradle Version Catalogs: this tool may not behave as expected.」→ 今現在、Gradle Version Catalog には gradle-versions-plugin が必須では? hatena-bookmark

👉 【Gradle Version Catalog】libs.versions.toml キー名の形式 camelCase vs kebab-case hatena-bookmark


Kotlin スコープ関数 の上手な使い分け その1 - apply

kotlin scope function

使い分けが難しいと言われているスコープ関数ですが。

以下、どれでも同じ結果を取得できます。


val bundle = Bundle()
bundle.putInt("x", 1)
bundle.putInt("y", 2)

val run = Bundle().run {
  putInt("x", 1)
  putInt("y", 2)
  this
}

val let = Bundle().let {
  it.putInt("x", 1)
  it.putInt("y", 2)
  it
}

val with = with(Bundle()) {
  putInt("x", 1)
  putInt("y", 2)
  this
}

val apply = Bundle().apply {
  putInt("x", 1)
  putInt("y", 2)
}

val also = Bundle().also {
  it.putInt("x", 1)
  it.putInt("y", 2)
}

val runNE = run {
  val bundleNE = Bundle()
  bundleNE.putInt("x", 1)
  bundleNE.putInt("y", 2)
  bundleNE
}

println("bundle = $bundle")
println("run    = $run")
println("let    = $let")
println("with   = $with")
println("apply  = $apply")
println("also   = $also")
println("runNE  = $runNE")


I/System.out: bundle = Bundle[{x=1, y=2}]
I/System.out: run    = Bundle[{x=1, y=2}]
I/System.out: let    = Bundle[{x=1, y=2}]
I/System.out: with   = Bundle[{x=1, y=2}]
I/System.out: apply  = Bundle[{x=1, y=2}]
I/System.out: also   = Bundle[{x=1, y=2}]
I/System.out: runNE  = Bundle[{x=1, y=2}]

どれが書きやすいですかね。

どれが分かりやすく管理しやすいですか。

 

■ apply の便利な使い方 (公式)

実装を見てみます。


public inline fun <T> T.apply(block: T.() -> Unit): T {
  contract {...}
  block()
  return this
}

Kotlin 公式リファレンスには使い分けとして以下の説明が書かれてます。

apply executes a block of code on an object and returns the object itself. Inside the block, the object is referenced by this. This function is handy for initializing objects.

apply は、オブジェクトに対してコードのブロックを実行し、そのオブジェクト自身を返します。ブロックの内部では、オブジェクトはthisで参照されます。
この関数は、オブジェクトを初期化するのに便利です。

Object configuration
オブジェクトの設定

Builder-style usage of methods that return Unit
Unitを返すメソッドのBuilder的な使い方


fun arrayOfMinusOnes(size: Int): IntArray {
  return IntArray(size).apply { fill(-1) }
}

Configure properties of an object (apply)
オブジェクトのプロパティを設定する


val myRectangle = Rectangle().apply {
  length = 4
  breadth = 5
  color = 0xFAFAFA
}

👉 Kotlin Examples: Learn Kotlin Programming By Example hatena-bookmark
👉 Scope functions | Kotlin hatena-bookmark
👉 Idioms | Kotlin hatena-bookmark

 

■ まとめ

「apply」は「オブジェクトの初期設定」に使う と良いです。

コンストラクタの引数 や Builder の有無に関係なしに使えます。

使い方のイメージは Builder パターンのスタイルです。


fun newIntent(context: Context, movie: Movie): Intent {
  return Intent(context, PlaybackActivity::class.java)
    .apply {
       putExtra(MOVIE, movie)
    }
}


private val messagesSent = MutableLiveData<Int>().apply { value = 0 }
private val dinosClicked = MutableLiveData<Int>().apply { value = 0 }
private val dropText = MutableLiveData<String>().apply { value = "Drop Things Here!" }


private val paint = Paint().apply {
  color = drawColor
  isAntiAlias = true
  isDither = true
  style = Paint.Style.STROKE // default: FILL
  strokeJoin = Paint.Join.ROUND // default: MITER
  strokeCap = Paint.Cap.ROUND // default: BUTT
  strokeWidth = STROKE_WIDTH // default: Hairline-width (really thin)
}

apply ブロック内に if を使うこともできます。

👉 Kotlin スコープ関数 の上手な使い分け その1 - apply hatena-bookmark
👉 Kotlin スコープ関数 の上手な使い分け その2 - also hatena-bookmark
👉 Kotlin スコープ関数 の上手な使い分け その3 - with hatena-bookmark
👉 Kotlin スコープ関数 の上手な使い分け その4 - let hatena-bookmark
👉 Kotlin スコープ関数 の上手な使い分け その5 - run hatena-bookmark