← Blog of oldlisper

Изменение системы модулей в RESTAS

· 02.01.2013 00:00
· original author: archimag

Изменение системы модулей в RESTAS

Под новый год переписал всю систему модулей в RESTAS.

Во время разбора старого кода всё гадал: что же я курил, когда это писал? Там было понятие модуля и понятие субмодуля и всё это так мутно. Теперь остались только модули. Макрос mount-submodule переименован в mount-module, специальные переменные *baseurl* и *default-render-method* выкинуты, вместо них теперь используются декларации :url и :render-method.

Для демонстрации (и не только для этого) я разделил код arblog на три отдельных модуля: #:arblog.public, #:arblog.admin и #:arblog.static, а модуль #:arblog просто соединяет их вместе:

(restas:mount-module -public- (#:arblog.public)
  (: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 следующим образом:

(restas:define-module #:myblog
  (: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). А при монтировании модуля в пакет добавляются символы для каждого маршрута в монтируемом модуле, например, в случае кода:

(in-package #:arblog)

(restas:mount-module -public- (#:arblog.public)
  (:inherit-parent-context t)
)

В пакете #: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 после редактирования сообщения необходимо перенаправлять автора на страницу просмотра сообщения:

(restas:redirect 'arblog::-public-.one-post :id "идентификатор_сообщения")

Это работает следующим образом: в текущем модуле ищется маршрут связанный с символом 'arblog::-public-.one-post, если такого нет, то поиск продолжается дальше в родительском модуле и т.д.

Правда, для этого в момент написания кода необходимо знать точную структуру приложения (впрочем, как и в аналогичной ситуации при использовании Flask). Поэтому в реальном коде я вместо этого добавил в модуль #:arblog.admin переменную arblog.admin:*post-permalink-route*, которая используется для генерации маршрута просмотра сообщения и настраивается при монтировании модуля (см. код выше).

Теперь мне RESTAS нравится намного больше, но вот кроме arblog теперь ничего больше не работает. Придётся "чинить" все остальные мои приложения (но это в общем, довольно тривиально), так что я видимо главный пострадавший от такого "рефакторига" :) А то я ведь даже arblog не могу на сервере обновить, ведь тогда "отвалится" lisper.ru.