久しぶりの更新。treeコマンドを作った。

はじまり

何だか最近は更新も滞って何も書いていませんでした。
たまたま、clojureでtreeコマンドを実装しているのをみて作ってみました。

treeコマンドをsequenceだけを使って実装できそうな気がしたのです。
例えば、1,2,3…という数列を作る時には、iterateにincと数字を渡せば良いのと同じように、
上手い具合に、何かの関数とルートになるディレクトリのパスだけ渡して綺麗に書けないかなーと。

(iterate inc 1) ;; (1 2 3 4 ....
(iterate f "<root-directory>") ;; (<root-directory> ... 

コード

reverseが必要だったり、empty?で調べているところが気にくわないのですが完成しました。
30行くらいです。まー、まずまずといったところです。

(ns tool.tree 
  (:import java.io.File))
    
(defn- check-cons [x y]
  (if (empty? x) y (cons x y)))

(defn- dir-files [dir]
  (-> (if (string? dir) (File. dir) dir) .listFiles sort))

(defn files-extend [seqs]
  (let [[[x & xs] & rest] seqs]
    (cond (and x (.isDirectory x)) (check-cons (dir-files x) (cons xs rest))
	  (not x) rest
	  :else (check-cons xs rest))))

(defn- prn-tree-left-side [xs]
  (doseq [x (reverse xs)]
    (print (if (empty? x) "       " "│     "))))

(defn tree [dir]
  (println dir)
  (let [origin (dir-files dir)]
    (doseq [[xs & seqs] (take-while identity (iterate files-extend [origin]))]
      (when-let [[x & xr] xs]
	(prn-tree-left-side seqs)
	(let [prefix (if (empty? xr) "└── " "├── ")]
	  (println prefix (.getName x)))))))

(->> *command-line-args* (map tree) dorun)