Map 在Clojure中,是否有一种惯用的方法在宏定义中分解映射?

Map 在Clojure中,是否有一种惯用的方法在宏定义中分解映射?,map,macros,clojure,noir,destructuring,Map,Macros,Clojure,Noir,Destructuring,我在一个web项目中使用了noir,我已经达到了限制用户访问的程度,这取决于用户对defpage宏定义的所有可能路径的访问级别(和子级别)。原来我有 (defpage [:post "/mysite"] {:as input} (if-not (has-reqd-user-level? :levelX :sublevelY "/grantedRoute") (noir.response/redirect "/insufficientRights") ...)) 然后我想这会

我在一个web项目中使用了noir,我已经达到了限制用户访问的程度,这取决于用户对defpage宏定义的所有可能路径的访问级别(和子级别)。原来我有

(defpage [:post "/mysite"] {:as input}
  (if-not (has-reqd-user-level? :levelX :sublevelY "/grantedRoute")
    (noir.response/redirect "/insufficientRights")
    ...))
然后我想这会消除样板代码:

(defmacro defpage-with-user-level [level sublevel granted-route route data expr]
  `(defpage ~route ~data
     (if-not (has-reqd-user-level? ~level ~sublevel ~granted-route)
       (noir.response/redirect "/insufficientRights")
       ~expr)))
最后,我们使用它如下:

(defpage-with-user-level :levelX :sublevelY "/grantedRoute"
  [:post "/mysite"] {:as input}
  (html
    [:body [:h1 (str "Hello " (:name input) "!")]]))
但正如Rich Hickey在这篇文章中所提到的,它感觉有点尴尬,因为位置绑定在已经存在地图的情况下并不惯用

然而,我一直在寻找一些关于在宏中使用解构绑定的示例或讨论,遗憾的是,我没有发现它们的任何明确用途,因为它的未赋值表达式一直在传递

因此,我想到了以下解决方案:

(defmacro defpage-with-user-level [dts expr]
  `(defpage (:route ~dts) (:data ~dts)
     (if-not (has-reqd-user-level? (:level ~dts) (:sublevel ~dts) (:granted-route ~dts))
       (noir.response/redirect "/insufficientRights")
       ~expr)))
但现在还不清楚如何将映射本地信息的数据映射从:get和:post传递到一个本地信息中,如上面的示例所示


我的第一次尝试没有受到阻碍,这样做对吗?还是我真的需要使用第二种方法?我希望不是。还有其他选择吗?请告诉我。

您的第一个解决方案很好。Rich谈论的是使用普通的旧映射来传递数据,而不是为每种类型的数据创建新的类型/类。例如:您可以使用简单的映射来表示用户信息,而不是创建一个类来表示用户数据

就第二次尝试而言,您可以在宏中使用映射反结构化,如下所示:

(defmacro defpage-with-user-level [{:keys [route data level sublevel granted-route]} expr]
  `(defpage ~route ~data
     (if-not (has-reqd-user-level? ~level ~sublevel ~granted-route)
       (noir.response/redirect "/insufficientRights")
       ~expr)))

(defpage-with-user-level {:level :levelX 
                          :sublevel :sublevelY 
                          :granted-route "/grantedRoute"
                          :route [:post "/mysite"] 
                          :data {:as input}}
  (html
    [:body [:h1 (str "Hello " (:name input) "!")]]))

非常感谢你!这正是我想知道的。所以,我应该坚持你提出的解决方案,还是应该使用我的第一次尝试?基本上,正如你在Rick的帖子中提到的那样,我们将页面数据作为地图封装,所以我想你的更正确。顺便说一句,这家伙很富有,而不是Rick;)大笨蛋!!很抱歉非常感谢。