From cac05c040cfa42440f73eea2c1e4c645a40c9363 Mon Sep 17 00:00:00 2001 From: Kjetil Orbekk Date: Tue, 6 Jul 2021 22:21:23 -0400 Subject: some clojure stuff --- clojure/project.clj | 1 + clojure/src/csvtool/core.clj | 106 +++++++++++++++++++++++++++++++++++++++---- 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"))))) -- cgit v1.2.3