Sfoglia il codice sorgente

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 anni fa
parent
commit
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>"))