Регистрация | Войти
Lisp — программируемый язык программирования
RSS
Инициализация вложеных модулей
necto - 31.10.2013 23:35, Сообщений - 14
Добрый день!
В моём проекте есть три уровня вложенности. Назову эти модули так: site->gallery->upload. На самом низком используется некая директория, где я работаю с файлами. Путь хранится в параметре upload:*dir*. Я хочу иметь возможность на самом первом уровне задавать эту директорию. Как это сделать?
Я пробовал завести копию в gallery:*dir*, которая клонируется в upload:*dir* при монтировании, но проблема в том, что монтирование upload происходит до монтирования gallery, и я не смогу таким образом передать параметр из корневого модуля.
restas:initialize-module-instance :after также  не помогает, поскольку в модуле gallery, мы имеем другой контекст (а значит править upload:*dir* бесполезно),
а для модуля upload она вызывается опять же ещё до того, как подмонтирована сама gallery (а значит значение из корневого модуля не известно).

Пока я выхожу из ситуации, используя свой хак для restas, который позволяет входить в контекст дочерних модулей.
Как это сделать канонично?
Или, если таких ситуаций быть не должно, что неправильно в архитектуре приложения?
[#]
Если использовать свежий restas, то сейчас в макросе mount-module есть параметр :inherit-parent-context, установив который в T можно добиться наследования контекста от родительского модуля.

См. пример использования здесь.
archimag - 01.11.2013 00:16
[#] Ответ на комментарий от archimag 01.11.2013 00:16
Из примера не ясно: как же всё-таки задать значение переменной из restas:initialize-module-instance из модуля gallery?
necto - 01.11.2013 23:35
[#] Ответ на комментарий от necto 01.11.2013 23:35
мне нужно, я полагаю, что-то типа gallery:-upl-.*dir*, по аналогии с символами для маршрутов. Но я не нашёл такого символа
necto - 01.11.2013 23:37
[#] Ответ на комментарий от necto 01.11.2013 23:35
> как же всё-таки задать значение переменной из restas:initialize-module-instance из модуля gallery?

Это не нужно.  Ибо:

> Я хочу иметь возможность на самом первом уровне задавать эту директорию.

Так и надо делать. А при монтировании модулей использовать опцию :inherit-parent-context. Единственное, я не помню, сработает ли передать вглубь на несколько уровней. Но если нет, то я поправлю код.
archimag - 01.11.2013 23:52
[#] Ответ на комментарий от archimag 01.11.2013 23:52
Тогда как задать upload:*dir*, соответствующий модулю -upl- из корневого контекста site? Можно ли сделать это при монтировании gallery?
necto - 02.11.2013 09:40
[#] Ответ на комментарий от necto 02.11.2013 09:40
В примере, насколько я вижу, :inherit-parent-context используется только для работы с дочерними маршрутами. Не понятно каков синтаксис для работы именно с контекстами вложенных модулей.
necto - 02.11.2013 09:43
[#] Ответ на комментарий от necto 02.11.2013 09:40
Я чего-то сильно не понимаю. Что, собственно, не так. inherit-parent-context позволяет наследовать контекст от родительского модуля. Таким образом, переменные, установленные на более верхних уровнях, транслируются на нижние. Сделано это специально для того, что не заниматься "ручным" копированием контекста в restas:initialize-module-instance. Что получается не так?
archimag - 02.11.2013 11:26
[#] Ответ на комментарий от archimag 02.11.2013 11:26
На самом деле в модуле gallery у меня два модуля upload: -upload1-, -upload2-. Если я задам upload:*dir*, в котором из этих модулей значение поменяется?
necto - 02.11.2013 17:12
[#] Ответ на комментарий от necto 02.11.2013 17:12

(ql:quickload "restas")

(restas:define-module #:inner (:export #:*inner-var*
                                       #:some-route
)
)


(defvar inner:*inner-var* :default)

(restas:define-route inner:some-route ("" :content-type "text/plain")
  (:render-method #'princ-to-string)
  inner:*inner-var*
)


(restas:define-module #:outer (:use #:cl))

(in-package #:outer)

(restas:mount-module inner1 (:inner)
  (:url "1/")
  (:inherit-parent-context t)
)


(restas:mount-module inner2 (:inner)
  (:url "2/")
  (inner:*inner-var* :changed)
)


(restas:mount-module inner3 (:inner)
  (:url "3/")
)


(restas:define-module #:outer-outer (:use #:cl))

(in-package #:outer-outer)

(restas:mount-module medium (:outer)
  (:url "0/")
  (inner:*inner-var* :inherited)
)


(in-package #:cl-user)

(restas:start :outer-outer :port 8080)

;; http://localhost:8080/0/1/ -> INHERITED
;; http://localhost:8080/0/2/ -> CHANGED
;; http://localhost:8080/0/3/ -> DEFAULT
Menschenkindlein - 03.11.2013 19:55
[#] Ответ на комментарий от Menschenkindlein 03.11.2013 19:55
Это, кажется, не совсем то. Необходимо брать контекст верхнего модуля и с его помощью инициализировать нижний. Я внёс пару небольших исправлений в initialize-module-instance (см. в git), так что теперь данный пример можно переделать следующим образом:

(ql:quickload "restas")

(restas:define-module #:inner
  (:export #:*inner-var* #:some-route)
)


(defvar inner:*inner-var* :default)

(restas:define-route inner:some-route ("" :content-type "text/plain")
  (:render-method #'princ-to-string)
  inner:*inner-var*
)


(restas:define-module #:outer
  (:use #:cl)
  (:export #:*params*)
)


(in-package #:outer)

(defvar *params* '("1" "2" "3"))

(restas:mount-module inner1 (:inner)
  (:url "1/")
)


(restas:mount-module inner2 (:inner)
  (:url "2/")
)


(restas:mount-module inner3 (:inner)
  (:url "3/")
)


(defmethod restas:initialize-module-instance :before ((pkg (eql #.*package*)) context)
  (flet ((init-mounted-module (symbol value)
           (restas:context-add-variable (restas:module-context (restas:find-mounted-module symbol))
                                        'inner:*inner-var*
                                        value
)
)
)

    (let ((*params* (restas:context-symbol-value context '*params*)))
      (init-mounted-module 'inner1 (first *params*))
      (init-mounted-module 'inner2 (second *params*))
      (init-mounted-module 'inner3 (third *params*))
)
)
)


(restas:define-module #:outer-outer (:use #:cl))

(in-package #:outer-outer)

(restas:mount-module medium (:outer)
  (:inherit-parent-context t)
)


(in-package #:cl-user)

(restas:start :outer-outer
              :port 8080
              :context (restas:make-context '((outer:*params* . ("4" "5" "6"))))
)



;; http://localhost:8080/1/ -> 4
;; http://localhost:8080/2/ -> 5
;; http://localhost:8080/3/ -> 6
archimag - 03.11.2013 22:06
[#] Ответ на комментарий от Menschenkindlein 03.11.2013 19:55
Спасибо! Это то, что нужно.
necto - 07.11.2013 12:29
[#] Ответ на комментарий от archimag 03.11.2013 22:06
:context (restas:make-context '((outer:*params* . ("4" "5" "6")))))
В таком варианте конечно можно задать разные параметры для разных подмодулей. Однако, на мой взгляд, более наглядно было бы использовать схему с введением новых символов, по аналогии с маршрутами: outer:inner1.*inner-var*, outer:inner2.*inner-var*, ... Или, воизбежание чрезмерной генерации символов, можно использовать списки, например:

(restas:mount-module medium (:outer)
  (outer:inner1 inner:*inner-var* "1")
  (outer:inner2 inner:*inner-var* "2"))

necto - 07.11.2013 12:38
[#] Ответ на комментарий от necto 07.11.2013 12:38
Ещё можно ввести специальную конструкцию для переименования. В этом случае удастся инкапсулировать подмодули:


(ql:quickload "restas")

(restas:define-module #:inner
  (:export #:*inner-var* #:some-route)
)


(defvar inner:*inner-var* :default)

(restas:define-route inner:some-route ("" :content-type "text/plain")
  (:render-method #'princ-to-string)
  inner:*inner-var*
)


(restas:define-module #:outer
  (:use #:cl)
  (:export #:*params*)
)


(in-package #:outer)

(defvar *params* '("1" "2" "3"))

(restas:mount-module inner1 (:inner)
  (:url "1/")
)


(restas:mount-module inner2 (:inner)
  (:url "2/")
)


(restas:mount-module inner3 (:inner)
  (:url "3/")
)


(restas:rename-var (inner1 inner:*inner-var*) *v1*)
(restas:rename-var (inner2 inner:*inner-var*) *v2*)
(restas:rename-var (inner3 inner:*inner-var*) *v3*)

(restas:define-module #:outer-outer (:use #:cl))

(in-package #:outer-outer)

(restas:mount-module medium (:outer)
  (:inherit-parent-context t)
  (*v1* "1")
  (*v2* "2")
  (*v3* "3")
)


(in-package #:cl-user)

(restas:start :outer-outer
              :port 8080
)


;; http://localhost:8080/1/ -> 4
;; http://localhost:8080/2/ -> 5
;; http://localhost:8080/3/ -> 6

necto - 07.11.2013 12:45
[#] Ответ на комментарий от necto 07.11.2013 12:45
> Ещё можно ввести специальную конструкцию для переименования

Я придерживаюсь того взгляда, что каждая новая возможность должна доказать своё право на существование.
archimag - 07.11.2013 15:28
@2009-2013 lisper.ru