惯用的clojure前缀替换

时间:2013-04-09 10:19:35

标签: clojure

我有一张代表有关subversion提交信息的地图。

示例内容:

(def commit 
  {:repository "/var/group1/project1"
   :revision-number "1234"
   :author "toolkit"
   etc..}

我想根据前缀匹配更改存储库,以便:

/var/group1 maps to http://foo/group1
/var/group2 maps to http://bar/group2

我创建了两个函数,如:

(defn replace-fn [prefix replacement]
  (fn [str]
    (if (.startsWith str prefix)
      (.replaceFirst str prefix replacement)
      str)))

(def replace-group1 (replace-fn "/var/group1" "http://foo/group1"))
(def replace-group2 (replace-fn "/var/group2" "http://bar/group2"))

现在我必须应用它们:

(defn fix-repository [{:keys [repository] :as commit}]
  (assoc commit :repository
    (replace-group1
      (replace-group2 repository))))

但这意味着我必须在我的fix-repository中为每个新的替代品添加一个额外的包装器。

我想简单地说:

  • 给出提交地图
  • 提取:存储库值
  • 循环替换前缀列表
  • 如果任何前缀匹配,请使用新字符串
  • 替换:repository value
  • 否则,请单独保留:repository值。

我似乎无法构建正确的循环,减少或其他解决方案。

2 个答案:

答案 0 :(得分:2)

您可以使用功能组合:

(def commit 
  {:repository "/var/group2/project1"
   :revision-number "1234"
   :author "toolkit"})

(defn replace-fn [prefix replacement]
  (fn [str]
    (if (.startsWith str prefix)
      (.replaceFirst str prefix replacement)
      str)))

(def replacements
  (comp (replace-fn "/var/group1" "http://foo/group1")
        (replace-fn "/var/group2" "http://foo/group2")))

(defn fix-repository [commit replacements]
  (update-in commit [:repository] replacements))

(fix-repository commit replacements)

答案 1 :(得分:1)

这样的事情怎么样?

(defn replace-any-prefix [replacements-list string]
  (or (first
        (filter identity
          (map (fn [[p r]]
                 (when (.startsWith string p)
                    (.replaceFirst string p r)))
               replacements-list)))
      string)))

(update-in commit
           [:repository]
           (partial replace-any-prefix
                    [["/var/group1" "http://foo/group1"]
                     ["/var/group2" "http:/foo/group2"]]))

更新文档:http://clojuredocs.org/clojure_core/clojure.core/update-in