Browse Source

Consolidate pages and posts into entries

master
Dylan Baker 5 years ago
parent
commit
fb03f04bc1
7 changed files with 523 additions and 531 deletions
  1. 13
    14
      src/commands.rs
  2. 354
    0
      src/entry.rs
  3. 1
    2
      src/main.rs
  4. 15
    38
      src/page.rs
  5. 140
    161
      src/post.rs
  6. 0
    134
      src/render.rs
  7. 0
    182
      src/write.rs

+ 13
- 14
src/commands.rs View File

@@ -7,9 +7,7 @@ use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher};
7 7
 use toml::Value;
8 8
 
9 9
 use config::Config;
10
-use page::{parse_page, read_pages_dir};
11
-use post::{parse_post, read_posts_dir, Post};
12
-use write::{write_page, write_post, write_post_listing};
10
+use entry::{parse_entry, read_entry_dir, write_entry, write_entry_listing, Entry};
13 11
 
14 12
 pub fn build(include_drafts: bool) {
15 13
     let cwd = env::current_dir().expect("Couldn't read current directory");
@@ -49,31 +47,32 @@ pub fn build(include_drafts: bool) {
49 47
 
50 48
     let post_paths = match include_drafts {
51 49
         true => {
52
-            let mut posts = read_posts_dir(&cwd.join("posts"));
53
-            posts.append(&mut read_posts_dir(&cwd.join("drafts")));
50
+            let mut posts = read_entry_dir(&cwd.join("posts"));
51
+            posts.append(&mut read_entry_dir(&cwd.join("drafts")));
54 52
             posts
55 53
         }
56
-        false => read_posts_dir(&cwd.join("posts")),
54
+        false => read_entry_dir(&cwd.join("posts")),
57 55
     };
58 56
 
59
-    let page_paths = read_pages_dir(&cwd.join("pages"));
57
+    let page_paths = read_entry_dir(&cwd.join("pages"));
60 58
 
61
-    let mut posts: Vec<Post> = post_paths
59
+    let mut posts: Vec<Entry> = post_paths
62 60
         .into_iter()
63
-        .map(|entry| parse_post(entry.path()))
64
-        .collect::<Vec<Post>>();
61
+        .map(|entry| parse_entry(entry.path()))
62
+        .collect::<Vec<Entry>>();
63
+
65 64
     posts.sort_by(|a, b| b.date.cmp(&a.date));
66 65
 
67 66
     for post in &posts {
68
-        write_post(&cwd, &layout_template, &post_template, &post, &config);
67
+        write_entry(&cwd, &layout_template, &post_template, &post, &config);
69 68
     }
70 69
 
71 70
     for entry in page_paths.into_iter() {
72
-        let page = parse_page(entry.path());
73
-        write_page(&cwd, &layout_template, &page_template, &page, &config);
71
+        let page = parse_entry(entry.path());
72
+        write_entry(&cwd, &layout_template, &page_template, &page, &config);
74 73
     }
75 74
 
76
-    write_post_listing(
75
+    write_entry_listing(
77 76
         &cwd,
78 77
         &layout_template,
79 78
         &post_listing_template,

+ 354
- 0
src/entry.rs View File

@@ -0,0 +1,354 @@
1
+use chrono::NaiveDate;
2
+use comrak::{markdown_to_html, ComrakOptions};
3
+use regex::Regex;
4
+
5
+use std::fs;
6
+use std::path;
7
+
8
+use config::Config;
9
+
10
+#[derive(Debug)]
11
+pub enum EntryKind {
12
+    Page,
13
+    Post,
14
+}
15
+
16
+#[derive(Debug)]
17
+pub struct Entry {
18
+    pub kind: EntryKind,
19
+    pub title: String,
20
+    pub slug: String,
21
+    pub body: String,
22
+    pub date: Option<NaiveDate>,
23
+}
24
+
25
+impl Entry {
26
+    fn render(&self, template: &str, config: &Config) -> String {
27
+        template
28
+            .replace(
29
+                "{{ page_title }}",
30
+                &format!("{} | {}", &self.title, &config.site_name),
31
+            )
32
+            .replace("{{ title }}", &self.title)
33
+            .replace("{{ slug }}", &self.slug)
34
+            .replace(
35
+                "{{ body }}",
36
+                &markdown_to_html(&self.body, &ComrakOptions::default()),
37
+            )
38
+    }
39
+}
40
+
41
+pub fn read_entry_dir(cwd: &path::PathBuf) -> Vec<fs::DirEntry> {
42
+    match fs::read_dir(cwd) {
43
+        Ok(entries) => entries.into_iter().map(|entry| entry.unwrap()).collect(),
44
+        Err(err) => panic!(err),
45
+    }
46
+}
47
+
48
+pub fn parse_entry(path: path::PathBuf) -> Entry {
49
+    let contents = fs::read_to_string(&path).expect("Couldn't read post file");
50
+
51
+    lazy_static! {
52
+        static ref re_with_date: Regex =
53
+            Regex::new(r"^# (?P<title>.*) \| (?P<date>\d{4}-\d{2}-\d{2})\n\n(?s)(?P<body>.*)")
54
+                .unwrap();
55
+        static ref re_without_date: Regex =
56
+            Regex::new(r"^# (?P<title>.*)\n\n(?s)(?P<body>.*)").unwrap();
57
+        static ref slug_re: Regex = Regex::new(r"(?P<slug>\S+).md").unwrap();
58
+    }
59
+
60
+    let filename = &path.file_name().unwrap().to_str().unwrap();
61
+    let slug = &slug_re
62
+        .captures(filename)
63
+        .expect("Couldn't parse slug from filename")["slug"];
64
+
65
+    if let Some(date_string) = &re_with_date.captures(&contents) {
66
+        let title = &re_with_date
67
+            .captures(&contents)
68
+            .expect("Couldn't parse title")["title"];
69
+        let body = &re_with_date
70
+            .captures(&contents)
71
+            .expect("Couldn't parse title")["body"];
72
+        let date = Some(
73
+            NaiveDate::parse_from_str(&date_string["date"], "%Y-%m-%d")
74
+                .expect("Couldn't parse date"),
75
+        );
76
+        Entry {
77
+            kind: EntryKind::Post,
78
+            title: String::from(title),
79
+            body: String::from(body),
80
+            slug: String::from(slug),
81
+            date: date,
82
+        }
83
+    } else {
84
+        let title = &re_without_date
85
+            .captures(&contents)
86
+            .expect("Couldn't parse title")["title"];
87
+        let body = &re_without_date
88
+            .captures(&contents)
89
+            .expect("Couldn't parse title")["body"];
90
+        Entry {
91
+            kind: EntryKind::Page,
92
+            title: String::from(title),
93
+            body: String::from(body),
94
+            slug: String::from(slug),
95
+            date: None,
96
+        }
97
+    }
98
+}
99
+
100
+pub fn write_entry(
101
+    cwd: &path::PathBuf,
102
+    layout: &str,
103
+    post_template: &str,
104
+    entry: &Entry,
105
+    config: &Config,
106
+) {
107
+    let root_path = match entry.kind {
108
+        EntryKind::Post => cwd.join("public").join("posts").join(&entry.slug),
109
+        EntryKind::Page => cwd.join("public").join(&entry.slug),
110
+    };
111
+
112
+    match fs::create_dir(&root_path) {
113
+        Ok(_) => {}
114
+        Err(err) => match err.kind() {
115
+            std::io::ErrorKind::AlreadyExists => {}
116
+            _ => panic!(err),
117
+        },
118
+    }
119
+
120
+    let template = layout.replace("{{ contents }}", &post_template);
121
+
122
+    fs::write(
123
+        &root_path.join("index.html"),
124
+        entry.render(&template, &config),
125
+    )
126
+    .expect("Unable to write file");
127
+}
128
+
129
+pub fn write_entry_listing(
130
+    cwd: &path::PathBuf,
131
+    layout: &str,
132
+    post_listing_template: &str,
133
+    post_item_template: &str,
134
+    posts: &Vec<Entry>,
135
+    config: &Config,
136
+) {
137
+    fs::write(
138
+        cwd.join("public").join("index.html"),
139
+        render_post_listing(
140
+            layout,
141
+            post_listing_template,
142
+            post_item_template,
143
+            posts,
144
+            config,
145
+        ),
146
+    )
147
+    .expect("Unable to write file");
148
+}
149
+
150
+pub fn render_post_listing(
151
+    layout: &str,
152
+    post_listing_template: &str,
153
+    post_item_template: &str,
154
+    posts: &Vec<Entry>,
155
+    config: &Config,
156
+) -> String {
157
+    layout
158
+        .replace("{{ page_title }}", &format!("{}", config.site_name))
159
+        .replace(
160
+            "{{ contents }}",
161
+            &post_listing_template.replace(
162
+                "{{ post_listing }}",
163
+                &posts
164
+                    .iter()
165
+                    .map(|post| post.render(&post_item_template, &config))
166
+                    .collect::<Vec<String>>()
167
+                    .join("\n"),
168
+            ),
169
+        )
170
+}
171
+
172
+#[cfg(test)]
173
+mod tests {
174
+
175
+    use super::{render_post_listing, write_entry, write_entry_listing, Config, Entry, EntryKind};
176
+    use chrono::NaiveDate;
177
+    use std::{env, fs};
178
+    use uuid::Uuid;
179
+
180
+    #[test]
181
+    fn test_render_post() {
182
+        let config = Config {
183
+            site_name: String::from("Test Site"),
184
+        };
185
+
186
+        let post = Entry {
187
+            title: String::from("hello world"),
188
+            body: String::from("lorem ipsum dolor sit amet"),
189
+            slug: String::from("hello-world"),
190
+            date: Some(NaiveDate::from_ymd(2019, 1, 1)),
191
+            kind: EntryKind::Post,
192
+        };
193
+
194
+        let output = post.render(
195
+            "<html><head><title>{{ page_title }}</title></head><body><article><h1>{{ title }}</h1><div>{{ body }}</div></article></body></html>", &config
196
+        )
197
+        .replace("\n", "");
198
+
199
+        assert_eq!(
200
+            "<html><head><title>hello world | Test Site</title></head><body><article><h1>hello world</h1><div><p>lorem ipsum dolor sit amet</p></div></article></body></html>",
201
+            &output,
202
+        );
203
+    }
204
+
205
+    #[test]
206
+    fn test_render_post_listing() {
207
+        let config = Config {
208
+            site_name: String::from("Test Site"),
209
+        };
210
+
211
+        let posts = vec![
212
+            Entry {
213
+                title: String::from("First post"),
214
+                body: String::from("lorem ipsum dolor sit amet"),
215
+                slug: String::from("first-post"),
216
+                date: Some(NaiveDate::from_ymd(2019, 1, 1)),
217
+                kind: EntryKind::Post,
218
+            },
219
+            Entry {
220
+                title: String::from("Second post"),
221
+                body: String::from("lorem ipsum dolor sit amet"),
222
+                slug: String::from("second-post"),
223
+                date: Some(NaiveDate::from_ymd(2019, 1, 1)),
224
+                kind: EntryKind::Post,
225
+            },
226
+            Entry {
227
+                title: String::from("Third post"),
228
+                body: String::from("lorem ipsum dolor sit amet"),
229
+                slug: String::from("third-post"),
230
+                date: Some(NaiveDate::from_ymd(2019, 1, 1)),
231
+                kind: EntryKind::Post,
232
+            },
233
+        ];
234
+
235
+        let output = render_post_listing(
236
+            "<html><head><title>{{ page_title }}</title></head><body>{{ contents }}</body></html>",
237
+            "<ul>{{ post_listing }}</ul>",
238
+            "<li><a href=\"/{{ slug }}\">{{ title }}</a></li>",
239
+            &posts,
240
+            &config,
241
+        )
242
+        .replace("\n", "");
243
+
244
+        assert_eq!(
245
+            "<html><head><title>Test Site</title></head><body><ul><li><a href=\"/first-post\">First post</a></li><li><a href=\"/second-post\">Second post</a></li><li><a href=\"/third-post\">Third post</a></li></ul></body></html>",
246
+            &output,
247
+        );
248
+    }
249
+
250
+    #[test]
251
+    fn test_write_entry() {
252
+        let temp_dir = env::temp_dir();
253
+        let working_dir = temp_dir.join(&Uuid::new_v4().to_string());
254
+        fs::create_dir(&working_dir).unwrap();
255
+        env::set_current_dir(&working_dir).unwrap();
256
+
257
+        let cwd = env::current_dir().unwrap();
258
+        fs::create_dir(cwd.join("public")).unwrap();
259
+        fs::create_dir(cwd.join("public").join("posts")).unwrap();
260
+
261
+        let layout =
262
+            "<html><head><title>{{ page_title }}</title></head><body>{{ contents }}</body></html>";
263
+        let post_template = "<article><h1>{{ title }}</h1><div>{{ body }}</div></article>";
264
+        let post = Entry {
265
+            title: String::from("Hello world"),
266
+            body: String::from("Lorem ipsum dolor sit amet"),
267
+            slug: String::from("hello-world"),
268
+            date: Some(NaiveDate::from_ymd(2019, 1, 1)),
269
+            kind: EntryKind::Post,
270
+        };
271
+        let config = Config {
272
+            site_name: "Test Site".to_string(),
273
+        };
274
+
275
+        write_entry(&cwd, &layout, &post_template, &post, &config);
276
+
277
+        let content = fs::read_to_string(
278
+            cwd.join("public")
279
+                .join("posts")
280
+                .join("hello-world")
281
+                .join("index.html"),
282
+        )
283
+        .unwrap();
284
+
285
+        assert_eq!(
286
+            "<html><head><title>Hello world | Test Site</title></head><body><article><h1>Hello world</h1><div><p>Lorem ipsum dolor sit amet</p></div></article></body></html>",
287
+	    content.replace("\n", "")
288
+	);
289
+
290
+        fs::remove_dir_all(temp_dir.join(&working_dir)).unwrap();
291
+    }
292
+
293
+    #[test]
294
+    fn test_write_post_listing() {
295
+        let temp_dir = env::temp_dir();
296
+        let working_dir = temp_dir.join(&Uuid::new_v4().to_string());
297
+        fs::create_dir(&working_dir).unwrap();
298
+        env::set_current_dir(&working_dir).unwrap();
299
+
300
+        let cwd = env::current_dir().unwrap();
301
+        fs::create_dir(cwd.join("public")).unwrap();
302
+
303
+        let layout =
304
+            "<html><head><title>{{ page_title }}</title></head><body>{{ contents }}</body></html>";
305
+        let post_listing_template = "<ul>{{ post_listing }}</ul>";
306
+        let post_item_template = "<li><a href=\"/{{ slug }}\">{{ title }}</a></li>";
307
+        let posts = vec![
308
+            Entry {
309
+                title: String::from("First post"),
310
+                body: String::from("lorem ipsum dolor sit amet"),
311
+                slug: String::from("first-post"),
312
+                date: Some(NaiveDate::from_ymd(2019, 1, 1)),
313
+                kind: EntryKind::Post,
314
+            },
315
+            Entry {
316
+                title: String::from("Second post"),
317
+                body: String::from("lorem ipsum dolor sit amet"),
318
+                slug: String::from("second-post"),
319
+                date: Some(NaiveDate::from_ymd(2019, 1, 1)),
320
+                kind: EntryKind::Post,
321
+            },
322
+            Entry {
323
+                title: String::from("Third post"),
324
+                body: String::from("lorem ipsum dolor sit amet"),
325
+                slug: String::from("third-post"),
326
+                date: Some(NaiveDate::from_ymd(2019, 1, 1)),
327
+                kind: EntryKind::Post,
328
+            },
329
+        ];
330
+        let config = Config {
331
+            site_name: "Test Site".to_string(),
332
+        };
333
+        write_entry_listing(
334
+            &cwd,
335
+            &layout,
336
+            &post_listing_template,
337
+            &post_item_template,
338
+            &posts,
339
+            &config,
340
+        );
341
+
342
+        assert_eq!(
343
+            "<html><head><title>Test Site</title></head><body><ul><li><a href\
344
+             =\"/first-post\">First post</a></li><li><a href=\"/second-post\">\
345
+             Second post</a></li><li><a href=\"/third-post\">Third post</a></li\
346
+             ></ul></body></html>",
347
+            fs::read_to_string(&cwd.join("public").join("index.html"))
348
+                .unwrap()
349
+                .replace("\n", ""),
350
+        );
351
+
352
+        fs::remove_dir_all(temp_dir.join(&working_dir)).unwrap();
353
+    }
354
+}

+ 1
- 2
src/main.rs View File

@@ -15,10 +15,9 @@ use commands::{build, new, watch};
15 15
 
16 16
 mod commands;
17 17
 mod config;
18
+mod entry;
18 19
 mod page;
19 20
 mod post;
20
-mod render;
21
-mod write;
22 21
 
23 22
 fn main() {
24 23
     let matches = App::new("casaubon")

+ 15
- 38
src/page.rs View File

@@ -1,38 +1,15 @@
1
-use regex::Regex;
2
-
3
-use std::fs;
4
-use std::path;
5
-
6
-#[derive(Debug)]
7
-pub struct Page {
8
-    pub title: String,
9
-    pub body: String,
10
-    pub slug: String,
11
-}
12
-
13
-pub fn read_pages_dir(cwd: &path::PathBuf) -> Vec<fs::DirEntry> {
14
-    match fs::read_dir(cwd) {
15
-        Ok(pages) => pages.into_iter().map(|page| page.unwrap()).collect(),
16
-        Err(err) => panic!(err),
17
-    }
18
-}
19
-
20
-pub fn parse_page(path: path::PathBuf) -> Page {
21
-    let contents = fs::read_to_string(&path).expect("Couldn't read page file");
22
-
23
-    lazy_static! {
24
-        static ref re: Regex = Regex::new(r"^# (?P<title>.*)\n\n(?s)(?P<body>.*)").unwrap();
25
-        static ref slug_re: Regex = Regex::new(r"(?P<slug>\S+).md").unwrap();
26
-    }
27
-
28
-    let title = &re.captures(&contents).expect("Couldn't parse title")["title"];
29
-    let body = &re.captures(&contents).expect("Couldn't parse body")["body"];
30
-
31
-    let filename = &path.file_name().unwrap().to_str().unwrap();
32
-    let slug = &slug_re.captures(filename).expect("Couldn't parse slug")["slug"];
33
-    Page {
34
-        title: String::from(title),
35
-        body: String::from(body),
36
-        slug: String::from(slug),
37
-    }
38
-}
1
+// #[derive(Debug)]
2
+// pub struct Page {
3
+//     pub title: String,
4
+//     pub body: String,
5
+//     pub slug: String,
6
+// }
7
+
8
+// impl Page {
9
+//     fn render(&self, template: &str) -> String {
10
+//         template
11
+//             .replace("{{ title }}", &self.title)
12
+//             .replace("{{ slug }}", &self.slug)
13
+//             .replace("{{ body }}", &self.body)
14
+//     }
15
+// }

+ 140
- 161
src/post.rs View File

@@ -1,161 +1,140 @@
1
-use chrono::NaiveDate;
2
-use regex::Regex;
3
-
4
-use std::fs;
5
-use std::path;
6
-
7
-#[derive(Debug)]
8
-pub struct Post {
9
-    pub title: String,
10
-    pub body: String,
11
-    pub slug: String,
12
-    pub date: NaiveDate,
13
-}
14
-
15
-pub fn read_posts_dir(cwd: &path::PathBuf) -> Vec<fs::DirEntry> {
16
-    match fs::read_dir(cwd) {
17
-        Ok(posts) => posts.into_iter().map(|post| post.unwrap()).collect(),
18
-        Err(err) => panic!(err),
19
-    }
20
-}
21
-
22
-pub fn parse_post(path: path::PathBuf) -> Post {
23
-    let contents = fs::read_to_string(&path).expect("Couldn't read post file");
24
-
25
-    lazy_static! {
26
-        static ref re: Regex =
27
-            Regex::new(r"^# (?P<title>.*) \| (?P<date>\d{4}-\d{2}-\d{2})\n\n(?s)(?P<body>.*)")
28
-                .unwrap();
29
-        static ref slug_re: Regex = Regex::new(r"(?P<slug>\S+).md").unwrap();
30
-    }
31
-
32
-    let title = &re.captures(&contents).expect("Couldn't parse title")["title"];
33
-    let date = &re.captures(&contents).expect("Couldn't parse date")["date"];
34
-    let body = &re.captures(&contents).expect("Couldn't parse body")["body"];
35
-
36
-    let filename = &path.file_name().unwrap().to_str().unwrap();
37
-    let slug = &slug_re.captures(filename).expect("Couldn't parse slug")["slug"];
38
-    Post {
39
-        title: String::from(title),
40
-        body: String::from(body),
41
-        slug: String::from(slug),
42
-        date: NaiveDate::parse_from_str(&date, "%Y-%m-%d").expect("Couldn't parse date"),
43
-    }
44
-}
45
-
46
-#[cfg(test)]
47
-mod tests {
48
-    #[allow(unused_imports)]
49
-    use super::*;
50
-    #[allow(unused_imports)]
51
-    #[allow(unused_imports)]
52
-    use std::{env, fs, path};
53
-    #[allow(unused_imports)]
54
-    use uuid::Uuid;
55
-
56
-    #[test]
57
-    fn test_read_posts_dir() {
58
-        let temp_dir = env::temp_dir();
59
-        let working_dir = temp_dir.join(&Uuid::new_v4().to_string());
60
-        fs::create_dir(&working_dir).unwrap();
61
-        env::set_current_dir(&working_dir).unwrap();
62
-
63
-        let cwd = env::current_dir().unwrap();
64
-        fs::create_dir(cwd.join("posts")).unwrap();
65
-
66
-        let post_body = "# This is a post\n\nHere is some content that goes in the post";
67
-
68
-        let mut uuids: Vec<String> = vec![];
69
-
70
-        for _ in 1..11 {
71
-            let uuid = String::from(Uuid::new_v4().to_string());
72
-            uuids.push(uuid.clone());
73
-            fs::write(
74
-                cwd.join("posts").join(format!("{}.md", &uuid)),
75
-                &String::from(post_body),
76
-            )
77
-            .unwrap();
78
-        }
79
-
80
-        let mut expected_paths: Vec<String> = uuids
81
-            .into_iter()
82
-            .map(|uuid| {
83
-                String::from(
84
-                    cwd.join("posts")
85
-                        .join(format!("{}.md", uuid))
86
-                        .to_str()
87
-                        .unwrap(),
88
-                )
89
-            })
90
-            .collect();
91
-        expected_paths.sort();
92
-        let mut actual_paths: Vec<String> = read_posts_dir(&cwd.join("posts"))
93
-            .into_iter()
94
-            .map(|dir_entry| String::from(dir_entry.path().to_str().unwrap()))
95
-            .collect();
96
-        actual_paths.sort();
97
-
98
-        assert_eq!(expected_paths, actual_paths);
99
-
100
-        fs::remove_dir_all(temp_dir.join(&working_dir)).unwrap();
101
-    }
102
-
103
-    #[test]
104
-    fn test_parse_post() {
105
-        let temp_dir = env::temp_dir();
106
-        let working_dir = temp_dir.join(&Uuid::new_v4().to_string());
107
-        fs::create_dir(&working_dir).unwrap();
108
-        env::set_current_dir(&working_dir).unwrap();
109
-
110
-        let cwd = env::current_dir().unwrap();
111
-        fs::create_dir(cwd.join("posts")).unwrap();
112
-
113
-        let slug = Uuid::new_v4().to_string();
114
-        let filename = format!("{}.md", slug);
115
-        fs::write(
116
-            cwd.join("posts").join(&filename),
117
-            "# This is a post | 2019-01-01\n\nHere is some content that goes in the post",
118
-        )
119
-        .unwrap();
120
-
121
-        let post = parse_post(cwd.join("posts").join(&filename));
122
-        let date = NaiveDate::from_ymd(2019, 1, 1);
123
-        assert_eq!("This is a post", post.title);
124
-        assert_eq!("Here is some content that goes in the post", post.body);
125
-        assert_eq!(slug, post.slug);
126
-        assert_eq!(date, post.date);
127
-
128
-        fs::remove_dir_all(temp_dir.join(&working_dir)).unwrap();
129
-    }
130
-
131
-    #[test]
132
-    fn test_post_with_multiple_paragraphs() {
133
-        let temp_dir = env::temp_dir();
134
-        let working_dir = temp_dir.join(&Uuid::new_v4().to_string());
135
-        fs::create_dir(&working_dir).unwrap();
136
-        env::set_current_dir(&working_dir).unwrap();
137
-
138
-        let cwd = env::current_dir().unwrap();
139
-        fs::create_dir(cwd.join("posts")).unwrap();
140
-
141
-        let slug = Uuid::new_v4().to_string();
142
-        let filename = format!("{}.md", slug);
143
-        fs::write(
144
-            cwd.join("posts").join(&filename),
145
-            "# This is a post | 2019-01-01\n\nHere is a line\n\nHere is another line\n\nAnd a third",
146
-        )
147
-        .unwrap();
148
-
149
-        let post = parse_post(cwd.join("posts").join(&filename));
150
-        let date = NaiveDate::from_ymd(2019, 1, 1);
151
-        assert_eq!("This is a post", post.title);
152
-        assert_eq!(
153
-            "Here is a line\n\nHere is another line\n\nAnd a third",
154
-            post.body
155
-        );
156
-        assert_eq!(slug, post.slug);
157
-        assert_eq!(date, post.date);
158
-
159
-        fs::remove_dir_all(temp_dir.join(&working_dir)).unwrap();
160
-    }
161
-}
1
+// use chrono::NaiveDate;
2
+
3
+// #[derive(Debug)]
4
+// pub struct Post {
5
+//     pub title: String,
6
+//     pub body: String,
7
+//     pub slug: String,
8
+//     pub date: NaiveDate,
9
+// }
10
+
11
+// impl Post {
12
+//     fn date(&self) -> String {
13
+//         self.date.format("%Y-%m-%d").to_string()
14
+//     }
15
+
16
+//     fn render(&self, template: &str) -> String {
17
+//         template
18
+//             .replace("{{ title }}", &self.title)
19
+//             .replace("{{ slug }}", &self.slug)
20
+//             .replace("{{ body }}", &self.body)
21
+//             .replace("{{ date }}", &self.date())
22
+//     }
23
+// }
24
+
25
+// #[cfg(test)]
26
+// mod tests {
27
+//     #[allow(unused_imports)]
28
+//     use super::*;
29
+//     #[allow(unused_imports)]
30
+//     #[allow(unused_imports)]
31
+//     use std::{env, fs, path};
32
+//     #[allow(unused_imports)]
33
+//     use uuid::Uuid;
34
+
35
+//     #[test]
36
+//     fn test_read_posts_dir() {
37
+//         let temp_dir = env::temp_dir();
38
+//         let working_dir = temp_dir.join(&Uuid::new_v4().to_string());
39
+//         fs::create_dir(&working_dir).unwrap();
40
+//         env::set_current_dir(&working_dir).unwrap();
41
+
42
+//         let cwd = env::current_dir().unwrap();
43
+//         fs::create_dir(cwd.join("posts")).unwrap();
44
+
45
+//         let post_body = "# This is a post\n\nHere is some content that goes in the post";
46
+
47
+//         let mut uuids: Vec<String> = vec![];
48
+
49
+//         for _ in 1..11 {
50
+//             let uuid = String::from(Uuid::new_v4().to_string());
51
+//             uuids.push(uuid.clone());
52
+//             fs::write(
53
+//                 cwd.join("posts").join(format!("{}.md", &uuid)),
54
+//                 &String::from(post_body),
55
+//             )
56
+//             .unwrap();
57
+//         }
58
+
59
+//         let mut expected_paths: Vec<String> = uuids
60
+//             .into_iter()
61
+//             .map(|uuid| {
62
+//                 String::from(
63
+//                     cwd.join("posts")
64
+//                         .join(format!("{}.md", uuid))
65
+//                         .to_str()
66
+//                         .unwrap(),
67
+//                 )
68
+//             })
69
+//             .collect();
70
+//         expected_paths.sort();
71
+//         let mut actual_paths: Vec<String> = read_posts_dir(&cwd.join("posts"))
72
+//             .into_iter()
73
+//             .map(|dir_entry| String::from(dir_entry.path().to_str().unwrap()))
74
+//             .collect();
75
+//         actual_paths.sort();
76
+
77
+//         assert_eq!(expected_paths, actual_paths);
78
+
79
+//         fs::remove_dir_all(temp_dir.join(&working_dir)).unwrap();
80
+//     }
81
+
82
+//     #[test]
83
+//     fn test_parse_post() {
84
+//         let temp_dir = env::temp_dir();
85
+//         let working_dir = temp_dir.join(&Uuid::new_v4().to_string());
86
+//         fs::create_dir(&working_dir).unwrap();
87
+//         env::set_current_dir(&working_dir).unwrap();
88
+
89
+//         let cwd = env::current_dir().unwrap();
90
+//         fs::create_dir(cwd.join("posts")).unwrap();
91
+
92
+//         let slug = Uuid::new_v4().to_string();
93
+//         let filetitle = format!("{}.md", slug);
94
+//         fs::write(
95
+//             cwd.join("posts").join(&filetitle),
96
+//             "# This is a post | 2019-01-01\n\nHere is some content that goes in the post",
97
+//         )
98
+//         .unwrap();
99
+
100
+//         let post = parse_post(cwd.join("posts").join(&filetitle));
101
+//         let date = NaiveDate::from_ymd(2019, 1, 1);
102
+//         assert_eq!("This is a post", post.title);
103
+//         assert_eq!("Here is some content that goes in the post", post.body);
104
+//         assert_eq!(slug, post.slug);
105
+//         assert_eq!(date, post.date);
106
+
107
+//         fs::remove_dir_all(temp_dir.join(&working_dir)).unwrap();
108
+//     }
109
+
110
+//     #[test]
111
+//     fn test_post_with_multiple_paragraphs() {
112
+//         let temp_dir = env::temp_dir();
113
+//         let working_dir = temp_dir.join(&Uuid::new_v4().to_string());
114
+//         fs::create_dir(&working_dir).unwrap();
115
+//         env::set_current_dir(&working_dir).unwrap();
116
+
117
+//         let cwd = env::current_dir().unwrap();
118
+//         fs::create_dir(cwd.join("posts")).unwrap();
119
+
120
+//         let slug = Uuid::new_v4().to_string();
121
+//         let filetitle = format!("{}.md", slug);
122
+//         fs::write(
123
+//             cwd.join("posts").join(&filetitle),
124
+//             "# This is a post | 2019-01-01\n\nHere is a line\n\nHere is another line\n\nAnd a third",
125
+//         )
126
+//         .unwrap();
127
+
128
+//         let post = parse_post(cwd.join("posts").join(&filetitle));
129
+//         let date = NaiveDate::from_ymd(2019, 1, 1);
130
+//         assert_eq!("This is a post", post.title);
131
+//         assert_eq!(
132
+//             "Here is a line\n\nHere is another line\n\nAnd a third",
133
+//             post.body
134
+//         );
135
+//         assert_eq!(slug, post.slug);
136
+//         assert_eq!(date, post.date);
137
+
138
+//         fs::remove_dir_all(temp_dir.join(&working_dir)).unwrap();
139
+//     }
140
+// }

+ 0
- 134
src/render.rs View File

@@ -1,134 +0,0 @@
1
-use comrak::{markdown_to_html, ComrakOptions};
2
-
3
-use config::Config;
4
-use page::Page;
5
-use post::Post;
6
-
7
-pub fn render_post(layout: &str, post_template: &str, post: &Post, config: &Config) -> String {
8
-    layout
9
-        .replace(
10
-            "{{ page_title }}",
11
-            &format!("{} | {}", post.title, config.site_name),
12
-        )
13
-        .replace(
14
-            "{{ contents }}",
15
-            &post_template
16
-                .replace("{{ title }}", &post.title)
17
-                .replace(
18
-                    "{{ body }}",
19
-                    &markdown_to_html(&post.body, &ComrakOptions::default()),
20
-                )
21
-                .replace("{{ date }}", &post.date.format("%Y-%m-%d").to_string()),
22
-        )
23
-}
24
-
25
-pub fn render_page(layout: &str, page_template: &str, page: &Page, config: &Config) -> String {
26
-    layout
27
-        .replace(
28
-            "{{ page_title }}",
29
-            &format!("{} | {}", page.title, config.site_name),
30
-        )
31
-        .replace(
32
-            "{{ contents }}",
33
-            &page_template.replace("{{ title }}", &page.title).replace(
34
-                "{{ body }}",
35
-                &markdown_to_html(&page.body, &ComrakOptions::default()),
36
-            ),
37
-        )
38
-}
39
-
40
-pub fn render_post_listing(
41
-    layout: &str,
42
-    post_listing_template: &str,
43
-    post_item_template: &str,
44
-    posts: &Vec<Post>,
45
-    config: &Config,
46
-) -> String {
47
-    layout
48
-        .replace("{{ page_title }}", &format!("{}", config.site_name))
49
-        .replace(
50
-            "{{ contents }}",
51
-            &post_listing_template.replace(
52
-                "{{ post_listing }}",
53
-                &posts
54
-                    .iter()
55
-                    .map(|ref post| {
56
-                        post_item_template
57
-                            .replace("{{ slug }}", &post.slug)
58
-                            .replace("{{ title }}", &post.title)
59
-                            .replace("{{ date }}", &post.date.format("%Y-%m-%d").to_string())
60
-                    })
61
-                    .collect::<Vec<String>>()
62
-                    .join("\n"),
63
-            ),
64
-        )
65
-}
66
-
67
-#[cfg(test)]
68
-mod tests {
69
-    use super::{render_post, render_post_listing, Config, Post};
70
-    #[allow(unused_imports)]
71
-    use chrono::NaiveDate;
72
-
73
-    #[test]
74
-    fn test_render_post() {
75
-        let output = render_post(
76
-            "<html><head><title>{{ page_title }}</title></head><body>{{ contents }}</body></html>",
77
-            "<article><h1>{{ title }}</h1><div>{{ body }}</div></article>",
78
-            &Post {
79
-                title: String::from("hello world"),
80
-                body: String::from("lorem ipsum dolor sit amet"),
81
-                slug: String::from("hello-world"),
82
-                date: NaiveDate::from_ymd(2019, 1, 1),
83
-            },
84
-            &Config {
85
-                site_name: "Test Site".to_string(),
86
-            },
87
-        )
88
-        .replace("\n", "");
89
-
90
-        assert_eq!(
91
-            "<html><head><title>hello world | Test Site</title></head><body><article><h1>hello world</h1><div><p>lorem ipsum dolor sit amet</p></div></article></body></html>",
92
-            &output,
93
-        );
94
-    }
95
-
96
-    #[test]
97
-    fn test_render_post_listing() {
98
-        let posts = vec![
99
-            Post {
100
-                title: String::from("First post"),
101
-                body: String::from("lorem ipsum dolor sit amet"),
102
-                slug: String::from("first-post"),
103
-                date: NaiveDate::from_ymd(2019, 1, 1),
104
-            },
105
-            Post {
106
-                title: String::from("Second post"),
107
-                body: String::from("lorem ipsum dolor sit amet"),
108
-                slug: String::from("second-post"),
109
-                date: NaiveDate::from_ymd(2019, 1, 1),
110
-            },
111
-            Post {
112
-                title: String::from("Third post"),
113
-                body: String::from("lorem ipsum dolor sit amet"),
114
-                slug: String::from("third-post"),
115
-                date: NaiveDate::from_ymd(2019, 1, 1),
116
-            },
117
-        ];
118
-        let output = render_post_listing(
119
-            "<html><head><title>{{ page_title }}</title></head><body>{{ contents }}</body></html>",
120
-            "<ul>{{ post_listing }}</ul>",
121
-            "<li><a href=\"/{{ slug }}\">{{ title }}</a></li>",
122
-            &posts,
123
-            &Config {
124
-                site_name: "Test Site".to_string(),
125
-            },
126
-        )
127
-        .replace("\n", "");
128
-
129
-        assert_eq!(
130
-            "<html><head><title>Test Site</title></head><body><ul><li><a href=\"/first-post\">First post</a></li><li><a href=\"/second-post\">Second post</a></li><li><a href=\"/third-post\">Third post</a></li></ul></body></html>",
131
-            &output,
132
-        );
133
-    }
134
-}

+ 0
- 182
src/write.rs View File

@@ -1,182 +0,0 @@
1
-use config::Config;
2
-use page::Page;
3
-use post::Post;
4
-use render::{render_page, render_post, render_post_listing};
5
-use std::fs;
6
-use std::path;
7
-
8
-pub fn write_post(
9
-    cwd: &path::PathBuf,
10
-    layout: &str,
11
-    post_template: &str,
12
-    post: &Post,
13
-    config: &Config,
14
-) {
15
-    match fs::create_dir(cwd.join("public").join("posts").join(&post.slug)) {
16
-        Ok(_) => {}
17
-        Err(err) => match err.kind() {
18
-            std::io::ErrorKind::AlreadyExists => {}
19
-            _ => panic!(err),
20
-        },
21
-    }
22
-    fs::write(
23
-        cwd.join("public")
24
-            .join("posts")
25
-            .join(&post.slug)
26
-            .join("index.html"),
27
-        render_post(layout, post_template, post, config),
28
-    )
29
-    .expect("Unable to write file");
30
-}
31
-
32
-pub fn write_page(
33
-    cwd: &path::PathBuf,
34
-    layout: &str,
35
-    page_template: &str,
36
-    page: &Page,
37
-    config: &Config,
38
-) {
39
-    match fs::create_dir(cwd.join("public").join(&page.slug)) {
40
-        Ok(_) => {}
41
-        Err(err) => match err.kind() {
42
-            std::io::ErrorKind::AlreadyExists => {}
43
-            _ => panic!(err),
44
-        },
45
-    }
46
-    fs::write(
47
-        cwd.join("public").join(&page.slug).join("index.html"),
48
-        render_page(layout, page_template, page, config),
49
-    )
50
-    .expect("Unable to write file");
51
-}
52
-
53
-pub fn write_post_listing(
54
-    cwd: &path::PathBuf,
55
-    layout: &str,
56
-    post_listing_template: &str,
57
-    post_item_template: &str,
58
-    posts: &Vec<Post>,
59
-    config: &Config,
60
-) {
61
-    fs::write(
62
-        cwd.join("public").join("index.html"),
63
-        render_post_listing(
64
-            layout,
65
-            post_listing_template,
66
-            post_item_template,
67
-            posts,
68
-            config,
69
-        ),
70
-    )
71
-    .expect("Unable to write file");
72
-}
73
-
74
-#[cfg(test)]
75
-mod tests {
76
-    use chrono::NaiveDate;
77
-
78
-    #[allow(unused_imports)]
79
-    use super::*;
80
-    #[allow(unused_imports)]
81
-    use std::{env, fs};
82
-    #[allow(unused_imports)]
83
-    use uuid::Uuid;
84
-
85
-    #[test]
86
-    fn test_write_post() {
87
-        let temp_dir = env::temp_dir();
88
-        let working_dir = temp_dir.join(&Uuid::new_v4().to_string());
89
-        fs::create_dir(&working_dir).unwrap();
90
-        env::set_current_dir(&working_dir).unwrap();
91
-
92
-        let cwd = env::current_dir().unwrap();
93
-        fs::create_dir(cwd.join("public")).unwrap();
94
-        fs::create_dir(cwd.join("public").join("posts")).unwrap();
95
-
96
-        let layout =
97
-            "<html><head><title>{{ page_title }}</title></head><body>{{ contents }}</body></html>";
98
-        let post_template = "<article><h1>{{ title }}</h1><div>{{ body }}</div></article>";
99
-        let post = Post {
100
-            title: String::from("Hello world"),
101
-            body: String::from("Lorem ipsum dolor sit amet"),
102
-            slug: String::from("hello-world"),
103
-            date: NaiveDate::from_ymd(2019, 1, 1),
104
-        };
105
-        let config = Config {
106
-            site_name: "Test Site".to_string(),
107
-        };
108
-
109
-        write_post(&cwd, &layout, &post_template, &post, &config);
110
-
111
-        let content = fs::read_to_string(
112
-            cwd.join("public")
113
-                .join("posts")
114
-                .join("hello-world")
115
-                .join("index.html"),
116
-        )
117
-        .unwrap();
118
-
119
-        assert_eq!(
120
-            "<html><head><title>Hello world | Test Site</title></head><body><article><h1>Hello world</h1><div><p>Lorem ipsum dolor sit amet</p></div></article></body></html>",
121
-            content.replace("\n", "")
122
-        );
123
-
124
-        fs::remove_dir_all(temp_dir.join(&working_dir)).unwrap();
125
-    }
126
-
127
-    #[test]
128
-    fn test_write_post_listing() {
129
-        let temp_dir = env::temp_dir();
130
-        let working_dir = temp_dir.join(&Uuid::new_v4().to_string());
131
-        fs::create_dir(&working_dir).unwrap();
132
-        env::set_current_dir(&working_dir).unwrap();
133
-
134
-        let cwd = env::current_dir().unwrap();
135
-        fs::create_dir(cwd.join("public")).unwrap();
136
-
137
-        let layout =
138
-            "<html><head><title>{{ page_title }}</title></head><body>{{ contents }}</body></html>";
139
-        let post_listing_template = "<ul>{{ post_listing }}</ul>";
140
-        let post_item_template = "<li><a href=\"/{{ slug }}\">{{ title }}</a></li>";
141
-        let posts = vec![
142
-            Post {
143
-                title: String::from("First post"),
144
-                body: String::from("lorem ipsum dolor sit amet"),
145
-                slug: String::from("first-post"),
146
-                date: NaiveDate::from_ymd(2019, 1, 1),
147
-            },
148
-            Post {
149
-                title: String::from("Second post"),
150
-                body: String::from("lorem ipsum dolor sit amet"),
151
-                slug: String::from("second-post"),
152
-                date: NaiveDate::from_ymd(2019, 1, 1),
153
-            },
154
-            Post {
155
-                title: String::from("Third post"),
156
-                body: String::from("lorem ipsum dolor sit amet"),
157
-                slug: String::from("third-post"),
158
-                date: NaiveDate::from_ymd(2019, 1, 1),
159
-            },
160
-        ];
161
-        let config = Config {
162
-            site_name: "Test Site".to_string(),
163
-        };
164
-        write_post_listing(
165
-            &cwd,
166
-            &layout,
167
-            &post_listing_template,
168
-            &post_item_template,
169
-            &posts,
170
-            &config,
171
-        );
172
-
173
-        assert_eq!(
174
-            "<html><head><title>Test Site</title></head><body><ul><li><a href=\"/first-post\">First post</a></li><li><a href=\"/second-post\">Second post</a></li><li><a href=\"/third-post\">Third post</a></li></ul></body></html>",
175
-            fs::read_to_string(&cwd.join("public").join("index.html"))
176
-                .unwrap()
177
-                .replace("\n", ""),
178
-        );
179
-
180
-        fs::remove_dir_all(temp_dir.join(&working_dir)).unwrap();
181
-    }
182
-}

Loading…
Cancel
Save