-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathPhonebookApp.sml
82 lines (65 loc) · 2.61 KB
/
PhonebookApp.sml
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
(* Simple phonebook with shared state across clients.
Uses an in-memory "database" implemented as a list.
*)
structure Database =
struct
type ('key, 'data) table = ('key * 'data) list
fun toList x = x
val empty = []
fun update(a,b,[]) = [(a,b)]
| update(a,b,(a1,b1)::t) = if a = a1 then (a,b)::t
else (a1,b1)::update(a,b,t)
end
structure PhonebookApp : WebApp =
struct
type state = (string, string) Database.table
val initial = Database.empty
structure HU = HtmlUtils
fun showPhoneBook phonebook =
( HU.webpage "Names and numbers"
(HU.ul (map (fn (name, no) => name^": "^no)
(Database.toList phonebook)))
, phonebook)
fun main phonebook =
( HU.webpage "Phonebook"
(concat [ HU.p (HU.link "add" "Add person to phonebook")
, HU.p (HU.link "list" "List phonebook")
])
, phonebook)
fun addPage phonebook =
( HU.webpage "Add Person"
(HU.form "addperson"
[ HU.p ("Name: "^ HU.inputText "name")
, HU.p ("Phone number: "^ HU.inputText "number")
, HU.p (HU.submit "Insert")
])
, phonebook)
(* The following three functions deals (rudimentary) with the query
path of an URL (http://en.wikipedia.org/wiki/Query_string).
splitArguments: split path into path and query string
getArgs: transform the fields part of a query string into a list of pairs
findArg: find the value bound to a given name in the output from getArgs
*)
fun splitArguments path = String.tokens (fn c => c = #"?") path
fun getArgs args =
map (fn arg => let val [name, value] = String.tokens (fn c => c = #"=") arg
in (name, value)
end)
(String.tokens (fn c => c = #"&") args)
fun findArg name binds = Option.map #2 (List.find (fn(n, _) => name = n) binds)
fun addPerson phonebook args =
let val bindings = getArgs (hd args)
in case (findArg "name" bindings, findArg "number" bindings) of
(SOME name, SOME number) => (HU.Redirect "/",
Database.update(name, number, phonebook))
| _ => raise Fail "Wrong input"
end
fun response (path, phonebook) =
case splitArguments path of
"list" :: _ => showPhoneBook phonebook
| "add" :: _ => addPage phonebook
| "addperson" :: args => addPerson phonebook args
| _ => main phonebook
end
structure AppServer = WebServerFct(PhonebookApp)
val _ = AppServer.start(SOME 10001)