Есть ли способ добавить функции в динамически созданное пространство имен?
Я создаю noir webapp, и мне нужно динамически создавать новые представления и модели. Я слежу за примерами noir, в которых представление и контроллер для ресурса имеют отдельные пространства имен, и я нашел, что это очень чистый подход.
В соответствии с этим мне нужно иметь возможность динамически создавать новые пространства имен, соответствующие представлениям и моделям, а затем ставить в них соответствующие функции. Моя идея заключалась в том, чтобы макросы указывались в отдельном пространстве имен, которое при вызове в новом пространстве имен предоставляло соответствующие маршруты /partials/whatever.
Например (пропустите мой первый defmacro):
(ns project.views.proto
(:use noir.core
hiccup.core
hiccup.element
hiccup.form))
(defmacro def-all-page
[path]
`(defpage ~path []
(html
[:h1 "Ya'll here"])))
вызывается из...
(ns project.proto
(:use [clojure.contrib.with-ns :only [with-ns]])
(create-ns 'foo)
(intern 'foo 'path "path") ; In reality, the path is dynamic which is why I intern it
(with-ns 'foo
(clojure.core/refer-clojure)
(use 'noir.core
'hiccup.core
'hiccup.element
'[project.views.proto :only [def-all-page]])
(def-all-page path)
Однако вызов этого из моего нового пространства имен дает мне исключение NullPointerException. Я бы очень признателен за любую помощь, и есть ли лучший подход. Например, просто используя ссылку для пространства имен, которое содержит все необходимые определения?
Первое сообщение, и я не думаю, что это повторение этого. Спасибо!
Ответы
Ответ 1
Прежде всего, этот вопрос немного устарел. Оба Нойра и Clojure развились за последний год. Для ясности я возьму Noir из уравнения и постараюсь ответить на ваш вопрос о динамическом создании функций с помощью макросов.
Следуйте за REPL:
$ lein repl
user=> (in-ns 'foo)
#<Namespace foo>
foo=> (clojure.core/refer-clojure)
nil
foo=> (defmacro say-hello-to
#_=> [name]
#_=> `(defn ~(symbol (str "hello-" name))
#_=> []
#_=> ~(str "hello: " name)))
#'foo/say-hello-to
Здесь мы создаем пространство имен "foo", которое содержит макрос для определения функций "hello-yourname". Позвольте создать другое пространство имен:
foo=> (in-ns 'bar)
#<Namespace bar>
bar=> (clojure.core/refer-clojure)
nil
bar=> (refer 'foo :only '[say-hello-to])
nil
bar=> (say-hello-to "tom")
#'bar/hello-tom
bar=> (say-hello-to "jerry")
#'bar/hello-jerry
Посмотрим, действительно ли они работают:
bar=> (hello-tom)
"hello: tom"
bar=> (hello-jerry)
"hello: jerry"
Я думаю, что это очень близко к вашему оригинальному примеру.
Надеюсь, это поможет!