SwiftUIのTextは+演算子で結合できる(fontやforegroundColorなどを変えていてもできる)
SwiftUI.Text
には+
演算子が用意されているのでText("Foo") + Text("Bar")
のように結合ができるText("Foo").font(.title) + Text("Bar").foregroundColor(.secondary)
のように一部のmodifierを付けていても結合できる- これらのmodifierは、多くのViewでは
some View
が戻り値だが、Textでは型が変わらずにTextのままなので、そのまま+
演算子が使える
- これらのmodifierは、多くのViewでは
基本的なテクニックではあるけれど、modifierを呼び出した結果が some View
じゃないのは意外と気にせずに使っている部分でもありそうなのでメモ。
CircleCI公式のDockerイメージにはyqがプリインストールされているので、自分で入れる必要はない
CircleCIのダイナミックコンフィグとsetup
ワークフロー*1で、path-filtering
Orbやcontinuation
Orbを使う時の話題ですが、タイトルがすべてです。
設定ファイルをマージする用途でyqを使うために、自分でインストールするような記述を色んなブログで見かけたりもしたのですが、path-filtering/filter
job, continuation/continue
jobのデフォルトexecutorとなるDockerイメージにはyqがプリインストール済みです。
Open Test Reporting: platform-agnosticなテストレポートのフォーマット
たまたまJUnit 5.9.0のリリースノートを読んでいたら面白いものが目に着きました。
- XML reports in new Open Test Reporting format
テストレポートのフォーマットとしてはJUnitがデファクトスタンダードのようになっていて、様々なプログラミング言語やテストフレームワーク、またCIサービスがテスト結果のサマリー表示のためにサポートしています。しかしJUnitは元々Java世界のものであり、他言語のテスト結果をJUnitフォーマットに出力しようとすると構造を無理矢理合わせることになったり、拡張性もなかったり(もしくは独自拡張になったり)します。言語・テストフレームワーク非依存な新しい仕様を定義することでこうした状況を解消しようという取り組みで面白いですね。
Design goalsとして
- human-readable
- streamable
- machine-readable
- schema-aware
- extensible
の5つが挙げられています。ファイル形式としてはJSONとかではなく、JUnitと同じくXMLではあるんですね 👀
JSON is less verbose than XML, but the latter provides more expressive ways to define schemas. Moreover, XML has typed extensions built-in via the use of multiple schemas. Thus, the new formats use XML with accompanying XML schemas.
世の中のエコシステムがどれだけここに乗っかっていくか気になるところですが、まずは本家JUnit自体がサポートしたということで、着目していきたいですね。
SwiftUI.ViewとUIHostingControllerの初期化順序の調整
UIHostingControllerを使ってSwiftUI.View
を表示する時に、Viewの引数に渡すクロージャーの中でViewControllerを使いたいことが稀によくある(本当に?)。
素直に考えるとこうなる。
// 順序的にvcを使えない let view = FooView(onTap: { // vcで何かしたい }) let vc = UIHostingController(rootView: view)
少し頭を捻るとこうなる。
let view = FooView() let vc = UIHostingController(rootView: view) vc.rootView.onTap = { [weak vc] in ... }
UIHostingController.rootView
は public var rootView: Content
なので、rootViewのプロパティを変更することはできる。だけどViewのプロパティを自分で書き換えるのはなんだかしっくりこない。
rootViewがvarということは別のことが考えられる。
let vc = UIHostingController<FooView?>(rootView: nil) let view = FooView(onTap: { [weak vc] in ... }) vc.rootView = view
rootViewをnilで初期化しておき、後で差し替える作戦。 open class UIHostingController<Content> : UIViewController where Content : View
という定義に対してnilを渡せるのか?という気持ちに一瞬なるが、これはOptional(とNever)がconditonal conformanceでViewに準拠しているのでvalidである。
extension Optional : View where Wrapped : View { public typealias Body = Never }
という感じで、rootViewにnilを渡すことによる遅延初期化を上手く使っていきましょうというお話でした。
RenovateのHandlebarsテンプレート用の`lowercase`ヘルパーを追加した
RenovateとHandlebarsのテンプレート
Renovateでは様々な設定オプションや正規表現を用いるregex
managerでHandlebarsのテンプレートを使用できる箇所があります。
例えばPRのdescriptionの内容を追加できるprBodyNotes
などがありますが、RenovateがPRを作る際のブランチ名を決めるbranchName
もデフォルト値は次のようなテンプレートになっています。
"{{{branchPrefix}}}{{{additionalBranchPrefix}}}{{{branchTopic}}}"
次のリンクはテンプレート中で使えるフィールド(変数)のドキュメントです。
repology
datasourceと大文字小文字
さて、最近regex
managerと組み合わせてrepology
datasourceを使いたいことがありました。repology
datasourceの中で使われているRepologyのSingle project API*1 https://repology.org/api/v1/project/$project
の問い合わせでは、プロジェクト名が全て小文字である必要があります。
https://repology.org/api/v1/project/firefox
なら結果が得られますが、https://repology.org/api/v1/project/Firefox
だと結果は空になってしまいます。
正規表現で何かしらのファイルからキャプチャできるライブラリーの名称に大文字が含まれていると、そのままではrepology
datasourceで問い合わせることができません。またRenovateが組み込みで提供するHandlebarsのヘルパー(テンプレート内で使える関数のようなもの)は当時、次の6つでした。
stringToPrettyJSON
encodeURIComponent
replace
containsString
and
or
replace
を複数回使って個々のライブラリーを列挙するわけにもいかないので、lowercase
ヘルパーを追加しようと思い立ちました。まずIssueを立てて方針に問題がないかを確認してから、自分で実装まで行いました。
実装自体はJavaScriptのtoLowerCase()
を呼んでヘルパーとして登録するだけで至極簡単ですね。
まとめ
これで packageNameTemplate: "{{{lowercase depName}}}"
のようにして、キャプチャしたライブラリー名を小文字に変換してRepologyへの問い合わせに使えるようになりました。めでたしめでたし。
regex
managerとrepology
datasourceの組み合わせについては、後日また実用例の紹介をする予定です。乞うご期待(自分へのプレッシャー)。
Renovateの「About us」というドキュメントにcontributorとしてノミネートされた
はい。
RenovateのAbout usというドキュメントにcontributorとして名前を載せていただきました。今後もできる範囲で貢献していければと思います!https://t.co/3qjx9Fa446https://t.co/cH06beUtqy
— Sho Ikeda (@ikesyo) 2022年5月27日
こちらのページからご確認いただけます。
これまでのPR一覧を見ると、社内でRenovateを導入していくにあたってGradleとかsbt周りをいじったり、ちょっとしたリファクタリングなどもやっていた感じですね。今後も何かしら少しずつ貢献していきたい所存です。
あわせて読みたい
Accompanistの開発版のバージョニングが独特で、Renovateと相性が悪い
Accompanistとは
Google公式の、Jetpack Composeを補完する拡張ライブラリーです。
Accompanistの開発版のバージョニング
直近の0.24系の開発版が次のようになっている。
- v0.24.0-alpha
- v0.24.1-alpha
- v0.24.2-alpha
- v0.24.3-alpha
- v0.24.4-alpha
- v0.24.5-alpha
- v0.24.6-alpha
- v0.24.7-alpha
- v0.24.8-beta(ここからbetaに変わった)
- v0.24.9-beta
- v0.24.10-beta
SemVer的に見ると、v0.24.z
のz部分はmajor・minor・patchのpatch部分に見えるが、Accompanistは現状SemVer(のpatch)を使ったバージョニングではなさそうで、z部分は開発版として何番目のリリースか、という数字でしかないようである。alphaの中で何番目、betaの中で何番目、という情報はなく、開発版全体として何番目で、その時の状態がalphaかbetaなのかが最後に付く、となっている。
SemVerなら
- v0.24-alpha.1
- v0.24-alpha.2
- v0.24-alpha.3
- v0.24-alpha.4
- v0.24-alpha.5
- v0.24-alpha.6
- v0.24-alpha.7
- v0.24-alpha.8
- v0.24-beta.1
- v0.24-beta.2
- v0.24-beta.3
という付け方になるであろう。
Renovateでの開発版のバージョンへの更新
RenovateはデフォルトでignoreUnstable
という設定がオンになっていて、安定版から開発版(非安定版)への更新がされないようになっている。ただし例外があって、現在使用中のバージョンが安定版ではなく開発版であり、更新対象となる最新版とmajor・minor・patchが一致する場合は(SemVerでいうところのpre-release version以降だけが更新されたら)更新してくれる。
By default, Renovate won't update any package versions to unstable versions (e.g.
4.0.0-rc3
) unless the current version has the samemajor.minor.patch
and was already unstable (e.g. it was already on4.0.0-rc2
).
ここでAccompanistの開発版のバージョニングに戻ってみると、SemVerの観点では毎回patch部分が更新されていることになる。従って先述の条件を満たさず、例えば v0.24.8-beta
から v0.24.10-beta
への更新のPRは用意されないことになっている。この、ある開発版から、major・minor・patchが一致しない別の開発版への更新が起きないことはドキュメントにも明記されている。
Renovate will also not "jump" unstable versions automatically, e.g. if you are on
4.0.0-rc2
and newer versions4.0.0
and4.1.0-alpha.1
exist then Renovate will update you to4.0.0
only.
ということで、このようなバージョニングでも開発版に追従していきたい時*1は ignoreUnstable
を明示的にオフ(false
)にしましょう。
"packageRules": [ { "matchPackagePatterns": ["^com\\.google\\.accompanist:"], "ignoreUnstable": false } ]