obsidian_parser/obfile/
obfile_on_disk.rs1use crate::error::Error;
2use crate::obfile::{ObFile, ResultParse, parse_obfile};
3use serde::de::DeserializeOwned;
4use std::marker::PhantomData;
5use std::{collections::HashMap, path::PathBuf};
6
7#[derive(Debug, Default, PartialEq, Eq, Clone)]
32pub struct ObFileOnDisk<T = HashMap<String, serde_yml::Value>>
33where
34 T: DeserializeOwned + Default + Clone + Send,
35{
36 pub path: PathBuf,
38
39 phantom: PhantomData<T>,
40}
41
42impl<T: DeserializeOwned + Default + Clone + Send> ObFile<T> for ObFileOnDisk<T> {
43 #[allow(
57 clippy::unwrap_used,
58 reason = "The documentation states that panics are possible"
59 )]
60 fn content(&self) -> String {
61 let data = std::fs::read(&self.path).unwrap();
62 let raw_text = String::from_utf8(data).unwrap();
63
64 match parse_obfile(&raw_text).unwrap() {
65 ResultParse::WithProperties {
66 content,
67 properties: _,
68 } => {
69 #[cfg(feature = "logging")]
70 log::trace!("Frontmatter detected, parsing properties");
71
72 content.to_string()
73 }
74 ResultParse::WithoutProperties => {
75 #[cfg(feature = "logging")]
76 log::trace!("No frontmatter found, storing raw content");
77
78 raw_text
79 }
80 }
81 }
82
83 #[allow(
88 clippy::unwrap_used,
89 reason = "The documentation states that panics are possible"
90 )]
91 fn properties(&self) -> T {
92 let data = std::fs::read(&self.path).unwrap();
93 let raw_text = String::from_utf8(data).unwrap();
94
95 match parse_obfile(&raw_text).unwrap() {
96 ResultParse::WithProperties {
97 content: _,
98 properties,
99 } => {
100 #[cfg(feature = "logging")]
101 log::trace!("Frontmatter detected, parsing properties");
102
103 serde_yml::from_str(properties).unwrap()
104 }
105 ResultParse::WithoutProperties => {
106 #[cfg(feature = "logging")]
107 log::trace!("No frontmatter found, storing raw content");
108
109 T::default()
110 }
111 }
112 }
113
114 #[inline]
115 fn path(&self) -> Option<PathBuf> {
116 Some(self.path.clone())
117 }
118
119 fn from_string<P: AsRef<std::path::Path>>(
123 _raw_text: &str,
124 path: Option<P>,
125 ) -> Result<Self, Error> {
126 let path_buf = path.expect("Path is required").as_ref().to_path_buf();
127
128 Self::from_file(path_buf)
129 }
130
131 fn from_file<P: AsRef<std::path::Path>>(path: P) -> Result<Self, Error> {
133 let path_buf = path.as_ref().to_path_buf();
134
135 if !path_buf.is_file() {
136 return Err(Error::IsNotFile(path_buf));
137 }
138
139 Ok(Self {
140 path: path_buf,
141 phantom: PhantomData,
142 })
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149 use crate::obfile::ObFileDefault;
150 use crate::obfile::impl_tests::{from_file, from_file_with_unicode, impl_test_for_obfile};
151 use crate::test_utils::init_test_logger;
152 use std::io::Write;
153 use tempfile::NamedTempFile;
154
155 impl_test_for_obfile!(impl_from_file, from_file, ObFileOnDisk);
156
157 impl_test_for_obfile!(
158 impl_from_file_with_unicode,
159 from_file_with_unicode,
160 ObFileOnDisk
161 );
162
163 #[test]
164 #[should_panic]
165 fn use_from_string_without_path() {
166 init_test_logger();
167 ObFileOnDisk::from_string_default("", None::<&str>).unwrap();
168 }
169
170 #[test]
171 #[should_panic]
172 fn use_from_file_with_path_not_file() {
173 init_test_logger();
174 let temp_dir = tempfile::tempdir().unwrap();
175
176 ObFileOnDisk::from_file_default(temp_dir.path()).unwrap();
177 }
178
179 #[test]
180 fn get_path() {
181 init_test_logger();
182 let test_file = NamedTempFile::new().unwrap();
183 let file = ObFileOnDisk::from_file_default(test_file.path()).unwrap();
184
185 assert_eq!(file.path().unwrap(), test_file.path());
186 assert_eq!(file.path, test_file.path());
187 }
188
189 #[test]
190 fn get_content() {
191 init_test_logger();
192 let test_data = "DATA";
193 let mut test_file = NamedTempFile::new().unwrap();
194 test_file.write_all(test_data.as_bytes()).unwrap();
195
196 let file = ObFileOnDisk::from_file_default(test_file.path()).unwrap();
197 assert_eq!(file.content(), test_data);
198 }
199
200 #[test]
201 fn get_properties() {
202 init_test_logger();
203 let test_data = "---\ntime: now\n---\nDATA";
204 let mut test_file = NamedTempFile::new().unwrap();
205 test_file.write_all(test_data.as_bytes()).unwrap();
206
207 let file = ObFileOnDisk::from_file_default(test_file.path()).unwrap();
208 assert_eq!(file.content(), "DATA");
209 assert_eq!(file.properties()["time"], "now");
210 }
211}