Несколько месяцев назад компания Wolfram Research открыла общий доступ к Wolfram Language Paclet Repository. Это централизованное хранилище пользовательских пакетов, написанных на языке Wolfram. Данное хранилище не является чем-то новым само по себе. Для языка Wolfram уже есть несколько возможных способов публикации пакетов. Однако, у официального репозитория есть несколько очень важный преимуществ перед существующими решениями. В этой статье я сначала коротко расскажу что из себя представляет репозиторий, а затем пошагово покажу как опубликовать в него свой собственный пакет при помощи предоставленных компанией Wolfram Research инструментов.

Что такое пакет на языке Wolfram

Пакет - это почти любой код, который можно загрузить в текущую сессию пользователя. Это может быть всего один файл, где есть одна функция, а может быть довольно большая библиотека, где много файлов с исходным кодом и функций. Обычно расширение у файлов с кодом это *.wl или *.m, однако, иногда попадаются пакеты с файлами *.mx, которые представляют собой сериализованный варианты *.m и *.wl. Чаще всего, к сожалению, пользователи свои пакеты распространяют как есть в виде одного файла или папки с набором файлов. Но чуть-чуть более ответственные пользователи для удобства других людей упаковывают свой код в специальный файл с расширением *.paclet. Изначально паклеты придумали исключительно для того, чтобы стандартизировать создание документации для модулей Mathematica, однако, позже их возможности применения увеличились и на сегодняшний день *.paclet - это по сути архив, где содержится код, документация к нему и специальный файл PacletInfo.wl, который выполняет функцию, похожую на ту, что несет в себе например файл package-info.java для файлов *.jar. И что самое важное - PacletInfo.wl содержит в себе информацию для функции PacletInstall, которая выполняет стандартную установку пакетов. Интересно, что как и с файлам *.jar, файлы *.paclet можно просто распаковать архиватором, взять файлы с исходным кодом и в ручную поместить в нужную директорию, по сути выполнив установку.

Как устанавливать пакеты

Будем считать, что у пользователя уже установлены Wolfram Mathematica или Wolfram Engine. Тогда если он вдруг каким-то образом уже нашел необходимый для себя пакет, то у него есть несколько вариантов этот пакет установить.

Если это просто папка с файлами или один файл

Самый просто вариант - это использовать пакет без установки, а просто поместить найденный файл или папку рядом с вашим рабочим блокнотом, а в самом блокноте тогда нужно будет просто выполнить следующий код:

SetDirectory[NotebookDirectory[]]; 
Get["PackageName`"]

Или даже без изменения рабочей директории для текущей сессии:

Get["/path/to/the/package"]

Или даже без скачивания на свой компьютер - вы можете импортировать исходники прямо из github (или из любого другого места, доступного по http/https), если там всего один файл:

Get["https://raw.githubusercontent.com/UserName/RepoName/master/PackageName.wl"]

Однако, удобнее всего поместить пакет в ту директорию, где Wolfram Language всегда сможет его найти без необходимости указания полного пути или изменения рабочий директории. Такое расположение всегда можно посмотреть если посмотреть значение системной переменной:

$Path

Эта переменная - просто список директорий, по которым проходит ядро Wolfram в поисках пакета или при импорте любого файла. И там скорее всего будет строка примерно вот такого вида (для пользователей Windows и Mathematica):

C:\Users\UserName\AppData\Roaming\Mathematica\Applications

Вот это и есть та самая папка, куда стоит помещать готовые пакеты, если вы их устанавливаете в ручную. Кроме того, путь к это директории можно получить использую другую системную переменную языка Wolfram:

FileNameJoin[{$UserBaseDirectory, "Applications"}]

Т.е. вам будет достаточно скопировать любой скачанный на компьютер файл в эту директорию, после чего код из него он станет доступен для импорта в любом блокноте Wolfram:

CopyFile[
  FileNameJoin[{$HomeDirectory, "Downloads", "PackageName.wl"}], 
  FileNameJoin[{$UserBaseDirectory, "Applications", "PackageName.wl"}]
]

Get["PackageName`"]

Если это упакованный паклет

Тогда все очень просто. Либо распаковать его при помощи специальной функции и поместить файлы в папку с локальными пользовательскими пакетами:

dir = ExtractPacletArchive[
  FileNameJoin[{$HomeDirectory, "Downloads", "PackageName.paclet"}]
]

CopyDirectory[
  dir, 
  FileNameJoin[{$UserBaseDirectory, "Applications", "PackageName"}]
]

Либо воспользоваться недавно (в 2020 году) добавленной функций, которая сделает это автоматически, но еще и с сохранением информации о версии пакета:

PacletInstall[FileNameJoin[{$HomeDirectory, "Downloads", "PackageName.paclet"}]]

Тогда скачанный пакет установится в папку, путь в которой можно получить вот так:

FileNameJoin[{$UserBasePacletsDirectory, "Repository"}]

Кроме того, начиная с версии 12.1 в языке Wolfram стала доступна подобная установка пакетов прям по http/https. Выглядеть это будет примерно вот так:

PacletInstall["https://github.com/UserName/PackageName/releases/download\
/vX.Y.Z/PackageName-X.Y.Z.paclet"]

Где можно найти пакеты

Чаще всего пользователи, как и для всех остальных языков программирования, публикуют исходный код своих пакетов на github. Там же в разделе с релизами можно добавить и упакованные пакеты или архивы с исходными файлами. Выше мы рассмотрели как установить упакованный пакет напрямую по ссылке на загрузку файла, однако, некоторые пользователи либо запускаются собственные паклет-сайты. Кроме того, достаточно долгое время существовал официальный закрытый репозиторий компании Wolfram Research, из которого скачивались встроенные в Wolfram Language пакеты. Этот репозиторий является хранилищем по умолчанию, из него можно получать обновления встроенных пакетов, но в него никто ничего не может добавлять.

О Wolfram Language Paclet Repository

Не так давно появился Wolfram Function Repository, статья о котором есть на хабре (перевод статьи опубликовал Пётр Тенишев, который является администратором в группе по Wolfram Mathematica. Если вдруг читатели заинтересуются дополнительными материалами по языку Wolfram, то там постоянно появляется что-то новое на русском языке). Теперь компания добавила примерно тоже самое, но не для конкретных функций, а для пакетов. Пользователи получили возможность выложить в репозиторий любой свой пакет, после чего он станет доступен всем. Ключевым отличием является то, что данный репозиторий включен в список мест, откуда Wolfram Language может скачивать пакеты по умолчанию. То есть больше не нужно самостоятельно добавлять в системные настройки путь до паклет-сайта или указывать расположение архива напрямую.

Вторым отличием является то, что компания Wolfram Research выложила заранее заготовленный блокнот на языке Wolfram, в котором в виде дополнительного пользовательского интерфейса реализованы основные действия с пакетами. По сути этот блокнот похож чем-то на maven или ms build, но в достаточно необычной оболочке. На самом деле далее мы увидим какие именно шаги позволяет делать этот блокнот-сборщик.

Третье отличие - в репозиторий пакетов по умолчанию можно выкладывать и документацию на языке Wolfram. Т.е. сразу же писать блокноты с документацией и их отправлять в репозиторий. В общем лучше один раз увидеть...

Получаем PublisherID

Это просто необходимая системная переменная, которая будет связана с вашим аккаунтов в Wolfram Cloud. Для того чтобы его получить нужно просто иметь аккаунт на wolframcloud.com. А затем перейти на страницу, где можно заполнить форму и отправить запрос на получение PublisherID. Я уже выкладывал пакеты в репозиторий, поэтому у меня есть PublisherID == KirillBelov. Именно под этим именем я могу публиковать свои пакеты в репозитоии. Сделано это очевидно для того, чтобы не возникало ситуации когда пользователи выкладывают одинаковые пакеты. Ниже скриншот формы для получения идентификатора:

Создаем проект

Собственно перейдем к практике. В данный момент, пока я пишу эти строки, у меня на компьютере есть совсем небольшой пакет, где есть чуть-чуть исходного кода и он хорошо подходит для демонстрационных целей. В статье мы не будем описывать сам процесс написания пакета, а сосредоточимся только на его подготовке и публикации. Мой пакет называется BankCalculator. Он умеет показывать ожидаемый доход от банковских вкладов. В данный момент папка с проектом выглядит следующим образом:

Директория с проектом
Директория с проектом

Файл BankCalculator.wl переместим во внутреннюю папку Kernel. Если этой папки нет, то ее можно просто создать. Это нужно для удобства сборщика, т.к. сборщик ищет файлы в определенной папке. Если же файлы с исходным кодом будут находиться рядом с файлом PacletInfo.wl, то сборщик может найти лишние файлы.

Так же нужно добавить в эту директорию файл PacletInfo.wl и заполнить его необходимо следующими данными:

PacletObject[<|
	"Name" -> "KirillBelov/BankCalculator", 
	"Description" -> "Bank calculator", 
	"Creator" -> "Kirill Belov", 
	"License" -> "MIT", 
	"Version" -> "1.0.0", 
	"WolframVersion" -> "13.0+", 
	"PublisherID" -> "KirillBelov", 
	"Extensions" -> {
		{
			"Kernel", 
			"Root" -> "Kernel", 
			"Context" -> {
				{"KirillBelov`BankCalculator`", "BankCalculator.wl"}
			}, 
			"Symbols" -> {}
		}, 
		{"Documentation", "Language" -> "English"}
	}
|>]

PacletObject это просто тип, который говорит о том, что это файл с описанием пакета. $PublisherID мы получали в одном из пунктов выше. Значение ключа "Name" должно соответствовать шаблону "$PublisherID/$PackageName", Контекст соответственно должен выглядеть как "$PublisherID`PackageName`". Контекст - это аналог пространств имен, в котором будут находится все функции пакета. Этот же контекст должен быть указан в файле BankCalculator.wl. Все остальные ключи ассоциации интуитивно понятны. Теперь папка с проектом выглядит следующим образом:

Добавлен PacletInfo.wl
Добавлен PacletInfo.wl

Скачиваем шаблон сборщика

Для того, чтобы перейти к дальнейшей работе нам необходимо скачать специальный блокнот по следующей ссылке: https://resources.wolframcloud.com/PacletRepository/Unnamed-Paclet.nb. Это пустой шаблон для любого пакета. Нам не важно куда скачать и поместить данный блокнот.

Создаем PacletResource.nb

Открываем только что скачанный блокнот:

Нас приветствует всего одна кнопка Select Paclet Directory. Нажимаем на нее, после чего откроется следующее окно с полем ввода, где можно указать путь до нашего пакета:

Подтверждаем выбор, после чего открывается следующее окно, где нас уже информируют о том, что в указанной директории нашелся файл PacletInfo.wl с указанными именем пакета, контекстом и директорий. Опять подтверждаем выбор:

Далее мы получили почти окончательный результат настройки - сгенерированный блокнот, в котором добавлено меню для проверки, сборки и выкладки проекта в репозиторий. Выглядит он следующим образом:

Опять же, все достаточно интуитивно понятно. Правда первое, что я бы рекомендовал сделать сохранить данный блокнот в директорию с проектом. Назвать его можно как угодно, я назывe этот файл ResourceDefenition.nb. Теперь в папке с проектом уже 3 файла, плюс добавилась новая (пустая на данный момент) директория для документации к проекту:

После того, как файл с определением пакета был сохранен в папку с проектом можно переключить галочку с указанием расположения файлов в поле "Paclet Directory":

Рассмотрим внимательнее дополнительный пункты меню (которые на сером фоне и ниже). Там есть несколько разделов, которые отвечают как раз за шаги поверки, сборки и публикации пакета.

  • Open Sample - тут все понятно - просто показывает примеры

  • Guidelines - открывает в браузере ссылку на небольшое руководство

  • Tools - в данный момент этот раздел как раз развернут на скриншоте выше и содержит в себе дополнительное меню [Template Input | Literal Input | ... ].

  • Check - позволяет запустить анализатор кода пакета. Причем можно отдельно выбрать что анализировать: документацию, исходный код или текущий блокнот с определением пакета

  • Build - собирает пакет или документацию

  • Deploy - публикует пакет в собственное хранилище в облаке Wolfram

  • Submit to Repository - то ради чего написана эта статья. Возможность выложить результат в публичный репозиторий пакетов

Заполнение шаблона

Сначала заполним все самые простые поля ввода. Вставим картинку для заголовка:

Просто картинка
Просто картинка

Укажем базовое описание. Basic Description автоматически добавилось описание из файла PacletInfo.wl. Путь к основном файлу документации мы пока не можем указать, так как пока что документации не написана:

Описание
Описание

Вот этот раздел можно не трогать, так как ячейки с таким стилем не публикуются, а нужны только для разработчика. Но стоит отметить, что точно так же эти ячейки были сгенерированы автоматически на основе информации из PacletInfo.wl:

Код для импорта текущего пакета
Код для импорта текущего пакета

Добавим несколько базовых примеров:

И дополнительные примеры:

В последнем разделе должно быть автоматически добавлено имя автора. так же выберем подходящие разделы для пакета и укажем ключевые слова.

В самом низу отмечаем тип пакета, т.е. с чем он будет взаимодействовать. В нашем случае - это просто пакет, который используется встроенные функции Wolfram Language и не читает никакие файлы и не обращается к внешним сервисам:

Документация

Приступим к созданию документации. В версии 13 стали доступны встроенные средства для создания документации к функциям. Эти же средства встроены в виде дополнительного меню в наш рабочий блокнот. В нашем пакете всего два имени, поэтому создать для них документацию не составит труда. Для этого выбираем пункт меню "New Function Page":

После нажатия откроется автоматически форма, где можно ввести имя функции:

После подтверждения откроется автоматически сгенерированный файл для этой функции. При этом, опции (если есть) и описание использования копируются напрямую из определения. Страница документации будет выглядеть вот так:

Минимально заполненная страница
Минимально заполненная страница

В таких блокнотах необходимо заполнить описание, добавить ссылки на связанные руководства и функции. Но самое главное добавить максимально показательные примеры.

После того как страницы будут созданы и заполнены - можно создать одно объединяющее руководство или "гайд", где будут список доступных функций пакета. Для этого в том же меню определения пакета нужно выбрать уже "New Guide Page". Введем название и получим блокнот вот такого вида:

Гайд по функциям
Гайд по функциям

Отдельно стоит сказать про то, как нужно пользоваться палитрой Documentation Tools. Вот она:

Это набор кнопок, который чаще всего форматирует выделенный мышкой текст. Т.е. например, я хочу вставить внутреннюю ссылку на страницу CalcROI из страницы Deposit. Для этого я пишу имя CalcROI там где хочу чтобы была ссылка, выделяю его, а затем мышкой кликаю п кнопке Link to Function, которую можно увидеть на скриншоте выше. В принципе с остальными кнопками все работает примерно так же. На этом наша первая версия документации закончена, перейдем к следующим шагам.

Проверка и сборка

После того как определение пакета оформлено, документация написана (документация на самом деле не обязательна) можно проверить пакет. Из дополнительного меню просто выбирает пункт Check > All. С нажатием этой кнопки запустится процесс анализа кода блокнота и пакета, результат которого визуально отобразится в виде сообщений под дополнительным меню и прямо в блокноте:

В общем-то в нашем случае есть только рекомендации, которые мы пока что проигнорируем, но часто анализатор показывает и серьезные ошибки. Если они были - их необходимо исправить. А мы перейдем уже к шагу сборки. Из дополнительного меню запустим процесс сборки пакета - Build > All:

Окно подтверждения
Окно подтверждения

После подтверждения в папке проекта появится директория build, в которой окажется результат сборки:

Это уже упакованный файл с расширением *.paclet, который можно установить на локальный компьютер при помощи PacletInstall и тот же самый пакет в виде папки - по сути содержание паклета.

Отправка в облако

Если выбрать пункт Deploy > Publicy in the Cloud, то готовый пакет будет опубликован в вашем личном хранилище в Wolfram Cloud. После завершения сборки автоматически откроется браузер на странице этого пакета. Выглядеть страница в браузере будет вот так:

Соответственно здесь контент из определения пакета, а так же слева видно ссылки на документацию. Вот как выглядит собранная документация:

Отправка в публичный репозиторий

Собственно кульминация всей этой статьи. Давайте просто нажмем на кнопку и опубликуем пакет в Wolfram Language Paclet Repository. :

Перейдем на страницу со опубликованными пакетами:

Видим, что пакет опубликован
Видим, что пакет опубликован

Теперь пакет можно найти в публичном репозитории или читатели просто могут посмотреть его по прямой ссылке: https://resources.wolframcloud.com/PacletRepository/resources/KirillBelov/BankCalculator/.

Установка

Собственно заключительный шаг - пробуем установить пакет, посчитать доход. Следуем инструкции на странице пакета, открываем любой блокнот Mathematica или консоль Wolfram Engune и выполняем код:

PacletSiteUpdate /@ PacletSites[]; 
PacletInstall["KirillBelov/BankCalculator"]

Пакет установлен и можно что-то посчитать:

Заключение

На этом на сегодня все. В заключении я хочу описать свои личные эмоции по поводу появления такого хранилища пользовательских пакетов. Я являюсь давним фанатом языка Wolfram и очень давно хотел чтобы нечто подобное NuGet или Maven появилось и для Wolfram Language. Сначала я своим глазам не поверил, когда появился Wolfram Engine, затем когда появился Function Repository, а теперь еще и репозиторий пакетов. Для меня лично это одна из лучших новостей касающихся языка Wolfram за последние годы вместе с бесплатным ядром. Я очень надеюсь, что читателям будет полезна эта статья и что она у кого-то вызовет интерес к языку Wolfram. Всем спасибо за внимание!

Комментарии (0)