Skip to content

Commit fb66c12

Browse files
authored
Support column widths 2.5.x (#1271)
* Fixes #1265. Support setting column widths * Update changelog
1 parent 9f9248a commit fb66c12

File tree

6 files changed

+120
-9
lines changed

6 files changed

+120
-9
lines changed

CHANGELOG.adoc

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ For a detailed view of what has changed, refer to the {url-repo}/commits/main[co
1313

1414
== Unreleased
1515

16+
Bug Fixes::
17+
18+
* Column#setWidth is ignored (#1265) (@Vampire)
19+
1620
== 2.5.12 (2024-03-10)
1721

1822
Improvement::

asciidoctorj-api/src/main/java/org/asciidoctor/ast/Table.java

+6
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,10 @@ enum VerticalAlignment {
5353
*/
5454
void setGrid(String grid);
5555

56+
/**
57+
* Computes the percentual column widths for all columns.
58+
* Before calling this method all columns must have been added to the Table by adding them to
59+
* {@link #getColumns()} and the desired widths must have been set by calling {@link Column#setWidth(int)}.
60+
*/
61+
void assignColumnWidths();
5662
}

asciidoctorj-core/src/main/java/org/asciidoctor/jruby/ast/impl/TableImpl.java

+21
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import org.asciidoctor.jruby.internal.RubyObjectWrapper;
88
import org.jruby.RubyArray;
99
import org.jruby.RubyNil;
10+
import org.jruby.runtime.ThreadContext;
1011
import org.jruby.runtime.builtin.IRubyObject;
1112

1213
import java.util.AbstractList;
@@ -72,6 +73,26 @@ public List<Row> getHeader() {
7273
return rows.getHeader();
7374
}
7475

76+
@Override
77+
public void assignColumnWidths() {
78+
int widthBase = 0;
79+
RubyArray autowidthCols = getRuntime().newArray();
80+
for (Column column : getColumns()) {
81+
int width = column.getWidth();
82+
if (width < 0) {
83+
autowidthCols.add(((ColumnImpl)column).getRubyObject());
84+
} else {
85+
widthBase += width;
86+
}
87+
}
88+
ThreadContext threadContext = getRuntime().getThreadService().getCurrentContext();
89+
90+
getRubyObject().callMethod(threadContext, "assign_column_widths", new IRubyObject[] {
91+
getRuntime().newFixnum(widthBase),
92+
autowidthCols.isEmpty() ? getRuntime().getNil() : autowidthCols
93+
});
94+
}
95+
7596
private class Rows extends RubyObjectWrapper {
7697

7798
public Rows(IRubyObject rubyNode) {

asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/GithubContributorsBlockMacro.groovy

+12-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import org.asciidoctor.util.TestHttpServer
1212
class GithubContributorsBlockMacro extends BlockMacroProcessor {
1313

1414
private static final String IMAGE = 'image'
15+
private static final String WIDTHS = 'widths'
1516

1617
GithubContributorsBlockMacro(String macroName) {
1718
super(macroName)
@@ -29,12 +30,22 @@ class GithubContributorsBlockMacro extends BlockMacroProcessor {
2930
table.grid = 'rows'
3031
table.title = "Github contributors of $target"
3132

33+
List<Integer> widths = [1,2,2]
34+
if (attributes.containsKey(WIDTHS)) {
35+
widths = (attributes[WIDTHS] as String).split(',').collect {Integer.parseInt(it) }
36+
}
3237
// Create the columns 'Login' and 'Contributions'
3338
Column avatarColumn = createTableColumn(table, 0)
39+
avatarColumn.width = widths[0]
3440
Column loginColumn = createTableColumn(table, 1)
41+
loginColumn.width = widths[1]
3542
Column contributionsColumn = createTableColumn(table, 2)
43+
contributionsColumn.width = widths[2]
3644
contributionsColumn.horizontalAlignment = Table.HorizontalAlignment.CENTER
37-
45+
table.columns << avatarColumn
46+
table.columns << loginColumn
47+
table.columns << contributionsColumn
48+
table.assignColumnWidths()
3849
// Create the single header row with the column titles
3950
Row headerRow = createTableRow(table)
4051
headerRow.cells << createTableCell(avatarColumn, 'Avatar')

asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/WhenABlockMacroProcessorCreatesATable.groovy

+74-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.asciidoctor.extension
22

33
import org.asciidoctor.Asciidoctor
4+
import org.asciidoctor.Options
45
import org.asciidoctor.OptionsBuilder
56
import org.asciidoctor.SafeMode
67
import org.asciidoctor.util.ClasspathResources
@@ -9,36 +10,59 @@ import org.jboss.arquillian.spock.ArquillianSputnik
910
import org.jboss.arquillian.test.api.ArquillianResource
1011
import org.jsoup.Jsoup
1112
import org.jsoup.nodes.Document
13+
import org.jsoup.select.Elements
1214
import org.junit.rules.TemporaryFolder
1315
import org.junit.runner.RunWith
1416
import spock.lang.Specification
1517

18+
import static java.nio.charset.StandardCharsets.UTF_8
19+
1620
@RunWith(ArquillianSputnik)
1721
class WhenABlockMacroProcessorCreatesATable extends Specification {
1822

1923
public static final String FIRST_TD = 'td:first-child'
2024
public static final String SECOND_TD = 'td:nth-child(2)'
2125
public static final String THIRD_TD = 'td:nth-child(3)'
2226
public static final String IMG_ELEMENT = 'img'
27+
public static final String COL = 'col'
28+
public static final String STYLE = 'style'
29+
public static final String WIDTH = 'width'
30+
public static final String WIDTH_2 = '2%'
31+
public static final String WIDTH_3 = '3%'
32+
public static final String WIDTH_20 = '20%'
33+
public static final String WIDTH_40 = '40%'
2334
public static final String CONTRIBUTOR = 'bob'
2435
public static final String BLOCKMACRO_NAME = 'githubcontributors'
2536

2637
public static final String AVATAR_URL_REGEXP = /https:\/\/avatars.githubusercontent.com\/u\/.*/
38+
public static final String CSS_QUERY_TABLE = 'table'
39+
public static final String CLASS_GRID_ROWS = 'grid-rows'
40+
public static final String CLASS_HALIGN_LEFT = 'halign-left'
41+
public static final String CLASS_HALIGN_CENTER = 'halign-center'
42+
public static final String ATTR_SRC = 'src'
43+
public static final int THREE = 3
2744

2845
@ArquillianResource
2946
private Asciidoctor asciidoctor
3047

3148
@ArquillianResource
3249
private TemporaryFolder tmp
3350

51+
@ArquillianResource
52+
private ClasspathResources classpathResources
53+
3454
private static final String DOCUMENT = '''
3555
= AsciidoctorJRuby contributors
3656
3757
githubcontributors::asciidoctor/asciidoctorj[]
3858
'''
3959

40-
@ArquillianResource
41-
private ClasspathResources classpathResources
60+
private static final String DOCUMENT_WITH_NEGATIVE_WIDTHS = '''
61+
= AsciidoctorJRuby contributors
62+
63+
githubcontributors::asciidoctor/asciidoctorj[widths="2,3,-1"]
64+
'''
65+
4266

4367
def setup() {
4468
TestHttpServer.start(['http://api.github.com/repos/asciidoctor/asciidoctorj/contributors' : classpathResources.getResource('githubcontributors.json')])
@@ -60,18 +84,61 @@ githubcontributors::asciidoctor/asciidoctorj[]
6084
asciidoctor.convert(DOCUMENT, OptionsBuilder.options().safe(SafeMode.SAFE).inPlace(false).baseDir(tmp.getRoot()).toDir(tmp.getRoot()).toFile(resultFile))
6185

6286
then:
63-
Document htmlDocument = Jsoup.parse(resultFile, 'UTF-8')
87+
Document htmlDocument = Jsoup.parse(resultFile, UTF_8.name())
88+
89+
Elements cols = htmlDocument.select(COL)
90+
cols.size() == THREE
91+
cols.get(0).attr(STYLE).contains(WIDTH_20) || cols.get(0).attr(WIDTH).equals(WIDTH_20)
92+
cols.get(1).attr(STYLE).contains(WIDTH_40) || cols.get(1).attr(WIDTH).equals(WIDTH_40)
93+
cols.get(2).attr(STYLE).contains(WIDTH_40) || cols.get(2).attr(WIDTH).equals(WIDTH_40)
94+
95+
htmlDocument.select(CSS_QUERY_TABLE).hasClass(CLASS_GRID_ROWS)
96+
97+
htmlDocument.select(FIRST_TD).every { tdElement -> tdElement.select(IMG_ELEMENT).size() == 1 }
98+
htmlDocument.select(FIRST_TD).every { tdElement -> tdElement.select(IMG_ELEMENT)[0].attr(ATTR_SRC) =~ AVATAR_URL_REGEXP }
99+
100+
htmlDocument.select(SECOND_TD).size() == htmlDocument.select(SECOND_TD) != 0
101+
htmlDocument.select(SECOND_TD).size() != 0
102+
103+
htmlDocument.select(SECOND_TD).every { tdElement -> tdElement.hasClass(CLASS_HALIGN_LEFT) }
104+
htmlDocument.select(THIRD_TD).every { tdElement -> tdElement.hasClass(CLASS_HALIGN_CENTER) }
105+
106+
htmlDocument.select(SECOND_TD).find { tdElement -> tdElement.text() == CONTRIBUTOR } != null
107+
}
108+
109+
def "the table should be rendered to html with negative widths"() {
110+
given:
111+
asciidoctor.javaExtensionRegistry().blockMacro(BLOCKMACRO_NAME, GithubContributorsBlockMacro)
112+
File resultFile = tmp.newFile('resultWithNegativeWidth.html')
113+
114+
when:
115+
def options = Options.builder()
116+
.safe(SafeMode.SAFE)
117+
.inPlace(false)
118+
.baseDir(tmp.getRoot())
119+
.toFile(resultFile)
120+
.build()
121+
asciidoctor.convert(DOCUMENT_WITH_NEGATIVE_WIDTHS, options)
122+
123+
then:
124+
Document htmlDocument = Jsoup.parse(resultFile, UTF_8.name())
125+
126+
Elements cols = htmlDocument.select(COL)
127+
cols.size() == THREE
128+
cols.get(0).attr(STYLE).contains(WIDTH_2) || cols.get(0).attr(WIDTH).equals(WIDTH_2)
129+
cols.get(1).attr(STYLE).contains(WIDTH_3) || cols.get(1).attr(WIDTH).equals(WIDTH_3)
130+
cols.get(2).attr(STYLE).length() == 0 && cols.get(2).attr(WIDTH).length() == 0
64131

65-
htmlDocument.select('table').hasClass('grid-rows')
132+
htmlDocument.select(CSS_QUERY_TABLE).hasClass(CLASS_GRID_ROWS)
66133

67134
htmlDocument.select(FIRST_TD).every { tdElement -> tdElement.select(IMG_ELEMENT).size() == 1 }
68-
htmlDocument.select(FIRST_TD).every { tdElement -> tdElement.select(IMG_ELEMENT)[0].attr('src') =~ AVATAR_URL_REGEXP }
135+
htmlDocument.select(FIRST_TD).every { tdElement -> tdElement.select(IMG_ELEMENT)[0].attr(ATTR_SRC) =~ AVATAR_URL_REGEXP }
69136

70137
htmlDocument.select(SECOND_TD).size() == htmlDocument.select(SECOND_TD) != 0
71138
htmlDocument.select(SECOND_TD).size() != 0
72139

73-
htmlDocument.select(SECOND_TD).every { tdElement -> tdElement.hasClass('halign-left')}
74-
htmlDocument.select(THIRD_TD).every { tdElement -> tdElement.hasClass('halign-center')}
140+
htmlDocument.select(SECOND_TD).every { tdElement -> tdElement.hasClass(CLASS_HALIGN_LEFT) }
141+
htmlDocument.select(THIRD_TD).every { tdElement -> tdElement.hasClass(CLASS_HALIGN_CENTER) }
75142

76143
htmlDocument.select(SECOND_TD).find { tdElement -> tdElement.text() == CONTRIBUTOR } != null
77144
}

config/codenarc/codenarc.groovy

+3-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ ruleset {
4343
ruleset('rulesets/braces.xml') {
4444
exclude 'IfStatementBraces'
4545
}
46-
ruleset('rulesets/size.xml')
46+
ruleset('rulesets/size.xml') {
47+
exclude 'AbcMetric'
48+
}
4749
ruleset('rulesets/junit.xml') {
4850
// Does not play well with Spock tests
4951
exclude 'JUnitPublicNonTestMethod'

0 commit comments

Comments
 (0)