Upcoming Changes
cfilipov opened this issue · 1 comments
The API of this lib has seen several major changes. But it has been converging on what I think resembles a good API.
New Text Table Creation
As of v1.0.0-alpha.4 this is how you create a text table:
let table = TextTable<Person> {
[Column("Name" <- $0.name),
Column("Age" <- $0.age),
Column("Birthday" <- $0.birhtday)]
}
This has one major disadvantage:
The closure that maps the type to a column value is intertwined with the rest of the column definition. You can't get the column definition without calling the closure, and you can't call the closure unless you pass in a value. This is problematic when you need column information up front, before the first row is even processed. The callback ends up calling the closure using the first row multiple times just to get the column definition.
I propose the next version will have the following API instead:
let table: TextTable<Person> = [
{ $0.name } <- Column("Name"),
{ $0.country } <- Column("Country"),
{ $0.visited } <- Column("Last Visit")
]
Since the example above didn't customize the columns in any way, the following is also valid:
let table: TextTable<Person> = [
{ $0.name } <- "Name",
{ $0.country } <- "Country",
{ $0.visited } <- "Last Visit"
]
The goal is that this library will have good-enough defaults that for most cases one wouldn't be compelled to customize each column.
The <-
operator is just syntactic sugar that allows us to keep the property mapping visually close to the column name so it reads better. The following is equivalent to the previous two examples:
let table: TextTable<Person> = [
Column("Name", valueMapping: { $0.name }),
Column("Country", valueMapping: { $0.country }),
Column("Last Visit", valueMapping: { $0.visited })
]
Note the differences to the current API:
TextTable<T>
now conforms toExpressibleByArrayLiteral
. Instead of passing a closure on theinit
method ofTextTable
, you are now passing an array literal of columns.- The value mapping for the column is defined as an individual closure for each column instead of a single closure for all columns.
Customizing the columns works similar to the current version:
let table: TextTable<Person> = [
{ $0.name } <- Column("Name", align: .left),
{ $0.country } <- Column("Country", align: .center, width: 12, truncate: .head),
{ $0.visited } <- Column("Last Visit", align: .right, formatter: df)
]
String Constructor Instead of String Method
Another change to consider: Extending String
with an init
for TextTable
instead of using a string(for:)
method.
let s = String(table: table)
Instead of
let s = table.string(for: data)
Stream Print
TextTable
tries to be memory efficient. It will not copy the contents of your collection, instead it will call back to your collection whenever it needs a value.
Currently the print
method on table just creates a string using the aforementioned API and just passes it to Swift.print
. The next version will instead stream the contents of the table to Swift.print
roughly line-by-line as the table is generated.
Conformance to Sequence Type
TextTable
will actually conform to swift's Collection
(or maybe just provide a Sequence
). This will let one lazily pull the string parts of the rendered table.