Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 113 additions & 1 deletion otus-06/src/otus_06/homework.clj
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
(ns otus-06.homework)
(ns otus-06.homework
(:require [clojure.java.io :as io]
[clojure.string :as string]))

;; Загрузить данные из трех файлов на диске.
;; Эти данные сформируют вашу базу данных о продажах.
Expand Down Expand Up @@ -94,3 +96,113 @@


;; Файлы находятся в папке otus-06/resources/homework
(defn- split-line [line]
(string/split line #"\|"))

(defn- fmt-line [line]
(-> line
split-line
rest
vec))
(def ^:private tables {:customer "resources/homework/cust.txt"
:product "resources/homework/prod.txt"
:sales "resources/homework/sales.txt"})
(defn- print-table [fmt-fn name]
(with-open [rdr (io/reader (tables name))]
(doseq [lines (line-seq rdr)]
(println (fmt-fn lines)))))

(defn- table-value [table-key id & [value-col id-col]]
(with-open [rdr (io/reader (tables table-key))]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Правильно не верил, здесь обращение к несуществующей таблез. И если бы в вашей ИДЕ стоял линтер (самостоятельно, или как часть плагина), он бы подчеркнул красным )

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Делал ночью, не допушил эту правку. Использую емакс и practicalli, там всё настроено

(loop [lines (line-seq rdr)]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Имхо нагляднее и короче через функции на сиквенсах - filter, some etc.

(let [line-vec (split-line (first lines))]
(cond (= (line-vec (or id-col 0)) id) (line-vec value-col)
(empty? (rest lines)) nil
:else (recur (rest lines)))))))

(defn- fmt-sales-line [line]
(let [line-vec (fmt-line line)
[customer-id product-id count] line-vec]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Можно сразу (let [[customer-id product-id count] (fmt-line line)]

(vector (table-value :customer customer-id 1)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Можно через литерал вектора [(table-value :customer customer-id 1) ...]

(table-value :product product-id 1)
count)))

(defn- get-product-price [id]
(let [price-col 2]
(parse-double (table-value :product id price-col))))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Если не распарсит, вернет nil, а ниже он умножается => будет эксепшен )


(defn- get-total-product-price [[_ product-id product-count-str]]
(let [product-count (Integer/parseInt product-count-str)]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Без трай-катча вылетит эксепшен, если не распарсит инт )

(* (get-product-price product-id)
product-count)))

(defn- get-total-product-count [[_ _ product-count]]
(Integer/parseInt product-count))

(defn- print-total [name table-key get-total-value]
(let [fomat-str {:customer "%s: %.2f"
:product "%s: %d"}
sales-columns {:customer 0
:product 1}
id (table-value table-key name 0 1)]
(with-open [rdr (io/reader (tables :sales))]
(loop [lines (line-seq rdr)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reduce имхо тут бы смотрелся гораздо уместнее )

total 0]
(if (empty? lines)
(println (format (fomat-str table-key) name total))
(let [line (fmt-line (first lines))
line-id (line (sales-columns table-key))
total-product (get-total-value line)
rest-lines (rest lines)]
(recur rest-lines (if (= id line-id)
(+ total total-product)
total))))))))

(defn- print-menu []
(println "
*** Sales Menu ***
------------------
1. Display Customer Table
2. Display Product Table
3. Display Sales Table
4. Total Sales for Customer
5. Total Count for Product
6. Exit

Enter an option?
"))

(defn- make-action [input]
(cond (= input "1") (do (print-table fmt-line :customer)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(case input ?

true)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true во всех кейсах смотрится немного искусственно, можно nil по дефолту если всё ок, и true наоборот, если надо прекращать безобразие )

(= input "2") (do (print-table fmt-line :product)
true)
(= input "3") (do (print-table fmt-sales-line :sales)
true)
(= input "4") (do (println "Input customer name:")
(print-total (read-line) :customer get-total-product-price)
true)
(= input "5") (do (println "Input product name:")
(print-total (read-line) :product get-total-product-count)
true)
(= input "6") nil
:else true))

(defn -main []
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Приятная мелочь, все приватные функции неймспейса через defn-, хороший стиль

(print-menu)
(loop [num (read-line)]
(and (make-action num)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Понтово, and без ифов/кейсов, функциональный паттерн )

(do (print-menu)
(recur (read-line))))))

(comment
(table-value :product "3" 2)
(table-value :customer "Sue Jones" 0 1)
(table-value :customer "3" 1)
(print-table fmt-line :product)
(print-table fmt-line :customer)
(print-table fmt-line :sales)
(print-total "Sue Jones" :customer get-total-product-price)
(print-total "shoess" :product get-total-product-count)
(-main)
())