Clojure обеспечивает загрузку кода и отслеживание зависимостей с помощью библиотек. Библиотека - это именованная единица исходного кода Clojure, содержащаяся в Java-ресурсе в пределах classpath. Обычно библиотека предоставляет полный набор определений, составляющих одно пространство имен Clojure.
Конвенции библиотек
Clojure определяет соглашения для именования и структурирования библиотека:
- Имя библиотеки - это символ, который обычно содержит две или более частей, разделенных точками.
- Контейнер библиотеки - это Java-ресурс, чей путь относительно класса определяется из имени библиотеки:
- Путь - это строка.
- Точки в имени библиотеки заменяются косыми чертами в пути.
- Дефисы в имени библиотеки заменяются подчеркиванием в пути.
- Путь может заканчиваться на “.class”, “.clj” или “.cljc” (см. ниже Порядок загрузки библиотеки)
- Библиотека начинается с формы “ns”, которая:
- создает пространство имен Clojure, которое разделяет его имя, и
- объявляет свои зависимости от классов Java, основных средств Clojure и/или других библиотек,
Clojure гарантирует, что если вызов “ns” завершается без выброса исключения, то объявленные зависимости были удовлетворены и возможности, которые они предоставляют, доступны.
Пример библиотеки
Простая библиотека:
(ns com.my-company.clojure.examples.my-utils
(:import java.util.Date)
(:use [clojure.string :only (join)])
(:require [clojure.java.io :as jio]))
- Форма
nsназывает пространство имен библиотеки и объявляет ее зависимости. Судя по названию, эта библиотека обычно определена в исходном файле по пути, относящемуся к классу: com/my_company/clojure/examples/my_utils.clj (обратите внимание на переводы с точки на слеш и с дефиса на подчеркивание). - Пункт
:importдекларирует использование этой библиотекойjava.util.Dateи делает его доступным для кода в этой библиотеке, используя его неквалифицированное имя. - Пункт
:useобъявляет зависимость от библиотекиclojure.stringтолько для ее функцииjoin. join может использоваться в коде этой библиотеки, используя ее неквалифицированное имя. - Пункт
:requireобъявляет зависимость от библиотекиclojure.java.ioи позволяет использовать ее члены, используя более короткий псевдоним пространства именjio.
Списки префиксов
Часто бывает, что библиотека зависит от нескольких других библиотек, полные имена которых имеют общий префикс. В вызовах require и use (и в выражениях :require и :use внутри формы ns) общий префикс может быть извлечен и предоставлен один раз с помощью списка префиксов. Например, эти две формы эквивалентны:
(require 'clojure.contrib.def 'clojure.contrib.except 'clojure.contrib.sql)
(require '(clojure.contrib def except sql))
Связанные функции
Создание пространства имен: ns
Обеспечение загрузки библиотеки: require use
Перечисление загруженных библиотек: loaded-libs
Порядок загрузки библиотеки
Библиотеки могут существовать как в скомпилированном (.class), так и в исходном виде (.clj или .cljc). В некоторых случаях в classpath может существовать один из них или даже все. Библиотека загружается из одного из них на основе следующих правил:
- Файл
.classвсегда предпочтительнее исходного файла, если только временная метка исходного файла не новее, чем у файла.class, в этом случае предпочтение отдается исходному файлу. - Файл
.clj(специфичный для платформы) всегда предпочтительнее файла.cljc(общего для всех платформ).
Второе правило позволяет автору библиотеки поставлять как переносимое общее определение библиотеки, так и поставлять специфические для платформы библиотеки, которые переопределяют переносимую версию, чтобы сделать что-то, использующее возможности хост-платформы.