В этой статье не будет сравнения Clojure с другими языками, так как отталкиваясь от скромного опыта сравнивать не с чем.
Основная информация о Clojure
Clojure — это мультипарадигмальный язык программирования общего назначения поощряющий функциональное программирование. Основой этого языка и его синтаксиса является Lisp и его S-expressions. В отличие от Lisp'a Clojure включает и другие типы данных (коллекции), такие как: векторы, ассоциативные массивы, множества и очень удобные в использовании ключевые-слова.
Код компилируется JVM в java байт-код, что позволяет развертывать приложения на большом количестве платформ и само-собой использовать все доступные 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 "Проверьте правильность введенных данных"))))
Так-же позволяет настраивать доступ к страницам в 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 очень удобный инструмент для работы с базами данных, все благодаря его коллекциям.
Небольшой пример:
(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.
Ссылки на описанные библиотеки
Дополнительные ссылки
На этом пожалуй все, в дальнейших статьях если к ним проявится интерес я расскажу про каждую библиотеку в отдельности, про замечательный веб-сервер immutant, ну и конечно же про ClojureScript который удобно использовать при разработке front-end приложений и компилируется он в javascript. Так-же хотелось бы осветить фреймфорк Luminus, который очень сильно помог мне разобраться с веб-разработкой на Clojure. Надеюсь моя, хоть и не всеобъемлющая статья заинтересует вас просмотреть возможности этого замечательного инструмента.
Благодарю, всего вам лучшего!
This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.
Комментариев нет:
Отправить комментарий