@@ -0,0 +1,167 @@
1+module Realistic.Todo15 (benchmark) where
2+
3+import Benchmark
4+import String
5+
6+
7+benchmark : Benchmark.Benchmark
8+benchmark =
9+ Benchmark.suite "todomvc business logic"
10+ [ run "type in 5 todos, each 15 characters long" typingActions
11+ , run "do everything" batchActions
12+ ]
13+
14+
15+run : String -> List Action -> Benchmark.Benchmark
16+run description actions =
17+ Benchmark.test
18+ (description ++ " - " ++ toString (List.length actions) ++ " actions")
19+ (\_ -> List.foldl update emptyModel actions)
20+
21+
22+typingActions =
23+ let
24+ enter i =
25+ List.map (\n -> UpdateField (String.repeat n "X")) [1..15]
26+ ++ [ Add ]
27+ in
28+ List.concatMap enter [1..5]
29+
30+
31+batchActions =
32+ let
33+ addTask i =
34+ [ UpdateField ("My task " ++ toString i)
35+ , Add
36+ ]
37+
38+ editTask i =
39+ [ EditingTask i True
40+ , UpdateTask i "New Task text"
41+ , EditingTask i False
42+ ]
43+
44+ check i =
45+ Check i True
46+
47+ uncheck i =
48+ Check i False
49+
50+ isEven i =
51+ i % 2 == 0
52+ in
53+ List.concat
54+ [ List.concatMap addTask [1..50]
55+ , [CheckAll True, CheckAll False]
56+ , List.concatMap editTask (List.filter isEven [1 .. 50])
57+ , List.map check [5, 7, 9, 13, 17, 23, 37]
58+ , List.map uncheck [7, 13, 23, 37]
59+ , [DeleteComplete, Delete 7, Delete 23]
60+ , List.concatMap addTask [51..80]
61+ , List.map check (List.filter isEven [51..80])
62+ , [DeleteComplete, CheckAll True, DeleteComplete]
63+ ]
64+
65+
66+
67+-- MODEL
68+
69+
70+type alias Model =
71+ { tasks : List Task
72+ , field : String
73+ , uid : Int
74+ , visibility : String
75+ }
76+
77+
78+type alias Task =
79+ { description : String
80+ , completed : Bool
81+ , editing : Bool
82+ , id : Int
83+ }
84+
85+
86+newTask : String -> Int -> Task
87+newTask desc id =
88+ { description = desc
89+ , completed = False
90+ , editing = False
91+ , id = id
92+ }
93+
94+
95+emptyModel : Model
96+emptyModel =
97+ { tasks = []
98+ , visibility = "All"
99+ , field = ""
100+ , uid = 0
101+ }
102+
103+
104+
105+-- UPDATE
106+
107+
108+type Action
109+ = NoOp
110+ | UpdateField String
111+ | EditingTask Int Bool
112+ | UpdateTask Int String
113+ | Add
114+ | Delete Int
115+ | DeleteComplete
116+ | Check Int Bool
117+ | CheckAll Bool
118+ | ChangeVisibility String
119+
120+
121+update : Action -> Model -> Model
122+update action model =
123+ case action of
124+ NoOp -> model
125+
126+ Add ->
127+ { model |
128+ uid <- model.uid + 1,
129+ field <- "",
130+ tasks <-
131+ if String.isEmpty model.field
132+ then model.tasks
133+ else model.tasks ++ [newTask model.field model.uid]
134+ }
135+
136+ UpdateField str ->
137+ { model | field <- str }
138+
139+ EditingTask id isEditing ->
140+ let updateTask t = if t.id == id then { t | editing <- isEditing } else t
141+ in
142+ { model | tasks <- List.map updateTask model.tasks }
143+
144+ UpdateTask id task ->
145+ let updateTask t = if t.id == id then { t | description <- task } else t
146+ in
147+ { model | tasks <- List.map updateTask model.tasks }
148+
149+ Delete id ->
150+ { model | tasks <- List.filter (\t -> t.id /= id) model.tasks }
151+
152+ DeleteComplete ->
153+ { model | tasks <- List.filter (not << .completed) model.tasks }
154+
155+ Check id isCompleted ->
156+ let updateTask t = if t.id == id then { t | completed <- isCompleted } else t
157+ in
158+ { model | tasks <- List.map updateTask model.tasks }
159+
160+ CheckAll isCompleted ->
161+ let updateTask t = { t | completed <- isCompleted }
162+ in
163+ { model | tasks <- List.map updateTask model.tasks }
164+
165+ ChangeVisibility visibility ->
166+ { model | visibility <- visibility }
167+