На Хабре не так уж и много статей о Clojure, и это печально, намерен это исправить. Ниже я расскажу об отличном на мой субъективный взгляд инструменте — языке программирования Clojure и его библиотеках для создания веб-приложений.
В этой статье не будет сравнения Clojure с другими языками, так как отталкиваясь от скромного опыта сравнивать не с чем.
Clojure — это мультипарадигмальный язык программирования общего назначения поощряющий функциональное программирование. Основой этого языка и его синтаксиса является Lisp и его S-expressions. В отличие от Lisp'a Clojure включает и другие типы данных (коллекции), такие как: векторы, ассоциативные массивы, множества и очень удобные в использовании ключевые-слова. Код Clojure компилируется в JVM байткод, что позволяет развертывать приложения на большом количестве платформ и само-собой использовать все доступные Java библиотеки.
В интернетах полно информации о структурах Clojure, поэтому я пропущу описание оных.
Нельзя не сказать о сложившимся вокруг этого языка программирования сообществе, которое не столь огромно, но очень дружелюбно к новичкам и не только, они с готовностью помогают решать возникшие проблемы. Имеется большое количество видеоматериалов по самым разным аспектам использования Clojure, только вот практически все они на английском языке (рай для самореализации переводчиков). В конце статьи будут ссылки.
Альтернатива Maven. Используется для управления зависимостями проекта, настройками библиотек и глобальными настройками проекта. Предоставляет консольные команды для создания, тестирования, компиляции и запуска приложений.
Проекты на Clojure создаются с помощью команды: $ lein new <название шаблона проекта (app|compojure|luminus...)> <название проекта>
Это создает каталог с проектом Clojure, имеющую все необходимые файлы и каталоги. И конечно же создает файл project.clj в котором и подключаются все библиотеки и выставляются глобальные настройки: библиотек, проекта, компиляции, repl и т.п…
Ring — представляет из себя слой абстракции над HTTP, предоставляя взаимодействие с ним через простой API. Очень успешно применяется при создании модульных приложений.
Примеры использования, можно увидеть на их странице github (ссылка в конце статьи). Я же использую еще одну абстракцию над Ring, которая на мой взгляд более упрощает работу с маршрутами Ring и называется Compojure.
Библиотека для маршрутизации Ring, с её помощью можно удобно упаковывать маршруты и использовать их в handler'e проекта.
Не стану приводить пример request'a так как вы все прекрасно понимаете как он выглядит. На этом о Compojure закончено.
Библиотека для авторизации и аутентификации пользователей. Упаковывает сессии авторизованных пользователей в HTTP заголовок в свой backend, имеет функции для шифрования паролей и т.п…
Пример шифрования пароля:
Так-же Buddy позволяет настраивать доступ к страницам в middleware.
HTML шаблонизатор, вдохновленный Django. Позволяет очень гибко работать с данными в HTML шаблонах.
И сам шаблон:
Библиотека для работы с mongodb, вообще Clojure очень удобный инструмент для работы с базами данных, все благодаря его коллекциям. Monger это Clojure MongoDB клиент (суть библиотека), предоставляющий функции, высокого и низкого уровня для взаимодействия с API MongoDB. Библиотека написана весьма лаконично и в то же время предоставляет все необходимое для полноценного использования MongoDB в приложениях. Нельзя не заметить огромный плюс — это очень развернутая и подробная документация на официальном сайте.
Скобок много, нужно привыкнуть, но внимательный человек обратит внимание, что их не больше чем фигурных скобок в том-же JavaScript.
На этом пожалуй все, в дальнейших статьях если к ним проявится интерес я расскажу про каждую библиотеку в отдельности, про замечательный веб-сервер immutant, ну и конечно же про ClojureScript который удобно использовать при разработке front-end приложений и компилируется он в javascript. Так-же хотелось бы осветить фреймфорк Luminus, который очень сильно помог мне разобраться с веб-разработкой на Clojure. Надеюсь моя, хоть и не всеобъемлющая статья заинтересует вас просмотреть возможности этого замечательного инструмента.
Благодарю, всего вам лучшего!
В этой статье не будет сравнения Clojure с другими языками, так как отталкиваясь от скромного опыта сравнивать не с чем.
Основная информация о Clojure
Clojure — это мультипарадигмальный язык программирования общего назначения поощряющий функциональное программирование. Основой этого языка и его синтаксиса является Lisp и его S-expressions. В отличие от Lisp'a Clojure включает и другие типы данных (коллекции), такие как: векторы, ассоциативные массивы, множества и очень удобные в использовании ключевые-слова. Код Clojure компилируется в JVM байткод, что позволяет развертывать приложения на большом количестве платформ и само-собой использовать все доступные Java библиотеки.
В интернетах полно информации о структурах Clojure, поэтому я пропущу описание оных.
Комюнити
Нельзя не сказать о сложившимся вокруг этого языка программирования сообществе, которое не столь огромно, но очень дружелюбно к новичкам и не только, они с готовностью помогают решать возникшие проблемы. Имеется большое количество видеоматериалов по самым разным аспектам использования Clojure, только вот практически все они на английском языке (рай для самореализации переводчиков). В конце статьи будут ссылки.
Leiningen
Альтернатива Maven. Используется для управления зависимостями проекта, настройками библиотек и глобальными настройками проекта. Предоставляет консольные команды для создания, тестирования, компиляции и запуска приложений.
Проекты на Clojure создаются с помощью команды: $ lein new <название шаблона проекта (app|compojure|luminus...)> <название проекта>
Это создает каталог с проектом Clojure, имеющую все необходимые файлы и каталоги. И конечно же создает файл project.clj в котором и подключаются все библиотеки и выставляются глобальные настройки: библиотек, проекта, компиляции, repl и т.п…
Пример файла project.clj:
(defproject test "0.1.0-SNAPSHOT" :description "Описание" :url "http://test.ru" :dependencies [[org.clojure/clojure "1.7.0"] [selmer "0.8.2"] [com.taoensso/timbre "4.0.2"] [com.taoensso/tower "3.0.2"] [markdown-clj "0.9.67"] [environ "1.0.0"] [compojure "1.3.4"] [ring/ring-defaults "0.1.5"] [ring/ring-session-timeout "0.1.0"] [metosin/ring-middleware-format "0.6.0"] [metosin/ring-http-response "0.6.2"] [bouncer "0.3.3"] [prone "0.8.2"] [org.clojure/tools.nrepl "0.2.10"] [buddy "0.6.0"] [com.novemberain/monger "2.0.1"] [org.immutant/web "2.0.2"] [clojure.joda-time "0.6.0"]] :min-lein-version "2.0.0" :uberjar-name "test.jar" :jvm-opts ["-server"] ;;enable to start the nREPL server when the application launches ;:env {:repl-port 7001} :main test.core :plugins [[lein-environ "1.0.0"] [lein-ancient "0.6.5"]] :profiles {:uberjar {:omit-source true :env {:production true} :aot :all} :dev {:dependencies [[ring-mock "0.1.5"] [ring/ring-devel "1.3.2"] [pjstadig/humane-test-output "0.7.0"]] :repl-options {:init-ns test.core} :injections [(require 'pjstadig.humane-test-output) (pjstadig.humane-test-output/activate!)] :env {:dev true}}})
Ring
Ring — представляет из себя слой абстракции над HTTP, предоставляя взаимодействие с ним через простой API. Очень успешно применяется при создании модульных приложений.
Примеры использования, можно увидеть на их странице github (ссылка в конце статьи). Я же использую еще одну абстракцию над Ring, которая на мой взгляд более упрощает работу с маршрутами Ring и называется Compojure.
Compojure
Библиотека для маршрутизации Ring, с её помощью можно удобно упаковывать маршруты и использовать их в handler'e проекта.
Привожу простой пример:
(defroutes auth-routes ; Очистка сессии (GET "/logout" ; Мы можем передать запрос контроллеру ; полностью request (-> logout-controller)) ; Обработчик авторизации через POST запрос (POST "/login" ; Или передать определенные параметры [login password] (login-controller login password)) ; Авторизация ; Указан GET запрос и можно вызвать ; представление страницы напрямую ; или упаковать все в контроллер ; из которого будет вызвана функция ; представления страницы (GET "/login" request (view/login-page)))
Такое тоже возможно:
(defroutes users-routes ; Страница просмотра профиля (GET "/profile/:login" ; В request в :params уже будет доступно ; значение login с ключом указанным выше :login request ; Синтаксический сахар под названием -> ; передает первый входящий аргумент ; функции обработчику. (-> profile-view-controller-GET)))
Не стану приводить пример request'a так как вы все прекрасно понимаете как он выглядит. На этом о Compojure закончено.
Buddy
Библиотека для авторизации и аутентификации пользователей. Упаковывает сессии авторизованных пользователей в HTTP заголовок в свой backend, имеет функции для шифрования паролей и т.п…
Пример шифрования пароля:
(buddy.hashers/encrypt "qwerty")
Пример функции авторизации из моего проекта:
(defn login-controller "Авторизация пользователя" [request] (let [ ; Получить данные из формы form {:login (get-in request [:form-params "login"]) :password (get-in request [:form-params "password"])} ; Проверить данные на валидность validate (bouncer/validate form valid/login-validator) ; Обработать ошибки errors (first validate) return-errors (fn [message] (util/return-messages view/login-page :error-message message :data validate))] ; Ошибки при валидации (if-not errors ; Наличие пользователя с указанным логином (if (true? (db/user-exist? {:login (:login form)})) ; Получить структуру пользователя (let [user (db/get-user {:login (:login form)} [:password])] ; Соответсвие паролей (if (hashers/check (:password form) (:password user)) (do ; Обновить :visited (db/update-user {:login (:login form)} {:visited (util/date-time)}) ; Создать новую сессию (util/create-session request (:login form) "/")) ; Если пароли не совпали (return-errors "Неверный пароль"))) ; Если логин не найден (return-errors "Логин не найден")) ; Ошибка при валидации (return-errors "Проверьте правильность введенных данных"))))
Так-же Buddy позволяет настраивать доступ к страницам в middleware.
Пример:
(def rules [{:pattern #"^/user/edit$" :handler authenticated-user} (defn on-error [request response] {:status 403 :headers {"Content-Type" "text/html"} :body (str "Нет доступа к " (:uri request) ".<br>" response)}) (defn wrap-restricted [handler] (restrict handler {:handler authenticated? :on-error on-error})) (defn wrap-identity [handler] (fn [request] (binding [*identity* (or (get-in request [:session :identity]) nil)] (handler request)))) (defn wrap-auth [handler] (-> handler wrap-identity (wrap-authentication (session-backend)))) ; И пример middleware base: (defn wrap-base [handler] (-> handler wrap-dev ; Наши правила доступа (wrap-access-rules {:rules rules :on-error on-error}) ; Сама авторизация wrap-auth ; Сессия (wrap-idle-session-timeout {:timeout (* 60 30) :timeout-response (redirect "/")}) wrap-formats (wrap-defaults (-> site-defaults (assoc-in [:security :anti-forgery] false) (assoc-in [:session :store] (memory-store session/mem)))) wrap-servlet-context wrap-internal-error wrap-uri))
Selmer
HTML шаблонизатор, вдохновленный Django. Позволяет очень гибко работать с данными в HTML шаблонах.
(defn registration-page "Страница регистрации пользователя" [] (render "registration.html" {:foo [1 2 3 4 5]})))
И сам шаблон:
<ul> {% for i in foo %} {{i}} {% endfor %} </ul>
Monger
Библиотека для работы с mongodb, вообще Clojure очень удобный инструмент для работы с базами данных, все благодаря его коллекциям. Monger это Clojure MongoDB клиент (суть библиотека), предоставляющий функции, высокого и низкого уровня для взаимодействия с API MongoDB. Библиотека написана весьма лаконично и в то же время предоставляет все необходимое для полноценного использования MongoDB в приложениях. Нельзя не заметить огромный плюс — это очень развернутая и подробная документация на официальном сайте.
Небольшой пример:
(ns test.users.db (:require monger.joda-time [monger.collection :as m] [test.db :refer [db]])) (def collection "users") (defn get-user "Найти пользователя" ([query] (m/find-one-as-map db collection query)) ([query fields] (m/find-one-as-map db collection query fields))) ; Пример использования: ; Вернет нужные нам поля (get-user {:login "test"} [:first-name :last-name]) ; Вернет весь документ (get-user {:login "test"})
Про обилие скобок
Скобок много, нужно привыкнуть, но внимательный человек обратит внимание, что их не больше чем фигурных скобок в том-же JavaScript.
Ссылки на описанные библиотеки
Дополнительные ссылки
- Список библиотек Clojure
- Документация к функциям и ядру
- Clojure howto
- Clojure docs
- Задачки по Clojure (на любой уровень сложности)
На этом пожалуй все, в дальнейших статьях если к ним проявится интерес я расскажу про каждую библиотеку в отдельности, про замечательный веб-сервер immutant, ну и конечно же про ClojureScript который удобно использовать при разработке front-end приложений и компилируется он в javascript. Так-же хотелось бы осветить фреймфорк Luminus, который очень сильно помог мне разобраться с веб-разработкой на Clojure. Надеюсь моя, хоть и не всеобъемлющая статья заинтересует вас просмотреть возможности этого замечательного инструмента.
Благодарю, всего вам лучшего!