ペンギン村 Tech Blog

技術をこよなく愛するエンジニア集団が在住するペンギン村から、世界へ役立つ(かもしれない)技術情報を発信する技術系ブログです。某アラレちゃんが済む村とは一切関係ありません。んちゃ!

SwiftPrettyPrint 1.1.0 をリリースしました。

先週、 SwiftPrettyPrint の 1.1.0 をリリースしました。このリリースには以下の2つのインテグレーションが含まれています。

  • LLDB
  • Combine

本記事では、その2つの機能について解説したいと思います。

そもそも SwiftPrettyPrint って?

SwiftPrettyPrint はその名の通り、Swift で pretty-print するためのデバッグ支援系のライブラリで、標準の print よりもスマートに出力することを目的としています。

github.com

これは例を見たほうが早いかもしれません。例えば、以下は Dictionary を標準関数である print debugPrint dump でそれぞれ出力したものです。

let dictionary = [
    “one”: 1,
    “two”: nil,
]

print(dictionary)
// ["two": nil, "one": Optional(1)]

debugPrint(dictionary)
// ["two": nil, "one": Optional(1)]

dump(dictionary)
// ▿ 2 key/value pairs
//   ▿ (2 elements)
//     - key: "two"
//     - value: nil
//   ▿ (2 elements)
//     - key: "one"
//     ▿ value: Optional(1)
//       - some: 1

この例では要素が小さいためそれほど読みづらくは感じませんが、Dictionary の構造が大きくなるにつれて読みづらさが増すのは容易に想像がつくと思います。

SwiftPrettyPrint を利用すると以下のように出力されます。

Pretty.print(dictionary)
// ["one": 1, "two": nil]

Pretty.prettyPrint(dictionary)
// [
//     "one": 1,
//     "two": nil
// ]

Swift でリテラルとして記述する時と同様の形式で出力されるため、視認性の良い出力になっているのが分かります。

デバッグ中に print や LLDB の po コマンドで値を出力したものの、出力内容が読みづらくてストレスを感じた経験を持つ方は少なくないと思いますが、そのようなストレスを無くすというのがこのライブラリの大きな目標となっています。

ユースケースにあわせて利用しやすいように、以下のようなオプションも用意していますが、その詳細については README に譲りたいと思います。

  • 出力時の共通ラベル
  • インデントサイズの変更
  • ログとして出力
  • 演算子ベースの API

LLDB 統合

前述したように、SwiftPrettyPrint は主にデバッグに使用されることを想定しているため、最初の正式リリースである 1.0.0 から LLDB で使用しやすい API を用意していました。

(lldb) e pp >>> dictionary
[
    “one”: 1,
    “two”: nil
]

しかし、これは微妙に覚えにくいもので、 LLDB において使用頻度の高い po コマンドに比べるとタイプが面倒であるというのも事実でした。

そこで 1.1.0 では公式として LLDB 統合を提供することに決定しました。

ローカルの ~/.lldbinit に以下を追加するか、

command regex _p  's/(.+)/e -l swift -o -- Pretty.print(%1)/'
command regex _pp 's/(.+)/e -l swift -o -- Pretty.prettyPrint(%1)/'

lowmad という LLDB スクリプトを管理する CLI ツールを利用して、以下のコマンドからインストールできます。

$ lowmad install https://github.com/YusukeHosonuma/SwiftPrettyPrint.git

これにより _p または _pp コマンドで利用できるようになります。

(lldb) _p dictionary
["one": 1, "two": nil]

(lldb) _pp dictionary
[
    "one": 1,
    "two": nil
]

Combine 統合

Combine にはデバッグを支援するための print オペレーターが標準で備わっていますが、以下のような欠点があると感じていました。

  • pretty-print されない
  • 出力タイミングを限定したい場合に handleEvents を利用する必要がある

そこでよりベターな print オペレーターという位置づけを目指して、SwiftPrettyPrint として Combine 統合を提供することに決定しました。

[[1, 2], [3, 4]]
    .publisher
    .prettyPrint("🍌", when: [.output, .completion], format: .multiline)
    .sink { _ in }
    .store(in: &cancellables)
// =>
// 🍌: receive value: [1, 2]
// 🍌: receive value: [3, 4]
// 🍌: receive finished

基本的な使い方は print オペレーターと同様ですが、オプショナルな引数として出力タイミングを限定する when: 、出力フォーマットを指定する format: が用意されています。

またエイリアスAPI として、単数行で出力する p 、複数行で出力する pp オペレーターも用意されています。

[[1, 2], [3, 4]]
    .publisher
    .p("🍎")  // Output as single-line
    .pp("🍊") // Output as multiline
    .sink { _ in }
    .store(in: &cancellables)

おわりに

そんなわけで、SwiftPrettyPrint 1.1.0 に含まれる LLDB と Combine への統合について解説しました。

実は SwiftPrettyPrint はツイッターでの周知しかしておらず、公式として記事を書くのはこれが初となります。もし便利だと感じたら、知り合いの iOS エンジニアの方などにもシェアいただければ開発者冥利につきます。

ペンギン村 OSS チーム一同(文:tobi462

P.S.

SwiftPrettyPrint はインストール手段として CocoaPods / Carthage / Swift Package Manager の3種類を提供していますが、現時点では CocoaPods を推奨(Recommended)としています。

pod "SwiftPrettyPrint", "~> 1.1.0", :configuration => "Debug" # enabled on `Debug` build only

これは条件付き依存ライブラリとして簡潔にセットアップできるのが CocoaPods のみであるためですが、Swift Package Manager でもこうした機能が追加される見込みです。

github.com

この機能が実装され、Xcode でも利用できるようになれば、推奨するパッケージマネージャは Swift Package Manager になる予定です。