我正在编写一个小应用程序,其中包含密码更改功能和验证码,以确保密码质量。目前,验证器在地图中指定如下:
(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函数时,解决验证函数的最实用方法是什么?
过去几周我尝试了很多方法但是我从来没有对结果表格感到满意(并且没有一种方法可行!)。
一般来说,我想问题是“当命名空间中的函数调用时,符号中的符号是如何被解析的?”
我也对我的实施方面的任何一般性评论感兴趣。
答案 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形式中的符号结果仍然在编译时发生时间。要记住的更重要的是它几乎不需要它。