rcw/
lib.rs

1use std::{error::Error, fs};
2
3use comfy_table::{
4    modifiers::{UTF8_ROUND_CORNERS, UTF8_SOLID_INNER_BORDERS},
5    presets::UTF8_FULL,
6    Attribute, Cell, CellAlignment, ContentArrangement, Table,
7};
8
9pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
10    let contents = fs::read_to_string(&config.file_path)?;
11
12    let line_count = count_lines(&contents);
13    let word_count = count_words(&contents);
14    let byte_count = count_bytes(&contents);
15    let char_count = count_chars(&contents);
16
17    let mut table = Table::new();
18    table
19        .load_preset(UTF8_FULL)
20        .apply_modifier(UTF8_SOLID_INNER_BORDERS)
21        .apply_modifier(UTF8_ROUND_CORNERS)
22        .set_content_arrangement(ContentArrangement::Dynamic)
23        .set_header(vec![
24            Cell::new("Lines")
25                .add_attribute(Attribute::Bold)
26                .set_alignment(CellAlignment::Left),
27            Cell::new("Words")
28                .add_attribute(Attribute::Bold)
29                .set_alignment(CellAlignment::Left),
30            Cell::new("Bytes")
31                .add_attribute(Attribute::Bold)
32                .set_alignment(CellAlignment::Left),
33            Cell::new("Chars")
34                .add_attribute(Attribute::Bold)
35                .set_alignment(CellAlignment::Left),
36            Cell::new("File")
37                .add_attribute(Attribute::Bold)
38                .set_alignment(CellAlignment::Left),
39        ])
40        .add_row(vec![
41            Cell::new(line_count.to_string()).set_alignment(CellAlignment::Left),
42            Cell::new(word_count.to_string()).set_alignment(CellAlignment::Left),
43            Cell::new(byte_count.to_string()).set_alignment(CellAlignment::Left),
44            Cell::new(char_count.to_string()).set_alignment(CellAlignment::Left),
45            Cell::new(config.file_path).set_alignment(CellAlignment::Left),
46        ]);
47    println!("{table}");
48
49    Ok(())
50}
51
52pub fn count_lines<'a>(contents: &'a str) -> usize {
53    contents.lines().count()
54}
55
56pub fn count_bytes<'a>(contents: &'a str) -> usize {
57    contents.bytes().count()
58}
59
60pub fn count_words<'a>(contents: &'a str) -> usize {
61    contents.split_whitespace().count()
62}
63
64pub fn count_chars<'a>(contents: &'a str) -> usize {
65    contents.chars().count()
66}
67
68pub struct Config {
69    pub file_path: String,
70}
71
72impl Config {
73    pub fn build(args: &[String]) -> Result<Config, &'static str> {
74        let file_path = args[1].clone();
75
76        Ok(Config { file_path })
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83
84    #[test]
85    fn count_lines_test() {
86        let contents = "\
87        The quick brown fox
88        jumped over the lazy dog.
89        If the dog moved,
90        was it really lazy ?";
91
92        assert_eq!(count_lines(contents), 4);
93    }
94
95    #[test]
96    fn count_bytes_test() {
97        let contents = "The quick brown fox jumped over the lazy dog.";
98        assert_eq!(count_bytes(contents), 45);
99    }
100
101    #[test]
102    fn count_words_test() {
103        let contents = "The quick brown fox jumped over the lazy dog.";
104        assert_eq!(count_words(contents), 9);
105    }
106
107    #[test]
108    fn count_chars_test() {
109        let contents = "The quick brown fox jumped over the lazy dog.";
110        assert_eq!(count_words(contents), 9);
111    }
112
113}