diff --git a/README.md b/README.md index f98418a..b62acf3 100644 --- a/README.md +++ b/README.md @@ -338,6 +338,63 @@ _file : examples/readme8.cr_ ┖──────────┸──────┸──────┸──────────────┸──────────────┸──────────────┚ ``` +As of release 0.9.4, formatting has been enhanced by a new method +: `Tablo.fpjust`, which allows alignment on decimal point for floating point +values, after removing non significant digits. + +To illustrate, running the program below : +```crystal +require "tablo" + +data = [ + # Name Initial Initial Initial Initial Initial + # cost cost cost cost cost + ["Charlie", 420.50, 420.50, 420.50, 420.50, 420.50], + ["Max", 575.32, 575.32, 575.32, 575.32, 575.32], + ["Simba", 498.00, 498.00, 498.00, 498.00, 498.00], + ["Coco", 276.36, 276.36, 276.36, 276.36, 276.36], + ["Ruby", 320.95, 320.95, 320.95, 320.95, 320.95], + ["Freecat", 0.0, 0.0, 0.0, 0.0, 0.0 ], +] + +Tablo.fpjust(data, 1, 5, nil) # Params: data array, column, decimals, mode +Tablo.fpjust(data, 2, 4, 0) +Tablo.fpjust(data, 3, 3, 1) +Tablo.fpjust(data, 4, 2, 2) +Tablo.fpjust(data, 5, 1, 3) +table = Tablo::Table.new(data) do |t| + t.add_column("Name") { |n| n[0] } + t.add_column("Initial\ncost\nmode=nil\ndec=5") { |n| n[1] } + t.add_column("Initial\ncost\nmode=0\ndec=4") { |n| n[2] } + t.add_column("Initial\ncost\nmode=1\ndec=3") { |n| n[3] } + t.add_column("Initial\ncost\nmode=2\ndec=2") { |n| n[4] } + t.add_column("Initial\ncost\nmode=3\ndec=1") { |n| n[5] } +end +table.shrinkwrap! +puts table +``` +_file : examples/readme11.cr_ + +produces the following output : +```text + ++---------+-----------+---------+---------+---------+---------+ +| Name | Initial | Initial | Initial | Initial | Initial | +| | cost | cost | cost | cost | cost | +| | mode=nil | mode=0 | mode=1 | mode=2 | mode=3 | +| | dec=5 | dec=4 | dec=3 | dec=2 | dec=1 | ++---------+-----------+---------+---------+---------+---------+ +| Charlie | 420.50000 | 420.5 | 420.5 | 420.5 | 420.5 | +| Max | 575.32000 | 575.32 | 575.32 | 575.32 | 575.3 | +| Simba | 498.00000 | 498. | 498 | 498 | 498.0 | +| Coco | 276.36000 | 276.36 | 276.36 | 276.36 | 276.4 | +| Ruby | 320.95000 | 320.95 | 320.95 | 320.95 | 320.9 | +| Freecat | 0.00000 | 0. | 0 | | 0.0 | ++---------+-----------+---------+---------+---------+---------+ +``` +**Caution:** _Notice that this method alters the input data array, turning a floating point +column into a string column._ + ##### Table methods There are essentially 4 methods useful for the user : _add_column_, _each_, _horizontal_rule_ and _shrinkwrap!_ diff --git a/examples/readme11.cr b/examples/readme11.cr new file mode 100644 index 0000000..f7ee4fe --- /dev/null +++ b/examples/readme11.cr @@ -0,0 +1,28 @@ +require "tablo" + +data = [ + # Name Initial Initial Initial Initial Initial + # cost cost cost cost cost + ["Charlie", 420.50, 420.50, 420.50, 420.50, 420.50], + ["Max", 575.32, 575.32, 575.32, 575.32, 575.32], + ["Simba", 498.00, 498.00, 498.00, 498.00, 498.00], + ["Coco", 276.36, 276.36, 276.36, 276.36, 276.36], + ["Ruby", 320.95, 320.95, 320.95, 320.95, 320.95], + ["Freecat", 0.0, 0.0, 0.0, 0.0, 0.0], +] + +Tablo.fpjust(data, 1, 5, nil) # Params: data array, column, decimals, mode +Tablo.fpjust(data, 2, 4, 0) +Tablo.fpjust(data, 3, 3, 1) +Tablo.fpjust(data, 4, 2, 2) +Tablo.fpjust(data, 5, 1, 3) +table = Tablo::Table.new(data) do |t| + t.add_column("Name") { |n| n[0] } + t.add_column("Initial\ncost\nmode=nil\ndec=5") { |n| n[1] } + t.add_column("Initial\ncost\nmode=0\ndec=4") { |n| n[2] } + t.add_column("Initial\ncost\nmode=1\ndec=3") { |n| n[3] } + t.add_column("Initial\ncost\nmode=2\ndec=2") { |n| n[4] } + t.add_column("Initial\ncost\nmode=3\ndec=1") { |n| n[5] } +end +table.shrinkwrap! +puts table diff --git a/shard.yml b/shard.yml index f9b3fa1..2a7bed7 100644 --- a/shard.yml +++ b/shard.yml @@ -1,9 +1,9 @@ name: tablo -version: 0.9.0 +version: 0.9.4 authors: - Hubert Toullec -crystal: 0.27.0 +crystal: 0.35.1 license: MIT diff --git a/spec/commons_spec.cr b/spec/commons_spec.cr index 22c035a..7f8574e 100644 --- a/spec/commons_spec.cr +++ b/spec/commons_spec.cr @@ -45,4 +45,48 @@ describe Tablo do Tablo.connector("abcdefghijklmno", Tablo::TColumn::Right).should eq('l') end end + + # def fpjust(data : Array(Array(Tablo::CellType?)), col, nbdec, mode) + describe "FP align method" do + it "correctly format FP adjust - mode = nil" do + tdata = [[0.0000.as(Tablo::CellType)], + [0.02000.as(Tablo::CellType)], + [17.0.as(Tablo::CellType)], + [1234.5678.as(Tablo::CellType)], + ] + Tablo.fpjust(tdata, 0, 4, nil).to_s.should eq(%([[" 0.0000"], [" 0.0200"], [" 17.0000"], ["1234.5678"]])) + end + it "correctly format FP adjust - mode 0" do + tdata = [[0.0000.as(Tablo::CellType)], + [0.02000.as(Tablo::CellType)], + [17.0.as(Tablo::CellType)], + [1234.5678.as(Tablo::CellType)], + ] + Tablo.fpjust(tdata, 0, 4, 0).to_s.should eq(%([[" 0. "], [" 0.02 "], [" 17. "], ["1234.5678"]])) + end + it "correctly format FP adjust - mode 1" do + tdata = [[0.0000.as(Tablo::CellType)], + [0.02000.as(Tablo::CellType)], + [17.0.as(Tablo::CellType)], + [1234.5678.as(Tablo::CellType)], + ] + Tablo.fpjust(tdata, 0, 2, 1).to_s.should eq(%([[" 0 "], [" 0.02"], [" 17 "], ["1234.57"]])) + end + it "correctly format FP adjust - mode 2" do + tdata = [[0.0000.as(Tablo::CellType)], + [0.02000.as(Tablo::CellType)], + [17.0.as(Tablo::CellType)], + [1234.5678.as(Tablo::CellType)], + ] + Tablo.fpjust(tdata, 0, 2, 2).to_s.should eq(%([[" "], [" 0.02"], [" 17 "], ["1234.57"]])) + end + it "correctly format FP adjust - mode 3" do + tdata = [[0.0000.as(Tablo::CellType)], + [0.02000.as(Tablo::CellType)], + [17.0.as(Tablo::CellType)], + [1234.5678.as(Tablo::CellType)], + ] + Tablo.fpjust(tdata, 0, 2, 3).to_s.should eq(%([[" 0.0 "], [" 0.02"], [" 17.0 "], ["1234.57"]])) + end + end end diff --git a/src/commons.cr b/src/commons.cr index de57cef..4364f61 100644 --- a/src/commons.cr +++ b/src/commons.cr @@ -150,4 +150,39 @@ module Tablo STYLE_ALL_BORDERS = "LC,MC,RC,TL,ML,BL" STYLE_NO_BORDERS = "mcml" STYLE_NO_MID_COL = "LCRCTLMLBL" + + # fpjust align floating point values on decimal separator + # + # Parameters : + # - col : the column to be formatted + # - nbdec : Number of decimals (using printf %.[nbdec]f format) + # - mode allows for tuning output : + # - nil : mere printf formatting + # - 0 : non signficant zeroes removed and decimal point kept even if no more decimal digits + # - 1 : non signficant zeroes removed and decimal point also removed if no more decimal digits + # - 2 : All blanks if value == zero + # - 3 : same as 0, but zero added after decimal point if no more decimal digits + def fpjust(data : Array(Array(Tablo::CellType?)), col, nbdec, mode) + fvleft = [] of String + fvright = [] of String + data.each do |r| + cell = ("%.#{nbdec}f" % r[col]) + dot = cell.index(".").as(Int32) + left, right = [cell[0..dot - 1], cell[dot + 1..-1]] + if !mode.nil? + right = right.gsub(/0*$/, "") + left = "" if left == "0" && right == "" && mode == 2 + right = "0" if right == "" && mode == 3 + end + fvleft << left + fvright << right + end + maxleft = (fvleft.map &.size).max + maxright = (fvright.map &.size).max + data.map_with_index do |r, i| + sep = fvright[i] == "" && (mode == 1 || mode == 2) ? " " : "." + r[col] = "#{fvleft[i].rjust(maxleft)}#{sep}#{fvright[i].ljust(maxright)}" + end + data + end end diff --git a/src/tablo.cr b/src/tablo.cr index 387024a..8889292 100644 --- a/src/tablo.cr +++ b/src/tablo.cr @@ -2,6 +2,6 @@ require "./table.cr" require "./column.cr" module Tablo - VERSION = "0.9.3" + VERSION = "0.9.4" extend self end