パクレットの概要

パクレットとはWolframの機能の一つであり,発見したり,インストールしたり,更新したり,Wolfram環境にシームレスに統合したりすることができるようにパッケージ化されている.パクレットにはWolfram言語ファイル,LibraryLinkライブラリ,パレットやスタイルシートのようなフロントエンドリソース,J/Linkで使うJavaライブラリ,ドキュメントノートブック等多様なコンテンツが含まれている.パクレットを形成する必須の要素はPacletInfo.wlファイルである.これはパクレット,その必要条件,Wolfram環境をどのように拡張するかを記述するメタデータの小さくて簡単なファイルである.
使用中のパクレットはPacletInfo.wlファイルの他,1つ以上のコンテンツファイルまたはサブディレクトリで構成される.パクレットは単独の.pacletファイルに圧縮することができ,配布やインストールに便利であるが,.pacletファイルにパッケージ化する必要はない.
パクレットは製品をコンポーネントに分けたり,通常の製品リリースサイクル外の更新やバグ修正を提供したりするために,Wolframシステムによって内部的に使われる.Mathematica 13のレイアウトには270個を超えるパクレットが含まれている.
パクレットシステムは文書化されユーザに公開されているので,自分自身の製品やパッケージを作成して配布することができる.Wolframはユーザからの投稿を受け付けるPaclet Repositoryを構築して,簡単に見付けられ使用可能なパクレットの活発な環境を作りたいと希望している.
PacletInfo.wlファイル
PacletInfo.wlファイルは,パクレットおよびそれが提供するリソースを記述するWolfram言語のメタデータの簡単なファイルである.PacletInfo.wlファイルがあることによってディレクトリやファイルの集合がパクレットになるのである.このファイルはPacletInfo.mという名前にしてもよい.
次はFileUtilitiesという名前の非常に単純な新規パクレットのPacletInfo.wlファイルである.このパクレットは単独の実装ファイルFileUtilities.wlで,数個の便利な関数を含む"FileUtilities`"コンテキストを定義する.パクレットのユーザは通常通りNeeds[FileUtilities`]を使って,セッションでパッケージをロードする.
PacletObject[<|
"Name" "FileUtilities",
"Version" "1.0",
"Extensions" {
{"Kernel", "Root" "Kernel", "Context" "FileUtilities`"}
}
|>]
"Name""Version"のフィールドはすべてのパクレットで必要であり,これだけが必須のフィールドである("Name""Version"しかないパクレットはたいして便利ではないが)."Extensions"フィールドは,そのパクレットが提供するリソースのタイプ,つまりパクレットがどのようにシステムを拡張するかを記述する場所である.パッケージがGetまたはNeedsでロードされるように定義する.wlまたは.mファイルを含むパクレットは,"Kernel"拡張を指定し,それが提供するコンテキストを列挙しなければならない.前の例にあるように,Wolframシステムには,ユーザがNeeds["FileUtilities`"]を実行すると,このパクレットはそのコンテキストに対応する.wlファイルを提供するということが分かっている.
どのパクレットにもバージョン番号がある.パクレットシステムは複数バージョンのパクレットをサポートするように設計されているが,デフォルトでは最高のバージョン番号を持つものを使用する.他の人が使用するパクレットをリリースしようとしている場合は,毎回バージョン番号を確実に更新しなければならない.そうしないと新規バージョンが以前のバージョンとは異なるものと認識されない.
PacletInfo.wlファイルにはWolfram言語シンタックスでコメントを加えることができる.
パクレット機能の本質は,PacletInfo.wlファイルを介してパクレットが提供するコンテンツを宣言することであり,パクレットがインストールされると,このタイプのコンテンツがシステムによって自動的に見付けられる.ユーザはパクレットをインストールする以外,通常何もする必要はない.パクレットが自身をシステムに「織り込み」,リソースが見付かるようにする.パレットがメニューに表示され,ドキュメントがヘルプビューアに表示され,コンテキストがNeedsでロードされる等するようになる.
Wolfram Engineが$Pathの値に基づいて多くのタイプのリソースを探すことをご存じかもしれない.パクレットシステムは,$Pathの手動変更を過去のものにするような,ずっと強力なルックアップ機構を備えている.Wolfram Engineがリソースを調べるとき,$Pathがまだ使われるが,最初に常にパクレットシステムに問い合せ,パクレットがリソースを提供しない場合だけ$Pathが使われる.
バージョン12.1からの変更 バージョン12.1ではPacletInfo.wlファイル形式に大きな変更が加わった.以前は式の頭部はPacletObjectではなくPacletであり,コンテンツはAssociationで囲まれていなかった.また規則の左辺は通常シンボル(文字列でも可能)であった.古い形式のファイルはまだサポートされるが,新規のパクレット開発には推奨されない.以下に示すのは,以前のPacletInfo.wlファイルの形式である. Paclet[ Name "FileUtilities", Version "1.0", Extensions { {"Kernel", Root "Kernel", Context "FileUtilities`"} } ]
PacletInfoフィールド
PacletInfo.wlファイルは多数のフィールドをサポートする.フィールドは常に"FieldName" -> valueという形式であり,valueは通常1つの文字列,または規則,リスト,文字列等の簡単な要素のリストである.任意のWolfram言語式をフィールドの値にすることはできない.これらのファイルはカーネルに読み込まれたときに評価されないため,評価して希望の値になるようなものを入れることはできない.このファイルの値は文字でなければならない.
"Name"フィールドは必須である.この名前によってパクレットが認知される.これはPacletInstallPacletFind等の関数で使われる.パクレット名には好きな文字が使えるが,ハイフン(-)はお勧めしない.必要な場合は単語を分けるものとしてアンダースコア(_)を1つ使うとよい.パクレット名は一意で意味のある識別子として以外は重要性はない.例えば,パクレット名はパクレットが提供するコンテキストやファイルの名前と通常一致しているが,その必要はない.
"Version"フィールドも必須である.バージョンは数字(例:1.0)ではなく文字列(例:"1.0")である.バージョンは5桁までのブロック("1.0.0.0.1234")にすることができ,バージョンの比較は通常想定される通りである("1.10"は"1.9"より大きい)."a"のような数字ではない文字は含むことができないが,将来的には可能になる予定である.
このフィールドを使うと,パクレットがどのバージョンのWolfram言語に対応しているかを指定することができる.このフィールドを空欄にしておくとすべてのバージョンに対応するものと想定される.パクレットの"WolframVersion"指定が現在実行中のインスタンスに一致しない場合,そのセッションではパクレットが不可視になる.この指定には,以下に示すように*,+,-,コンマが使える.
"13+"
13.0.0以降のすべてのバージョン
"13.1.0-"
13.1.0以前のすべてのバージョン
"13.*"
バージョン13(および13.1等のマイナーバージョン)のみ
"13"
バージョン13.xxのみ("13.*"と同じ)
"12.3,13.0"
バージョン12.3と13.0のみ
WolframVersionの対応指定
このフィールドは,パクレットが対応するオペレーティングシステムを指定することができる.このフィールドを空欄にしておくとパクレットがすべてのシステムに対応するものと想定される.パクレットの"SystemID"指定が現在実行中のインスタンスに一致しない場合,そのセッションではパクレットが不可視になる.値には単一の文字列(例:"MacOSX-x86-64")またはリスト(例:{"Windows-x86-64", "Linux-x86-64"})が使える.
"Kernel"拡張の付いたパクレットは,そのコンテキストをどのようにロードするかを指定することができる.デフォルトはManualであり,ユーザは自分のコンテキストでGetまたはNeedsを呼び出す必要がある."Startup"を指定するとカーネルが起動するたびにコンテキストをロードすることができる.Automaticでは,エキスポートされたシンボルのいずれかが初めて使われるときにコンテキストを自動ロードするよう指定できる.このシステムの詳細は後で説明する.ほとんどの開発者はこれはこのままにしており,デフォルトのManualのロード動作を信頼している.
Updating->Automaticと指定すると,パクレットがセッションで初めて使われるときに自己更新を行う.更新が利用できない場合は,このチェックは迅速でネットワークに触れない.更新が実行されるのはパクレットによって提供されるコンテキストが最初にロードされるときなので,自己更新は"Kernel"拡張を持つパクレットだけで利用できる."FrontEnd""Documentation"等,他のタイプの拡張を持つパクレットの場合は,パクレットのリソースが使われるまで更新のチェックは行われない.
"Root"フィールドは,パクレットの場所に対してパクレットのコンテンツが置かれる場所を指定する.パクレットの場所はPacletInfo.wlファイルがあるディレクトリと定義される."Root"のディフォルト値は"."であり,パクレットのコンテンツがPacletInfo.wlファイルを含むのと同じディレクトリにあることを意味する.PacletInfo.wlファイルがメインのコンテンツディレクトリの外にある等別のファイル構成を希望する場合は,"Root"フィールドを使ってそのコンテンツディレクトリを指定することができる.ほとんどの開発者はこのフィールドを使わない.ここで扱っておりほぼ指定されることのないパクレット"Root"と,後で説明する重要でよく使われるそれぞれの拡張の"Root"フィールドを混同しないようにしなければならない.
"Qualifier"フィールドは,1つのパクレットを別々のオペレーティングシステム用等に複数のパクレットに分けなければならない複雑な状況で使われる.例えば大きい実行ファイルまたは大きいLibraryLinkライブラリを含むパクレットがあり,それぞれのSystemIDに対して異なるものがあるとする.それぞれのSystemIDについてのサブディレクトリを含む1つのパクレットを作ることもできるが,これではそれぞれのシステムについてそれぞれのバイナリのコピーを含む,非常に大なものとなる.ユーザが使っていないオペレーティングシステムのために数十メガバイトのライブラリをダウンロードするようなことはしたくない.その代りに,パクレットを,意図したSystemIDに適したパクレットに分割することができる.この場合の詳細は後に説明する.
これらのフィールドはインストールされているパクレットの動作には影響しないが,ユーザにパクレットの用途,作成者,詳細やサポートの入手場所についての情報を提供するために使うことができる.
名前が文字列,値が文字列または文字列,規則,リスト等の簡単な要素のリストであれば,好きなフィールドにすることができる.Custom fieldsはパクレットシステムで直接使われることはないが,Wolfram言語コードを使って値を抽出することができる.
パクレットの拡張
パクレットはWolfram環境をさまざまな多くの方法で拡張することができる.パクレットの"Extensions"フィールドはパクレットシステムに,パクレットがどのようにWolframシステムを拡張するかを指示する.
パクレットシステムは基本的に宣言型である.PacletInfo.wlを介してパクレットが提供する要素を宣言すると,パクレットシステムはシステムの操作によってこれらの要素が確実に見つかるようにする.ある意味,パクレットは受動的なものである.パクレットはセッションにロードする必要がないからである.一旦インストールさえしてしまえば,それ以降パクレットはシステムに入り込み,パクレットが提供するリソースが自動的に見付けられるようになる.
パクレットシステムが拡張によって指定されたリソースを探すとき,以下のコンポーネントに基づいて完全パスを作成する:
paclet location / paclet root / extension root / resource path
前で述べた通り,パクレットには互換性を指定するトップレベルの"WolframVersion"フィールドおよび"SystemID"フィールドを入れることができる.これら2つのフィールドは拡張の中にも現れ,特定のシステムで可視となる拡張を制御することができる.例えば,実行しているSystemIDの種類によって異なるバージョンの.wlファイルがある場合,それぞれのシステムについて異なるサブディレクトリを指定する,異なる"SystemID"フィールドと異なる"Root"フィールドを持つ複数の拡張を持つことができる.
各拡張には,"Root""SystemID""Language""WolframVersion"のような異なる特性を使って,複数のタイプを指定することができる.
拡張のタイプ

Kernel

パクレットが提供することのできる最も一般的なリソースは,NeedsまたはGetでロードできるWolfram言語パッケージ(.wl,.mファイルまたはこれらのファイルの集合)であろう.これは"Kernel"拡張で指定する.
PacletObject[<|
"Name" "MyPaclet",
"Version" "0.0.1",
"Extensions" {
{"Kernel", "Root" "Kernel", "Context" {"MyPaclet`"}},
(* ... その他の拡張 *)
}
|>]
このようなPacletInfo.wlファイルでは,パクレットは以下のようなレイアウトであると想定される:

1.gif

Kernelサブディレクトリに.wlおよび.mを持つことは慣例として意図されたものであるが必須ではない."Kernel"は"Kernel"拡張のデフォルトの"Root"ではないため,Kernelサブディレクトリを使う場合は,上で示した通り,拡張の指定に"Root"->"Kernel"を入れなければならない..wlファイルをKernelサブディレクトリではなく,PacletInfo.wlファイルの隣に置きたい場合は,Kernel拡張で"Root"指定を"."にする必要がある.
コンテキストがパクレット名に一致する必要はない.

Subcontexts

メインの.wlファイルが"MyContext`"を定義し,サブコンテキスト"MyContext`SomeSubcontext`"を定義する別の.wlファイルであるSomeSubcontext.wlがある場合,SomeSubcontext.wlが自動的に見付けられるようにするためにはこれをどこに置けばよいであろうか.つまり,"MyContext`SomeSubcontext`"の検索がSomeSubcontext.wlファイルに解決するには,このファイルはどこにあるべきだろうか.答はMyContext.wlファイルの隣である.パクレットシステムはKernelディレクトリで"MyContext`SomeSubcontext`"をSomeSubcontext.wlファイルに解決することをサポートする."Kernel"拡張で"MyContext`"を宣言することで,"MyContext`"をKernelディレクトリに解決し,SomeSubcontextの部分はSomeSubcontext.wlファイルに解決すると考えることができる."MyContext`SomeSubcontext`AnotherSubcontext`"のような,より深くネストされたサブコンテキストの場合は,AnotherSubcontext.mファイルはKernel/SomeSubcontextディレクトリになければならない.サブコンテキストの階層はディレクトリの改装に対応している必要があるが,最初の部分"MyContext`"は"free"でありKernelディレクトリ自体にマップしている.

init.mファイル

旧式のアプリケーションの多くは,コンテキストに対応するファイルを見付けるための特別なカーネルの機能を使う.コンテキストが$Path上のファイルの場所にマップしていても,適切に名前の付いた.wlファイルまたは.mファイルがそこにない場合,カーネルはinit.mファイルを含むKernelサブディレクトリを探しそのファイルを読み込む.init.mファイルは通常Get[MyContext`MyContext`]のようなことだけを指示する.二重コンテキストはMyContext親ディレクトリの中のMyContext.mファイルに正しくマップする.これは,コンテキスト"MyContext`"が$Path上のMyContextディレクトリの中のMyContext.mファイルにマップできるようにする技である.このタイプのレイアウトはパクレットでサポートされているが,全く必要のないものであり,使わないことを強くお勧めする."Kernel"拡張の前の例では,「二重コンテキスト」でシステムを操作する必要はない.コンテキスト"MyContext`"は直接Kernel/MyContext.mファイルにマップするのでinit.mファイルは必要ない.

Documentation

パクレットは通常Wolframスタイルのドキュメントを提供する.そのようなドキュメントがある場合は"Documentation"拡張を宣言する."Documentation"拡張は標準の"Root"フィールド,"SystemID"フィールド,"WolframVersion"フィールドの他,"Language"フィールドもサポートする.ほとんどのパクレット作成者はこれらのフィールドを必要とせず,慣習的なドキュメントレイアウトに依存する:
PacletObject[<|
"Name" "MyPaclet",
"Version" "0.0.1",
"Extensions" {
{"Documentation"},
(* ... その他の拡張 *)
}
|>]
前のようにPacletInfo.wlファイルを使うと,パクレットは次のようなレイアウトを持つことが想定される:

2.gif

英語以外の言語のドキュメントがある場合は,英語の他,あるは代りに言語指定のサブディレクトリが必要になる.
前の例では,Englishディレクトリの正確なコンテンツが指定されていない.ドキュメントのオーサリングと構築は複雑なので,後のセクションで詳しく説明する.

FrontEnd

パクレットに,ノートブックフロントエンドで使われるリソース(スタイルシート,パレット,Bitmap,TextResources等)が含まれている場合,パクレットは"FrontEnd"拡張を宣言する必要がある.パクレットの中のスタイルシートやパレットは,フロントエンドメニューの適切な場所に自動的に現れる.
PacletObject[<|
"Name" "MyPaclet",
"Version" "0.0.1",
"Extensions" {
{"FrontEnd"},
(* ... その他の拡張 *)
}
|>]
この拡張に対してカスタムの"Root"を指定することもできるが,ほとんどの作成者は以下のようなデフォルトのレイアウトを使う:

3.gif

これはフロントエンド自体で見られるレイアウトと同じである:$InstallationDirectory/SystemFiles/FrontEnd.

Path

パクレットは,パスベースの検索のようなもので見付けなければならないファイルがあることを宣言することができる.パスの最初の部分はパクレット名である.
PacletObject[<|
"Name" "MyPaclet",
"Version" "0.0.1",
"Extensions" {
{"Path"},
(* ... その他の拡張 *)
}
|>]
パクレットは次のようになる.

4.gif

ファイルパスを想定する関数(GetOpenReadFindFileImport等)では,"MyPaclet/SomeFile.txt"の中で渡すことができる.パスの最初の部分はパクレット名と一致していなければならない.SomeFile.txtファイルがStuffという名前のサブディレクトリにある場合は,"MyPaclet/Stuff/SomeFile.txt"を指定する.

LibraryLink

パクレットにLibraryLinkライブラリが含まれる場合は,"LibraryLink"拡張を指定する:
PacletObject[<|
"Name" "MyPaclet",
"Version" "0.0.1",
"Extensions" {
{"LibraryLink"},
(* ... その他の拡張 *)
}
|>]
ほとんどのパクレット作成者はLibraryLinkが想定するデフォルトのレイアウトに依存する.パクレットのレイアウトは以下のようになる.

5.gif

このレイアウトではLibraryLoad["MyLibrary"]は自動的に動作する.パクレットにはないライブラリを見付けるためにLibraryLinkが使う値である$LibraryPathを変更する必要はない.

JLink

パクレットにJ/Linkで使うJavaクラスが含まれている場合は,"JLink"拡張を指定する:
PacletObject[<|
"Name" "MyPaclet",
"Version" "0.0.1",
"Extensions" {
{"JLink"},
(* ... その他の拡張 *)
}
|>]
ほとんどのパクレット作成者は,Javaディレクトリである"JLink"拡張のデフォルトのルートに依存する.パクレットは以下のようになる.

6.gif

このレイアウトでは,J/Linkはjarファイルに自動的にクラスを見付けることができる.J/LinkのAddToClassPath関数を呼び出す必要はない.

アセット

これまでに説明した拡張タイプはすべて自動的にシステムに「組み込まれる」ものである.パクレットで提供される.wlファイルを見付けるために,特別なパクレット認識の呼出し,例えばNeedsを使う必要はない.しかし,パクレットで提供したいもので,Wolframシステムで組込みの操作がないタイプのものも多くある."Asset"拡張は,"AssetLocation"セレクタを使って名前で見付けることができる任意のタイプのリソースを指定する一般的な方法である.
パクレットの中に,StartProcessで起動する実行ファイルがあるとする.一番よい方法は,"Asset"拡張を使って名前をその実行ファイルに割り当て,名前を使ってそのパスを検索するというものである.この方法を使うと,パッケージコードの中にハードコードされたパスを入れなくて済む.リソース名が実際のファイルの場所にマップされるのはPacletInfo.wlファイルの中だけであり,場所やファイル名を更新するのに変更を加える必要があるのはそこだけである.また,さまざまなSystemIDやWolframVersionのそれぞれに対する複数の実行ファイルを提供するのも簡単になる.
以下は,3つの異なるSystemIDに対する実行ファイルを含むパクレットの例である:
PacletObject[<|
"Name" "MyPaclet",
"Version" "0.0.1",
"Extensions" {
{"Asset", "Root" "Mac", "SystemID" "MacOSX-x86-64", "Assets" {{"my_exe", "MyExe.app"}}},
{"Asset", "Root" "Windows", "SystemID" "Windows-x86-64", "Assets" {{"my_exe", "MyExe.exe"}}},
{"Asset", "Root" "Linux", "SystemID" "Linux-x86-64", "Assets" {{"my_exe", "MyExe"}}},
(* ... その他の拡張 *)
}
|>]
"Asset"拡張の中の"Assets"フィールドは,文字列識別子を文字列のパスにマップするペアのリストである.パスは"subdir/MyExe.app"のようにディレクトリコンポーネントを含んでいてもよい.
パクレットレイアウトは以下のように見える.

7.gif

実行ファイルへの完全パスを取得して起動したい場合は,パッケージコードでPacletObject"AssetLocation"セレクタを使う:
返されたパスはオペレーティングシステムによって異なる場合がある.パクレットレイアウト内で実行ファイルの名前を変えたり実行ファイルを移動させたりする場合でもコードを変更する必要はない.

カスタム拡張

自分でカスタム拡張を作成することもできる.これを行うことで「プラグイン」タイプのシステムが実装できる.例えば,Wolfram言語で書かれたデジタルフィルタのためのフレームワークを書いているとする.パクレットはこれらのフィルタを操作するためのコードを提供し,それ自身のフィルタも提供するであろうが,他のパクレットがランタイムで自動的に見付けられるフィルタを提供できることを望んでいるとする.このとき,例えば"DigitalFilters"というカスタム拡張を作成し,そのようなフィルタを提供するパクレットがそれを使うようにすることができる:
PacletObject[<|
"Name" "MyPaclet",
"Version" "0.0.1",
"Extensions" {
{"DigitalFilters", "Root" "Filters"},
(* ... その他の拡張 *)
}
|>]
このパクレットには1つ以上の.wlファイルを含むFiltersディレクトリがある:

8.gif

フレームワークのコードはPacletManager`PacletResources関数を使って,"DigitalFilters"拡張を含むすべてのパクレットを見付けることができる.
PacletManager`PacletResourcesはリストのペア{{_PacletObject, {/full/path/to/extension/root}}, ...}を返す.それからすべての拡張のルートへのパスを抽出して列挙し,それらのディレクトリに.wl(またはその他の)ファイルをすべてロードすることができる.
PacletResources"System`"コンテキストではなく"PacletManager`"コンテキストにある理由は,単に設計がまだ実験的だからである.この目的のための機能は,最終的にパクレットシステムのメインのインターフェースの一部になるが,現段階ではPacletManager`PacletResourcesを使うことができる(この関数は将来的にもサポートされる).
複雑なパクレットの例
以下は,これまでに説明した多くの拡張および機能を持つ仮定上の複雑なパクレットである.このパクレットおよびこれがどのようにファイルのレイアウトと一致するかが分かれば,パクレット拡張がよく理解できているということになる.
PacletObject[<|
"Name" "MyPaclet",
"Version" "2.0.1.0.16382",
"SystemID" {"MacOSX-x86-64", "Windows-x86-64"}, (* このパクレットはMacとWindowsのユーザにだけ見える. *)
"WolframVersion" "12.1+", (* このパクレットはWolfram Engineのバージョン12以降にのみ認識される. *)
"Creator" "tgayley@wolfram.com",
"Description" "A demonstration paclet with no actual content.",
"Extensions" {
(* この拡張は12.1にだけ適切な.mファイルのバージョンを提供する. *)
{"Kernel", "Root" "Kernel121", "WolframVersion" "12.1", "Context" {"MyPackage`", "MyOtherPackage`"}},
(* この拡張は12.2以降にだけ適切な.mファイルのバージョンを提供する. *)
{"Kernel", "Root" "Kernel", "WolframVersion" "12.2+", "Context" {"MyPackage`", "MyOtherPackage`"}},
{"LibraryLink"},
{"Documentation"},
{"FrontEnd"},
{"Asset", "Root" -> "Assets", "Assets" {{"sun", "images/sun.jpg"}, {"moon", "images/moon.jpg"}}}
}
|>]
以下はマッチするファイルレイアウトである:

9.gif

インストールと更新
PacletInstallはパクレットをインストールし更新する関数である.ここで,この関数はWolframパクレットサーバで時々更新されるWolframパクレットをインストールする:
結果はPacletObject式である.これはパクレットのWolfram言語表現である.すでにBenchmarkパクレットをインストールしており,サーバ上にその更新があったとしたら,その更新はコマンドでダウンロード・インストールされていたはずである.パクレットがマシン上にあり更新があるかどうか不明な場合,PacletInstallは直ちに戻る.したがって,別のパクレットを使うコードを書いているなら,そのパクレットでPacletInstallを呼び出すとシステムやユーザに不必要に高価な操作をする心配がなくなる.
パクレットがインストールされていることを確かめたいが更新が利用できるからと言って更新したくはない場合は,AllowVersionUpdate -> Falseオプションを使うことができる.
パクレットは,パクレットシステムによって特別な場所にインストールされ,管理される:
これは通常の手順ではないが,パクレットディレクトリをレポジトリにコピーしたり削除したりすることができる.この変更は次にカーネルが再起動するまで検出されないが,PacletDataRebuild[]を呼び出すとパクレットシステムは手動で行われた変更を直ちに検出する.

.pacletファイルまたはURLからのインストール

PacletInstall["PacletName"]はパクレットのインストールや更新に非常に便利であるが,パクレットサーバに配備されたパクレットにしか使えない.後で説明するように,自分のパクレットサーバを構築するのは非常に簡単ではあるが,パクレットを.pacletファイルとしてファイルシステムまたはWeb(Wolfram Cloudを含む)から配布することもできる..pacletファイルは,後で説明するCreatePacletArchive関数で生成したパクレットディレクトリの圧縮版である..pacletファイルはパクレットサーバに配備されるものであるが,直接インストールすることもできる:
パクレットディレクトリは$UserBasePacletsDirectory/Repositoryに手動でコピーすることもできる.この場合,パクレットは次にカーネルが再起動するまで検出されないが,PacletDataRebuild[]を呼び出すとパクレットシステムはこの変更を直ちに検出する.

PacletSites

PacletSitesはシステムにとって既知のパクレットサイトのリストを返す関数である.現時点ではほとんどのユーザにとってこれはWolframの公開パクレットサーバ1つである:
PacletSiteRegisterおよびPacletSiteUnregisterを使うと,既知のパクレットサイトのこのリストを管理することができる.メインのWolframサイトを削除しようとしても,次のセッションの開始時に復元される.PacletSiteRegisterおよびPacletSiteUnregisterを使うのは,例えば所属機関が構築した追加のパクレットサーバについてシステムに知らせたいことがあるからである.このようなパクレットサイトを構築する方法は後で説明する.

PacletSiteUpdate

PacletInstallを呼び出してパクレットを入手または更新するとき,この関数はどのようにしてサーバ上に更新が利用できるかどうかを知るのであろうか.PacletInstallが毎回サーバをチェックするため高価な操作になっていると思う人が多いが,そうではない.PacletInstallはサーバ上にどのパクレットがあるかについてのデータのローカルキャッシュをチェックするだけである.そのデータのローカルキャッシュはPacletSiteUpdateを呼び出すことで更新される:
この操作は現在位置およびダウンロード速度によって1秒以上かかる.
PacletSiteUpdateは内部的に少なくとも数日につき1回,いろいろなときに呼び出されるが,一般にはそれよりも頻度が高い.どのパクレットが利用可能かについての最新データを確実に入手したい場合は自分でPacletSiteUpdateを呼び出すことができる.パクレットがつい最近サーバに配備されたことが分かっているなら,PacletSiteUpdateを呼び出してシステムに新バージョンについて確実に知らせることができる.
先に述べた通り,PacletInstallを呼び出しても通常PacletSiteUpdateを呼び出しはしないが,リクエストされたパクレットがローカルにインストールされておらずサーバデータのキャッシュにない場合は例外である.この場合は,潜在的に古いキャッシュ情報に基づいて失敗する代りに,内部的にPacletSiteUpdate呼び出されパクレットが利用可能かどうかを調べる.
パクレットを見付ける
パクレットはシステムに組み込まれるように設計されているので,パクレットに対する直接の操作はほぼ必要ない.例えば,Mathematica 13のレイアウトには何百ものパクレットが含まれているが,それらはシステムのサイレントコンポーネントなので,使うのにパクレットシステムの機能を知っている必要はないのである.しかし,システムのパクレットを調べて操作を実行すると便利なこともある.これは自分のパクレットを作ろうとしている開発者に必要となることが多い.

PacletFind

PacletFindはシステムにインストールされているパクレットを探す関数である.これはPacletObject式のリストを返す.PacletObjectはWolfram言語でのパクレット表現であり,さまざまなパクレットの特性を調べるのに使うことができる.PacletFindは,どのパクレットを返すかを制御する特性のAssociationを取る.
次のマシンには3つの異なるバージョンのNeuralNetworksパクレットがある:
パクレットシステムはバージョン番号が一番大きいパクレット(リストは順に並んでいる)だけを使うが,PacletFindは現行のシステムに対応するパクレットすべてを返す.3つの異なるバージョンがあるのは,一つはMathematica 13のレイアウトにあり,他の2つはMathematicaの古いバージョンのアップデートとしてダウンロードされてローカルレポジトリにあるからである.これらのパクレットはまだMathematica 13に対応するので出力に現れるが,13.0.3が一番大きい番号なのでこれが使われる.
以下はパクレットの場所である.古い2つはインストールされたパクレットのローカルレポジトリにあることが分かる.
デフォルトでは,PacletFindは現行のSystemIDとWolfram Engineのバージョンに対応するパクレットだけを返すが,オプションの"SystemID"->All"WolframVersion"->Allを使うと,対応していないものも表示できる.
ワイルドカード * を使うとパターンにマッチする名前のパクレットが表示できる:
以下は名前がNで始まり"Documentation"拡張を持つパクレットすべてを探す:

PacletFindRemote

PacletFindRemoteはパクレットサーバで利用可能なパクレットを見付ける関数である.
上の出力は,いくつかのバージョンのNeuralNetworksが対応し利用可能であることを示しているがPacletInstall["NeuralNetworks"]が使われるとどれもダウンロードされない.これらはすべてすでにインストールされているものよりもバージョン番号が低いからである.PacletFindRemoteはユーザが呼び出す必要があまりない関数であるが,パクレット開発者はこれを使うことで,サーバ上で何が利用可能かを知り,指定のパクレットに利用可能な更新があるかどうかを調べることができる.
パクレットについての情報を得る
特定のパクレットについての情報を得る方法はいくつかある.ほとんどの場合,最初のステップは知りたいパクレットを表すPacletObject式を得ることである.PacletObject式はPacletFind関数を使って得ることができる:
PacletFindは並べられたリストを返すので,システムで使われている最もバージョン番号が大きいパクレットがリストの最初にある.アクティブなパクレットだけが必要な場合はPacletObject["pacletname"]を使うことができる:
PacletObject["pacletname"]First[PacletFind["pacletname"]]と同じである.
Information関数を使うとかなり完全なデータを簡単に得ることができる:
絞り込んで呼び出すこともできる:
パクレットに関する情報の抽出の多くはPacletObjectに特性抽出シンタックスを適用して行うことができる:
複数の特性を一度に抽出することができる:
パクレットの開発
パクレットは,特化されたレポジトリ(Function Repository,Data Repository等)に入るほど単純ではない,Wolframシステムの機能のほとんどに対して理想的なパッケージ形式である.
PacletToolsパクレットは,ユーザがパクレットを作成する補助をするために提供されているが,手作業で簡単に作成することもできる.以下は1つの.wlファイルを含む簡単なパクレットを作成する例である.
まずパクレットのディレクトリ,例えば$UserDocumentsDirectory/MyPacletを作成する.このディレクトリの中に次の内容を含むPacletInfo.wlファイルを作成する.この作成にはノートブックフロントエンドでもテキストエディタでも使える:
PacletObject[<|
"Name" "MyPaclet",
"Version" "1.0",
"Extensions" {
{"Kernel", "Root" "Kernel", "Context" {"MyContext`"}}
}
|>]
ディレクトリの実際の名前(MyPaclet)は関係ない.名前は何でもよくPacletInfo.wlファイルの中の名前に一致している必要はない.パクレットの名前はPacletInfo.wlから来るので,親ディレクトリが同じ名前であるのは一般的な慣習に過ぎない.
次にMyPacletのカーネルサブディレクトリを作成する.これは,提供したい関数定義を含むMyContext.wlファイルを入れるディレクトリである.コンテキスト名("MyContext`")がパクレット名に一致している必要もないが,通常一致している.
さらにMyPaclet/KernelディレクトリにMyContext.wlファイルを作成し,以下のパッケージコンテンツを与える:
BeginPackage["MyContext`"]

Squared

Begin["`Private`"]

Squared[x_] := x^2

End[]

EndPackage[]
これでパクレットができた.これを他の人に配布するために,.pacletファイルとしてパックする(これは通常のzipファイルに過ぎないが,特別な慣習があるので,別のアーカイブユーティリティではなく常にCreatePacletArchiveを使うようにする).CreatePacletArchiveはパックするために与えられたディレクトリの隣に.pacletファイルを生成する:
CreatePacletArchiveはパクレット名とバージョン番号を組み合せたファイル名を作成する.この正確なファイル名はパクレットには要求されないので,好きに変更してもよい(.paclet拡張は残しておく).パクレットに関わるものはPacletInfo.wlファイルに入っている.
これでMyPaclet-1.0.pacletファイルを同僚に配布して,パクレットサーバに配備できる.
現行のセッションでこのパクレットが実行していることを確かめるために,インストールする.以下のようにして.pacletファイルを$UserBasePacletsDirecory/Repositoryに解凍し,システムで利用できるようにする:
パクレットのコンテキストをロードし,通常通りに使う:
その後はパクレットをアンインストールする必要がある.以下のようにして,インストールされた場所からパクレットディレクトリを削除する.

PacletDirectoryLoadとPacletDirectoryUnload

前のセクションでは,小さいパクレットの開発と配備を見てきた.パクレットでコードをアクティブに開発している場合は,最新の変更をテストするためだけにパクレットを.pacletファイルに圧縮してインストールしたくはないであろう.このような場合に使えるのがPacletDirectoryLoad関数である.PacletDirectoryLoadは標準的ではない場所でパクレットを探すよう,パクレットシステムに指示する.追加するディレクトリは2レベルまで深くパクレットを求めて検索され,そのパクレットは直ちにシステムで利用できるようになる.追加されたディレクトリは現行のカーネルセッションにだけ有効である.PacletDirectoryLoadはパクレット以外におけるPrependTo[$Path, "dir"]と同等のものだと考えることができる.
パクレット作成時の通常のワークフローは,標準のパクレットレイアウトにファイルを作成してからそこで編集するというものである.PacletDirectoryLoad["/my/development/dir"]を呼び出すと,パクレットシステムに開発中のパクレットをロードさせることができる.これはセッション中に1回するだけでよい.これで.wlファイルを編集しGet["MyContext`"]を繰り返し呼び出してパクレットを再ロードして最新の変更を見ることができる.
開発中にPacletInfo.wlファイルを変更する(新しい拡張タイプを加える等)場合は,PacletDataRebuild[]を呼び出してパクレットデータのキャッシュを再構築する必要があることをパクレットシステムに知らせなければならない.
PacletDirectoryLoadの便利な機能は,指定されたディレクトリのパクレットが別のところにインストールされているパクレットと全く同じバージョンである場合に,PacletDirectoryLoadのパクレットが別のものに優先して使われるというものである.この規則は「PacletDirectoryLoadが引き分けを制す」と言うことができる.つまり,パクレットを作成しているときに,ローカルレポジトリにそのパクレットのバージョン1.0.0がすでにインストールされている場合,PacletDirectoryLoadを使って,開発中のPacletInfo.wlファイルのバージョン番号を増やすことなく開発中のパクレットを指定することができるのである.どのパクレットの修正版をリリースするときでも,前のバージョンよりも大きいバージョン番号を与えることが非常に重要である.しかし開発中は毎回バージョン番号を増やさなくて済めば便利である.
PacletDirectoryUnloadはパクレットの検索パスからディレクトリを削除し,これらのディレクトリのパクレットをシステムから直ちに取り外す.例えばNeedsはこれらのパクレットのコンテキストを見付けなくなるし,パレットや他のフロントエンドリソースがフロントエンドのメニューから消える.もちろんパクレットからコードがすでにロードされていた場合は,PacletDirectoryUnloadはセッションからそれを消すことはない.

PacletDataRebuild

PacletDataRebuildは通常のパクレットシステム関数(PacletInstall等)外でパクレットを編集したときは常に呼び出す必要がある関数である.組込みのパクレットシステム関数だけを使っている場合はパクレットシステムが変更を追跡するが,PacletInfo.wlの変更等を手動で行う場合はパクレットシステムには何かが変更されたことを知る術はなくキャッシュが古くなる可能性がある.したがって,PacletDataRebuild[]を実行する必要があるのである.これによってパクレットシステムはシステムのPacletInfo.wlファイルをすべて再スキャンする.これにはほんと1,2秒しかかからない.
ユーザは必要でないときにPacletDataRebuildを呼び出すことがよくある.呼び出しても安全ではあるが,その働き,およびPacletInfo.wlに手動で変更を行った場合またはパクレットディレクトリを$UserBasePacletsDirectory/Repositoryにコピーしたりそこからコピーして移動した場合にだけ必要であるということを理解することが大切である.

ドキュメントのオーサリングと構築

ドキュメントの作成と構築はパクレット開発の複雑な部分である.Wolfram製品に同梱のドキュメントは,特化されたツールを使って一定の形式で作成され,別の特化されたツールを使って製品で見るようなファイルに処理される.パクレット作成者は組込みドキュメントのような外観と動作のドキュメントが作成したいので,それを援助するためにPacletToolsパクレットとDocumentationToolsパクレットが提供されている.詳細はそれぞれのパクレットのドキュメントに記されている.
パクレットサーバ
自分のマシン上,または会社や組織のために簡単にパクレットサーバを設定することができるサーバに論理は必要なく,実のところパクレット「サーバ」はネットワーク上に見える,特別なファイルが少し入ったディレクトリと同じくらい単純である.パクレットシステムには必要なファイルを自動的に作成するためのツールが備わっている.
自分で構築した,または誰かにもらった.pacletファイル一式があり,それを所属機関の人が見付けてインストールできるようにしたいとしよう.これに必要なのは,file: URLを介してネットワーク上の他の人がアクセスできるディレクトリだけである.次はホームディレクトリのPacletServerディレクトリにパクレット「サーバ」を設定する例である.このPacletSiteディレクトリにまずPacletサブディレクトリ(この名前でなければならない)を作成し,その中に.pacletファイルを必要なだけ置く.ここでPacletManager`BuildPacletSiteFiles関数を呼び出し,PacletServerディレクトリを指定する:
この関数はすべての.pacletファイルを調べ,それらから情報を抽出し,PacletSiteディレクトリにPacletSite.mとPacletSite.mzの2つのファイルを作成する.これらはPacletSiteUpdateを呼び出したときにクライアントが読み込むインデックスファイルである.一旦これら2つのファイルが作成されると,機能するパクレットサイトができたことになる.file: URLを使ってそれを加える.
PacletInstallPacletFindRemote等のコマンドがパクレットの最新バージョンを探したとき,このパクレットサーバが含まれるようになる.
Webサーバベースのパクレットサイトの設定方法も似ている.同じディレクトリ構造(.pacletファイルを含むPacletsサブディレクトリを持つ親ディレクトリ)を作成し,親ディレクトリでPacletManager`BuildPacletSiteFilesを呼び出す.このディレクトリをWebサーバにとって可視にするだけであり,他の人には以下のような親ディレクトリのURLを渡せばよい:
新しいパクレットがサーバに加えられるとき,再びBuildPacletSiteFilesを実行する.パクレットが古いバージョンにアップデートされる場合は,BuildPacletSiteFilesを呼び出す前にPacletsディレクトリから古いバージョンを削除する.