Crates.ioにクレートを公開する
プロジェクトの依存としてcrates.ioのパッケージを使用しましたが、 自分のパッケージを公開することで他の人とコードを共有することもできます。 crates.ioのクレート登録所は、自分のパッケージのソースコードを配布するので、 主にオープンソースのコードをホストします。
RustとCargoは、公開したパッケージを人が使用し、そもそも見つけやすくしてくれる機能を有しています。 これらの機能の一部を次に語り、そして、パッケージの公開方法を説明します。
役に立つドキュメンテーションコメントを行う
パッケージを正確にドキュメントすることで、他のユーザがパッケージを使用する方法や、いつ使用すべきかを理解する手助けをすることになるので、
ドキュメンテーションを書くことに時間を費やす価値があります。第3章で、2連スラッシュ、//
でRustのコードにコメントをつける方法を議論しました。
Rustには、ドキュメンテーション用のコメントも用意されていて、便利なことにドキュメンテーションコメントとして知られ、
HTMLドキュメントを生成します。クレートの実装法とは対照的にクレートの使用法を知ることに興味のあるプログラマ向けの、
公開API用のドキュメンテーションコメントの中身をこのHTMLは表示します。
ドキュメンテーションコメントは、2つではなく、3連スラッシュ、///
を使用し、テキストを整形するMarkdown記法もサポートしています。
ドキュメント対象の要素の直前にドキュメンテーションコメントを配置してください。
リスト14-1は、my_crate
という名のクレートのadd_one
関数用のドキュメンテーションコメントを示しています:
ファイル名: src/lib.rs
/// Adds one to the number given.
/// 与えられた数値に1を足す。
///
/// # Examples
///
/// ```
/// let five = 5;
///
/// assert_eq!(6, my_crate::add_one(5));
/// ```
pub fn add_one(x: i32) -> i32 {
x + 1
}
ここで、add_one
関数がすることの説明を与え、Examples
というタイトルでセクションを開始し、
add_one
関数の使用法を模擬するコードを提供しています。このドキュメンテーションコメントからcargo doc
を実行することで、
HTMLドキュメントを生成することができます。このコマンドはコンパイラとともに配布されているrustdoc
ツールを実行し、
生成されたHTMLドキュメントをtarget/docディレクトリに配置します。
利便性のために、cargo doc --open
を走らせれば、現在のクレートのドキュメント用のHTML(と、
自分のクレートが依存している全てのドキュメント)を構築し、その結果をWebブラウザで開きます。
add_one
関数まで下り、図14-1に示したように、ドキュメンテーションコメントのテキストがどう描画されるかを確認しましょう:
よく使われるセクション
# Examples
マークダウンのタイトルをリスト14-1で使用し、「例」というタイトルのセクションをHTMLに生成しました。
こちらがこれ以外にドキュメントでよくクレート筆者が使用するセクションです:
- Panics: ドキュメント対象の関数が
panic!
する可能性のある筋書きです。プログラムをパニックさせたくない関数の使用者は、 これらの状況で関数が呼ばれないことを確かめる必要があります。 - Errors: 関数が
Result
を返すなら、起きうるエラーの種類とどんな条件がそれらのエラーを引き起こす可能性があるのか解説すると、 呼び出し側の役に立つので、エラーの種類によって処理するコードを変えて書くことができます。 - Safety: 関数が呼び出すのに
unsafe
(unsafeについては第19章で議論します)なら、 関数がunsafeな理由を説明し、関数が呼び出し元に保持していると期待する不変条件を講義するセクションがあるべきです。
多くのドキュメンテーションコメントでは、これら全てのセクションが必要になることはありませんが、 これは自分のコードを呼び出している人が知りたいと思うコードの方向性を思い出させてくれるいいチェックリストになります。
テストとしてのドキュメンテーションコメント
ドキュメンテーションコメントに例のコードブロックを追加すると、ライブラリの使用方法のデモに役立ち、
おまけもついてきます: cargo test
を走らせると、ドキュメントのコード例をテストとして実行するのです!
例付きのドキュメントに上回るものはありません。しかし、ドキュメントが書かれてからコードが変更されたがために、
動かない例がついているよりも悪いものもありません。リスト14-1からadd_one
関数のドキュメンテーションとともに、
cargo test
を走らせたら、テスト結果に以下のような区域が見られます:
Doc-tests my_crate
running 1 test
test src/lib.rs - add_one (line 5) ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
さて、例のassert_eq!
がパニックするように、関数か例を変更し、再度cargo test
を実行したら、
docテストが、例とコードがお互いに同期されていないことを捕捉するところを目撃するでしょう!
含まれている要素にコメントする
docコメントの別スタイル、//!
は、コメントに続く要素にドキュメンテーションを付け加えるのではなく、
コメントを含む要素にドキュメンテーションを付け加えます。典型的には、クレートのルートファイル(慣例的には、src/lib.rs)内部や、
モジュールの内部で使用して、クレートやモジュール全体にドキュメントをつけます。
例えば、add_one
関数を含むmy_crate
クレートの目的を解説するドキュメンテーションを追加したいのなら、
//!
で始まるドキュメンテーションコメントをsrc/lib.rsファイルの先頭につけることができます。
リスト14-2に示したようにですね:
ファイル名: src/lib.rs
//! # My Crate
//!
//! `my_crate` is a collection of utilities to make performing certain
//! calculations more convenient.
//! #自分のクレート
//!
//! `my_crate`は、ユーティリティの集まりであり、特定の計算をより便利に行うことができます。
/// Adds one to the number given.
// --snip--
//!
で始まる最後の行のあとにコードがないことに注目してください。///
ではなく、//!
でコメントを開始しているので、
このコメントに続く要素ではなく、このコメントを含む要素にドキュメントをつけているわけです。
今回の場合、このコメントを含む要素はsrc/lib.rsファイルであり、クレートのルートです。
これらのコメントは、クレート全体を解説しています。
cargo doc --open
を実行すると、これらのコメントは、my_crate
のドキュメントの最初のページ、
クレートの公開要素のリストの上部に表示されます。図14-2のようにですね:
要素内のドキュメンテーションコメントは、特にクレートやモジュールを解説するのに有用です。 コンテナの全体の目的を説明し、クレートの使用者がクレートの体系を理解する手助けをするのに使用してください。
pub use
で便利な公開APIをエクスポートする
第7章において、mod
キーワードを使用してモジュールにコードを体系化する方法、pub
キーワードで要素を公開にする方法、
use
キーワードで要素をスコープに導入する方法について講義しました。しかしながら、クレートの開発中に、
自分にとって意味のある構造は、ユーザにはあまり便利ではない可能性があります。複数階層を含む階層で、
自分の構造体を体系化したくなるかもしれませんが、それから階層の深いところで定義した型を使用したい人は、
型が存在することを見つけ出すのに困難を伴う可能性もあります。また、そのような人は、
use my_crate::UsefulType
の代わりにuse my_crate::some_module::another_module::UsefulType;
と入力するのを煩わしく感じる可能性もあります。
自分の公開APIの構造は、クレートを公開する際に考慮すべき点です。自分のクレートを使用したい人は、 自分よりもその構造に馴染みがないですし、クレートのモジュール階層が大きければ、使用したい部分を見つけるのが困難になる可能性があります。
嬉しいお知らせは、構造が他人が他のライブラリから使用するのに便利ではない場合、内部的な体系を再構築する必要はないということです:
代わりに、要素を再エクスポートし、pub use
で自分の非公開構造とは異なる公開構造にできます。
再エクスポートは、ある場所の公開要素を一つ取り、別の場所で定義されているかのように別の場所で公開します。
例えば、芸術的な概念をモデル化するためにart
という名のライブラリを作ったとしましょう。
このライブラリ内には、2つのモジュールがあります: PrimaryColor
とSecondaryColor
という名前の2つのenumを含む、
kinds
モジュールとmix
という関数を含むutils
モジュールです。リスト14-3のようにですね:
ファイル名: src/lib.rs
//! # Art
//!
//! A library for modeling artistic concepts.
//! #芸術
//!
//! 芸術的な概念をモデル化するライブラリ。
pub mod kinds {
/// The primary colors according to the RYB color model.
/// RYBカラーモデルによる主色
pub enum PrimaryColor {
Red,
Yellow,
Blue,
}
/// The secondary colors according to the RYB color model.
/// RYBカラーモデルによる副色
pub enum SecondaryColor {
Orange,
Green,
Purple,
}
}
pub mod utils {
use kinds::*;
/// Combines two primary colors in equal amounts to create
/// a secondary color.
///2つの主色を同じ割合で混合し、副色にする
pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor {
// --snip--
}
}
図14-3は、cargo doc
により生成されるこのクレートのドキュメンテーションの最初のページがどんな見た目になるか示しています:
PrimaryColor
型もSecondaryColor
型も、mix
関数もトップページには列挙されていないことに注意してください。
kinds
とutils
をクリックしなければ、参照することができません。
このライブラリに依存する別のクレートは、現在定義されているモジュール構造を指定して、
art
の要素をインポートするuse
文が必要になるでしょう。リスト14-4は、
art
クレートからPrimaryColor
とmix
要素を使用するクレートの例を示しています:
ファイル名: src/main.rs
extern crate art;
use art::kinds::PrimaryColor;
use art::utils::mix;
fn main() {
let red = PrimaryColor::Red;
let yellow = PrimaryColor::Yellow;
mix(red, yellow);
}
リスト14-4はart
クレートを使用していますが、このコードの筆者は、PrimaryColor
がkinds
モジュールにあり、
mix
がutils
モジュールにあることを理解しなければなりませんでした。art
クレートのモジュール構造は、
art
クレートの使用者よりも、art
クレートに取り組む開発者などに関係が深いです。
クレートの一部をkinds
モジュールとutils
モジュールに体系化する内部構造は、art
クレートの使用方法を理解しようとする人には、
何も役に立つ情報を含んでいません。代わりに、開発者がどこを見るべきか計算する必要があるので、
art
クレートのモジュール構造は混乱を招き、また、開発者はモジュール名をuse
文で指定しなければならないので、
この構造は不便です。
公開APIから内部体系を除去するために、リスト14-3のart
クレートコードを変更し、pub use
文を追加して、
最上位で要素を再エクスポートすることができます。リスト14-5みたいにですね:
ファイル名: src/lib.rs
//! # Art
//!
//! A library for modeling artistic concepts.
pub use kinds::PrimaryColor;
pub use kinds::SecondaryColor;
pub use utils::mix;
pub mod kinds {
// --snip--
}
pub mod utils {
// --snip--
}
このクレートに対してcargo doc
が生成するAPIドキュメンテーションは、これで図14-4のようにトップページに再エクスポートを列挙しリンクするので、
PrimaryColor
型とSecondaryColor
型とmix
関数を見つけやすくします。
art
クレートのユーザは、それでも、リスト14-4にデモされているように、リスト14-3の内部構造を見て使用することもできますし、
リスト14-5のより便利な構造を使用することもできます。リスト14-6に示したようにですね:
ファイル名: src/main.rs
extern crate art;
use art::PrimaryColor;
use art::mix;
fn main() {
// --snip--
}
ネストされたモジュールがたくさんあるような場合、最上位階層でpub use
により型を再エクスポートすることは、
クレートの使用者の経験に大きな違いを生みます。
役に立つAPI構造を作ることは、科学というよりも芸術の領域であり、ユーザにとって何が最善のAPIなのか、
探究するために繰り返してみることができます。pub use
は、内部的なクレート構造に柔軟性をもたらし、
その内部構造をユーザに提示する構造から切り離してくれます。インストールしてある他のクレートを見て、
内部構造が公開APIと異なっているか確認してみてください。
Crates.ioのアカウントをセットアップする
クレートを公開する前に、crates.ioのアカウントを作成し、
APIトークンを取得する必要があります。そうするには、crates.ioのホームページを訪れ、
Githubアカウントでログインしてください。(現状は、Githubアカウントがなければなりませんが、
いずれは他の方法でもアカウントを作成できるようになる可能性があります。)ログインしたら、
https://crates.io/me/で自分のアカウントの設定に行き、
APIキーを取り扱ってください。そして、cargo login
コマンドをAPIキーとともに実行してください。
以下のようにですね:
$ cargo login abcdefghijklmnopqrstuvwxyz012345
このコマンドは、CargoにAPIトークンを知らせ、~/.cargo/credentialsにローカルに保存します。 このトークンは、秘密です: 他人とは共有しないでください。なんらかの理由で他人と実際に共有してしまったら、 古いものを破棄してcrates.ioで新しいトークンを生成するべきです。
新しいクレートにメタデータを追加する
アカウントはできたので、公開したいクレートがあるとしましょう。公開前に、
Cargo.tomlファイルの[package]
セクションに追加することでクレートにメタデータを追加する必要があるでしょう。
クレートには、独自の名前が必要でしょう。クレートをローカルで作成している間、
クレートの名前はなんでもいい状態でした。ところが、crates.ioのクレート名は、
最初に来たもの勝ちの精神で付与されていますので、一旦クレート名が取られてしまったら、
その名前のクレートを他の人が公開することは絶対できません。もう使われているか、
サイトで使いたい名前を検索してください。まだなら、Cargo.tomlファイルの[package]
以下の名前を編集して、
名前を公開用に使ってください。以下のように:
ファイル名: Cargo.toml
[package]
name = "guessing_game"
たとえ、独自の名前を選択していたとしても、この時点でcargo publish
を実行すると、警告とエラーが出ます:
$ cargo publish
Updating registry `https://github.com/rust-lang/crates.io-index`
warning: manifest has no description, license, license-file, documentation,
homepage or repository.
(警告: マニフェストに説明、ライセンス、ライセンスファイル、ドキュメンテーション、ホームページ、
リポジトリがありません)
--snip--
error: api errors: missing or empty metadata fields: description, license.
(エラー: APIエラー: 存在しないメタデータフィールド: description, license)
原因は、大事な情報を一部入れていないからです: 説明とライセンスは、 他の人があなたのクレートは何をし、どんな条件の元で使っていいのかを知るために必要なのです。 このエラーを解消するには、Cargo.tomlファイルにこの情報を入れ込む必要があります。
1文か2文程度の説明をつけてください。これは、検索結果に表示されますからね。
license
フィールドには、ライセンス識別子を与える必要があります。
Linux団体のSoftware Package Data Exchange(SPDX)に、この値に使用できる識別子が列挙されています。
例えば、自分のクレートをMITライセンスでライセンスするためには、
MIT
識別子を追加してください:
ファイル名: Cargo.toml
[package]
name = "guessing_game"
license = "MIT"
SPDXに出現しないライセンスを使用したい場合、そのライセンスをファイルに配置し、
プロジェクトにそのファイルを含め、それからlicense
キーを使う代わりに、
そのファイルの名前を指定するのにlicense-file
を使う必要があります。
どのライセンスが自分のプロジェクトに相応しいかというガイドは、
この本の範疇を超えています。Rustコミュニティの多くの人間は、MIT OR Apache-2.0
のデュアルライセンスを使用することで、
Rust自体と同じようにプロジェクトをライセンスします。この実践は、OR
で区切られる複数のライセンス識別子を指定して、
プロジェクトに複数のライセンスを持たせることもできることを模擬しています。
独自の名前、バージョン、クレート作成時にcargo new
が追加した筆者の詳細、説明、ライセンスが追加され、
公開準備のできたプロジェクト用のCargo.toml
ファイルは以下のような見た目になっていることでしょう:
ファイル名: Cargo.toml
[package]
name = "guessing_game"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
description = "A fun game where you guess what number the computer has chosen."
(コンピュータが選択した数字を言い当てる面白いゲーム)
license = "MIT OR Apache-2.0"
[dependencies]
Cargoのドキュメンテーションには、 指定して他人が発見し、より容易くクレートを使用できることを保証する他のメタデータが解説されています。
Crates.ioに公開する
アカウントを作成し、APIトークンを保存し、クレートの名前を決め、必要なメタデータを指定したので、 公開する準備が整いました!クレートを公開すると、特定のバージョンが、 crates.ioに他の人が使用できるようにアップロードされます。
公開は永久なので、クレートの公開時には気をつけてください。バージョンは絶対に上書きできず、 コードも削除できません。crates.ioの一つの主な目標が、 crates.ioのクレートに依存している全てのプロジェクトのビルドが、 動き続けるようにコードの永久アーカイブとして機能することなのです。バージョン削除を可能にしてしまうと、 その目標を達成するのが不可能になってしまいます。ですが、公開できるクレートバージョンの数に制限はありません。
再度cargo publish
コマンドを実行してください。今度は成功するはずです:
$ cargo publish
Updating registry `https://github.com/rust-lang/crates.io-index`
Packaging guessing_game v0.1.0 (file:///projects/guessing_game)
Verifying guessing_game v0.1.0 (file:///projects/guessing_game)
Compiling guessing_game v0.1.0
(file:///projects/guessing_game/target/package/guessing_game-0.1.0)
Finished dev [unoptimized + debuginfo] target(s) in 0.19 secs
Uploading guessing_game v0.1.0 (file:///projects/guessing_game)
おめでとうございます!Rustコミュニティとコードを共有し、誰でもあなたのクレートを依存として簡単に追加できます。
既存のクレートの新バージョンを公開する
クレートに変更を行い、新バージョンをリリースする準備ができたら、
Cargo.tomlファイルに指定されたversion
の値を変更し、再公開します。
セマンティックバージョンルールを使用して加えた変更の種類に基づいて次の適切なバージョン番号を決定してください。
そして、cargo publish
を実行し、新バージョンをアップロードします。
cargo yank
でCrates.ioからバージョンを削除する
以前のバージョンのクレートを削除することはできないものの、将来のプロジェクトがこれに新たに依存することを防ぐことはできます。 これは、なんらかの理由により、クレートバージョンが壊れている場合に有用です。そのような場面において、 Cargoはクレートバージョンの 取り下げ(yank) をサポートしています。
バージョンを取り下げると、既存のプロジェクトは、引き続きダウンロードしたりそのバージョンに依存したりしつづけられますが、 新規プロジェクトが新しくそのバージョンに依存しだすことは防止されます。つまるところ、取り下げは、 すでにCargo.lockが存在するプロジェクトは壊さないが、将来的に生成されたCargo.lockファイルは 取り下げられたバージョンを使わない、ということを意味します。
あるバージョンのクレートを取り下げるには、cargo yank
を実行し、取り下げたいバージョンを指定します:
$ cargo yank --vers 1.0.1
--undo
をコマンドに付与することで、取り下げを取り消し、再度あるバージョンにプロジェクトを依存させ始めることもできます:
$ cargo yank --vers 1.0.1 --undo
取り下げは、コードの削除は一切しません。例として、取り下げ機能は、誤ってアップロードされた秘密鍵を削除するためのものではありません。 もしそうなってしまったら、即座に秘密鍵をリセットしなければなりません。