2013-04-09 49 views
1

我有一张表示关于subversion commit的信息。idomatic clojure前缀替换

实施例的内容:

(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 

我创建2种功能,如:

(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)))) 

但这意味着我必须在我的修复库中为每个新替换项添加一个额外的包装器。

我想简单地说:

  • 鉴于提交地图
  • 提取:仓库值
  • 遍历更换名单前缀
  • 如果任何前缀匹配,替换:仓库价值使用新字符串
  • 否则,请保留:存储库值。

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

回答

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

+0

完美。谢谢 :-) – toolkit 2013-04-09 10:39:13

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)