Изменение системы модулей в RESTAS
Под новый год переписал всю систему модулей в RESTAS.
Во время разбора старого кода всё гадал: что же я курил, когда это писал? Там было понятие модуля и понятие субмодуля и всё это так мутно. Теперь остались только модули. Макрос mount-submodule переименован в mount-module, специальные переменные *baseurl* и *default-render-method* выкинуты, вместо них теперь используются декларации :url и :render-method.
Для демонстрации (и не только для этого) я разделил код arblog на три отдельных модуля: #:arblog.public, #:arblog.admin и #:arblog.static, а модуль #:arblog просто соединяет их вместе:
(:inherit-parent-context t))
(restas:mount-module -admin- (#:arblog.admin)
(:inherit-parent-context t)
(:url "/admin/")
(:decorators '@admin)
(arblog.admin:*post-permalink-route* '-public-.post-permalink))
(restas:mount-module -static- (#:arblog.static)
(:url "/static/"))
Здесь используется новая возможность - декларация :inherit-parent-context, с помощью которой можно указать, что при монтировании модуля он должен наследовать контекст родительского модуля, что позволяет использовать модуль #:arblog следующим образом:
(:use #:cl))
(in-package #:myblog)
(restas:mount-module -arblog- (#:arblog)
(arblog:*blog-name* "My blog")
(arblog:*posts-on-page* 10)
(arblog.internal.datastore:*datastore* (make-instance 'arblog.datastore.mongodb:arblog-mongo-datastore))
(arblog.internal.markup:*markup* (make-instance 'arblog.markup.rst:arblog-rst-markup))
;; (arblog.policy.markup:*markup* (make-instance 'arblog.markup.markdown:arblog-markdown-markup))
(arblog.internal.theme:*theme* (make-instance 'arblog.theme.mirev:arblog-mirev-theme))
(arblog:*disqus-enabled* nil))
(restas:start '#:myblog :port 8080)
Одним из основных мотивов для переписывания системы модулей была сложность генерации ссылок на маршруты, в других модулях. В старой схеме была какая-то адская схема с restas:genurl-submodule, которая требовала нахождения нужного модуля с помощью мутного API. Между тем, мне понравилась схема генерации ссылок в Flask, blueprints там, конечно, очень ограниченные и с модулями в RESTAS не сравнить, но генерация ссылок удобная и простая. В итоге, restas:genurl-submodule я просто удалил, теперь вся генерация ссылок делается через restas:genurl (либо, restas:genurl* - переименованная старая функция restas:gen-full-url). А при монтировании модуля в пакет добавляются символы для каждого маршрута в монтируемом модуле, например, в случае кода:
В пакете #:arblog появятся символы: -public-.entry, -public-.one-post, -public-.all-tags и т.д. для всех маршрутов в модуле #:arblog.public и эти символы можно использовать в функциях restas:genurl, restas:genurl* и restas:redirect: генерация URL будет происходить с учётом всех деклараций :url, использовавшихся при подключении модулей. При чём, эта схема работает до самого верха и, например, в пакете #:myblog (см. выше) будут создаваться символы: -arblog-.-public-.entry, -arblog-.-admin-.edit-post и т.д.
Данная схема работает и в том случае, когда надо генерировать ссылки не только на маршруты в примонтированных модулях, но для генерации ссылок на маршруты в "соседних" модулях. Например, в модуле #:arblog.admin после редактирования сообщения необходимо перенаправлять автора на страницу просмотра сообщения:
Это работает следующим образом: в текущем модуле ищется маршрут связанный с символом 'arblog::-public-.one-post, если такого нет, то поиск продолжается дальше в родительском модуле и т.д.
Правда, для этого в момент написания кода необходимо знать точную структуру приложения (впрочем, как и в аналогичной ситуации при использовании Flask). Поэтому в реальном коде я вместо этого добавил в модуль #:arblog.admin переменную arblog.admin:*post-permalink-route*, которая используется для генерации маршрута просмотра сообщения и настраивается при монтировании модуля (см. код выше).
Теперь мне RESTAS нравится намного больше, но вот кроме arblog теперь ничего больше не работает. Придётся "чинить" все остальные мои приложения (но это в общем, довольно тривиально), так что я видимо главный пострадавший от такого "рефакторига" :) А то я ведь даже arblog не могу на сервере обновить, ведь тогда "отвалится" lisper.ru.