16.7 Возможности

provide и require являются альтернативой autoload для автоматической загрузки файлов. Они работают на основе именованных возможностей. Автозагрузка запускается вызовом конкретной функции, а возможность загружается, когда другая программа впервые запрашивает её по имени.

Имя возможности — это символ, обозначающий набор функций, переменных и т. д. Файл, определяющий их, должен предоставлять эту возможность. Другая программа, использующая их, может гарантировать их определение, требуя эту возможность. Это загружает файл с определениями, если он ещё не был загружен.

Чтобы потребовать наличие возможности, вызовите require с именем возможности в качестве аргумента. require проверяет в глобальной переменной features, была ли уже предоставлена требуемая возможность. Если нет, он загружает возможность из соответствующего файла. Этот файл должен вызвать provide на верхнем уровне, чтобы добавить возможность в features; если этого не происходит, require выдаёт ошибку.

Например, в idlwave.el определение для idlwave-complete-filename содержит следующий код:

(defun idlwave-complete-filename ()
  "Использовать возможности comint для дополнения имени файла."
   (require 'comint)
   (let* ((comint-file-name-chars "~/A-Za-z0-9+@:_.$#%={}\\-")
          (comint-completion-addsuffix nil)
          ...)
       (comint-dynamic-complete-filename)))

Выражение (require 'comint) загружает файл comint.el, если он ещё не был загружен, обеспечивая определение comint-dynamic-complete-filename. Возможности обычно называются по именам файлов, которые их предоставляют, поэтому require не нужно указывать имя файла. (Обратите внимание, что важно, чтобы выражение require находилось вне тела let. Загрузка библиотеки, пока её переменные связаны через let, может иметь непредвиденные последствия, а именно — переменные становятся несвязанными после выхода из let.)

Файл comint.el содержит следующее выражение верхнего уровня:

(provide 'comint)

Это добавляет comint в глобальный список features, так что впоследствии (require 'comint) будет знать, что ничего делать не нужно.

Когда require используется на верхнем уровне в файле, он вступает в силу как при байт-компиляции этого файла (см. Байт-компиляция), так и при его загрузке. Это сделано на случай, если требуемый пакет содержит макросы, о которых байт-компилятор должен знать. Это также позволяет избежать предупреждений байт-компилятора о функциях и переменных, определённых в файле, загруженном через require.

Хотя вызовы require на верхнем уровне выполняются во время байт-компиляции, вызовы provide — нет. Поэтому вы можете гарантировать, что файл с определениями будет загружен до его байт-компиляции, включив provide, за которым следует require для той же возможности, как в следующем примере.

(provide 'my-feature)  ; Игнорируется байт-компилятором,
                       ;   выполняется load.
(require 'my-feature)  ; Выполняется байт-компилятором.

Компилятор игнорирует provide, затем обрабатывает require, загружая соответствующий файл. Загрузка файла выполняет вызов provide, поэтому последующий вызов require ничего не делает при загрузке файла.

Функция: provide feature &optional subfeatures

Эта функция объявляет, что feature теперь загружена или загружается в текущий сеанс Emacs. Это означает, что средства, связанные с feature, доступны или будут доступны для других Lisp-программ.

Непосредственный эффект вызова provide заключается в добавлении feature в начало features, если её там ещё нет, и вызове любого кода eval-after-load, ожидающего её (см. Хуки для загрузки). Аргумент feature должен быть символом. provide возвращает feature.

Если указан subfeatures, это должен быть список символов, обозначающих набор конкретных подвозможностей, предоставляемых этой версией feature. Вы можете проверить наличие подвозможности с помощью featurep. Идея подвозможностей в том, что они используются, когда пакет (являющийся одной feature) достаточно сложен, чтобы было полезно давать имена различным частям или функциональным возможностям пакета, которые могут быть загружены или не загружены, или могут присутствовать или отсутствовать в данной версии. См. Проверка доступности сетевых возможностей для примера.

features
     ⇒ (bar bish)

(provide 'foo)
     ⇒ foo
features
     ⇒ (foo bar bish)

Когда файл загружается для удовлетворения автозагрузки и останавливается из-за ошибки при вычислении его содержимого, любые определения функций или вызовы provide, произошедшие во время загрузки, отменяются. См. Автозагрузка.

Функция: require feature &optional filename noerror

Эта функция проверяет, присутствует ли feature в текущем сеансе Emacs (используя (featurep feature); см. ниже). Аргумент feature должен быть символом.

Если возможность отсутствует, require загружает filename с помощью load. Если filename не указан, то имя символа feature используется как базовое имя файла для загрузки. Однако в этом случае require настаивает на поиске feature с добавленным суффиксом ‘.el’ или ‘.elc’ (возможно, расширенным суффиксом сжатия); файл с именем, в точности совпадающим с feature, использоваться не будет. (Переменная load-suffixes задаёт точные требуемые суффиксы Lisp-файлов.)

Если noerror не равен nil, это подавляет ошибки при фактической загрузке файла. В этом случае require возвращает nil, если загрузка файла не удалась. Обычно require возвращает feature.

Если загрузка файла завершается успешно, но не предоставляет feature, require выдаёт ошибку об отсутствующей возможности.

Функция: require-with-check feature &optional filename noerror

Эта функция работает как require, за исключением случая, когда feature уже загружена (т. е. уже является элементом списка в features, см. ниже). Если feature уже загружена, эта функция проверяет, была ли feature предоставлена файлом, отличным от filename, и если да, то по умолчанию выдаёт ошибку. Если значение необязательного аргумента noerror равно reload, функция не выдаёт ошибку, а вместо этого принудительно перезагружает filename; если noerror имеет любое другое значение, отличное от nil, функция выдаёт предупреждение о том, что feature уже предоставлена другим файлом.

Функция: featurep feature &optional subfeature

Эта функция возвращает t, если feature была предоставлена в текущем сеансе Emacs (т. е. если feature является элементом features). Если subfeature не равен nil, то функция возвращает t, только если эта подвозможность также предоставлена (т. е. если subfeature является элементом свойства subfeature символа feature).

Переменная: features

Значение этой переменной — список символов, представляющих возможности, загруженные в текущем сеансе Emacs. Каждый символ был помещён в этот список вызовом provide. Порядок элементов в списке features не имеет значения.

Макрос use-package предоставляет удобный способ загрузки возможности и её настройки для использования. Он позволяет объединить требование возможности, как это делает require, с кодом, который должен быть выполнен, когда возможность действительно загружена, аналогично хукам времени загрузки (см. Хуки для загрузки). Декларативный синтаксис use-package делает его исключительно простым в использовании в пользовательских init-файлах.

Макрос: use-package feature &rest args

Этот макрос определяет, как загрузить именованную feature и как настроить и адаптировать её для использования. Аргументы args представляют собой пары ключ-значение. Некоторые из важных ключевых слов и их значений:

:init forms

Указывает forms, которые должны быть выполнены до загрузки feature.

:config forms

Указывает forms, которые должны быть выполнены после загрузки feature.

:defer condition

Если condition не равен nil, это указывает отложить загрузку feature до тех пор, пока не будут впервые использованы какие-либо автозагружаемые команды или переменные feature. Если condition является числом n, это указывает, что feature должна быть загружена через n секунд простоя.

:commands commands…

Указывает команды feature, которые должны быть автозагружаемыми.

:bind keybindings…

Указывает привязки клавиш для команд feature. Каждая привязка имеет вид

(key-sequence . command)

или

(:map keymap (key-sequence . command))

где key-sequence имеет форму, принимаемую макросом kbd (см. Последовательности клавиш).

Для получения более подробной информации о use-package см. Руководство пользователя use-package.