1use std::borrow::{Borrow, Cow};
2use crate::parsers::scripture::RE;
3
4use crate::{
5 locales::{nwt_en::Site, BibleError},
6 url::Url,
7};
8
9use super::scripture::Bible;
10
11pub type ScriptSlice = (Start, End);
18type Start = usize;
19type End = usize;
20
21pub type ScriptureCollection = Vec<String>;
23
24#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Copy)]
25struct Elements<'a> {
31 prefix: Option<&'a str>,
33 prefix_len: Option<usize>,
35 postfix: Option<&'a str>,
37 postfix_len: Option<usize>,
39}
40#[derive(Debug,PartialEq, Eq, PartialOrd, Ord, Clone)]
41pub struct Locations{
43 pub slices: Vec<ScriptSlice>,
45 pub string: String,
47}
48
49
50
51#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
52pub struct Script<'a> {
54 elements: Elements<'a>,
56 slices: Vec<ScriptSlice>,
58 string: String,
60}
61
62#[allow(unused_variables)]
63impl<'a> Script<'a> {
64 pub(crate) fn new<S>(text: S) -> Self
67 where
68 S: Into<String> + Clone,
69 {
70 let re: ®ex::Regex = &RE;
71
72 let text_to_str: Cow<str> = Cow::from(text.clone().into());
73 let matches = re.find_iter(Cow::borrow(&text_to_str));
74
75 let mut scrip_slices: Vec<ScriptSlice> = Vec::new();
76 for script in matches {
77 scrip_slices.push((script.start(), script.end()));
78 }
79
80 Self {
81 string: text.into(),
82 slices: scrip_slices,
83 elements: Elements {
84 ..Default::default()
85 },
86 }
87 }
88
89 pub fn prefix(mut self, prefix: &'a str) -> Self {
91 self.elements.prefix = Some(prefix);
92 self
93 }
94
95 pub fn postfix(mut self, postfix: &'a str) -> Self {
97 self.elements.postfix = Some(postfix);
98 self
99 }
100
101 #[allow(dead_code)]
102 fn is_prefix(&self) -> bool {
103 self.elements.prefix.is_some()
104 }
105
106 #[allow(dead_code)]
107 fn is_postfix(&self) -> bool {
108 self.elements.postfix.is_some()
109 }
110
111 pub(crate) fn surround(mut self) -> Self {
114 for item in self.slices.iter().rev() {
116 self.string.insert_str(
117 item.0 + (item.1 - item.0),
118 self.elements
119 .postfix
120 .map_or("", |postfix_value| postfix_value),
121 );
122
123 self.string.insert_str(
124 item.0,
125 self.elements.prefix.map_or("", |prefix_value| prefix_value),
126 );
127 }
128
129 self
130 }
131
132 pub(crate) fn url(mut self, site: &Site) -> Result<Self, BibleError> {
134 for (start, end) in self.slices.iter().rev() {
136 let verse_slice: String = self.get_from_slice(&(*start, *end));
137 let bible: Bible = Bible::parse(verse_slice.as_str())?;
138 let url: String = site.get_url(&bible)?;
139
140 self.string
141 .insert_str(*start + (*end - *start), format!("]({})", url).as_str());
142
143 self.string.insert(*start, '[');
144 }
145
146 Ok(self)
147 }
148
149 pub(crate) fn get_text(self) -> String {
151 self.string
152 }
153
154 pub(crate) fn get_from_slice(&self, slice: &(usize, usize)) -> String {
156 let clone_obj: Script<'a> = self.clone();
157 let text: String = clone_obj.get_text();
158
159 text[slice.0..slice.1].to_owned()
160 }
161
162 pub(crate) fn get_scriptures(&self) -> Result<ScriptureCollection, BibleError> {
164 let mut scripture_list:Vec<String> = Vec::new();
165
166 for i in self.slices.iter() {
167 let scripture_str: &str = self.string.get(i.0..i.1).unwrap();
168
169 if Bible::parse(scripture_str).is_ok() {
171 scripture_list.push(scripture_str.to_string());
172 }
173 }
174
175 Ok(scripture_list)
176 }
177
178 pub(crate) fn get_locations(&self) -> Locations {
180 Locations { slices: self.slices.clone(), string: self.string.clone() }
181 }
182
183}
184
185#[cfg(test)]
186mod test {
187 use super::*;
188 use pretty_assertions::assert_eq;
189
190 #[test]
191 fn is_prefix() {
192 let text: &str = "Testing";
193 let result_true: Script = Script::new(text).prefix("true");
194 let result_false: Script = Script::new(text); assert!(result_true.is_prefix());
197 assert!(!result_false.is_prefix());
198 }
199
200 #[test]
201 fn is_postfix() {
202 let text: &str = "Testing";
203 let result_true: Script = Script::new(text).postfix("true");
204 let result_false: Script = Script::new(text); assert!(result_true.is_postfix());
207 assert!(!result_false.is_postfix());
208 }
209
210 #[test]
211 fn find_slice_1() {
212 let text: &str = "A popular scripture is John 3:16.";
213 let expect: Vec<(usize, usize)> = vec![(23, 32)];
214 let result: Script = Script::new(text);
215 assert_eq!(result.slices, expect);
216 }
217
218 #[test]
219 fn find_slice_2() {
220 let text: &str = "John 3:16 and Matthew 24:14";
221 let expect: Vec<(usize, usize)> = vec![(0, 9), (14, 27)];
222 let result: Script = Script::new(text);
223 assert_eq!(result.slices, expect);
224 }
225
226 #[test]
227 fn find_slice_3() {
228 let text: &str = "John 3:16, Mathew 24:14, and Psalms 83:18 are commonly used.";
229 let result: Script = Script::new(text);
230 assert_eq!(result.slices, vec![(0, 9), (11, 23), (29, 41)]);
231 }
232
233 #[test]
234 fn single_scripture() {
235 let text: &str = "John 3:16";
236 let expect: &str = "[John 3:16]";
237 let got: String = Script::new(text)
238 .prefix("[")
239 .postfix("]")
240 .surround()
241 .get_text();
242 assert_eq!(got, expect);
243 }
244
245 #[test]
246 fn add_element_prefix_single_none() {
248 let text: &str = "Another popular scripture is John 3:16, it's quoted often.";
249 let expect: &str = "Another popular scripture is John 3:16, it's quoted often.";
250 let result: String = Script::new(text).surround().get_text();
251 assert_eq!(result, expect)
252 }
253
254 #[test]
255 fn add_element_prefix_single() {
256 let text: &str = "Another popular scripture is John 3:16, it's quoted often.";
257 let expect: &str = "Another popular scripture is [John 3:16, it's quoted often.";
258 let result: String = Script::new(text).prefix("[").surround().get_text();
259 assert_eq!(result, expect);
260 }
261
262 #[test]
263 fn add_element_prefix_single_to_string() {
264 let text: String = "Another popular scripture is John 3:16, it's quoted often.".to_string();
265 let expect: &str = "Another popular scripture is [John 3:16, it's quoted often.";
266 let result: String = Script::new(text).prefix("[").surround().get_text();
267 assert_eq!(result, expect);
268 }
269
270 #[test]
271 fn add_element_prefix_multi() {
273 let text: &str =
274 "Two popular scripture are John 3:16 and Matthew 24:14. They are quoted often.";
275 let expect: &str = "Two popular scripture are [prefix]John 3:16 and [prefix]Matthew 24:14. They are quoted often.";
276 let got: String = Script::new(text).prefix("[prefix]").surround().get_text();
277 assert_eq!(got, expect)
278 }
279
280 #[test]
281 fn add_element_postfix_single() {
282 let text: &str = "Another popular scripture is John 3:16, it's quoted often.";
283 let expect: &str = "Another popular scripture is John 3:16[postfix], it's quoted often.";
284 let got: String = Script::new(text).postfix("[postfix]").surround().get_text();
285 assert_eq!(got, expect)
286 }
287
288 #[test]
289 fn add_element_postfix_multi() {
290 let text: &str =
291 "Two popular scriptures are John 3:16 and Mathew 24:14. They are quoted often.";
292 let expect: &str = "Two popular scriptures are John 3:16[postfix] and Mathew 24:14[postfix]. They are quoted often.";
293 let got: String = Script::new(text).postfix("[postfix]").surround().get_text();
294 assert_eq!(got, expect)
295 }
296
297 #[test]
298 fn single_url() {
299 let text: &str = "A popular scriptures is John 3:16. It is quoted often.";
300 let expect: String = "A popular scriptures is [John 3:16](https://www.jw.org/en/library/bible/study-bible/books/john/3/#v43003016). It is quoted often.".to_string();
301 let got: String = Script::new(text).url(&Site::JwOrg).unwrap().get_text();
302 assert_eq!(got, expect)
303 }
304
305 #[test]
306 fn single_url_abbr() {
307 let text: &str = "A popular scriptures is Joh 3:16. It is quoted often.";
308 let expect: String = "A popular scriptures is [Joh 3:16](https://www.jw.org/en/library/bible/study-bible/books/john/3/#v43003016). It is quoted often.".to_string();
309 let got: String = Script::new(text).url(&Site::JwOrg).unwrap().get_text();
310 assert_eq!(got, expect)
311 }
312
313 #[test]
314 fn get_scripture() {
315 let text: &str =
316 "Two popular scriptures are John 3:16 and Matthew 24:14. They are quoted often.";
317 let expect: Vec<&str> = vec!["John 3:16", "Matthew 24:14"];
318 let got: Vec<String> = Script::new(text).get_scriptures().unwrap();
319 assert_eq!(got, expect)
320 }
321
322 #[test]
323 fn get_from_slice() {
324 let text: &str =
325 "Two popular scriptures are John 3:16 and Matthew 24:14. They are quoted often.";
326 let expect = "popular".to_string();
327 let got: String = Script::new(text).get_from_slice(&(4, 11));
328 assert_eq!(got, expect)
329 }
330
331 #[test]
332 fn get_locations1(){
333 let text: &str = "John 3:16 is well known.";
334 let expect: Locations = Locations{ slices: vec![(0, 9)], string: text.into() };
335 let got: Locations = Script::new(text).get_locations();
336 assert_eq!(got, expect);
337 }
338
339 #[test]
340 fn get_locations2(){
341 let text: &str = "John 3:16 is well known and if you know it, then it's easy to remember Timothy 3:16, another important scripture.";
342 let expect: Locations = Locations{ slices: vec![(0, 9), (71,83)], string: text.into() };
343 let got: Locations = Script::new(text).get_locations();
344 assert_eq!(got, expect);
345 }
346}