Регистрация | Войти
Lisp — программируемый язык программирования
ArBlog
lisomort - 27.03.2013 00:34, Сообщений - 5
Выдалась свободная минутка и некая небольшая необходимость продолжить знакомство с сокровищницей Lisp`а и RESTAS`а в частности.
Сгитил себе Arblog, подивился четкости кода, но некоторых вещей понять не смог. Помогите разобраться.
В первых вариантах моего использования RESTAS подключение шаблонов проходило по сценарию:

(closure-template:compile-template :common-lisp-backend -template-path-)
и дальше с прямым обращением к самим шаблонам. 
Сейчас я так понимаю есть варианты покрасивей через "apply-render-method". Отсюда возник вопрос. Как определяется собственно метод рендера, и как определяется для него соответствующий шаблон?
[#]
Дай угадаю: error: "Unknown as render (TITLE Hello BODY World) via NIL".
motopeh - 27.03.2013 00:46
[#]
> Как определяется собственно метод рендера

man restas::route-render-method помоему.
motopeh - 27.03.2013 00:58
[#]
Варианты "по-красивей" были изначально :) Также можно использовать также :render-method. Разница между :render-method и :apply-render-method в том, что в первом случае вызывается #'funcall, а во втором #'apply. 

Теперь, как определяется реальный метод. 

Структура arblog основана на "политиках", см. подробности в Использование policy-based design в RESTAS. В файле https://github.com/archimag/arblog/blob/master/core/defmodules.lisp объявленна такая "политика" theme.

(restas:define-policy #:theme
  (:interface-package #:arblog.policy.theme)
  (:interface-method-template "THEME-~A")
  (:internal-package #:arblog.internal.theme)
  (:internal-function-template "RENDER.~A")

  (define-method list-recent-posts (posts navigation))
  
  (define-method archive-for-year (year months))
  (define-method archive-for-month (year month posts))
  (define-method archive-for-day (year month day posts))
  (define-method one-post (post))

  (define-method all-tags (tags))
  (define-method posts-with-tag (tag posts navigation))

  (define-method admin-posts (posts navigation))
  (define-method admin-edit-post (&key title markup tags preview))
)

Здесь, фактически, происходит объявление интерфейса и создаётся динамическая переменная *theme*. Эту переменную нужно настроить при монтировании модуля, подставив объект, реализующий описанный интерфейс (политику).  В коде сейчас есть две таких реализации (https://github.com/archimag/arblog/tree/master/policies/theme): mirev (вдохновленно темой mirev из ныне усопшего Byteflow) и isimple (портированно из Wordpress).

Что может сбить с толку, это преобразование имён. В макросе restas:define-policy, например, объявляется метод  #'list-recent-posts, в коде модуля к нему обращаются как к #'render.list-recent-posts. Это из-за опции (:internal-function-template "RENDER.~A") в объявлении policy.
archimag - 27.03.2013 01:08
[#] Ответ на комментарий от archimag 27.03.2013 01:08
спасибо, с этим вроде как разобрался. Возникли еще вопросы. Вот например в коде datastore модуля берем любой метод:

(defmethod datastore-count-posts ((datastore arblog-mongo-datastore) &optional tag)
  (with-posts-collection (posts datastore)
    (mongo:collection-count posts
                            (and tag (make-query datastore "tags" tag)))))
в данном имени имя состоит из двух частей. datastore- это часть от interface-method-template, а обращаться мы будем к ней как написано в :internal-function-templateй. Т.е. ds.count.posts. Это вроде как понятно. Вопрос вот в чем. при объявлении метода мы указываем один параметр "тэги", при реализации добавляем экземпляр класса, т.к. она является методом, реализующим конкретное поведение generic метода. При обращении к данной функции он именно из реализации смотрит класс который используется, или происходит еще какая-то магия?

lisomort - 28.03.2013 23:22
[#] Ответ на комментарий от lisomort 28.03.2013 23:22
Еесли бы я делал вручную и мне было бы не лень, то я сделал бы так:

(defparameter *datastore* nil)

(defgenerice datastore-count-posts (datastore &optional tag))

(defun ds.count-posts (&optional tag)
  (datastore-count-posts *datastore* tag)

Функция ds.count-posts просто вызывает datastore-count-posts, передавая в качестве первого параметра значение переменной *datastore*. Т.е. ds.count-posts ничего не знает об используемой реализации. Значение *datastore* должно быть настроенно (через контекст) при монтировании модуля. Сейчас в коде arblog есть реализация datastore на базе MongoDB, но легко написать реализацию на базе PostgreSQL (via postmodern) или, например, BKNR.DATASTORE.

Смысл "магии" в том, что писать это вручную уж очень нудно, поэтому эту работу выполняет макрос define-policy.
archimag - 29.03.2013 00:16
@2009-2013 lisper.ru