Repository: Nukesor/comfy-table
Pull request #106 (2023-04-20 12:18:23)

Add 'add_row_if' and 'add_rows_if' methods
This PR adds the ability to only add (a) row(s) when the specified predicate evaluates to `true`. This enables a smoother "flow" when building tables. For example:

```rust
let mut table = Table::new();
table
    .set_header(&vec!["Header1", "Header2", "Header3"])
    .add_row(&vec![
        "This is a text",
        "This is another text",
        "This is the third text",
    ]);
if predicate {
    table.add_row(vec!["", "", ""]);
}
table
    .add_row(vec!["", "", ""])
    .add_row(vec!["", "", ""]);
```

With the changes introduced by this PR, we could write the above code like:

```rust
let mut table = Table::new();
table
    .set_header(&vec!["Header1", "Header2", "Header3"])
    .add_row(&vec![
        "This is a text",
        "This is another text",
        "This is the third text",
    ]);
    .add_row_if(|| predicate, vec!["", "", ""])
    .add_row(vec!["", "", ""])
    .add_row(vec!["", "", ""]);
```

The same feature is implemented for `add_rows_if`. I also added some tests, which should cover the newly added feature.


Patch:
diff --git a/src/table.rs b/src/table.rs
index 3134dff..fad5b01 100644
--- a/src/table.rs
+++ b/src/table.rs
@@ -136,6 +136,27 @@ impl Table {
         self
     }
 
+    /// Add a new row to the table if the predicate evaluates to `true`.
+    ///
+    /// ```
+    /// use comfy_table::{Table, Row};
+    ///
+    /// let mut table = Table::new();
+    /// let row = Row::from(vec!["One", "Two"]);
+    /// table.add_row_if(|index, row| true, row);
+    /// ```
+    pub fn add_row_if<P, T>(&mut self, predicate: P, row: T) -> &mut Self
+    where
+        P: Fn(usize, &T) -> bool,
+        T: Into<Row>,
+    {
+        if predicate(self.rows.len(), &row) {
+            return self.add_row(row);
+        }
+
+        self
+    }
+
     /// Add multiple rows to the table.
     ///
     /// ```
@@ -163,6 +184,31 @@ impl Table {
         self
     }
 
+    /// Add multiple rows to the table if the predicate evaluates to `true`.
+    ///
+    /// ```
+    /// use comfy_table::{Table, Row};
+    ///
+    /// let mut table = Table::new();
+    /// let rows = vec![
+    ///     Row::from(vec!["One", "Two"]),
+    ///     Row::from(vec!["Three", "Four"])
+    /// ];
+    /// table.add_rows_if(|index, rows| true, rows);
+    /// ```
+    pub fn add_rows_if<P, I>(&mut self, predicate: P, rows: I) -> &mut Self
+    where
+        P: Fn(usize, &I) -> bool,
+        I: IntoIterator,
+        I::Item: Into<Row>,
+    {
+        if predicate(self.rows.len(), &rows) {
+            return self.add_rows(rows);
+        }
+
+        self
+    }
+
     /// Enforce a max width that should be used in combination with [dynamic content arrangement](ContentArrangement::Dynamic).\
     /// This is usually not necessary, if you plan to output your table to a tty,
     /// since the terminal width can be automatically determined.


Test patch:
diff --git a/tests/all/add_predicate.rs b/tests/all/add_predicate.rs
new file mode 100644
index 0000000..3e38245
--- /dev/null
+++ b/tests/all/add_predicate.rs
@@ -0,0 +1,265 @@
+use pretty_assertions::assert_eq;
+
+use comfy_table::*;
+
+#[test]
+fn add_predicate_single_true() {
+    let mut table = Table::new();
+    table
+        .set_header(&vec!["Header1", "Header2", "Header3"])
+        .add_row(&vec![
+            "This is a text",
+            "This is another text",
+            "This is the third text",
+        ])
+        .add_row_if(
+            |_, _| true,
+            &vec![
+                "This is another text",
+                "Now\nadd some\nmulti line stuff",
+                "This is awesome",
+            ],
+        );
+
+    println!("{table}");
+    let expected = "
++----------------------+----------------------+------------------------+
+| Header1              | Header2              | Header3                |
++======================================================================+
+| This is a text       | This is another text | This is the third text |
+|----------------------+----------------------+------------------------|
+| This is another text | Now                  | This is awesome        |
+|                      | add some             |                        |
+|                      | multi line stuff     |                        |
++----------------------+----------------------+------------------------+";
+    assert_eq!("\n".to_string() + &table.to_string(), expected);
+}
+
+#[test]
+fn add_predicate_single_false() {
+    let mut table = Table::new();
+    table
+        .set_header(&vec!["Header1", "Header2", "Header3"])
+        .add_row(&vec![
+            "This is a text",
+            "This is another text",
+            "This is the third text",
+        ])
+        .add_row_if(
+            |_, _| false,
+            &vec![
+                "This is another text",
+                "Now\nadd some\nmulti line stuff",
+                "This is awesome",
+            ],
+        );
+
+    println!("{table}");
+    let expected = "
++----------------+----------------------+------------------------+
+| Header1        | Header2              | Header3                |
++================================================================+
+| This is a text | This is another text | This is the third text |
++----------------+----------------------+------------------------+";
+    assert_eq!("\n".to_string() + &table.to_string(), expected);
+}
+
+#[test]
+fn add_predicate_single_mixed() {
+    let mut table = Table::new();
+    table
+        .set_header(&vec!["Header1", "Header2", "Header3"])
+        .add_row(&vec![
+            "This is a text",
+            "This is another text",
+            "This is the third text",
+        ])
+        .add_row_if(
+            |_, _| false,
+            &vec!["I won't get displayed", "Me neither", "Same here!"],
+        )
+        .add_row_if(
+            |_, _| true,
+            &vec![
+                "This is another text",
+                "Now\nadd some\nmulti line stuff",
+                "This is awesome",
+            ],
+        );
+
+    println!("{table}");
+    let expected = "
++----------------------+----------------------+------------------------+
+| Header1              | Header2              | Header3                |
++======================================================================+
+| This is a text       | This is another text | This is the third text |
+|----------------------+----------------------+------------------------|
+| This is another text | Now                  | This is awesome        |
+|                      | add some             |                        |
+|                      | multi line stuff     |                        |
++----------------------+----------------------+------------------------+";
+    assert_eq!("\n".to_string() + &table.to_string(), expected);
+}
+
+#[test]
+fn add_predicate_single_wrong_row_count() {
+    let mut table = Table::new();
+    table
+        .set_header(&vec!["Header1", "Header2", "Header3"])
+        .add_row(&vec![
+            "This is a text",
+            "This is another text",
+            "This is the third text",
+        ])
+        .add_row_if(
+            |_, row| row.len() == 2,
+            &vec![
+                "This is another text",
+                "Now\nadd some\nmulti line stuff",
+                "This is awesome",
+            ],
+        );
+
+    println!("{table}");
+    let expected = "
++----------------+----------------------+------------------------+
+| Header1        | Header2              | Header3                |
++================================================================+
+| This is a text | This is another text | This is the third text |
++----------------+----------------------+------------------------+";
+    assert_eq!("\n".to_string() + &table.to_string(), expected);
+}
+
+#[test]
+fn add_predicate_multi_true() {
+    let mut table = Table::new();
+    let rows = vec![
+        Row::from(&vec![
+            "This is a text",
+            "This is another text",
+            "This is the third text",
+        ]),
+        Row::from(&vec![
+            "This is another text",
+            "Now\nadd some\nmulti line stuff",
+            "This is awesome",
+        ]),
+    ];
+
+    table
+        .set_header(&vec!["Header1", "Header2", "Header3"])
+        .add_rows_if(|_, _| true, rows);
+
+    println!("{table}");
+    let expected = "
++----------------------+----------------------+------------------------+
+| Header1              | Header2              | Header3                |
++======================================================================+
+| This is a text       | This is another text | This is the third text |
+|----------------------+----------------------+------------------------|
+| This is another text | Now                  | This is awesome        |
+|                      | add some             |                        |
+|                      | multi line stuff     |                        |
++----------------------+----------------------+------------------------+";
+    assert_eq!("\n".to_string() + &table.to_string(), expected);
+}
+
+#[test]
+fn add_predicate_multi_false() {
+    let mut table = Table::new();
+    table
+        .set_header(&vec!["Header1", "Header2", "Header3"])
+        .add_row(&vec![
+            "This is a text",
+            "This is another text",
+            "This is the third text",
+        ])
+        .add_rows_if(
+            |_, _| false,
+            vec![Row::from(&vec![
+                "This is another text",
+                "Now\nadd some\nmulti line stuff",
+                "This is awesome",
+            ])],
+        );
+
+    println!("{table}");
+    let expected = "
++----------------+----------------------+------------------------+
+| Header1        | Header2              | Header3                |
++================================================================+
+| This is a text | This is another text | This is the third text |
++----------------+----------------------+------------------------+";
+    assert_eq!("\n".to_string() + &table.to_string(), expected);
+}
+
+#[test]
+fn add_predicate_multi_mixed() {
+    let mut table = Table::new();
+    let rows = vec![
+        Row::from(&vec![
+            "This is a text",
+            "This is another text",
+            "This is the third text",
+        ]),
+        Row::from(&vec![
+            "This is another text",
+            "Now\nadd some\nmulti line stuff",
+            "This is awesome",
+        ]),
+    ];
+
+    table
+        .set_header(&vec!["Header1", "Header2", "Header3"])
+        .add_rows_if(|_, _| true, rows)
+        .add_rows_if(
+            |_, _| false,
+            vec![Row::from(&vec![
+                "I won't get displayed",
+                "Me neither",
+                "Same here!",
+            ])],
+        );
+
+    println!("{table}");
+    let expected = "
++----------------------+----------------------+------------------------+
+| Header1              | Header2              | Header3                |
++======================================================================+
+| This is a text       | This is another text | This is the third text |
+|----------------------+----------------------+------------------------|
+| This is another text | Now                  | This is awesome        |
+|                      | add some             |                        |
+|                      | multi line stuff     |                        |
++----------------------+----------------------+------------------------+";
+    assert_eq!("\n".to_string() + &table.to_string(), expected);
+}
+
+#[test]
+fn add_predicate_multi_wrong_rows_count() {
+    let mut table = Table::new();
+    table
+        .set_header(&vec!["Header1", "Header2", "Header3"])
+        .add_row(&vec![
+            "This is a text",
+            "This is another text",
+            "This is the third text",
+        ])
+        .add_rows_if(
+            |_, rows| rows.len() == 2,
+            vec![Row::from(&vec![
+                "This is another text",
+                "Now\nadd some\nmulti line stuff",
+                "This is awesome",
+            ])],
+        );
+
+    println!("{table}");
+    let expected = "
++----------------+----------------------+------------------------+
+| Header1        | Header2              | Header3                |
++================================================================+
+| This is a text | This is another text | This is the third text |
++----------------+----------------------+------------------------+";
+    assert_eq!("\n".to_string() + &table.to_string(), expected);
+}
diff --git a/tests/all/mod.rs b/tests/all/mod.rs
index 5082401..8f2a8fc 100644
--- a/tests/all/mod.rs
+++ b/tests/all/mod.rs
@@ -1,6 +1,7 @@
 use comfy_table::Table;
 use unicode_width::UnicodeWidthStr;
 
+mod add_predicate;
 mod alignment_test;
 #[cfg(feature = "tty")]
 mod combined_test;