Swiftにcpan相当のツールはあるのか?
モダンプログラミング言語は、
- 書いて
- 実行する
だけではなく、
- 機能をライブラリ
(library) にまとめ、 - モジュール
(module) として公開し - それを援用する
機能まで備えているものです。Perlのcpanを嚆矢に、
あります! Swift 3以降は。その名もSwiftPackage Manager。それ以前から同様の機能を提供するサードパーティー製のツールとしてはCarthageやCocoaPodsが存在していましたが、
ライブラリを作る
ではさっそく、
$ mkdir FizzBuzz
$ cd FizzBuzz
$ swift package init # --type=library
……(中略)……
Creating library package: FizzBuzz
Creating Package.swift
Creating README.md
Creating .gitignore
Creating Sources/
Creating Sources/FizzBuzz/FizzBuzz.swift
Creating Tests/
Creating Tests/LinuxMain.swift
Creating Tests/FizzBuzzTests/
Creating Tests/FizzBuzzTests/FizzBuzzTests.swift
Creating Tests/FizzBuzzTests/XCTestManifests.swift
実はこの時点でビルドしてテストできる状態になっています。
$ swift build
で、
Compile Swift Module 'FizzBuzz' (1 sources)
……(中略)……
$ swift test
となり、
Compile Swift Module 'FizzBuzzTests' (2 sources) Linking ./.build/x86_64-apple-macosx10.10/debug/FizzBuzzPackageTests.xctest/Contents/MacOS/ FizzBuzzPackageTests Test Suite 'All tests' started at 2018-05-21 07:23:10.304 Test Suite 'FizzBuzzPackageTests.xctest' started at 2018-05-21 07:23:10.305 Test Suite 'FizzBuzzTests' started at 2018-05-21 07:23:10.305 Test Case '-[FizzBuzzTests.FizzBuzzTests testExample]' started. Test Case '-[FizzBuzzTests.FizzBuzzTests testExample]' passed (0.085 seconds). Test Suite 'FizzBuzzTests' passed at 2018-05-21 07:23:10.390. Executed 1 test, with 0 failures (0 unexpected) in 0.085 (0.085) seconds Test Suite 'FizzBuzzPackageTests.xctest' passed at 2018-05-21 07:23:10.390. Executed 1 test, with 0 failures (0 unexpected) in 0.085 (0.085) seconds Test Suite 'All tests' passed at 2018-05-21 07:23:10.390. Executed 1 test, with 0 failures (0 unexpected) in 0.085 (0.085) seconds
しかしこの状態ではとくに何もしていません。実際にFizzBuzzしてみましょう。
$ swift package generate-xcodeproj
とすると Xcode Project が生成されるので、
$ open FizzBuzz.xcodeproj
で開きます

まずはモジュールを書き直しましょう。リスト1のとおり上書きします。Int
にfizzbuzz
プロパティを追加するだけの簡単なモジュールです。
extension Int {
public var fizzbuzz:String {
let fb = ("Fizz", "Buzz")
switch (self % 3, self % 5) {
case (0, 0) : return fb.0 + fb.1
case (0, _) : return fb.0
case (_, 0) : return fb.1
default : return "\(self)"
}
}
}
テストも書き直しましょう
final class FizzBuzzTests: XCTestCase {
func test0() { XCTAssertEqual(0.fizzbuzz, "FizzBuzz") }
func test1() { XCTAssertEqual(1.fizzbuzz, "1") }
func test2() { XCTAssertEqual(2.fizzbuzz, "2") }
func test3() { XCTAssertEqual(3.fizzbuzz, "Fizz") }
func test4() { XCTAssertEqual(4.fizzbuzz, "4") }
func test5() { XCTAssertEqual(5.fizzbuzz, "Buzz") }
}
今度は、

とりあえず最低限文化的なFizzBuzzモジュールができたので、
% git init % git add . % git commit -am 'version 0.0.0' % git tag 0.0.0
これで、
ライブラリを使う――ローカル編
今度はそれをほかから使ってみましょう。
$ cd ../
でFizzBuzzディレクトリを抜けたら、
$ mkdir FizzBuzzRun $ cd FizzBuzzRun $ swift package init --type=executable
--type=executable
に注目。デフォルトだとlibrary
で、
ここで、Package.
ファイルを編集します。これこそがSwift Package Managerの心臓部。空([]
)だったdependencies:
に、
dependencies: [
.package(url: "../FizzBuzz", from:"0.0.0")
]
を追加し、.target
の中に"FizzBuzz"
を追加します。
.target(
name: "FizzBuzzRun",
dependencies: ["FizzBuzz"]),
これで、main.
でimport FizzBuzz
する準備が整いました。
Sources/
import FizzBuzz
_ = (1...30).map{ print($0.fizzbuzz) }
あとはswift run
するだけです
% swift run
Fetching /Users/dankogai/Desktop/swift-38/FizzBuzz
Cloning /Users/dankogai/Desktop/swift-38/FizzBuzz
Resolving /Users/dankogai/Desktop/swift-38/FizzBuzz at 0.0.0
Compile Swift Module 'FizzBuzz' (1 sources)
Compile Swift Module 'FizzBuzzRun' (1 sources)
Linking ./.build/x86_64-apple-macosx10.10/debug/FizzBuzzRun
1
2
Fizz
4
Buzz
……(中略)……
23
Fizz
Buzz
26
Fizz
28
29
FizzBuzz
ライブラリを使う――リモート編
簡単ですね。しかし簡単とは言っても、
ではこれをもとにFizzBuzzするWebサーバを作りたいとします。http://
ならFizzBuzz
、http://
なら1
……程度の簡単なサーバですが、
Swift Package Managerはまさにそういうときのためにあるのです。まずはFizzBuzzRun
同様にFizzBuzzServer
という実行ファイルパッケージを生成します。
$ cd .. $ mkdir FizzBuzzServer $ cd FizzBuzzServer $ swift package init --type=executable
そしてPackage.
を編集します。
.package(url: "../FizzBuzz", from: "0.0.0"),
.package(url: "https://github.com/
PerfectlySoft/Perfect-HTTPServer.git", from:"3.0.0"),
このhttps://
に、.target
のdependencies:
にもその旨を追加しておきましょう。
.target(
name: "FizzBuzzServer",
dependencies: ["FizzBuzz","PerfectHTTPServer"]),
あとはmain.
を適宜書き換えるだけです。あえて説明抜きで全体をリスト3に示します。
import PerfectLib
import PerfectHTTP
import PerfectHTTPServer
import FizzBuzz
var routes = Routes()
routes.add(method: .get, uri: "/**") { q, r in
if let n = Int(q.path.dropFirst()) {
r.setBody(string: n.fizzbuzz)
} else {
r.status = .notFound
r.setBody(string: "\(q.path) : not found")
}
r.completed()
}
try! HTTPServer.launch(name: "localhost", port: 8181, routes: routes)
Ruby on RailsやPHPのLaravelを使っている人であれば、
swift run
[INFO] Starting HTTP server localhoston :::8181
Port 8181が待ち受け状態になりました。この状態で適当なブラウザでhttp://
にアクセスしてみましょう。FizzBuzz
と表示されましたか?
Swiftからもアクセスしてみましょう。URLにアクセスしてその中身を表示する程度であれば、
import Foundation
for n in (1...30) {
let url = URL(string:"http://localhost:8181/\(n)")!
let str = try! String(contentsOf:url)
print(str)
}
そうそう。Webサーバを止めなければいけませんね。通常のシェルプログラム同様、
次回予告
というわけで駆け足でSwift Package Managerを使ってみました。{cpan,pip,gem,npm}のユーザであれば見よう見まねで使える気がしてきたのではないでしょうか? 次回のWWDC特集をはさんで、
本誌最新号をチェック!
Software Design 2022年9月号
2022年8月18日発売
B5判/
定価1,342円
- 第1特集
MySQL アプリ開発者の必修5科目
不意なトラブルに困らないためのRDB基礎知識 - 第2特集
「知りたい」 「使いたい」 「発信したい」 をかなえる
OSSソースコードリーディングのススメ - 特別企画
企業のシステムを支えるOSとエコシステムの全貌
[特別企画] Red Hat Enterprise Linux 9最新ガイド - 短期連載
今さら聞けないSSH
[前編] リモートログインとコマンドの実行 - 短期連載
MySQLで学ぶ文字コード
[最終回] 文字コードのハマりどころTips集 - 短期連載
新生「Ansible」 徹底解説
[4] Playbookの実行環境 (基礎編)