Author: Kevin Schoon [kevinschoon@gmail.com]
Hash: 0ff1ecda694ddbe0a0d1902854f765fd6d15e51f
Timestamp: Tue, 22 Jun 2021 17:01:21 +0000 (3 years ago)

+57 -44 +/-2 browse
use regex for slug parsing
1diff --git a/lib/slug.ml b/lib/slug.ml
2index 9a2bd33..814f61d 100644
3--- a/lib/slug.ml
4+++ b/lib/slug.ml
5 @@ -1,7 +1,18 @@
6 open Core
7
8+ let pattern = Re.Pcre.regexp {|(.*)?note-(\d{8})-(\d{1,})(.md)?|}
9+
10 type t = { path : string; date : Date.t; index : int }
11
12+ let to_string slug = slug.path
13+
14+ let of_string path =
15+ let result = Re.all pattern path |> List.hd_exn in
16+ let items = Re.Group.all result |> Array.to_list in
17+ let date = Date.parse ~fmt:"%Y%m%d" (List.nth_exn items 2) in
18+ let index = int_of_string (List.nth_exn items 3) in
19+ { path; date; index }
20+
21 let shortname t =
22 let date_str = Date.format t.date "%Y%m%d" in
23 sprintf "note-%s-%d" date_str t.index
24 @@ -11,37 +22,32 @@ let compare s1 s2 = String.compare s1.path s2.path
25 let is_note path =
26 Filename.basename path |> String.is_substring ~substring:"note-"
27
28- let of_path path =
29- let slug = Filename.chop_extension (Filename.basename path) in
30- let split = String.split ~on:'-' slug in
31- let date = Date.parse ~fmt:"%Y%m%d" (List.nth_exn split 1) in
32- let index = int_of_string (List.nth_exn split 2) in
33- { path; date; index }
34-
35 let load state_dir =
36 state_dir |> Sys.ls_dir |> List.filter ~f:is_note
37 |> List.map ~f:(Filename.concat state_dir)
38- |> List.map ~f:of_path
39-
40- let next state_dir =
41- let slugs = load state_dir in
42- (* find all slugs for today (00:00:00 -> 23:59:59) *)
43- let now = Time.now () in
44- let today = Time.to_date ~zone:Time.Zone.utc now in
45- let tomorrow = Date.add_days today 1 in
46- let filtered =
47- List.filter
48- ~f:(fun slug -> Date.between ~low:today ~high:tomorrow slug.date)
49- slugs
50- in
51- let next_int =
52- List.fold ~init:(-1)
53- ~f:(fun accm slug -> if slug.index > accm then slug.index else accm)
54- filtered
55- + 1
56- in
57- let date_str = Date.format today "%Y%m%d" in
58- let path =
59- Filename.concat state_dir (Core.sprintf "note-%s-%d.md" date_str next_int)
60- in
61- { path; date = today; index = next_int }
62+ |> List.map ~f:of_string
63+
64+ let next ?(last = None) state_dir =
65+ let today = Time.now () |> Time.to_date ~zone:Time.Zone.utc in
66+ let today_str = Date.format today "%Y%m%d" in
67+ match last with
68+ | Some last ->
69+ let tomorrow = Date.add_days today 1 in
70+ if Date.between ~low:today ~high:tomorrow last.date then
71+ let index = last.index + 1 in
72+ let path =
73+ Filename.concat state_dir (sprintf "note-%s-%d.md" today_str index)
74+ in
75+ { path; date = today; index }
76+ else
77+ let index = 0 in
78+ let path =
79+ Filename.concat state_dir (sprintf "note-%s-%d.md" today_str index)
80+ in
81+ { path; date = today; index }
82+ | None ->
83+ let index = 0 in
84+ let path =
85+ Filename.concat state_dir (Core.sprintf "note-%s-%d.md" today_str index)
86+ in
87+ { path; date = today; index }
88 diff --git a/test/slug_test.ml b/test/slug_test.ml
89index c02fa90..f4af219 100644
90--- a/test/slug_test.ml
91+++ b/test/slug_test.ml
92 @@ -1,14 +1,22 @@
93 open Core
94 open Note_lib
95
96+ let test_slug_of_string () =
97+ let input = "/fuu/bar/note-19700101-0.md" in
98+ let slug = input |> Slug.of_string in
99+ Alcotest.(check string) "conversion" input (slug |> Slug.to_string);
100+ let input = "note-19700101-0" in
101+ let slug = input |> Slug.of_string in
102+ Alcotest.(check string) "bare" input (slug |> Slug.to_string)
103+
104 let test_slug_shortname () =
105- let s1 = Slug.of_path "fuu/note-19700101-0.md" in
106+ let s1 = Slug.of_string "fuu/note-19700101-0.md" in
107 Alcotest.(check string) "short name" "note-19700101-0" (Slug.shortname s1)
108
109 let test_slug_comparable () =
110 let s1, s2 =
111- ( Slug.of_path "fuu/note-19700101-0.md",
112- Slug.of_path "fuu/note-19700101-0.md" )
113+ ( Slug.of_string "fuu/note-19700101-0.md",
114+ Slug.of_string "fuu/note-19700101-0.md" )
115 in
116 Alcotest.(check bool) "identical paths" true (Slug.compare s1 s2 = 0)
117
118 @@ -17,25 +25,24 @@ let test_slug_path () =
119 let state_dir = Filename.temp_dir "note-test" "" in
120 let slug = Slug.next state_dir in
121 let expected =
122- Filename.concat state_dir (sprintf "note-%s-0.md" date_string)
123+ Filename.concat state_dir (sprintf "note-%s-0.md" date_string)
124 in
125 Alcotest.(check string) "path" expected slug.path
126
127 let test_slug_increment () =
128- let state_dir = Filename.temp_dir "note-test" "" in
129 let date_string = Time.format (Time.now ()) "%Y%m%d" ~zone:Time.Zone.utc in
130- for i = 0 to 5 do
131- let filename =
132- Filename.concat state_dir (sprintf "note-%s-%d.md" date_string i)
133- in
134- Out_channel.write_all filename ~data:""
135- done;
136- let slug = Slug.next state_dir in
137- Alcotest.(check int) "index" 6 slug.index
138+ let slug = Slug.next "/fuu/bar" in
139+ let expected = sprintf "/fuu/bar/note-%s-%d.md" date_string 0 in
140+ Alcotest.(check string) "check path" expected (slug |> Slug.to_string);
141+ let slug = Slug.next ~last:(Some slug) "/fuu/bar" in
142+ let expected = sprintf "/fuu/bar/note-%s-%d.md" date_string 1 in
143+ Alcotest.(check string) "check path" expected (slug |> Slug.to_string)
144
145 let () =
146 Alcotest.run "Slug"
147 [
148+ ( "slug-of-string",
149+ [ Alcotest.test_case "ofstring" `Quick test_slug_of_string ] );
150 ( "slug-comparable",
151 [ Alcotest.test_case "compare" `Quick test_slug_comparable ] );
152 ( "slug-shortname",