[OCaml] High Intensity Training Online
feat implement Weight, Reps, Rep_range
Concrete representations: Weight.t and Rep_range.t's bounds are floats and ints under the hood, made safe only through the smart constructors the .mli exposes. Rep_range.t is a plain pair, since its invariant (min <= max) is checked once at construction and never needs re-establishing. Wires test_units into the runner, retiring the placeholder smoke test.
Changed files
lib/core/units.ml
@@ -1,37 +1,49 @@
1
Removed:
(* Minimal stubs only; implementation deferred until after the review gate. *)
2
Removed:
3
1
type error = Negative | Not_positive | Inverted_range
4
2
5
Removed:
let pp_error _ _ = failwith "TODO"
3
Added:
let pp_error fmt = function
4
Added:
| Negative -> Format.pp_print_string fmt "must be non-negative and finite"
5
Added:
| Not_positive -> Format.pp_print_string fmt "must be strictly positive"
6
Added:
| Inverted_range ->
7
Added:
Format.pp_print_string fmt "range's minimum exceeds its maximum"
6
8
7
9
module Weight = struct
8
10
type t = float
9
11
10
Removed:
let of_kg _ = failwith "TODO"
11
Removed:
let to_kg _ = failwith "TODO"
12
Added:
let of_kg kg =
13
Added:
if Float.is_finite kg && kg >= 0.0 then Ok kg else Error Negative
14
Added:
15
Added:
let to_kg t = t
12
16
let zero = 0.0
13
Removed:
let compare _ _ = failwith "TODO"
14
Removed:
let equal _ _ = failwith "TODO"
15
Removed:
let pp _ _ = failwith "TODO"
17
Added:
let compare = Float.compare
18
Added:
let equal = Float.equal
19
Added:
let pp fmt t = Format.fprintf fmt "%g kg" t
16
20
end
17
21
18
22
module Reps = struct
19
23
type t = int
20
24
21
Removed:
let of_int _ = failwith "TODO"
22
Removed:
let to_int _ = failwith "TODO"
23
Removed:
let compare _ _ = failwith "TODO"
24
Removed:
let equal _ _ = failwith "TODO"
25
Removed:
let pp _ _ = failwith "TODO"
25
Added:
let of_int n = if n > 0 then Ok n else Error Not_positive
26
Added:
let to_int t = t
27
Added:
let compare = Int.compare
28
Added:
let equal = Int.equal
29
Added:
let pp fmt t = Format.fprintf fmt "%d reps" t
26
30
end
27
31
28
32
module Rep_range = struct
29
33
type t = Reps.t * Reps.t
30
34
31
Removed:
let make ~min:_ ~max:_ = failwith "TODO"
32
Removed:
let min _ = failwith "TODO"
33
Removed:
let max _ = failwith "TODO"
34
Removed:
let contains _ _ = failwith "TODO"
35
Removed:
let equal _ _ = failwith "TODO"
36
Removed:
let pp _ _ = failwith "TODO"
35
Added:
let make ~min ~max =
36
Added:
if Reps.to_int min <= Reps.to_int max then Ok (min, max)
37
Added:
else Error Inverted_range
38
Added:
39
Added:
let min (lo, _) = lo
40
Added:
let max (_, hi) = hi
41
Added:
42
Added:
let contains (lo, hi) r =
43
Added:
Reps.to_int lo <= Reps.to_int r && Reps.to_int r <= Reps.to_int hi
44
Added:
45
Added:
let equal (lo1, hi1) (lo2, hi2) = Reps.equal lo1 lo2 && Reps.equal hi1 hi2
46
Added:
47
Added:
let pp fmt (lo, hi) =
48
Added:
Format.fprintf fmt "%d-%d reps" (Reps.to_int lo) (Reps.to_int hi)
37
49
end
test/test_hito.ml
@@ -1,8 +1,4 @@
1
Removed:
(** Test harness entry point.
1
Added:
(** Test harness entry point. Per-module suites are registered here as their
2
Added:
implementations land. *)
2
3
3
Removed:
Per-module suites are registered here as their implementations land
4
Removed:
([Test_units.suite], [Test_exercise.suite], and so on). Until then this
5
Removed:
smoke test confirms the harness links against the library. *)
6
Removed:
7
Removed:
let smoke = [ ("links", `Quick, fun () -> ()) ]
8
Removed:
let () = Alcotest.run "hito" [ ("harness", smoke) ]
4
Added:
let () = Alcotest.run "hito" Test_units.suite