summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjetil Orbekk <kj@orbekk.com>2021-07-06 22:21:23 -0400
committerKjetil Orbekk <kj@orbekk.com>2021-07-06 22:21:23 -0400
commitcac05c040cfa42440f73eea2c1e4c645a40c9363 (patch)
tree9ba86f47237ec3a423440f4dde299a14cac83fcc
parent4226f9d0716dbe0274a76c46705c831da8a10d9a (diff)
some clojure stuff
-rw-r--r--clojure/project.clj1
-rw-r--r--clojure/src/csvtool/core.clj106
2 files changed, 99 insertions, 8 deletions
diff --git a/clojure/project.clj b/clojure/project.clj
index 6e26b8f..398c4bb 100644
--- a/clojure/project.clj
+++ b/clojure/project.clj
@@ -6,6 +6,7 @@
:dependencies [
[org.clojure/clojure "1.10.1"]
[org.clojure/data.csv "1.0.0"]
+ [org.clojure/tools.cli "1.0.206"]
]
:main ^:skip-aot csvtool.core
:target-path "target/%s"
diff --git a/clojure/src/csvtool/core.clj b/clojure/src/csvtool/core.clj
index 11e6bc7..a881ad8 100644
--- a/clojure/src/csvtool/core.clj
+++ b/clojure/src/csvtool/core.clj
@@ -1,21 +1,111 @@
(ns csvtool.core
+ (:require [clojure.data.csv :as csv]
+ [clojure.pprint :refer [pprint]]
+ [clojure.tools.cli :refer [parse-opts]]
+ [clojure.java.io :as io])
(:gen-class))
-(require '[clojure.data.csv :as csv]
- '[clojure.java.io :as io])
-
-(defn -main
- "I don't do a whole lot ... yet."
- [& args]
- (println "Hello, World!"))
+(defn mk-mapping [row & keys]
+ (->> (zipmap keys row)
+ (#(dissoc % :ignore))))
(defn my-read []
(with-open [reader (io/reader "in-file.csv")]
(doall
- (csv/read-csv reader))))
+ (map handle-record (csv/read-csv reader)))))
(defn my-write []
(with-open [writer (io/writer "out-file.csv")]
(csv/write-csv writer
[["abc" "def"]
["ghi" "jkl"]])))
+
+(defmacro wrap-matcher
+ ([] identity)
+
+ ([body]
+ `(fn [~'record]
+ (let [~'get #(get ~'record %)
+ ~'set #(assoc ~'record %1 %2)]
+ ~body)))
+
+ ([expr & next]
+ `(fn [record#]
+ ((wrap-matcher ~@next) ((wrap-matcher ~expr) record#)))))
+
+(defmacro matches
+ [keyword pattern]
+ `(wrap-matcher
+ (let [v# (~'get ~keyword)]
+ (and v# (re-matches ~pattern (~'get ~keyword))))))
+
+(defmacro defchain
+ ([] identity)
+
+ ([[pred & arg]]
+ (let [expr2
+ (if (= :do (first arg))
+ `((wrap-matcher ~@(rest arg)))
+ arg)]
+ `(fn [record#]
+ (if (~pred record#)
+ (~@expr2 record#)
+ record#))))
+
+ ([x & next]
+ `(fn [record#]
+ ((defchain ~@next)
+ ((defchain ~x) record#)))))
+
+(def always (constantly true))
+
+(def other-rules
+ (defchain
+ [(matches :desc #"Amazon.com.*")
+ :do (set :desc "Amazon purchase")]))
+
+(def my-rules
+ (defchain
+ [always :do (set :account2 "expenses:unknown")]
+
+ [(matches :desc #"(?i)key food.*")
+ :do
+ (set :desc "Key Foods")
+ (set :account2 "expenses:groceries")]
+
+ [(matches :desc #"(?i)google \*cloud")
+ :do
+ (set :desc "Google Cloud")
+ (set :account2 "expenses:services")]
+
+ [always other-rules]))
+
+(defn handle-record [row]
+ (let [record (mk-mapping row :date :postdate :desc :category :type :amount :memo)]
+ (my-rules record)
+ ))
+
+(defn process-file [path]
+ (with-open [reader (io/reader path)]
+ (doall
+ (let [csv (csv/read-csv reader)
+ ;; Skip header
+ data (drop 1 csv)
+ sample (take 10 data)
+ records (map handle-record sample)]
+ (pprint records)))))
+
+(def cli-options
+ [["-f" "--file" :required "Input file"]
+ ["-h" "--help"]])
+
+(defn -main
+ [& args]
+
+ (pprint (parse-opts args cli-options))
+
+ (let [{:keys [options arguments errors summary]} (parse-opts args cli-options)]
+ (cond
+ (:file options) (process-file (:file options))
+ :else
+ (do (println "Failed")))))