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
(общего для всех платформ).
Второе правило позволяет автору библиотеки поставлять как переносимое общее определение библиотеки, так и поставлять специфические для платформы библиотеки, которые переопределяют переносимую версию, чтобы сделать что-то, использующее возможности хост-платформы.