est/lib.rs
1//!# Estienne
2//!
3//!<img src="https://user-images.githubusercontent.com/6587811/190536556-aec1ba71-0aef-4878-9c1f-a9727e647083.png" alt="A digital image generated by an AI of a bearded man reading from a large book in the style of medieval painting." width=200 align=left hspace="20" vspace="20">
4//!
5//](https://github.com/JoelMon/Estienne/actions/workflows/rust.yml)
6//](https://www.repostatus.org/#wip)
7//!
8//!Estienne is a simple to use library for interacting with Biblical verses from text.
9//!The focus of Estienne is to provide a library for building applications that need to interact with files that contain Biblical scriptures such as lecture notes.
10//!No special syntax needs to be used in conjunction with scriptures in order for Estienne to parse the text successfully.
11//!
12//!Estienne is still in its initial stages and not ready for use.
13//!
14//!## The Name
15//!The library is named after Robert Estienne, a French theologian of the early Christian era.
16//!He is best remembered for being the first to print the New Testament divided with numbered verses.
17//
18//!
19//!## The Purpose
20//!The purpose of the library is to provide a simple way to manipulate Biblical verses within a line of text.
21//!The API will allow for easy manipulations of the verses, such as:
22//!- Returning a list of verses found in a line of text
23//!- Allowing a verses to be:
24//! - prefixed with arbitrary text
25//! - suffixed with arbitrary text
26//! - etc.
27//!
28//!## Contributing
29//!Contributions are welcomed, but please be aware that the project is still in its prototype phase and large portions of code might change at any moment.
30//!Feel free to open an issue if you have any questions or suggestions.
31
32pub mod locales;
33mod parsers;
34mod url;
35use locales::nwt_en::Site;
36use locales::BibleError;
37pub use parsers::surround::{ScriptSlice, ScriptureCollection, Locations};
38
39
40#[allow(non_camel_case_types)]
41#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
42pub enum Locale {
43 /// American English
44 en_us,
45 es_es,
46}
47
48
49/// Adds a prefix and postfix around each scripture found in and returns the modified string.
50///
51/// ## Example
52/// ```
53/// use est::surround;
54///
55/// let text: &str = "The scripture John 3:16 is known by a lot of people.";
56/// let expected:String = "The scripture <strong>John 3:16</strong> is known by a lot of people.".to_string();
57/// assert_eq!(expected, surround(text, "<strong>", "</strong>").unwrap());
58///
59/// ```
60pub fn surround<'a, S: Into<String> + Clone>(
61 text: S,
62 prefix: &'a str,
63 postfix: &'a str,
64) -> Result<String, BibleError> {
65 Ok(parsers::surround::Script::new(text)
66 .prefix(prefix)
67 .postfix(postfix)
68 .surround()
69 .get_text())
70}
71
72/// Adds Markdown link syntax around found scriptures to an Online Bible and the modified string is returned.
73/// When possible, it will link directly to the scripture being referenced.
74///
75/// The url function takes a Site enum coresponding to the translation being used.
76/// As an example, if you were building links for the english version of the online NWT translation,
77/// you would use `est::locales::nwt_en::Site::JwOrg` to build the proper link.
78///
79/// ## Example
80/// ```
81/// use est;
82/// use est::locales::nwt_en::Site::JwOrg;
83///
84/// let text: &str = "All friends should practice Proverbs 17:17!";
85/// let expected:String = "All friends should practice [Proverbs 17:17](https://www.jw.org/en/library/bible/study-bible/books/proverbs/17/#v20017017)!".to_string();
86/// assert_eq!(expected, est::url(&JwOrg, text).unwrap());
87/// ```
88pub fn url<S: Into<String> + Clone>(site: &Site, text: S) -> Result<String, BibleError> {
89 // TODO: Flip the order of the paramaters around, text should be first to follow the pattern set with the other functions.
90 Ok(parsers::surround::Script::new(text)
91 .url(site)?
92 .get_text())
93}
94
95/// Returns a vector of the scriptures found in the string passed in.
96///
97/// ## Example
98/// ```
99/// use est;
100///
101/// let text: &str = "A popular scripture is John 3:16, it is quoted often.";
102/// let expected:Vec<String> = vec!["John 3:16".to_string()];
103/// assert_eq!(expected, est::get_scriptures(text).unwrap());
104/// ```
105pub fn get_scriptures<S: Into<String> + Clone>(string: S) -> Result<ScriptureCollection, BibleError> {
106 parsers::surround::Script::new(string).get_scriptures()
107}
108
109
110/// Returns a Location struct containing the start and end index of each scripture found and the original string passed in.
111/// This function helps you process the scriptures in whatever manner that you need.
112///
113/// ## Example
114/// ```
115/// use est::Locations;
116///
117/// let text = "John 3:16 is well known and if you know it, then it's easy to remember Timothy 3:16, another important scripture.";
118/// let expect = Locations{ slices: vec![(0, 9), (71,83)], string: text.into() };
119/// assert_eq!(expect, est::get_locations(text));
120/// ```
121///
122/// If no scriptures are found in the string then `slices` will be an empty vec.
123/// ```
124/// use est::Locations;
125///
126/// let text = "This string contains no scripture.";
127/// let expect = Locations{ slices: vec![], string: text.into() };
128/// assert_eq!(expect, est::get_locations(text));
129/// ```
130pub fn get_locations<'a, S: Into<String> + Clone>(string: S) -> Locations {
131 parsers::surround::Script::new(string).get_locations()
132}
133
134#[cfg(test)]
135mod lib_test {
136 use super::*;
137 use pretty_assertions::assert_eq;
138
139 #[test]
140 fn t_single_url() {
141 let input: &str = "A popular scriptures is Re 12:12. It is quoted often.";
142 let expect: String = "A popular scriptures is [Re 12:12](https://www.jw.org/en/library/bible/study-bible/books/revelation/12/#v66012012). It is quoted often.".to_string();
143 let got: String = url(&Site::JwOrg, input).unwrap();
144 assert_eq!(got, expect)
145 }
146
147 #[test]
148 fn t_single_ranged_url() {
149 let input: &str = "A popular scriptures is Job 36:26-28. It is quoted often.";
150 let expect: String = "A popular scriptures is [Job 36:26-28](https://www.jw.org/en/library/bible/study-bible/books/job/36/#v18036026-v18036028). It is quoted often.".to_string();
151 let got: String = url(&Site::JwOrg, input).unwrap();
152 assert_eq!(got, expect)
153 }
154
155 #[test]
156 fn t_multipal_url() {
157 let input: &str = "Three well-known Bible scriptures are Proverbs 3:5, John 3:16, and Romans 8:28";
158 let expect: String = "Three well-known Bible scriptures are [Proverbs 3:5](https://www.jw.org/en/library/bible/study-bible/books/proverbs/3/#v20003005), [John 3:16](https://www.jw.org/en/library/bible/study-bible/books/john/3/#v43003016), and [Romans 8:28](https://www.jw.org/en/library/bible/study-bible/books/romans/8/#v45008028)".to_string();
159 let got: String = url(&Site::JwOrg, input).unwrap();
160 assert_eq!(got, expect)
161 }
162
163 #[test]
164 fn t_add_element_prefix_single() {
165 let input: &str = "Another popular scripture is John 3:16, it's quoted often.";
166 let expect: &str = "Another popular scripture is **John 3:16]], it's quoted often.";
167 let got = surround(input, "**", "]]").unwrap();
168 assert_eq!(got, expect);
169 }
170
171 #[test]
172 // Test if a String can be passed in as input.
173 fn t_add_element_prefix_single_to_string() {
174 let input: String = "Another popular scripture is John 3:16, it's quoted often.".into();
175 let expect: &str = "Another popular scripture is **John 3:16]], it's quoted often.";
176 let got = surround(input, "**", "]]").unwrap();
177 assert_eq!(got, expect);
178 }
179
180 #[test]
181 fn t_add_element_prefix_multi() {
182 let input:&str = "Other popular scriptures include John 3:16, Matthew 24:14, and Psalm 83:18, they are quoted often.";
183 let expect:&str = "Other popular scriptures include **John 3:16]], **Matthew 24:14]], and **Psalm 83:18]], they are quoted often.";
184 let got = surround(input, "**", "]]").unwrap();
185 assert_eq!(got, expect);
186 }
187
188 #[test]
189 fn t_add_element_prefix_ranged_multi() {
190 let input:&str = "Other popular scriptures include John 3:16, 17, Matthew 24:14-16, and Psalm 83:18, 17-20, they are quoted often.";
191 let expect:&str = "Other popular scriptures include **John 3:16, 17]], **Matthew 24:14-16]], and **Psalm 83:18, 17-20]], they are quoted often.";
192 let got = surround(input, "**", "]]").unwrap();
193 assert_eq!(got, expect);
194 }
195
196 #[test]
197 fn t_add_element_prefix_multi_no_scriptures() {
198 let input: &str = "There are no scriptures in this line.";
199 let expect: &str = "There are no scriptures in this line.";
200 let got = surround(input, "**", "]]").unwrap();
201 assert_eq!(got, expect);
202 }
203
204 #[test]
205 fn t_url_invalid_book() {
206 let input: &str = "A popular scriptures is Mary 12:12. It is quoted often.";
207 let result= url(&Site::JwOrg, input);
208 assert!(result.is_err());
209 assert_eq!(
210 result.unwrap_err(),
211 BibleError::BookNotFound("Mary".to_string())
212 );
213 }
214
215 #[test]
216 fn t_url_no_scripture() {
217 let input: &str = "This is not a scripture.";
218 let result = url(&Site::JwOrg, input);
219 assert!(result.is_ok());
220 }
221
222 #[test]
223 fn t_get_multiple_scriptures() {
224 let input: &str = "A popular scripture is John 3:16. Another is Matthew 24:14.";
225 let result = get_scriptures(input).unwrap();
226 assert_eq!(result, vec!["John 3:16", "Matthew 24:14"]);
227 }
228}