blob: a881ad846a2ca8c1e50706d4b8e7a17fbe9ea2ac (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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))
(defn mk-mapping [row & keys]
(->> (zipmap keys row)
(#(dissoc % :ignore))))
(defn my-read []
(with-open [reader (io/reader "in-file.csv")]
(doall
(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")))))
|