text_table 0.0.4

A library to create formatted plain-text tables from arbitrary data.
#![feature(plugin)]
#![plugin(speculate)]

extern crate text_table;

pub use text_table::Table;
pub use text_table::ToCell;

speculate! {
    it "renders basic table" {
        let mut table = Table::new();
        table.row(("foo", "bar"))
             .row(("baz baz", 1234))
             .row(("fooooo", "quux quux"))
             .row(&[1, 2][]);
        assert_eq!(table.write_to_string(), "
+---------+-----------+
| foo     | bar       |
| baz baz | 1234      |
| fooooo  | quux quux |
| 1       | 2         |
+---------+-----------+
".trim_left());
    }

    it "renders all ToCell types correctly" {
        let mut table = Table::new();
        table.row((1u8, 2u16, 3u32, 4u64, 5us))
             .row((-1i8, -2i16, -3i32, -4i64, -5is))
             .row((1.234f32, 5.678f64, "foo", "bar".to_string(), ()));
        assert_eq!(table.write_to_string(), "
+-------+-------+-----+-----+----+
| 1     | 2     | 3   | 4   | 5  |
| -1    | -2    | -3  | -4  | -5 |
| 1.234 | 5.678 | foo | bar |    |
+-------+-------+-----+-----+----+
".trim_left());
    }

    it "renders left, center, and right aligned cells correctly" {
        let mut table = Table::new();
        table.row(("foo foo foo", "bar bar bar", "baz".to_cell().right()))
             .row(("foo".to_cell().left(), "bar".to_cell().center(), "baz baz"))
             .row(((), "quux".to_cell().center(), "b".to_cell().center()));
        assert_eq!(table.write_to_string(), "
+-------------+-------------+---------+
| foo foo foo | bar bar bar |     baz |
| foo         |     bar     | baz baz |
|             |    quux     |    b    |
+-------------+-------------+---------+
".trim_left());
    }

    it "renders header and footer correctly" {
        let mut table = Table::new();
        table.row(("foo foo foo", "bar bar bar", "baz".to_cell().right()))
             .sep()
             .row(("foo".to_cell().left(), "bar".to_cell().center(), "baz baz"))
             .row(("foo".to_cell().left(), "bar".to_cell().center(), "baz baz"))
             .sep()
             .row(("foo", "bar".to_cell().center(), "baz baz baz"));
        assert_eq!(table.write_to_string(), "
+-------------+-------------+-------------+
| foo foo foo | bar bar bar |         baz |
+-------------+-------------+-------------+
| foo         |     bar     | baz baz     |
| foo         |     bar     | baz baz     |
+-------------+-------------+-------------+
| foo         |     bar     | baz baz baz |
+-------------+-------------+-------------+
".trim_left());
    }

    it "renders newlines in cells correctly" {
        let mut table = Table::new();
        table.row(("foo\nbar", 123))
             .row(("baz\n\nquux", "\n\n\n\n\n"))
             .row(("\nbaz\n", ()));
        assert_eq!(table.write_to_string(), "
+------+-----+
| foo  | 123 |
| bar  |     |
| baz  |     |
|      |     |
| quux |     |
|      |     |
|      |     |
|      |     |
|      |     |
| baz  |     |
|      |     |
+------+-----+
".trim_left());
    }

    describe "examples" {
        it "renders a bank statement" {
            #[derive(Copy)]
            enum Transaction {
                Deposit(u64),
                Withdraw(u64)
            }

            let entries = [
                ("2014-01-01", "Previous Balance", Transaction::Deposit(100), 100),
                ("2014-01-02", "Foo", Transaction::Withdraw(10), 90),
                ("2014-01-03", "Bar", Transaction::Withdraw(10), 80),
                ("2014-01-04", "Baz", Transaction::Deposit(50), 130),
                ("2014-01-05", "Quux", Transaction::Deposit(50), 180),
                ("2014-01-06", "Bye", Transaction::Withdraw(180), 0)
            ];

            let total_withdrawl = 200;
            let total_deposit = 200;

            let mut table = Table::new();
            table.row(("Date".to_cell().center(),
                       "Description".to_cell().center(),
                       "Withdrawls".to_cell().center(),
                       "Deposits".to_cell().center(),
                       "Balance".to_cell().center()));
            table.sep();
            for &(date, description, transaction, balance) in entries.iter() {
                let (w, d) = match transaction {
                    Transaction::Withdraw(x) => (x.to_cell().right(), "".to_cell()),
                    Transaction::Deposit(x) => ("".to_cell(), x.to_cell().right())
                };
                table.row((date, description, w, d, balance.to_cell().right()));
            }
            table.sep();
            table.row(((),
                       "Totals".to_cell().center(),
                       total_withdrawl.to_cell().right(),
                       total_deposit.to_cell().right(),
                       ()));
            assert_eq!(table.write_to_string(), "
+------------+------------------+------------+----------+---------+
|    Date    |   Description    | Withdrawls | Deposits | Balance |
+------------+------------------+------------+----------+---------+
| 2014-01-01 | Previous Balance |            |      100 |     100 |
| 2014-01-02 | Foo              |         10 |          |      90 |
| 2014-01-03 | Bar              |         10 |          |      80 |
| 2014-01-04 | Baz              |            |       50 |     130 |
| 2014-01-05 | Quux             |            |       50 |     180 |
| 2014-01-06 | Bye              |        180 |          |       0 |
+------------+------------------+------------+----------+---------+
|            |      Totals      |        200 |      200 |         |
+------------+------------------+------------+----------+---------+
".trim_left());
        }
    }
}