解析符号:require'd命名空间

时间:2011-07-26 04:47:03

标签: clojure

我正在编写一个小应用程序,其中包含密码更改功能和验证码,以确保密码质量。目前,验证器在地图中指定如下:

(def validations
  {:min-length 6
   :max-length 32})

验证映射在验证命名空间中定义,但我计划稍后将其移动到配置命名空间。我决定以这种方式使用地图是为非程序员直接进行配置。

验证命名空间中有许多验证函数,通常采用以下形式:

(defn min-length [n s]
  {:req (str "be at least " n " characters long")
   :pass? (>= (.length (or s "")) n)})

因此,使用(min-length 3 "clojure")上方的函数将返回{:req "be at least 3 characters long", :pass? true}

我可以使用此函数在验证命名空间中使用此函数验证密码:

(defn validate-new-password [password]
  (into {} (for [[k v] validations]
             [k (eval (list (-> k name symbol) v password))])))

结果如下:

>(validate-new-password "clojure")
{:min-length {:req "be at least 6 characters long", :pass? true}, 
 :max-length {:req "be no longer than 32 characters long", :pass? true}, 
 :min-digits {:req "have at least 1 digit", :pass? false},  
 :allow-whitespace {:req "not contain spaces or tabs", :pass? true}, 
 :allow-dict-words {:req "not be a dictionary word", :pass? false}}

从验证命名空间外部调用validate-new-password函数时,解决验证函数的最实用方法是什么?

过去几周我尝试了很多方法但是我从来没有对结果表格感到满意(并且没有一种方法可行!)。

一般来说,我想问题是“当命名空间中的函数调用时,符号中的符号是如何被解析的?”

我也对我的实施方面的任何一般性评论感兴趣。

2 个答案:

答案 0 :(得分:2)

没有必要进行评估,因为98%的情况都是如此。

(defn validate-new-password
  [password]
  (into {} (for [[k v] validations]
             [k ((->> k name (symbol "your.name.space") resolve) v password)])))

答案 1 :(得分:1)

要回答一般性问题(从问题的倒数第二段开始),符号通常在编译时解决 - 你必须走开(即使用resolve 1 < / sup>)将解决方案推迟到运行时。

也就是说,在这种情况下你可能不需要推迟解决方案,只需在验证命名空间中:require配置命名空间,并在相关位置引用config/validations

如果您希望配置命名空间依赖于验证命名空间(即:require:use本身,或者依赖于它的另一个命名空间,则会出现轻微的复杂情况。在这种情况下,您可以在验证命名空间中提供一些配置设置器,并使用来自配置的设置器。 E.g:

(def validations (atom default-validations))
(defn set-validations! [vs]   (reset! validations vs))
(defn add-validation!  [k v]  (swap! validations assoc k v))

然后将@validations替换为validations中的validate-new-password

或者,您可以将默认验证放在Var中并提供重新绑定Var的函数(可能这只需要发生一次,或者很少发生,所以使用Var应该不是问题):

(def validations default-validations)
(defn set-validations! [vs]  (.bindRoot validations vs))
(defn add-validation!  [k v] (alter-var-root validations assoc k v))

现在,如果你实际上无法预测,在编写代码时,你需要使用哪个命名空间来解析你的符号,那么kotarak的回答(使用resolve)就是要走的路。


1 您可以说eval也允许您这样做,虽然从技术上讲它在运行时执行编译,因此eval'd形式中的符号结果仍然在编译时发生时间。要记住的更重要的是它几乎不需要它。