tabular: go.pennock.tech/tabular Index | Files | Directories

package tabular

import "go.pennock.tech/tabular"

The tabular package provides for a model of a two-dimensional grid of cells, or a "table". Sub-packages provide for rendering such a table in convenient ways. For many uses, you only need to import the sub-package.

Sub-packages provide for rendering a TextTable which is designed for a fixed-cell grid layout of character cells, such as a Unix TTY; for rendering as an HTML table; for rendering as a CSV.

The core package provides a Table interface; each sub-package embeds a Table in their own core object, so all methods in the Table interface can be directly used upon such objects. These provide for your basic addition of cells, etc.

The API is designed to let you add data quickly, without error-checking every addition. Instead, error containers are used, and errors accumulate therein. The table is an error-container. A row which is not in a table is also an error container, but any such errors get moved into the table's collection when the row is added, and the row thenceforth uses the table's container.

In addition to tables of rows of cells, with virtual columns, we also have "properties" and "property callbacks". People using tables with pre-canned rendering should not need to care about these, but people writing renderers will need to.

Properties are held by cells, rows, columns and tables. They are metadata, designed to be used by sub-packages or anything doing non-trivial table embedding, to register extra data "about" something. They're akin to stdlib's "context", in that the various users can maintained their own namespaced properties, using a similar API, but can be automatically updated by the table.

Examples might include terminal text properties, color, calculation attributes.

Properties are held by anything which satisfies the PropertyOwner interface. Such objects then have GetProperty and SetProperty methods.

There is an API balancing act for callers to decide between registering a property upon the table itself, or wrapping the table: if you want the value to be automatically updated as a table is mutated, the property approach might make the most sense, but then with a simple API to present it via a method of your wrapper object.

A Property Callback is "anything with the UpdateProperties method", which can be registered with something in the table to be called to automatically update properties. These can be registered on a table, row, column or cell; most are applied to cells, but some are applied to larger objects. The registration needs to know what object is to hold the callback, which target the callback is to be applied to, when it should be invoked, and the new callback being registered.

Index

Package Files

atable.go cell.go doc.go error_containers.go error_types.go location.go pretty.go properties.go render_callbacks.go row.go table.go types.go version.go

Constants

const (
    // CB_AT_ADD called when an item is added to a container
    CB_AT_ADD callbackTime = iota

    // CB_AT_RENDER_PRECELL for callbacks registered on containers, to be
    // called before cell's own callbacks.  Use before dimensions/etc locked
    // down.
    CB_AT_RENDER_PRECELL

    // CB_AT_RENDER is called for two sets: table (not row/column) and cell
    // callbacks.  An assumption is that it might be used for deriving
    // properties such as dimensions, the effect of which cascade outwards.
    CB_AT_RENDER

    // CB_AT_RENDER_POSTCELL is called after the cell's own callbacks.
    CB_AT_RENDER_POSTCELL
)

These constants are used for callback functions, to control when the function is invoked.

const (
    CB_ON_ITSELF cbTarget = iota
    CB_ON_CELL
    CB_ON_ROW
)

These constants are used when registering a callback to indicate what should be passed to the callback. Eg, a row might have a set of callbacks to update the row itself, and a separate set of callbacks which are invoked upon each cell in the row.

const APIVersion string = "1.0"

Variables

var ErrMissingPropertyHolder = errors.New("tabular: missing item upon which to set a property")

ErrMissingPropertyHolder is returned if you call SetProperty upon a nil object.

var LinkerSpecifiedVersion string

We are a library, not a top-level binary, so we can't depend upon any particular top-level linker action specifying versions. That said, we can provide hooks for applications to cooperate, if they so choose.

*Clients* please consider invoking the `.version` shell-script inside this repo and passing it to the Go linker. See github.com/philpennock/character for an example.

func NoProperty Uses

func NoProperty() propertySet

func Versions Uses

func Versions() []string

type ATable Uses

type ATable struct {
    *ErrorContainer
    // contains filtered or unexported fields
}

An ATable is the top-level container for a grid in tabular. You should not be declaring fields to be of type ATable; instead, use the Table interface.

An ATable consists of rows of cells; there may also be a header row which defines names for columns. An ATable, a Column, a Row and a Cell can all contain both Properties, and callbacks for updating properties. The callbacks can each individually be registered to activate upon object addition or upon object rendering. Property Callbacks can take various child objects. For instance, a table-level callback upon cells might update a namespaced Property which holds the cell's rendered width when emitted as characters for terminal display.

func New Uses

func New() *ATable

New creates a new empty ATable, which satisfies Table.

func (*ATable) AddHeaders Uses

func (t *ATable) AddHeaders(items ...interface{}) Table

AddHeaders creates a header-row from the passed items and sets it as the table's header row. The table is returned.

func (*ATable) AddRow Uses

func (t *ATable) AddRow(row *Row) Table

AddRow adds a *Row to the *ATable, returning the table to allow for chaining. Any errors accumulate in the table. Any existing errors in the row become table errors.

func (*ATable) AddRowItems Uses

func (t *ATable) AddRowItems(items ...interface{}) Table

AddRowItems creates a row from the passed items and adds it to the table, returning the table for chaining.

func (*ATable) AddSeparator Uses

func (t *ATable) AddSeparator() Table

AddSeparator adds a rule to the table.

func (*ATable) AllRows Uses

func (t *ATable) AllRows() []*Row

AllRows returns an iterable of rows.

func (*ATable) AppendNewRow Uses

func (t *ATable) AppendNewRow() *Row

AppendNewRow creates a new row sized for the table (per NewRowSizedFor) and adds it to the Table, returning the row.

func (*ATable) CellAt Uses

func (t *ATable) CellAt(loc CellLocation) (*Cell, error)

CellAt returns a pointer to the cell found at the given row and column coordinates, where the top-left item is 1,1.

func (*ATable) Column Uses

func (t *ATable) Column(n int) *column

Column returns a representation of a given column in the table. Column counting starts at 1. Providing an invalid column count returns nil. Column 0 also exists but is the implicit defaults column, letting you set default column properties and then override for other columns.

func (*ATable) GetProperty Uses

func (pi *ATable) GetProperty(key interface{}) interface{}

GetProperty returns the property stored for the given key. If no such property has been stored, then nil will be returned. Thus we can't tell the difference between "nil stored" and "nothing stored", thus property storage is free to treat storing "nil" as "remove".

func (*ATable) GoString Uses

func (t *ATable) GoString() string

func (*ATable) Headers Uses

func (t *ATable) Headers() []Cell

Headers returns the headers of a table, as Cells TODO v2: what if we have multiple header rows? How does this change?

func (*ATable) InvokeRenderCallbacks Uses

func (t *ATable) InvokeRenderCallbacks()

InvokeRenderCallbacks is used by rendering packages to trigger a table-wide invocation of render-time callbacks.

We first invoke pre-cell callbacks going: table->column->row->cell We then invoke regular render callbacks cell->row->column->table

func (*ATable) NColumns Uses

func (t *ATable) NColumns() int

NColumns says how many columns are in the table

func (*ATable) NRows Uses

func (t *ATable) NRows() int

NRows says how many rows are in the table; separators count

func (*ATable) NewRowSizedFor Uses

func (t *ATable) NewRowSizedFor() *Row

NewRowSizedFor creates a new Row sized for the given table which it is called upon, assuming that NColumns() is usefully available.

func (*ATable) RegisterPropertyCallback Uses

func (tb *ATable) RegisterPropertyCallback(
    owner PropertyOwner,
    when callbackTime,
    target cbTarget,
    theNewCallback PropertyCallback,
) error

RegisterPropertyCallback is used to register your object, which has the UpdateProperties method available, upon something within the table, to be invoked against something (else, perhaps), at a specified time.

func (*ATable) SetProperty Uses

func (pi *ATable) SetProperty(key, value interface{}) error

SetProperty sets the value stored for a given key, removing any other values stored for that key first. If the value is nil then no value will be stored.

type AnonFielder Uses

type AnonFielder interface {
    AnonFields() []interface{}
}

AnonFielder to avoid caller having to iterate an []interface{} to construct strings; we then just do cell breakdown on each.

type Cell Uses

type Cell struct {
    // contains filtered or unexported fields
}

A Cell is one item in a table; it holds an object and fields calculated from it. If the object added is mutated after addition, it is the mutator's responsibility to call Update.

func NewCell Uses

func NewCell(object interface{}) Cell

NewCell creates a Cell, handling object rendering at init time. TODO: handle rune as rune, or as int? Any special flags to use?

func (*Cell) Empty Uses

func (c *Cell) Empty() bool

Empty returns true if the cell is "empty", whatever that might mean. This includes nothing stored, a cell of nil, or an empty string.

func (*Cell) GetProperty Uses

func (pi *Cell) GetProperty(key interface{}) interface{}

GetProperty returns the property stored for the given key. If no such property has been stored, then nil will be returned. Thus we can't tell the difference between "nil stored" and "nothing stored", thus property storage is free to treat storing "nil" as "remove".

func (*Cell) GoString Uses

func (cell *Cell) GoString() string

func (Cell) Height Uses

func (c Cell) Height() int

Height returns the height of a cell; usually this is the number of lines in the string representation of the object stored in the cell, as returned by Lines, but an object which has a Height method will override this.

func (Cell) Item Uses

func (c Cell) Item() interface{}

Item returns the object stored inside a cell.

func (Cell) Lines Uses

func (c Cell) Lines() []string

Lines returns the string representation of the content of a cell, as a splice of strings, one per line, without newlines; if the string has a final \n then there will NOT be an extra empty in the result for the "empty" final segment.

func (Cell) Location Uses

func (c Cell) Location() (loc CellLocation)

Location determines the current location of a cell

func (*Cell) SetProperty Uses

func (pi *Cell) SetProperty(key, value interface{}) error

SetProperty sets the value stored for a given key, removing any other values stored for that key first. If the value is nil then no value will be stored.

func (Cell) String Uses

func (c Cell) String() string

String returns some string representation of the content of a cell.

func (Cell) TerminalCellWidth Uses

func (c Cell) TerminalCellWidth() int

TerminalCellWidth returns the number of terminal cells which we believe are necessary to render the contents of the object stored in the cell. This is overriden by a TerminalCellWidth method on the object being stored. To a first approximation, this is how many runes are in a cell, but we handle combining characters, wide characters, etc.

func (*Cell) Update Uses

func (c *Cell) Update()

Update changes metadata to reflect the current state of the object stored in a cell.

type CellLocation Uses

type CellLocation struct {
    Row    int
    Column int
}

We measure from 1:1 so that 0:0 means "not initialized" and if either x or y is zero in a cell, we know the data is invalid. For some contexts, one or the other might be zero, to describe an entire row or column or just unknown.

type ErrorContainer Uses

type ErrorContainer struct {
    // contains filtered or unexported fields
}

ErrorContainer holds a list of errors. The tabular package uses a batched error model, where errors accumulate in the top-level linked object to which an item is being added.

func NewErrorContainer Uses

func NewErrorContainer() *ErrorContainer

NewErrorContainer creates an object which satisfies both ErrorReceiver and ErrorSource.

func (*ErrorContainer) AddError Uses

func (ec *ErrorContainer) AddError(err error)

AddError puts a Golang error object into the container. If the error is nil, this is a no-op.

func (*ErrorContainer) AddErrorList Uses

func (ec *ErrorContainer) AddErrorList(el []error)

AddErrorList takes a list of errors and adds them to the container. Any errors which are nil will be dropped.

func (*ErrorContainer) Errors Uses

func (ec *ErrorContainer) Errors() []error

Errors returns either a non-empty list of errors, or nil.

type ErrorReceiver Uses

type ErrorReceiver interface {
    AddError(error)
}

An ErrorReceiver can accumulate errors for later retrieval.

type ErrorSource Uses

type ErrorSource interface {
    Errors() []error
}

An ErrorSource can be interrogated for errors.

type Fielder Uses

type Fielder interface {
    Fields() []string
}

Fielder for ability to grab "a row" from a type.

type GoStringer Uses

type GoStringer interface {
    GoString() string
}

GoStringer to match fmt's.

type Heighter Uses

type Heighter interface {
    Height() int
}

Heighter lets an object override how tall it is.

type NoSuchCellError Uses

type NoSuchCellError struct {
    Location CellLocation
    // contains filtered or unexported fields
}

NoSuchCellError is returned when a table is asked for a cell at some coordinates which do not exist within the table.

func (NoSuchCellError) Error Uses

func (e NoSuchCellError) Error() string

type PropertyCallback Uses

type PropertyCallback interface {
    UpdateProperties(PropertyOwner) error
}

A PropertyCallback registration is used to update cell properties. Properties are akin to stdlib's "context", in that various users of cells can maintain their own namespaced properties, using a similar API. Examples might include terminal text properties, color, calculation attributes and more. A callback can be registered to be applied to any PropertyOwner, whether cell, row, column or table.

type PropertyOwner Uses

type PropertyOwner interface {
    SetProperty(interface{}, interface{}) error
    GetProperty(interface{}) interface{}
}

PropertyOwner is the high-level interface satisfied by anything which holds metadata in the form of properties.

type Row Uses

type Row struct {
    *ErrorContainer
    // contains filtered or unexported fields
}

A Row represents a row in a Table.

func NewRow Uses

func NewRow() *Row

NewRow creates a new Row.

func NewRowWithCapacity Uses

func NewRowWithCapacity(c int) *Row

NewRowWithCapacity create a new row pre-sized to contain the given number of Cells.

func (*Row) Add Uses

func (r *Row) Add(c Cell) *Row

Add adds one cell to this row, and returns the row for chaining, thus r.Add(c1).Add(c2).Add(c3)

func (*Row) AddError Uses

func (r *Row) AddError(e error)

AddError records that an error has happened when dealing with a row.

func (*Row) Cells Uses

func (r *Row) Cells() []Cell

Cells returns an iterable of the cells in a row. If it returns nil then you have a non-cell row (probably a separator).

func (*Row) GetProperty Uses

func (pi *Row) GetProperty(key interface{}) interface{}

GetProperty returns the property stored for the given key. If no such property has been stored, then nil will be returned. Thus we can't tell the difference between "nil stored" and "nothing stored", thus property storage is free to treat storing "nil" as "remove".

func (*Row) GoString Uses

func (row *Row) GoString() string

func (*Row) IsSeparator Uses

func (r *Row) IsSeparator() bool

IsSeparator is true iff a row is a "separator".

func (*Row) Location Uses

func (r *Row) Location() (loc CellLocation)

Location returns a row's CellLocation where the column is 0

func (*Row) SetProperty Uses

func (pi *Row) SetProperty(key, value interface{}) error

SetProperty sets the value stored for a given key, removing any other values stored for that key first. If the value is nil then no value will be stored.

type Stringer Uses

type Stringer interface {
    String() string
}

Stringer to match fmt's. Embedded newlines will be handled to provide lines.

type Table Uses

type Table interface {
    AddRow(row *Row) Table
    AddSeparator() Table
    NColumns() int
    NRows() int
    Headers() []Cell
    AddHeaders(items ...interface{}) Table
    AllRows() []*Row
    NewRowSizedFor() *Row
    AppendNewRow() *Row
    AddRowItems(items ...interface{}) Table
    CellAt(location CellLocation) (*Cell, error)
    Column(int) *column

    RegisterPropertyCallback(PropertyOwner, callbackTime, cbTarget, PropertyCallback) error
    InvokeRenderCallbacks()

    // Also the other interfaces embedded in ATable:
    ErrorReceiver
    ErrorSource
    PropertyOwner
}

The Table interface is a thin wrapper around the actual *ATable struct, so that methods can all be on the interface and objects which embed an unnamed table can be used as tables.

If you want to create and use a table for pre-canned rendering then look at sub-packages for TextTable, HTMLTable, etc wrappers.

type TerminalCellWidther Uses

type TerminalCellWidther interface {
    TerminalCellWidth() int
}

TerminalCellWidther should be implemented to override tabular's conception of how "wide" a cell's contents are.

Directories

PathSynopsis
auto
csv
examples
htmlThe html wrapper provides a means for generating HTML from a tabular table.
json
length
markdownMarkdown core does not support tables; for the most portable support, assuming HTML is the final target, use the `html` sub-package instead.
properties
properties/align
texttable
texttable/decorationThe decoration package provides controls for how text tables are decorated for rendering.

Package tabular imports 6 packages (graph) and is imported by 7 packages. Updated 2018-05-11. Refresh now. Tools for package owners.