minigrep_cli_tool/
lib.rs

1//! # minigrep_cli_tool
2//!
3//! A lightweight library module that powers the MiniGrep CLI tool.
4//!
5//! It provides two main functions for searching within text:
6//! - `search` (case-sensitive)
7//! - `search_case_insensitive` (case-insensitive)
8//!
9//! # Examples
10//! ```
11//! use minigrep_cli_tool::{search, search_case_insensitive};
12//!
13//! let query = "rust";
14//! let contents = "Rust is fast.\nTrust in Rust.";
15//!
16//! // Case-sensitive
17//! let matches: Vec<&str> = search(query, contents).collect();
18//!
19//! // Case-insensitive
20//! let matches_insensitive: Vec<&str> = search_case_insensitive(query, contents).collect();
21//! ```
22
23/// Searches for lines containing the query string in the provided text.
24///
25/// This function performs a **case-sensitive** search.
26///
27/// # Arguments
28/// - `query`: The substring to look for.
29/// - `contents`: The text to search within.
30///
31/// # Returns
32/// An iterator over lines that contain the query.
33///
34/// # Examples
35/// ```
36/// use minigrep_cli_tool::search;
37///
38/// let query = "safe";
39/// let contents = "Rust is safe.\nFast.\nProductive.";
40///
41/// let results: Vec<&str> = search(query, contents).collect();
42/// assert_eq!(results, vec!["Rust is safe."]);
43/// ```
44
45pub fn search<'a>(query: &str, contents: &'a str) -> impl Iterator<Item = &'a str> {
46    contents
47        .lines()
48        .filter(move |line| line.contains(query))
49}
50
51/// Searches for lines containing the query string, ignoring case.
52///
53/// # Arguments
54/// - `query`: The substring to look for.
55/// - `contents`: The text to search within.
56///
57/// # Returns
58/// An iterator over lines that contain the query, ignoring case.
59///
60/// # Examples
61/// ```
62/// use minigrep_cli_tool::search_case_insensitive;
63///
64/// let query = "RuSt";
65/// let contents = "Rust:\nReally productive.\nTrust in rust.";
66///
67/// let results: Vec<&str> = search_case_insensitive(query, contents).collect();
68/// assert_eq!(results, vec!["Rust:", "Trust in rust."]);
69/// ```
70
71pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> impl Iterator<Item = &'a str> {
72    contents
73        .lines()
74        .filter(|line| line.to_lowercase().contains(&query.to_lowercase()))
75}
76
77#[cfg(test)]
78mod tests {
79    use std::vec;
80
81    use super::*;
82
83    #[test]
84    fn one_result() {
85        let query = "duct";
86        let contents = "\
87Rust:
88safe, fast, productive.
89Pick three.";
90
91        let result: Vec<&str> = search(query, contents).collect();
92        assert_eq!(result, vec!["safe, fast, productive."]);
93    }
94
95    #[test]
96    fn multiple_result() {
97        let query = "ive";
98        let contents = "\
99Rust:
100really productive.
101also passive.
102probably problamatic.
103but simply lovely.
104Come dive into the world of rust.";
105
106        let result: Vec<&str> = search(query, contents).collect();
107        assert_eq!(
108            result,
109            vec![
110                "really productive.",
111                "also passive.",
112                "Come dive into the world of rust."
113            ]
114        )
115    }
116
117    #[test]
118    fn empty_content() {
119        let query = "hi";
120        let contents = "";
121
122        let result: Vec<&str> = search(query, contents).collect();
123        let expected: Vec<&str> = Vec::new();
124        assert_eq!(result, expected)
125    }
126
127    #[test]
128    fn empty_query() {
129        let query = "";
130        let contents = "\
131Rust:
132really productive.
133also passive.
134probably problamatic.
135but simply lovely.
136Come dive into the world of rust.";
137
138        let result: Vec<&str> = search(query, contents).collect();
139        let expected: Vec<&str> = contents.lines().collect();
140        assert_eq!(result, expected)
141    }
142
143    #[test]
144    fn empty_content_and_query() {
145        let query = "";
146        let contents = "";
147
148        let result: Vec<&str> = search(query, contents).collect();
149        let expected: Vec<&str> = Vec::new();
150        assert_eq!(result, expected)
151    }
152
153    #[test]
154    fn case_insensitive() {
155        let query = "rUsT";
156        let contents = "\
157Rust:
158really productive.
159also passive.
160probably problamatic.
161but simply lovely.
162Come dive into the world of rust.";
163
164        let result: Vec<&str> = search_case_insensitive(query, contents).collect();
165        assert_eq!(result, vec!["Rust:", "Come dive into the world of rust."]);
166    }
167
168    #[test]
169    fn case_sensitive() {
170        let query = "rUsT";
171        let contents = "\
172Rust:
173really productive.
174also passive.
175probably problamatic.
176but simply lovely.
177Come dive into the world of rust.";
178
179        let result: Vec<&str> = search(query, contents).collect();
180        let expected: Vec<&str> = Vec::new();
181        assert_eq!(result, expected);
182    }
183}