Skip to content
Skip to breadcrumbs
Skip to header menu
Skip to action menu
Skip to quick search
Quick Search
Browse
Pages
Blog
Labels
Attachments
Mail
Advanced
What’s New
Space Directory
Feed Builder
Keyboard Shortcuts
Confluence Gadgets
Log In
Sign Up
Dashboard
Groovy
Copy Page
You are not logged in. Any changes you make will be marked as
anonymous
. You may want to
Log In
if you already have an account. You can also
Sign Up
for a new account.
This page is being edited by
.
Paragraph
Paragraph
Heading 1
Heading 2
Heading 3
Heading 4
Heading 5
Heading 6
Preformatted
Quote
Bold
Italic
Underline
More colours
Strikethrough
Subscript
Superscript
Monospace
Clear Formatting
Bullet list
Numbered list
Outdent
Indent
Align left
Align center
Align right
Link
Table
Insert
Insert Content
Image
Link
Attachment
Symbol
Emoticon
Wiki Markup
Horizontal rule
tinymce.confluence.insert_menu.macro_desc
Info
JIRA Issue
Status
Gallery
Tasklist
Table of Contents
Other Macros
Page Layout
No Layout
Two column (simple)
Two column (simple, left sidebar)
Two column (simple, right sidebar)
Three column (simple)
Two column
Two column (left sidebar)
Two column (right sidebar)
Three column
Three column (left and right sidebars)
Undo
Redo
Find/Replace
Keyboard Shortcuts Help
<h1>Formatting simple tabular text data</h1> <p>This class has been posted first time on the Groovy-User Mailing List by Raffaele Castagno in this format:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class TableTemplateFactory { def columns = []; // contains columns names and theyr length def header1 = ''; // contains columns names def header2 = ''; // contains underscores def body = ''; // the rows of the table def footer = ''; // actually unused: can contain footer notes, totals, etc. def addColumn(name, size) { columns << [name:name, size:size]; } def getTemplate() { header1 = "\n"; columns.each{ header1 += ' <%print "'+it.name+'".center('+it.size+')%> ' }; header2 = "\n"; columns.each{ header2 += ' <%print "_"*'+it.size+' %> ' }; body = '\n<% rows.each {%>'; // If a value is longer than given column name, it will be trunked columns.each{body += ' ${it.'+it.name+'.toString().padRight('+it.size+').substring(0,'+it.size+')} '}; body += '\n<% } %>'; return header1 + header2 + body + footer; } } </pre></td></tr></table> <p> and later "groovyfied" by Gavin Grover:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class TableTemplateFactory{ def columns = [] def addColumn(name, size) { columns << [name:name, size:size]; this } def getTemplate() { """ ${columns.collect{ " <%print \"$it.name\".center($it.size)%> " }.join()} ${columns.collect{ " <%print \"_\"*$it.size %> " }.join()} <% rows.each {%>${columns.collect{ " \${it.${it.name}.toString().padRight($it.size).substring(0,$it.size)} " }.join()} <% } %>""" } } </pre></td></tr></table> <p> First version is here only as an example of the "groovify process". Of course, the Gavin's version is better.</p> <p>This class emulate the output of most RDBMS consoles (ie. Oracle SQL*, MySql).</p> <p>Here's an usage example (again, grooved up by Gavin):</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> import groovy.text.Template; import groovy.text.SimpleTemplateEngine def ttf = new TableTemplateFactory().addColumn("name", 15).addColumn("age", 4) def names = [] << [name:"Raffaele", age:"23"] << [name:"Griorgio", age:"30"] def binding = ['rows': names] println new SimpleTemplateEngine().createTemplate(ttf.template).make(binding).toString() </pre></td></tr></table> <p>This is the output:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> name age _______________ ____ Raffaele 23 Griorgio 30 </pre></td></tr></table> <p>Actually is really limited: column width must be declared, and strings are truncated to that given size.</p> <h1>Wish-list: </h1> <ul> <li>Automatic column width based on maximum string length</li> <li>Multiline records</li> <li>Multiline fields</li> <li>More formatting options (alignment, case, etc)</li> <li>Management of footer fields (totals, formulae, etc)</li> <li>Automatic line-wrap based on screen size</li> </ul> <h1>Version with ability to wrap text within a column (rather than truncating it).</h1> <p>The version below is part of a larger project that you are free to grab and use for you own. The main project wiki page is<br /> <a href="http://www.assembla.com/wiki/show/provisionizer/Provisionator_Main_Page" title="Build Lackey Labs Provisionizer">here</a>. We prefer static typing for our larger projects, so we have modified the original code to suit our style. Hope it is useful for you. Victor Vlasenko authored most of this enhancement under contract for <a href="http://buildlackey.com">Build Lackey Labs</a>, and I helped clean up the code a bit for presentation on this site []. <br class="atl-forced-newline" /></p> <h2>Summary of Enhancement</h2> <p> This enhancement enables wrapping-to-multi-lines for column text<br /> that exceeds the width of a given column. We break out word boundaries<br /> (white space) where possible, The implementation we built on truncated<br /> the overly long column value instead of wrapping it.</p> <h2>Example:</h2> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> for this data [col1: '1', col2: 'A very long text messsage for you with a superLongWordThatCantBeBrokenAtAWordBoundaryWithoutwrapping'] Instead of this: col1 col2 ---- -------------------- 1 A very long text mes We get this: col1 col2 ---- -------------------- 1 A very long text message for you with a superLongWordThatC antBeBrokenOnWordBou ndaryWithoutwrapping </pre></td></tr></table> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> package com.lackey.provis.cmdline.util /* * Reproduced from * http://groovy.codehaus.org/Formatting+simple+tabular+text+data * (with some code reformatting according to my readability preferences) */ class TableTemplateFactory { def columns = []; // contains columns names and their length def columnLen = [:]; // contains lengthes of the columns def header1 = ''; // contains columns names def header2 = ''; // contains underscores def body = ''; // the rows of the table def footer = ''; // actually unused: can contain footer notes, totals, etc. /** * Breaks up long line into multiline at the word boundary * * TODO move this method to some generic text utils class * * @param input long input line * @param lineWidth maximum output lines width * * @return multiline as an array of strings */ protected static List<String> wrapLine(input, lineWidth) { List<String> lines = [] def line = "" def addWord; addWord = {word -> // Add new word if we have space in current line if ((line.size() + word.size()) <= lineWidth) { line <<= word if (line.size() < lineWidth) line <<= " " // Our word is longer than line width, break it up } else if (word.size() > lineWidth) { def len = lineWidth - line.length() line <<= word.substring(0, len) word = word.substring(len) lines += line.toString() while (word.size() > lineWidth) { lines += word.substring(0, lineWidth); word = word.substring(lineWidth); } line = word if (line.size() > 0 && line.size() < lineWidth) line <<= " " // No more space in line - wrap to another line } else { lines += line.toString() line = "" addWord(word) } } input.split(" ").each() { addWord(it) } lines += line.toString() return lines } /** * Wraps values in rows according to the column width. Value wrapping performed at * the word boundary. * * @param rows input rows array * * @return rows array with multiline values */ public List<Map<String,String>> wrapRows(unwrappedRows) { List<Map<String,List<String>>> multilineRows = [] List<Integer> rowHeights = [] // Preprare unwrappedRows with multiline values unwrappedRows.each() { unwrappedRow -> def multiLineRow = [:] int height = 1 unwrappedRow.each() { column -> // column in unwrapped row List<String> multilineValue = wrapLine(column.value, columnLen[column.key]) if (multilineValue.size() > height) height = multilineValue.size() multiLineRow[column.key] = multilineValue // multiLineValue is list of strings } multilineRows << multiLineRow rowHeights << height } return foldMultiLineRowsIntoPlainRows(multilineRows, rowHeights) } // For each array of strings (wrapped lines) in multiLineRows we fold those in to // a new array of rows (plain rows). For any given columnn that consists of an array // of wrapped lines we either insert the appropriate wrapped line, or a blank if no // more lines are left for that column. // private List<Map<String,String>> foldMultiLineRowsIntoPlainRows( List<Map<String,List<String>>> multilineRows, List<Integer> rowHeights) { List<Map<String,String>> plainRows = [] multilineRows.eachWithIndex() { Map<String,List<String>> mlRow, int idx -> int height = rowHeights[idx] for (i in 0..<height) { Map<String,String> row = [:] mlRow.each() { Map.Entry<String, List<String>> col -> List<String> listOfStringsForColumn = mlRow[col.key] row[col.key] = listOfStringsForColumn[i] ?: "" } plainRows << row } } return plainRows } public TableTemplateFactory addColumn(String name, int size) { columns << [name: name, size: size]; columnLen[name] = size return this } def getTemplate() { header1 = "\n"; columns.each { header1 += ' <%print "' + it.name + '".center(' + it.size + ')%> ' }; header2 = "\n"; columns.each { header2 += ' <%print "_"*' + it.size + ' %> ' }; body = '\n<% rows.each {%>'; // If a value is longer than given column name, it will be trunked columns.each { body += ' ${it.' + it.name + '.toString().padRight(' + it.size + ').substring(0,' + it.size + ')} ' }; body += '\n<% } %>'; return header1 + header2 + body + footer; } } package com.lackey.provis; /* * * Copyright 2009. Build Lackey Labs. All Rights Reserved. * * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions * and limitations under the License. * * Author: cbedford * Date: Jan 18, 2009 * Time: 3:21:52 PM */ import org.testng.annotations.* import org.testng.TestNG import org.testng.TestListenerAdapter import org.slf4j.* import groovy.text.Template; import groovy.text.SimpleTemplateEngine import com.lackey.provis.cmdline.util.TableTemplateFactory public class TestTableTemplates { private static Logger logger = LoggerFactory.getLogger(TestTableTemplates.class.name) @Test (enabled = true) public void test_X() { final TableTemplateFactory factory = new TableTemplateFactory() def ttf = factory.addColumn("name", 15).addColumn("age", 4) def names = [] << [name:"Raffaele Smoke BOON laforge calm nwe box ooex", age:"23"] << [name:"Griorgio", age:"30"] def binding = ['rows': names] println new SimpleTemplateEngine().createTemplate(ttf.template).make(binding).toString() } @Test (enabled = true) public void testWrapLineSingleWord() { TableTemplateFactory ttf = new TableTemplateFactory() assert (ttf.wrapLine("aa bb cc", 2) == ["aa", "bb", "cc"]) } @Test (enabled = true) public void testWrapLineSeveralWords() { TableTemplateFactory ttf = new TableTemplateFactory() assert (ttf.wrapLine("This is some text that must be broken up to multiline" + " at a word boundary", 9) == ["This is ", "some text", "that must", "be broken", "up to ", "multiline", "at a word", "boundary "]) } @Test (enabled = true) public void testWrapLineWithLongWord() { TableTemplateFactory ttf = new TableTemplateFactory() assert (ttf.wrapLine("A very long text message for you with a" + " superLongWordThatCantBeBrokenOnWordBoundaryWithoutwrapping", 20) == ["A very long text ", "message for you with", "a superLongWordThatC", "antBeBrokenOnWordBou", "ndaryWithoutwrapping"]) } @Test (enabled = true) public void testMultilineRowWrappingWithActualPrinting() { def ttf = new TableTemplateFactory().addColumn("name", 15).addColumn("age", 4) def names = [] << [name:"Raffaele Gudinio BanderasHulioLopezMakachino", age:"819 4096"] << [name:"Griorgio", age:"30"] def wrappedNames = ttf.wrapRows(names) assert wrappedNames == [["name":"Raffaele ", "age":"819 "], ["name":"Gudinio Bandera", "age":"4096"], ["name":"sHulioLopezMaka", "age":""], ["name":"chino ", "age":""], ["name":"Griorgio ", "age":"30 "]] def binding = ['rows': wrappedNames ] final String templateOutput = getTemplateOutput(binding, ttf) System.out.println templateOutput } private String getTemplateOutput(Map<Object, List> binding, TableTemplateFactory ttf) { return new SimpleTemplateEngine().createTemplate(ttf.template).make(binding).toString() } } </pre></td></tr></table> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre /></td></tr></table>
Please type the word appearing in the picture.
Attachments
Labels
Location
Watch this page
< Edit
Preview >
Loading…
Save
Cancel
Next hint
search
attachments
weblink
advanced