February 1, 2021
By: Kevin

脚本编码sed vs babashka

问题: 我们的代码中有namespace中含有_的情况

(ns store-pc.final_custom.final_custom_customer_views
  (:require
   [re-frame.core :as rf]
   [store-pc.final_custom.final_custom_customer_events]
   [store-pc.full-custom.components.customer-info :refer [customer-info-page]]))

是违反编码规范的, 因为盘根错节的依赖关系, 手动修改非常麻烦.

我们希望能够通过脚本一次性修改完成, 2021年1月30号我直播修改的时候尝试了sed命令和babashka脚本两种方式, sed脚本处理不完全, 所以最终使用babashka来实现的完整替换.

直播的连接

事后我想sed也是可以完成这个功能的, 只不过需要把ns声明在一行的情况单独处理:

find src -name "*.cljs" | xargs -I {} sed -i'bk'  -e "/(ns.*[^)]$/, /)/ s/_/-/g"  -e "/(ns.*)$/ s/_/-/g"  {}
# (ns.*[^)]$ 对应于(ns 开始, 但是不以)结束的情况, 进行多行查找
# (ns.*)$    对应于(ns开始, )结束在同一行的情况

对比下面的babashka脚本, sed的方案还是要简单很多

(require '[clojure.java.io :as io] )
(require '[clojure.string :refer [join replace]])

(def matcher (.getPathMatcher
              (java.nio.file.FileSystems/getDefault)
              "glob:*.{cljs,cljc}"))

(defn get-all-cljs-file-path []
  (->> "./src"
       io/file                               ;; 目录生成文件对象
       file-seq                              ;; 遍历所有的文件(文件夹)
       (filter #(.isFile %))                 ;; 过滤, 只要文件
       (filter #(.matches matcher (.getFileName (.toPath %)))) ;; 过滤, clj/cljs/cljc文件
       (mapv #(.getPath %))
       ))


(defn split-file [s]
  (loop [input s
         output ""
         depth  0]
    (if (and (zero? depth)
             (seq output)
             (= \) (last output)))
      [output (join input)]
      (recur (rest input)
             (str output (first input))
             (case (first input)
               \( (inc depth)
               \) (dec depth)
               depth)
             ))))

(defn process-file [file]
  (let [src-str (slurp file)
        [ns rest] (split-file src-str)]
    (spit file (str (replace ns "_" "-")
                    rest))))

(->> (get-all-cljs-file-path)
     (mapv process-file))

;;(first-sexp "(ns a_b_c (+ 111))  () []1")

;; => ["(ns a_b_c (+ 111))" "  () []1"]

;; -> (ns a_b_c (+ 1 1))

希望对大家有启发.

Tags: clojure babashka sed