是否有一种干净的方法来向动态创建的命名空间添加函数?

时间:2012-04-22 20:04:25

标签: macros clojure lisp noir

我正在创建一个noir webapp,我需要动态创建新的视图和模型。我一直在关注黑色示例,其中资源的视图和控制器具有单独的命名空间,我发现它是一种非常干净的方法。

为此,我需要能够动态创建与视图和模型相对应的新命名空间,然后在其中实现相应的功能。我的想法是在一个单独的命名空间中指定宏,当在新命名空间中调用时,它将提供适当的路由/部分/其他。

例如(原谅我的第一个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。我非常感谢任何帮助,以及是否有更好的方法。比如,只使用引用包含所有必要定义的命名空间?

第一篇文章,我不认为这是this的重复。谢谢!

1 个答案:

答案 0 :(得分:1)

首先,这个问题已经过时了。 Noir和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"

我认为这与你原来的例子非常接近。

希望这有帮助!