From a4751366065d7623f67c4579493ab9f0a52f9be4 Mon Sep 17 00:00:00 2001 From: Paul King Date: Fri, 16 Jun 2023 23:20:44 +1000 Subject: [PATCH] GROOVY-11103: Provide an ascii barchart method --- .../codehaus/groovy/util/StringUtil.groovy | 29 +++++++++++++++++++ src/test/groovy/GroovyMethodsTest.groovy | 12 ++++++++ 2 files changed, 41 insertions(+) diff --git a/src/main/groovy/org/codehaus/groovy/util/StringUtil.groovy b/src/main/groovy/org/codehaus/groovy/util/StringUtil.groovy index 00fc6b7aaed..3f07060096d 100644 --- a/src/main/groovy/org/codehaus/groovy/util/StringUtil.groovy +++ b/src/main/groovy/org/codehaus/groovy/util/StringUtil.groovy @@ -60,4 +60,33 @@ class StringUtil { text } } + + private static String BLOCK = '\u2588' + private static char FRACTIONAL_OFFSET = BLOCK.codePointAt(0) + 7 + + /** + * Draw a band whose width is proportional to (x - min) and equal to width + * when x equals max. Unicode block element characters are used to draw + * fractional blocks. A 1/8 block is always added at the start of the bar. + * + * If using Windows command-line, make sure you are using the Unicode + * codepage (65001) and a font that supports block elements (like Cascadia). + * + * @param x the value for the bar to be drawn + * @param min the minimum value + * @param max the maximum value + * @param width how many characters should the maximum value be rendered as (default 40) + * @return the rendered ascii barchart string + * @since 5.0.0 + */ + static String bar(Number x, Number min, Number max, int width = 40) { + int fracWidth = width * 8 + assert min < max && x >= min && x <= max + Number interval = max - min + int barWidth = ((x - min) / interval * fracWidth).intValue() + int fullChunks = barWidth.intdiv(8) + int remainder = barWidth % 8 + // unicode for fractional blocks (7/8, 6/8, etc.) are adjacent + BLOCK * fullChunks + Character.valueOf(FRACTIONAL_OFFSET - remainder as char) + } } diff --git a/src/test/groovy/GroovyMethodsTest.groovy b/src/test/groovy/GroovyMethodsTest.groovy index e4eb16ff7cf..0592e73e949 100644 --- a/src/test/groovy/GroovyMethodsTest.groovy +++ b/src/test/groovy/GroovyMethodsTest.groovy @@ -1136,6 +1136,18 @@ class GroovyMethodsTest extends GroovyTestCase { assert 'Hello, World!'.tr(' --', 'Z') == 'HelloZZWorldZ' } + void testBar() { + assert StringUtil.bar(0, 0, 39) == '\u258f' + assert StringUtil.bar(1, 0, 39) == '\u2588\u258f' + assert StringUtil.bar(2, 0, 39) == '\u2588\u2588\u258f' + assert StringUtil.bar(0, 0, 39, 80) == '\u258f' + assert StringUtil.bar(1, 0, 39, 80) == '\u2588\u2588\u258f' + assert StringUtil.bar(2, 0, 39, 80) == '\u2588\u2588\u2588\u2588\u258f' + assert StringUtil.bar(0, 0, 39, 20) == '\u258f' + assert StringUtil.bar(1, 0, 39, 20) == '\u258b' + assert StringUtil.bar(2, 0, 39, 20) == '\u2588\u258f' + } + void testListTake() { def data = [ new ArrayList( [ 1, 2, 3 ] ),