Added a Json REST handler.
This commit is contained in:
parent
dfa8ccd0ac
commit
78977d9fef
|
@ -2,6 +2,7 @@
|
||||||
:description "FIXME: write description"
|
:description "FIXME: write description"
|
||||||
:url "http://example.com/FIXME"
|
:url "http://example.com/FIXME"
|
||||||
:dependencies [[org.clojure/clojure "1.6.0"]
|
:dependencies [[org.clojure/clojure "1.6.0"]
|
||||||
|
[org.clojure/data.json "0.2.6"]
|
||||||
[lib-noir "0.8.1"]
|
[lib-noir "0.8.1"]
|
||||||
[compojure "1.1.6"]
|
[compojure "1.1.6"]
|
||||||
[ring-server "0.3.1"]
|
[ring-server "0.3.1"]
|
||||||
|
|
|
@ -26,9 +26,11 @@
|
||||||
|
|
||||||
(def item-prices {:caramel-wafer 10 :teacake 16 :snowball 22})
|
(def item-prices {:caramel-wafer 10 :teacake 16 :snowball 22})
|
||||||
|
|
||||||
|
|
||||||
(defn coin-value [coin]
|
(defn coin-value [coin]
|
||||||
(coin-values coin))
|
(coin-values coin))
|
||||||
|
|
||||||
|
|
||||||
(defn coins-value [coins]
|
(defn coins-value [coins]
|
||||||
"Sum the value of this list of coins."
|
"Sum the value of this list of coins."
|
||||||
(cond coins (apply + (map coin-value coins))
|
(cond coins (apply + (map coin-value coins))
|
||||||
|
@ -36,35 +38,71 @@
|
||||||
|
|
||||||
|
|
||||||
(defn message-machine [machine message]
|
(defn message-machine [machine message]
|
||||||
"Return a machine with this message"
|
"Return a machine like this machine but with this message"
|
||||||
(assoc (dissoc machine :message) :message (.toString message)))
|
(assoc (dissoc machine :message) :message (.toString message)))
|
||||||
|
|
||||||
|
|
||||||
(defn coin-return [machine]
|
(defn coin-return [machine]
|
||||||
"Return all tendered coins in this machine."
|
"Return all tendered coins in this machine."
|
||||||
(message-machine (assoc (dissoc machine :tendered) :change (:tendered machine)) "Coins returned"))
|
(message-machine
|
||||||
|
(assoc (dissoc machine :tendered) :change (:tendered machine))
|
||||||
|
"Coins returned"))
|
||||||
|
|
||||||
|
|
||||||
(defn add-coin [machine coin]
|
(defn add-coin [machine coin]
|
||||||
"Add this coin to this machine."
|
"Add this coin to this machine."
|
||||||
(if
|
(if
|
||||||
(member? (keys coin-values) coin)
|
(member? (keys coin-values) coin)
|
||||||
(message-machine (assoc (dissoc machine :tendered) :tendered (cons coin (:tendered machine))) (str "Added a " coin))
|
(message-machine
|
||||||
(message-machine (assoc (dissoc machine :change) :change (cons coin (:change machine))) (str "Sorry, this machine doesn't accept " coin "s"))))
|
(assoc (dissoc machine :tendered) :tendered (cons coin (:tendered machine)))
|
||||||
|
(str "Added a " coin))
|
||||||
|
(message-machine
|
||||||
|
(assoc (dissoc machine :change) :change (cons coin (:change machine)))
|
||||||
|
(str "Sorry, this machine doesn't accept " coin "s"))))
|
||||||
|
|
||||||
|
|
||||||
(defn add-coins [machine coins]
|
(defn add-coins [machine coins]
|
||||||
"Add these coins to this machine"
|
"Add these coins to this machine"
|
||||||
(cond (empty? coins) machine
|
(if (empty? coins) machine
|
||||||
true (add-coins (add-coin machine (first coins)) (rest coins))))
|
(add-coins (add-coin machine (first coins)) (rest coins))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn add-merk
|
||||||
|
"Return a machine like this machine but with one merk added."
|
||||||
|
[machine]
|
||||||
|
(add-coin machine :merk))
|
||||||
|
|
||||||
|
|
||||||
|
(defn add-bawbee
|
||||||
|
"Return a machine like this machine but with one bawbee added."
|
||||||
|
[machine]
|
||||||
|
(add-coin machine :bawbee))
|
||||||
|
|
||||||
|
|
||||||
|
(defn add-plack
|
||||||
|
"Return a machine like this machine but with one plack added."
|
||||||
|
[machine]
|
||||||
|
(add-coin machine :plack))
|
||||||
|
|
||||||
|
|
||||||
|
(defn add-bodle
|
||||||
|
"Return a machine like this machine but with one bodle added."
|
||||||
|
[machine]
|
||||||
|
(add-coin machine :bodle))
|
||||||
|
|
||||||
|
|
||||||
(defn magic-inc [maybenum]
|
(defn magic-inc [maybenum]
|
||||||
"A wrapper round inc which treats nil as zero."
|
"A wrapper round inc which treats nil as zero."
|
||||||
(cond (nil? maybenum) 1
|
(cond (nil? maybenum) 1
|
||||||
true (inc maybenum)))
|
true (inc maybenum)))
|
||||||
|
|
||||||
|
|
||||||
(defn sum-coin [coin sums]
|
(defn sum-coin [coin sums]
|
||||||
"Adds this coin (assumed to be on of :merk, :plack, :bawbee, :bodle)
|
"Adds this coin (assumed to be on of :merk, :plack, :bawbee, :bodle)
|
||||||
to this map of sums."
|
to this map of sums."
|
||||||
(update-in sums [coin] magic-inc))
|
(update-in sums [coin] magic-inc))
|
||||||
|
|
||||||
|
|
||||||
(defn sum-coins
|
(defn sum-coins
|
||||||
"takes a list in the form (:merk :merk :bawbee :plack :bodle) and returns
|
"takes a list in the form (:merk :merk :bawbee :plack :bodle) and returns
|
||||||
a wallet {:merk 2 :plack 1 :bawbee 1 :bodle 1}. Optional second argument: an
|
a wallet {:merk 2 :plack 1 :bawbee 1 :bodle 1}. Optional second argument: an
|
||||||
|
@ -76,56 +114,64 @@
|
||||||
true (sum-coins (rest coins) (sum-coin (first coins) sums)))))
|
true (sum-coins (rest coins) (sum-coin (first coins) sums)))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defn subtract-denomination [list position]
|
(defn subtract-denomination [list position]
|
||||||
"given a list of four numbers and a position, return a similar list with one subtracted
|
"given a list of four numbers and a position, return a similar list with one subtracted
|
||||||
from the number at this position in the list"
|
from the number at this position in the list"
|
||||||
(cond (= (count list) position)(cons (- (first list) 1) (rest list))
|
(cond (= (count list) position)(cons (- (first list) 1) (rest list))
|
||||||
true (cons (first list) (subtract-denomination (rest list) position))))
|
true (cons (first list) (subtract-denomination (rest list) position))))
|
||||||
|
|
||||||
(defn subtract-nickle [list]
|
|
||||||
|
(defn subtract-bodle [list]
|
||||||
(subtract-denomination list 1))
|
(subtract-denomination list 1))
|
||||||
|
|
||||||
|
|
||||||
(defn subtract-bawbee [list]
|
(defn subtract-bawbee [list]
|
||||||
(subtract-denomination list 2))
|
(subtract-denomination list 2))
|
||||||
|
|
||||||
|
|
||||||
(defn subtract-plack [list]
|
(defn subtract-plack [list]
|
||||||
(subtract-denomination list 3))
|
(subtract-denomination list 3))
|
||||||
|
|
||||||
|
|
||||||
(defn subtract-merk [list]
|
(defn subtract-merk [list]
|
||||||
(subtract-denomination list 4))
|
(subtract-denomination list 4))
|
||||||
|
|
||||||
(defn- in-make-change [amount merk plack bawbee bodle]
|
|
||||||
|
(defn- in-make-change [amount merk bawbee plack bodle]
|
||||||
"Given this amount of change to make, and this number each of merks, placks, bawbees
|
"Given this amount of change to make, and this number each of merks, placks, bawbees
|
||||||
and bodles, return a tuple (merk plack bodle bawbee) which indicates the number remaining
|
and bodles, return a tuple (merk plack bodle bawbee) which indicates the number remaining
|
||||||
after making change, or nil if not possible"
|
after making change, or nil if not possible"
|
||||||
(cond
|
(cond
|
||||||
(= amount 0) (list merk plack bawbee bodle)
|
(= amount 0) (list merk bawbee plack bodle)
|
||||||
(and (>= amount (:merk coin-values)) (> merk 0))
|
(and (>= amount (:merk coin-values)) (> merk 0))
|
||||||
(in-make-change (- amount (:merk coin-values)) (- merk 1) plack bawbee bodle)
|
(in-make-change (- amount (:merk coin-values)) (- merk 1) bawbee plack bodle)
|
||||||
(and (>= amount (:plack coin-values)) (> plack 0))
|
|
||||||
(in-make-change (- amount (:plack coin-values)) merk (- plack 1) bawbee bodle)
|
|
||||||
(and (>= amount (:bawbee coin-values)) (> bawbee 0))
|
(and (>= amount (:bawbee coin-values)) (> bawbee 0))
|
||||||
(in-make-change (- amount (:bawbee coin-values)) merk plack (- bawbee 1) bodle)
|
(in-make-change (- amount (:bawbee coin-values)) merk (- bawbee 1) plack bodle)
|
||||||
|
(and (>= amount (:plack coin-values)) (> plack 0))
|
||||||
|
(in-make-change (- amount (:plack coin-values)) merk bawbee (- plack 1) bodle)
|
||||||
(and (>= amount (:bodle coin-values)) (> bodle 0))
|
(and (>= amount (:bodle coin-values)) (> bodle 0))
|
||||||
(in-make-change (- amount (:bodle coin-values)) merk plack bawbee (- bodle 1))))
|
(in-make-change (- amount (:bodle coin-values)) merk bawbee plack (- bodle 1))))
|
||||||
|
|
||||||
|
|
||||||
(defn n-of [elt n]
|
(defn n-of [elt n]
|
||||||
"return a list of n instances of elt"
|
"return a list of n instances of elt"
|
||||||
(cond (<= n 0) nil
|
(cond (<= n 0) nil
|
||||||
true (cons elt (n-of elt (dec n)))))
|
true (cons elt (n-of elt (dec n)))))
|
||||||
|
|
||||||
|
|
||||||
(defn to-coins [quadtuple]
|
(defn to-coins [quadtuple]
|
||||||
"Given a list in the form (merks placks bawbies bodles), return a
|
"Given a list in the form (merks bawbies placks bodles), return a
|
||||||
flat list of coin symbols"
|
flat list of coin symbols"
|
||||||
|
(let [n (count quadtuple)]
|
||||||
(remove nil?
|
(remove nil?
|
||||||
(flatten
|
(flatten
|
||||||
(list
|
(list
|
||||||
(n-of :merk (nth quadtuple 0))
|
(n-of :merk (if (> n 0) (nth quadtuple 0) 0))
|
||||||
(n-of :plack (nth quadtuple 1))
|
(n-of :bawbee (if (> n 1) (nth quadtuple 1) 0))
|
||||||
(n-of :bawbee (nth quadtuple 2))
|
(n-of :plack (if (> n 2) (nth quadtuple 2) 0))
|
||||||
(n-of :bodle (nth quadtuple 3))
|
(n-of :bodle (if (> n 3) (nth quadtuple 3) 0))
|
||||||
))))
|
)))))
|
||||||
|
|
||||||
|
|
||||||
(defn make-change [amount coins]
|
(defn make-change [amount coins]
|
||||||
"Given this amount of change to make, and this number each of merks, placks, bawbees
|
"Given this amount of change to make, and this number each of merks, placks, bawbees
|
||||||
|
@ -133,11 +179,11 @@
|
||||||
number of each remaining after making change, or nil if not possible"
|
number of each remaining after making change, or nil if not possible"
|
||||||
(to-coins
|
(to-coins
|
||||||
(let [merk (:merk coins)
|
(let [merk (:merk coins)
|
||||||
plack (:plack coins)
|
|
||||||
bawbee (:bawbee coins)
|
bawbee (:bawbee coins)
|
||||||
|
plack (:plack coins)
|
||||||
bodle (:bodle coins)]
|
bodle (:bodle coins)]
|
||||||
(map #(- %1 %2) (map #(or % 0) (list merk plack bawbee bodle))
|
(map #(- %1 %2) (map #(or % 0) (list merk bawbee plack bodle))
|
||||||
(apply in-make-change (map #(or % 0) (list amount merk plack bawbee bodle)))
|
(apply in-make-change (map #(or % 0) (list amount merk bawbee plack bodle)))
|
||||||
))))
|
))))
|
||||||
|
|
||||||
|
|
||||||
|
@ -164,30 +210,36 @@
|
||||||
the keys of these maps, using this default when no value present"
|
the keys of these maps, using this default when no value present"
|
||||||
(in-op-maps op (union (keys map1) (keys map2)) map1 map2 dflt))
|
(in-op-maps op (union (keys map1) (keys map2)) map1 map2 dflt))
|
||||||
|
|
||||||
|
|
||||||
(defn add-wallets [wallet1 wallet2]
|
(defn add-wallets [wallet1 wallet2]
|
||||||
(op-maps + wallet1 wallet2 0))
|
(op-maps + wallet1 wallet2 0))
|
||||||
|
|
||||||
|
|
||||||
(defn subtract-change-machine [machine change]
|
(defn subtract-change-machine [machine change]
|
||||||
"return a copy of this machine which has this amount of change removed from its coins"
|
"return a copy of this machine which has this amount of change removed from its coins"
|
||||||
(let [coins (:coins machine)]
|
(let [coins (:coins machine)]
|
||||||
(assoc (dissoc machine :coins) :coins (subtract-change coins change))))
|
(assoc (dissoc machine :coins) :coins (subtract-change coins change))))
|
||||||
|
|
||||||
|
|
||||||
(defn make-change-machine [machine change]
|
(defn make-change-machine [machine change]
|
||||||
"given this machine and these numbers of coins to remove, return a copy of the machine
|
"given this machine and these numbers of coins to remove, return a copy of the machine
|
||||||
with the coins removed"
|
with the coins removed"
|
||||||
(cond (empty? change) machine
|
(cond (empty? change) machine
|
||||||
true (assoc (dissoc (subtract-change-machine machine change) :change ) :change change )))
|
true (assoc (dissoc (subtract-change-machine machine change) :change ) :change change )))
|
||||||
|
|
||||||
|
|
||||||
(defn remove-from-stock [machine item]
|
(defn remove-from-stock [machine item]
|
||||||
"return a copy of this machine with one fewer of this item in stock"
|
"return a copy of this machine with one fewer of this item in stock"
|
||||||
(update-in machine [:stock item] dec))
|
(update-in machine [:stock item] dec))
|
||||||
|
|
||||||
|
|
||||||
(defn deliver-item [machine item]
|
(defn deliver-item [machine item]
|
||||||
"Remove an item matching this item from stock and add it to the output hopper"
|
"Remove an item matching this item from stock and add it to the output hopper"
|
||||||
(remove-from-stock
|
(remove-from-stock
|
||||||
(assoc (dissoc machine :output) :output (cons item (:output machine)))
|
(assoc (dissoc machine :output) :output (cons item (:output machine)))
|
||||||
item))
|
item))
|
||||||
|
|
||||||
|
|
||||||
(defn store-coins-machine [machine]
|
(defn store-coins-machine [machine]
|
||||||
;; add the tendered coins to the coin stacks
|
;; add the tendered coins to the coin stacks
|
||||||
(let [wallet (sum-coins (:tendered machine))]
|
(let [wallet (sum-coins (:tendered machine))]
|
||||||
|
@ -195,30 +247,34 @@
|
||||||
(dissoc (dissoc machine :tendered) :coins)
|
(dissoc (dissoc machine :tendered) :coins)
|
||||||
:coins (add-wallets wallet (:coins machine)))))
|
:coins (add-wallets wallet (:coins machine)))))
|
||||||
|
|
||||||
|
|
||||||
(defn get-item [machine item]
|
(defn get-item [machine item]
|
||||||
(let [item-price (item item-prices)
|
(let [item-price (item item-prices)
|
||||||
coins (:coins machine)
|
coins (:coins machine)
|
||||||
tendered (coins-value (:tendered machine))
|
tendered (coins-value (:tendered machine))
|
||||||
change (make-change (- tendered item-price) coins)]
|
change (if
|
||||||
;; (print (list "hello" item-price coins tendered change ))
|
(> tendered item-price) (make-change (- tendered item-price) coins))]
|
||||||
|
(print (list "hello" item-price coins tendered change ))
|
||||||
(cond (> 0 (item (:stock machine))) (message-machine (coin-return machine) (str "Sorry, " item " not in stock"))
|
(cond (> 0 (item (:stock machine))) (message-machine (coin-return machine) (str "Sorry, " item " not in stock"))
|
||||||
(<= tendered item-price) (message-machine machine "Please insert more money")
|
(< tendered item-price) (message-machine machine "Please insert more money")
|
||||||
(= change '(0 0 0 0)) (message-machine (coin-return machine) "Sorry, I don't have enough change.")
|
(= change '()) (message-machine (coin-return machine) "Sorry, I don't have enough change.")
|
||||||
true (message-machine
|
true (message-machine
|
||||||
(store-coins-machine
|
(store-coins-machine
|
||||||
(make-change-machine
|
(make-change-machine
|
||||||
(deliver-item machine item) change))
|
(deliver-item machine item) change))
|
||||||
(str "Enjoy your " item)))))
|
(str "Enjoy your " item)))))
|
||||||
|
|
||||||
|
|
||||||
(defn get-caramel-wafer [machine]
|
(defn get-caramel-wafer [machine]
|
||||||
(get-item machine :caramel-wafer))
|
(get-item machine :caramel-wafer))
|
||||||
|
|
||||||
|
|
||||||
(defn get-teacake [machine]
|
(defn get-teacake [machine]
|
||||||
(get-item machine :teacake))
|
(get-item machine :teacake))
|
||||||
|
|
||||||
(defn get-snowball [machine]
|
(defn get-snowball [machine]
|
||||||
(get-item machine :snowball))
|
(get-item machine :snowball))
|
||||||
|
|
||||||
;; (get-caramel-wafer (add-coin (add-coin (make-default-machine) :merk) :merk))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
(ns vending.handler
|
(ns vending.handler
|
||||||
(:require [compojure.core :refer [defroutes]]
|
(:require [compojure.core :refer [defroutes]]
|
||||||
[vending.routes.home :refer [home-routes]]
|
[vending.routes.home :refer [home-routes]]
|
||||||
|
[vending.routes.json :refer [json-routes]]
|
||||||
[vending.middleware :as middleware]
|
[vending.middleware :as middleware]
|
||||||
[noir.util.middleware :refer [app-handler]]
|
[noir.util.middleware :refer [app-handler]]
|
||||||
[compojure.route :as route]
|
[compojure.route :as route]
|
||||||
|
@ -44,7 +45,7 @@
|
||||||
|
|
||||||
(def app (app-handler
|
(def app (app-handler
|
||||||
;; add your application routes here
|
;; add your application routes here
|
||||||
[home-routes app-routes]
|
[home-routes json-routes app-routes]
|
||||||
;; add custom middleware here
|
;; add custom middleware here
|
||||||
:middleware [middleware/template-error-page
|
:middleware [middleware/template-error-page
|
||||||
middleware/log-request]
|
middleware/log-request]
|
||||||
|
|
82
src/vending/routes/json.clj
Normal file
82
src/vending/routes/json.clj
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
(ns ^{:doc "A set of REST requests which manipulate a vending machine held in the session server-side."
|
||||||
|
:author "Simon Brooke"}
|
||||||
|
vending.routes.json
|
||||||
|
(:use compojure.core)
|
||||||
|
(:require [clojure.data.json :as json]
|
||||||
|
[noir.session :as session]
|
||||||
|
[vending.core :as machine]
|
||||||
|
[vending.util :as util]))
|
||||||
|
|
||||||
|
|
||||||
|
(defn- perform-action
|
||||||
|
"Apply this function to the machine in the session, if there is one, or else to a new default
|
||||||
|
machine; cache the result in the session; and return a JSON formatted representation of the result."
|
||||||
|
[function]
|
||||||
|
(let [machine (apply function (list (or (session/get :machine) (machine/make-default-machine))))]
|
||||||
|
(session/put! :machine machine)
|
||||||
|
(json/write-str machine)))
|
||||||
|
|
||||||
|
|
||||||
|
;;; Each of these action functions perform an action on the machine in the session, if there is one,
|
||||||
|
;;; or on a new default machine if there is no machine in the session. They return (and cache in the
|
||||||
|
;;; session) the new state of the machine after the action; the machine returned is returned as a
|
||||||
|
;;; JSON string.
|
||||||
|
|
||||||
|
(defn coin-return-action
|
||||||
|
"Return all the coins that have been tendered since the last sale."
|
||||||
|
[]
|
||||||
|
(perform-action machine/coin-return))
|
||||||
|
|
||||||
|
|
||||||
|
(defn add-merk-action
|
||||||
|
"Insert one merk into the coin slot of the machine in the session."
|
||||||
|
[]
|
||||||
|
(perform-action machine/add-merk))
|
||||||
|
|
||||||
|
|
||||||
|
(defn add-bawbee-action
|
||||||
|
"Insert one bawbee into the coin slot of the machine in the session."
|
||||||
|
[]
|
||||||
|
(perform-action machine/add-bawbee))
|
||||||
|
|
||||||
|
|
||||||
|
(defn add-plack-action
|
||||||
|
"Insert one plack into the coin slot of the machine in the session."
|
||||||
|
[]
|
||||||
|
(perform-action machine/add-plack))
|
||||||
|
|
||||||
|
|
||||||
|
(defn add-bodle-action
|
||||||
|
"Insert one bodle into the coin slot of the machine in the session."
|
||||||
|
[]
|
||||||
|
(perform-action machine/add-bodle))
|
||||||
|
|
||||||
|
|
||||||
|
(defn select-caramel-wafer-action
|
||||||
|
"Request one caramel wafer from the machine in the session."
|
||||||
|
[]
|
||||||
|
(perform-action machine/get-caramel-wafer))
|
||||||
|
|
||||||
|
|
||||||
|
(defn select-teacake-action
|
||||||
|
"Request one teacake from the machine in the session."
|
||||||
|
[]
|
||||||
|
(perform-action machine/get-teacake))
|
||||||
|
|
||||||
|
|
||||||
|
(defn select-snowball-action
|
||||||
|
"Request one snowball from the machine in the session."
|
||||||
|
[]
|
||||||
|
(perform-action machine/get-snowball))
|
||||||
|
|
||||||
|
|
||||||
|
(defroutes json-routes
|
||||||
|
(GET "/coin-return" [] (coin-return-action))
|
||||||
|
(GET "/add-merk" [] (add-merk-action))
|
||||||
|
(GET "/add-bawbee" [] (add-bawbee-action))
|
||||||
|
(GET "/add-plack" [] (add-plack-action))
|
||||||
|
(GET "/add-bodle" [] (add-bodle-action))
|
||||||
|
(GET "/select-caramel-wafer" [] (select-caramel-wafer-action))
|
||||||
|
(GET "/select-teacake" [] (select-teacake-action))
|
||||||
|
(GET "/select-snowball" [] (select-snowball-action))
|
||||||
|
)
|
Loading…
Reference in a new issue