summaryrefslogtreecommitdiff
path: root/clojure/src/csvtool/core.clj
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")))))