Skip to content

Commit

Permalink
Issue39 alignment (#61)
Browse files Browse the repository at this point in the history
* add test for last column included in filter

* add option to specify justification overrides to specified columns

* add usage and justification examples

* change flag to -i and use colon for overrides

* update justification examples

* fix usage output
  • Loading branch information
Guitarbum722 authored Sep 1, 2017
1 parent 423ac4b commit b671025
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 15 deletions.
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 35,7 @@ $ make release
### Usage - CLI examples

```
Usage: align [-h] [-f] [-o] [-q] [-s] [-d] [-a]
Usage: align [-h] [-f] [-o] [-q] [-s] [-d] [-a] [-c] [-i]
Options:
-h | --help help
-f input file. If not specified, pipe input to stdin
Expand All @@ -45,6 45,7 @@ Options:
-d output delimiter (defaults to the value of sep)
-a <left>, <right>, <center> justification (default: left)
-c output specific fields (default: all fields)
-i override justification by column number (e.g. 2:center,5:right)
```

_Specify your input file, output file, delimiter._
Expand All @@ -68,6 69,19 @@ Value1 | Value2
CoolValue1 | CoolValue2 | CoolValue3
```

Column filtering (specifiy output fields and optionally override the justification of the output fields). This might be useful if you would like to display a dollar amount or number field differently. The specified fields are indexed at 1.

```sh
# output fields 1,3,5 justified 'right'
$ cat file.csv | align -a right -c 1,3,5

# output fields 1,2,3,7,8 with default justification (left) except for field 7, which is right justified
$ cat file.csv | align -c 1,2,3,7,8 -i 1:right,7:center

#output all fields by default, with right justification, with overridden justification on certain columns
$ cat file.csv | align -a right -i 1:center,5:left
```

Support for worldwide characters.
```
first , last , middle , email
Expand Down
20 changes: 16 additions & 4 deletions align.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 32,8 @@ type TextQualifier struct {

// PaddingOpts provides configurability for left/center/right justification and padding length
type PaddingOpts struct {
Justification justification
Justification justification
columnOverride map[int]justification //override the justification of specified columns
}

// Align scans input and writes output with aligned text
Expand Down Expand Up @@ -185,7 186,18 @@ func (a *Align) export(lines []string) {
}
}

word = pad(word, tempColumn, a.columnCounts[columnNum], a.padOpts)
j := a.padOpts.Justification

// override justification for the specified columnNum in the key for the PaddingOpts.columnOverride map
if len(a.padOpts.columnOverride) > 0 {
for k, v := range a.padOpts.columnOverride {
if k == columnNum 1 {
j = v
}
}
}

word = pad(word, tempColumn, a.columnCounts[columnNum], j)
columnNum
tempColumn

Expand All @@ -205,10 217,10 @@ func (a *Align) export(lines []string) {
}

// pad s based on the supplied PaddingOpts
func pad(s string, columnNum, count int, p PaddingOpts) string {
func pad(s string, columnNum, count int, j justification) string {
padLength := countPadding(s, count)

switch p.Justification {
switch j {
case JustifyLeft:
s = trailingPad(s, padLength)
case JustifyRight:
Expand Down
38 changes: 33 additions & 5 deletions align_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 232,12 @@ var exportCases = []struct {
[]int{1, 3},
0,
},
{
strings.NewReader("first,middle,last"),
bytes.NewBufferString(""),
[]int{1, 4},
0,
},
{
strings.NewReader("first,middle,last"),
bytes.NewBufferString(""),
Expand All @@ -250,6 256,7 @@ var runCases = []struct {
dValue string
aValue string
cValue string
iValue string
shouldErr bool
}{
{
Expand All @@ -260,10 267,30 @@ var runCases = []struct {
helpValue: true,
shouldErr: true,
},
{
iValue: "1:right,2:center",
shouldErr: true,
},
{
iValue: "1:left,2:,NaN:left",
shouldErr: true,
},
{
iValue: "3:noexist",
shouldErr: true,
},
{
cValue: "a2-right,NaN",
shouldErr: true,
},
{
cValue: "1,2",
shouldErr: true,
},
{
cValue: "1-left,2-right,3-center",
shouldErr: true,
},
{
cValue: "1,2,a",
shouldErr: true,
Expand Down Expand Up @@ -344,6 371,7 @@ func TestRun(t *testing.T) {
*aFlag = tt.aValue
*cFlag = tt.cValue
*qFlag = tt.qValue
*iFlag = tt.iValue

code, _ := run()

Expand Down Expand Up @@ -408,7 436,7 @@ func TestSplit(t *testing.T) {

func TestPad(t *testing.T) {
for _, tt := range paddingCases {
got := pad(tt.input, 1, tt.columnCount, tt.po)
got := pad(tt.input, 1, tt.columnCount, tt.po.Justification)

if len(got) != tt.expected {
t.Fatalf("pad(%v) =%v; want %v", tt.input, got, tt.expected)
Expand Down Expand Up @@ -458,11 486,11 @@ func TestCountPadding(t *testing.T) {
func BenchmarkColumnCounts(b *testing.B) {
input := `First,Middle,Last,Email,Region,City,Zip,Full_Name,First,Middle,Last,Email,Region,City,Zip,Full_Name,First,Middle,Last,Email,Region,City,Zip,Full_Name
Karleigh,Destiny,Dean,[email protected],Stockholms län,Märsta,9038,Shaine Reilly,Karleigh,Destiny,Dean,[email protected],Stockholms län,Märsta,9038,Shaine Reilly,Karleigh,Destiny,Dean,[email protected],Stockholms län,Märsta,9038,Shaine Reilly
Alisa,Walker,Armand,[email protected],Himachal Pradesh,Shimla,MZ0 4QS,Olivia Velez ,Alisa,Walker,Armand,[email protected],Himachal Pradesh,Shimla,MZ0 4QS,Olivia Velez ,Alisa,Walker,Armand,[email protected],Himachal Pradesh,Shimla,MZ0 4QS,Olivia Velez
Karleigh,Destiny,Dean,[email protected],Stockholms län,Märsta,9038,Shaine Reilly,Karleigh,Destiny,Dean,[email protected],Stockholms län,Märsta,9038,Shaine Reilly,Karleigh,Destiny,Dean,[email protected],Stockholms län,Märsta,9038,Shaine Reilly
Alisa,Walker,Armand,[email protected],Himachal Pradesh,Shimla,MZ0 4QS,Olivia Velez ,Alisa,Walker,Armand,[email protected],Himachal Pradesh,Shimla,MZ0 4QS,Olivia Velez ,Alisa,Walker,Armand,[email protected],Himachal Pradesh,Shimla,MZ0 4QS,Olivia Velez
Alisa,Walker,Armand,[email protected],Himachal Pradesh,Shimla,MZ0 4QS,Olivia Velez ,Alisa,Walker,Armand,[email protected],Himachal Pradesh,Shimla,MZ0 4QS,Olivia Velez ,Alisa,Walker,Armand,[email protected],Himachal Pradesh,Shimla,MZ0 4QS,Olivia Velez
Karleigh,Destiny,Dean,[email protected],Stockholms län,Märsta,9038,Shaine Reilly,Karleigh,Destiny,Dean,[email protected],Stockholms län,Märsta,9038,Shaine Reilly,Karleigh,Destiny,Dean,[email protected],Stockholms län,Märsta,9038,Shaine Reilly
Alisa,Walker,Armand,[email protected],Himachal Pradesh,Shimla,MZ0 4QS,Olivia Velez ,Alisa,Walker,Armand,[email protected],Himachal Pradesh,Shimla,MZ0 4QS,Olivia Velez ,Alisa,Walker,Armand,[email protected],Himachal Pradesh,Shimla,MZ0 4QS,Olivia Velez
Alisa,Walker,Armand,[email protected],Himachal Pradesh,Shimla,MZ0 4QS,Olivia Velez ,Alisa,Walker,Armand,[email protected],Himachal Pradesh,Shimla,MZ0 4QS,Olivia Velez ,Alisa,Walker,Armand,[email protected],Himachal Pradesh,Shimla,MZ0 4QS,Olivia Velez
Karleigh,Destiny,Dean,[email protected],Stockholms län,Märsta,9038,Shaine Reilly,Karleigh,Destiny,Dean,[email protected],Stockholms län,Märsta,9038,Shaine Reilly,Karleigh,Destiny,Dean,[email protected],Stockholms län,Märsta,9038,Shaine Reilly
Alisa,Walker,Armand,[email protected],Himachal Pradesh,Shimla,MZ0 4QS,Olivia Velez ,Alisa,Walker,Armand,[email protected],Himachal Pradesh,Shimla,MZ0 4QS,Olivia Velez ,Alisa,Walker,Armand,[email protected],Himachal Pradesh,Shimla,MZ0 4QS,Olivia Velez
`

a := newAlign(strings.NewReader(input), os.Stdout, comma, TextQualifier{On: false})
Expand Down
43 changes: 38 additions & 5 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 11,7 @@ import (
"strings"
)

const usage = `Usage: align [-h] [-f] [-o] [-q] [-s] [-d] [-a]
const usage = `Usage: align [-h] [-f] [-o] [-q] [-s] [-d] [-a] [-c] [-i]
Options:
-h | --help help
-f input file. If not specified, pipe input to stdin
Expand All @@ -21,6 21,7 @@ Options:
-d output delimiter (defaults to the value of sep)
-a <left>, <right>, <center> justification (default: left)
-c output specific fields (default: all fields)
-i override justification by column number (e.g. 2:center,5:right)
`

func main() {
Expand All @@ -39,6 40,7 @@ var sFlag *string
var dFlag *string
var aFlag *string
var cFlag *string
var iFlag *string

func init() {
flag.Usage = func() {
Expand All @@ -54,6 56,7 @@ func init() {
dFlag = flag.String("d", "", "")
aFlag = flag.String("a", "left", "")
cFlag = flag.String("c", "", "")
iFlag = flag.String("i", "", "")
}

func run() (int, error) {
Expand All @@ -79,6 82,36 @@ func run() (int, error) {
var output io.Writer
var qu TextQualifier
var outColumns []int
var justifyOverrides = make(map[int]justification)

if *iFlag != "" {
c := strings.Split(*iFlag, ",")

for _, v := range c {
if strings.HasSuffix(v, ":right") || strings.HasSuffix(v, ":center") || strings.HasSuffix(v, ":left") {
overrides := strings.Split(v, ":")
v = overrides[0]

num, err := strconv.Atoi(v)
if err != nil {
return 1, errors.New("make sure entry for -v are numbers with a justification separated by ':' (ie 1-right,3-center)")
}

switch overrides[1] {
case "left":
justifyOverrides[num] = JustifyLeft
case "center":
justifyOverrides[num] = JustifyCenter
case "right":
justifyOverrides[num] = JustifyRight
}
}
}

if len(justifyOverrides) < 1 {
return 1, errors.New("make sure entry for -v are numbers with a justification separated by ':' (ie 1:right,3:center)")
}
}

if *cFlag != "" {
c := strings.Split(*cFlag, ",")
Expand Down Expand Up @@ -143,13 176,13 @@ func run() (int, error) {

switch *aFlag {
case "left":
aligner.updatePadding(PaddingOpts{Justification: JustifyLeft})
aligner.updatePadding(PaddingOpts{Justification: JustifyLeft, columnOverride: justifyOverrides})
case "right":
aligner.updatePadding(PaddingOpts{Justification: JustifyRight})
aligner.updatePadding(PaddingOpts{Justification: JustifyRight, columnOverride: justifyOverrides})
case "center":
aligner.updatePadding(PaddingOpts{Justification: JustifyCenter})
aligner.updatePadding(PaddingOpts{Justification: JustifyCenter, columnOverride: justifyOverrides})
default:
aligner.updatePadding(PaddingOpts{Justification: JustifyLeft})
aligner.updatePadding(PaddingOpts{Justification: JustifyLeft, columnOverride: justifyOverrides})
}
aligner.filterColumns(outColumns)
aligner.outputSep(*dFlag)
Expand Down

0 comments on commit b671025

Please sign in to comment.