diff options
| -rw-r--r-- | lib/asciidoctor/parser.rb | 12 | ||||
| -rw-r--r-- | lib/asciidoctor/table.rb | 61 | ||||
| -rw-r--r-- | test/tables_test.rb | 24 |
3 files changed, 62 insertions, 35 deletions
diff --git a/lib/asciidoctor/parser.rb b/lib/asciidoctor/parser.rb index e7755fb1..1dae26fa 100644 --- a/lib/asciidoctor/parser.rb +++ b/lib/asciidoctor/parser.rb @@ -2272,10 +2272,10 @@ class Parser table.assign_caption attributes.delete('caption') end - if attributes['cols'].nil_or_empty? + if (cols = attributes['cols']).nil_or_empty? || (cols = cols.rstrip).empty? explicit_col_specs = false else - table.create_columns(parse_col_specs(attributes['cols'])) + table.create_columns(parse_col_specs cols) explicit_col_specs = true end @@ -2372,12 +2372,8 @@ class Parser end end - table.attributes['colcount'] ||= parser_ctx.col_count - - if !explicit_col_specs - # TODO further encapsulate this logic (into table perhaps?) - even_width = (100.0 / parser_ctx.col_count).floor - table.columns.each {|c| c.assign_width(0, even_width) } + unless (table.attributes['colcount'] ||= table.columns.size) == 0 || explicit_col_specs + table.assign_col_widths end table.partition_header_footer attributes diff --git a/lib/asciidoctor/table.rb b/lib/asciidoctor/table.rb index bd900ede..95873887 100644 --- a/lib/asciidoctor/table.rb +++ b/lib/asciidoctor/table.rb @@ -99,21 +99,45 @@ class Table < AbstractBlock # Internal: Creates the Column objects from the column spec # # returns nothing - def create_columns(col_specs) - total_width = 0 + def create_columns col_specs cols = [] + width_base = 0 col_specs.each do |col_spec| - total_width += col_spec['width'] - cols << Column.new(self, cols.size, col_spec) + width_base += col_spec['width'] + cols << (Column.new self, cols.size, col_spec) end - - unless cols.empty? + unless (@columns = cols).empty? @attributes['colcount'] = cols.size - even_width = (100.0 / cols.size).floor - cols.each {|c| c.assign_width(total_width, even_width) } + assign_col_widths(width_base == 0 ? nil : width_base) end + nil + end + + # Internal: Assign column widths to columns + # + # This method rounds the percentage width values to 4 decimal places and + # donates the balance to the final column. + # + # This method assumes there's at least one column in the columns array. + # + # width_base - the total of the relative column values used for calculating percentage widths (default: nil) + # + # returns nothing + def assign_col_widths width_base = nil + pf = 10.0 ** 4 # precision factor (multipler / divisor) for managing precision of calculated result + total_width = col_pcwidth = 0 + + if width_base + @columns.each {|col| total_width += (col_pcwidth = col.assign_width nil, width_base, pf) } + else + col_pcwidth = ((100 * pf / @columns.size).to_i) / pf + col_pcwidth = col_pcwidth.to_i if col_pcwidth.to_i == col_pcwidth + @columns.each {|col| total_width += col.assign_width col_pcwidth } + end + + # donate balance, if any, to final column + @columns[-1].assign_width(((100 - total_width + col_pcwidth) * pf).round / pf) unless total_width == 100 - @columns = cols nil end @@ -167,19 +191,18 @@ class Table::Column < AbstractNode # # This method assigns the colpcwidth and colabswidth attributes. # - # returns nothing - def assign_width(total_width, even_width) - if total_width > 0 - width = ((@attributes['width'].to_f / total_width) * 100).floor - else - width = even_width + # returns the resolved colpcwidth value + def assign_width col_pcwidth, width_base = nil, pf = 10000.0 + if width_base + col_pcwidth = ((@attributes['width'].to_f / width_base) * 100 * pf).to_i / pf + col_pcwidth = col_pcwidth.to_i if col_pcwidth.to_i == col_pcwidth end - @attributes['colpcwidth'] = width + @attributes['colpcwidth'] = col_pcwidth if parent.attributes.key? 'tableabswidth' - @attributes['colabswidth'] = ((width.to_f / 100) * parent.attributes['tableabswidth']).round + # FIXME calculate more accurately (only used in DocBook output) + @attributes['colabswidth'] = ((col_pcwidth / 100.0) * parent.attributes['tableabswidth']).round end - - nil + col_pcwidth end end diff --git a/test/tables_test.rb b/test/tables_test.rb index 15b9c3c3..09905935 100644 --- a/test/tables_test.rb +++ b/test/tables_test.rb @@ -16,10 +16,14 @@ context 'Tables' do |======= EOS cells = [%w(A B C), %w(a b c), %w(1 2 3)] - output = render_embedded_string input + doc = document_from_string input, :header_footer => false + table = doc.blocks[0] + assert 100, table.columns.map {|col| col.attributes['colpcwidth'] }.reduce(:+) + output = doc.convert assert_css 'table', output, 1 assert_css 'table.tableblock.frame-all.grid-all.spread', output, 1 - assert_css 'table > colgroup > col[style*="width: 33%"]', output, 3 + assert_css 'table > colgroup > col[style*="width: 33.3333%"]', output, 2 + assert_css 'table > colgroup > col:last-of-type[style*="width: 33.3334%"]', output, 1 assert_css 'table tr', output, 3 assert_css 'table > tbody > tr', output, 3 assert_css 'table td', output, 9 @@ -489,10 +493,10 @@ I am getting in shape! assert_css 'table[style*="width: 80%"]', output, 1 assert_xpath '/table/caption[@class="title"][text()="Table 1. Horizontal and vertical source data"]', output, 1 assert_css 'table > colgroup > col', output, 4 - assert_css 'table > colgroup > col:nth-child(1)[@style*="width: 17%"]', output, 1 - assert_css 'table > colgroup > col:nth-child(2)[@style*="width: 11%"]', output, 1 - assert_css 'table > colgroup > col:nth-child(3)[@style*="width: 11%"]', output, 1 - assert_css 'table > colgroup > col:nth-child(4)[@style*="width: 58%"]', output, 1 + assert_css 'table > colgroup > col:nth-child(1)[@style*="width: 17.647%"]', output, 1 + assert_css 'table > colgroup > col:nth-child(2)[@style*="width: 11.7647%"]', output, 1 + assert_css 'table > colgroup > col:nth-child(3)[@style*="width: 11.7647%"]', output, 1 + assert_css 'table > colgroup > col:nth-child(4)[@style*="width: 58.8236%"]', output, 1 assert_css 'table > thead', output, 1 assert_css 'table > thead > tr', output, 1 assert_css 'table > thead > tr > th', output, 4 @@ -1023,9 +1027,13 @@ sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin nobody:x:99:99:Nobody:/:/sbin/nologin |=== EOS - output = render_embedded_string input + doc = document_from_string input, :header_footer => false + table = doc.blocks[0] + assert 100, table.columns.map {|col| col.attributes['colpcwidth'] }.reduce(:+) + output = doc.convert assert_css 'table', output, 1 - assert_css 'table > colgroup > col[style*="width: 14%"]', output, 7 + assert_css 'table > colgroup > col[style*="width: 14.2857"]', output, 6 + assert_css 'table > colgroup > col:last-of-type[style*="width: 14.2858%"]', output, 1 assert_css 'table > tbody > tr', output, 6 assert_xpath '//tr[4]/td[5]/p/text()', output, 0 assert_xpath '//tr[3]/td[5]/p[text()="MySQL:Server"]', output, 1 |
