Просмотр исходного кода

shopping_list: What, where and how much.

This version has the basic grouping (category, initial, price, weight)
in place but the frontend, the sorting and a storage backend are
lacking.

Dedicated to my little sister, thus intended to eventually demonstrate
at least the concepts to here and an exercise in creating beautiful
abstractions in a functional language.

At least one criterion is partly fulfilled: it's a simple solution and
so far it works well. It's almost like an algebra which is quite
pleasing.

Well now, have fun, take care an' good night.
Lucas Stadler лет назад: 12
Родитель
Сommit
3fc221240c

+ 13 - 0
clj/shopping_list/project.clj

@ -0,0 +1,13 @@
1
(defproject shopping-list "0.0-SNAPSHOT"
2
  :description "A shopping list in Clojure & ClojureScript"
3
  :dependencies [[org.clojure/clojure "1.5.0"]
4
                 [ring "1.2.0-beta2"]
5
                 [compojure "1.1.5"]]
6
  :plugins [[lein-ring "0.8.3"]
7
            [lein-cljsbuild "0.3.0"]]
8
  :ring {:handler shopping-list.server/shopping-list}
9
  :cljsbuild {:builds [{:source-paths ["."]
10
                        :compiler {:output-to "js/shoppinglist.js"
11
                                   :optimizations :whitespace
12
                                   :pretty-print true}}]}
13
  :source-paths ["."])

+ 88 - 0
clj/shopping_list/shopping_list.clj

@ -0,0 +1,88 @@
1
(ns shopping-list
2
  (:use [clojure.core :as core])
3
  (:use [clojure.repl :as repl]))
4
5
(defn sort-map
6
  ([m] (sort-map compare m))
7
  ([c m] (apply sorted-map-by c (reduce #(into %1 %2) (seq m)))))
8
9
(def example-article
10
  (sort-map
11
    {:all-articles
12
       [{:name "spinach", :price 3.1, :weight 0.5, :category "vegetables"}
13
        {:name "apple", :price 2.3, :weight 1.34, :category "vegetables"}
14
        {:name "onion bread", :price 1.79, :weight 1.1, :category "baked goods"}
15
        {:name "soy pudding", :price 1.99, :weight 0.5, :category "sweeties"}
16
        {:name "gum hearts", :price 2.49, :weight 0.4, :category "sweeties"}]}))
17
18
(defn create []
19
  {:known_articles []
20
   :articles []
21
   :sort-method :default})
22
23
(defn mmap [f m]
24
  (into (sorted-map) (map (fn [[key val]]
25
                  [key (f val)])
26
                m)))
27
28
(defn sort-by [key-or-keyfn grouped-articles]
29
  (mmap #(core/sort-by key-or-keyfn %) grouped-articles))
30
31
(def sort-by-category
32
  (partial sort-by :category))
33
34
(sort-by-category {:expensive-things
35
                     [{:category "a" :n 1}, {:category "b" :n 2} {:category "c" :n 3}]
36
                   :cheap-things
37
                     [{:category "d" :n 4}, {:category "a" :n 5}]})
38
(defn regroup-by [key-or-keyfn grouped-articles]
39
  (sort-map
40
    (group-by key-or-keyfn (flatten (vals grouped-articles)))))
41
42
(defn first-char-of-name [article]
43
  (first (:name article)))
44
45
(def group-by-name
46
  (partial mmap #(group-by first-char-of-name)))
47
48
(def regroup-by-name
49
  (partial regroup-by first-char-of-name))
50
51
(def group-by-category
52
  (partial mmap #(group-by :category %)))
53
54
(def regroup-by-category
55
  (partial regroup-by :category))
56
57
(defn categorize-by-price [article]
58
  (let [price (:price article)]
59
    (condp >= price ; (> x price)
60
      0.5 "<0.5$"
61
      1 "<1$"
62
      2.5 "<2.5$"
63
      5 "<5$"
64
      10 "<10$"
65
      (Integer/MAX_VALUE) ">10$")))
66
67
(def group-by-price
68
  (partial mmap #(group-by categorize-by-price %)))
69
70
(def regroup-by-price
71
  (partial regroup-by categorize-by-price))
72
73
(defn categorize-by-weight [article]
74
  (let [weight (:weight article)]
75
    (condp >= weight
76
      0.1 "<100g"
77
      0.25 "<250g"
78
      0.5 "<500g"
79
      1 "<1kg"
80
      2.5 "<2.5kg"
81
      5 "<5kg"
82
      (Integer/MAX_VALUE) ">5kg")))
83
84
(def group-by-weight
85
  (partial mmap #(group-by categorize-by-weight %)))
86
87
(def regroup-by-weight
88
  (partial regroup-by categorize-by-weight))

+ 30 - 0
clj/shopping_list/shopping_list/server.clj

@ -0,0 +1,30 @@
1
(ns shopping-list.server
2
  (:require [shopping-list :as sl])
3
  (:use ring.util.response)
4
  (:use compojure.core)
5
  (:require [compojure.route :as route])
6
  (:use hiccup.core))
7
8
9
(defn render-groups [groups]
10
  (for [[group-name group-items] groups]
11
    [:div
12
     [:h2 (str group-name)]
13
     [:ul
14
      (for [item group-items]
15
        (let [{:keys [name price weight category]} item]
16
          [:li (str name)]))]]))
17
18
(defn index []
19
  (html
20
   [:html
21
    [:head [:title "BUY ALL THE THINGS"]]
22
    [:body
23
     [:div {:id "main"}
24
      [:h1 "Hi there"]
25
      [:p "Mhh yeah, what's up?"]
26
      (render-groups (sl/sort-map (comp identity compare) (sl/regroup-by-name sl/example-articles)))]]]))
27
28
(defroutes shopping-list
29
  (GET "/" [] (index))
30
  (route/not-found "<h1>oops. alternate reality monsters</h1>"))