Swift Packagesでライブラリを自作する方法

「Swift Packagesによるライブラリの作成方法」は4部構成です。
記事を順番に読み進めると、Swift Packagesでライブラリを自作して公開できるようになります。

- 第1部: Swift Packagesでライブラリを自作する　__←イマココ__
- 第2部: [自作パッケージをSwift Package Indexに追加する](https://qiita.com/uhooi/items/689801dad2cf2e0a37b4)
- 第3部: [自作パッケージをCocoaPodsに追加する](https://qiita.com/uhooi/items/5ce382cb0c1c6bc018d9)
- 第4部: [自作パッケージをCarthageに対応する](https://qiita.com/uhooi/items/ada0a02737ecb2d1c8d7)

## はじめに

Swift製のライブラリを自作する実績を解除したかったので、かんたんなライブラリを自作することにしました。

## 「Swift Packages」とは？

Swiftのコードを再利用可能にするコンポーネントです。
Swift Packages（以下「パッケージ」と呼ぶ）にすることで、Swift製のライブラリやCLIツールをかんたんに自作できます。

## 環境

- OS： macOS Big Sur 11.4
- Xcode：12.4 (12D4e)
- Swift：5.3.2
- swift-tools：5.3

## パッケージの作成方法

例として「swift-string-transform」というリポジトリに「StringTransform」というパッケージを作成します。

### GitHubにリポジトリを作成する

GitHubにリポジトリを作成します。
パブリックにすることで誰でも使え、GitHub Actionsを無料で使えるのでオススメです。

リポジトリを作成したらクローンしてブランチを切ります。

```shell-session
$ git clone https://github.com/uhooi/swift-string-transform.git
$ cd swift-string-transform
$ git switch -c feature/create_package
```

### パッケージの基盤を生成する

`swift package init` コマンドを実行するだけで、パッケージの基盤が生成されます。

デフォルトだとパッケージ名がカレントディレクトリ名になるようなので、私は `--name` オプションでパッケージの名前を指定しています。

`--type` オプションでパッケージの種類を指定します。
今回はライブラリを作成するので `library` とします。
CLIツールを作成する場合は `executable` を指定します。

```shell-session
$ swift package init --name StringTransform --type library
Creating library package: StringTransform
Creating Package.swift
Creating Sources/
Creating Sources/StringTransform/StringTransform.swift
Creating Tests/
Creating Tests/LinuxMain.swift
Creating Tests/StringTransformTests/
Creating Tests/StringTransformTests/StringTransformTests.swift
Creating Tests/StringTransformTests/XCTestManifests.swift
```

上記の他に `README.md` と `.gitignore` が存在しない場合は生成されます。

### .gitignoreを作成する

Gitリポジトリを作成した場合、 `.gitignore` を更新します。

私は「swift-argument-parser」を参考に更新しました。
https://github.com/apple/swift-argument-parser/blob/0.4.3/.gitignore

```:.gitignore
.DS_Store
/.build
/Packages
/*.xcodeproj
.swiftpm
.*.sw?
```

### CIを構築する（任意）

できる限り実装前にCIを構築します。
GitHub Actionsを使えば一瞬で構築できます。

```yaml:.github/workflows/main.yml
name: CI

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

env:
  DEVELOPER_DIR: /Applications/Xcode_12.4.app

jobs:
  build:
    runs-on: macOS-latest
    steps:
    - uses: actions/checkout@v2
    - name: Build
      run: swift build -v

  test:
    runs-on: macOS-latest
    steps:
    - uses: actions/checkout@v2
    - name: Test
      run: swift test -v
```

これで `main` ブランチへPRを出すときとプッシュするとき（PRのマージを含む）に、自動でビルドとテストが実行されます。

### ライブラリを実装する

CI環境が整ったら、ライブラリを実装します。

Finderで `Package.swift` をダブルクリックするか、以下のコマンドを実行することでXcodeが起動します。

```shell-session
$ open Package.swift
```

`Sources` フォルダに製品コード、 `Tests` フォルダにテストコードを実装します。

製品コードでユーザーが呼び出すクラスなどに `public` を付け忘れないよう注意です。
`public` なクラスやメソッドにはドキュメンテーションコメントを付けると親切です。

私は `String` の拡張メソッドを2つ実装しました。

```swift:Sources/StringTransform/String+Transform.swift
import Foundation

extension String {
    
    /// Transform Hiragana to Katakana.
    /// - Returns: The transformed string.
    /// - SeeAlso: ``toHiragana()``
    public func toKatakana() -> String? {
        applyingTransform(.hiraganaToKatakana, reverse: false)
    }
    
    /// Transform Katakana to Hiragana.
    /// - Returns: The transformed string.
    /// - SeeAlso: ``toKatakana()``
    public func toHiragana() -> String? {
        applyingTransform(.hiraganaToKatakana, reverse: true)
    }
}
```

### 対応プラットフォームを明記する（任意）

`Package.swift` の詳細な説明は省略しますが、プラットフォームのみ説明します。

`platforms:` に、対応するプラットフォームの最低バージョンを記述します。
省略するとデフォルト値が使われます。

私はソースコードを見て対応プラットフォームのバージョンがわかるように、すべて明記しています。

```swift:Package.swift
// ...
let package = Package(
    // ...
    platforms: [
        .iOS(.v9),
        .macOS(.v10_11),
        .tvOS(.v9),
        .watchOS(.v2),
    ],
    // ...
)
```

### READMEを編集する（任意）

最後にREADMEを編集します。
最低限「ライブラリのインストール方法」と「ライブラリの使い方」があると親切です。

あとはバッジを付けまくるとカッコいいのでオススメです。
参考: https://github.com/uhooi/swift-string-transform/blob/main/README.md
![スクリーンショット 2021-06-19 18.43.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138245/88ffc8c8-1210-844c-e742-664bc8836b66.png)

すべて英語で書くと、カッコいいし日本語が読めない人にも伝わるのでオススメです。

### 変更をコミットしてプッシュする

変更をコミットしてGitHubのリモートリポジトリへプッシュします。

```shell-session
$ git add -A
$ git commit -m 'Create package'
$ git push origin feature/create_package
```

GitHubで `main` ブランチへ向かってPRを作成し、マージします。

### リリースする

GitHubから手動でリリースします。
タグには `v` などのプリフィックスを付けず、 [セマンティックバージョニング](https://semver.org/lang/ja/) に準拠したバージョンを指定します。

初回は `0.1.0` でリリースするのがいいと思います。
参考: https://github.com/uhooi/swift-string-transform/releases/tag/0.1.0

これで自作パッケージのリリースが完了です :tada:

## パッケージの使い方

自作パッケージを使う方法を説明します。

### パッケージを追加する

iOSアプリ開発などXcodeプロジェクトで自作パッケージを使う場合、Xcodeから追加します。
詳細は [公式ドキュメント](https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app) をご参照ください。

他のパッケージから自作パッケージを使う場合、 `Package.swift` に依存を追加します。

```diff_swift:Package.swift
let package = Package(
    dependencies: [
+       .package(url: "https://github.com/uhooi/swift-string-transform", .upToNextMajor(from: "0.1.0")),
    ],
    targets: [
        .target(
            name: "<your-target-name>",
+           dependencies: ["StringTransform"]),
    ]
)
```

### パッケージのコードを呼び出す

パッケージを追加したら、 `import {ライブラリ名}` で自作ライブラリのコードを呼び出せます。

```swift
import StringTransform

"てすと".toKatakana() // "テスト"
"テスト".toHiragana() // "てすと"
```

## おわりに

Swift Packagesでライブラリを自作する実績を解除できました！
文字列を変換するだけのシンプルなライブラリですが、よかったらスターを付けて、実際に使ってみてください :relaxed:

https://github.com/uhooi/swift-string-transform

みなさんの素晴らしい自作ライブラリにも期待しています :eyes:

## 参考リンク

- [Swift Packages | Apple Developer Documentation](https://developer.apple.com/documentation/swift_packages)
- [swift-package-manager/Usage.md at main · apple/swift-package-manager](https://github.com/apple/swift-package-manager/blob/main/Documentation/Usage.md)
- https://twitter.com/the_uhooi/status/1403524915777523714?s=20