Skip to content

Commit

Permalink
added function `str/align
Browse files Browse the repository at this point in the history
  • Loading branch information
juerg committed Dec 8, 2023
1 parent 786356a commit 07f1b74
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 1 deletion.
1 change: 1 addition & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ All notable changes to this project will be documented in this file.

### Added

- function `str/align`
- bytebuf allocation with random values
- bytebuf allocation with a fill value
- an example script comparing AES-256 CBC, AES-256 GCM, and AES-256 ZIP
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@ public DocSection section() {
trim.addItem(diBuilder.getDocItem("str/trim-left"));
trim.addItem(diBuilder.getDocItem("str/trim-right"));

final DocSection align = new DocSection("Align", "primitives.strings.align");
strings.addSection(align);
align.addItem(diBuilder.getDocItem("str/align"));

final DocSection hex = new DocSection("Hex", "primitives.strings.hex");
strings.addSection(hex);
hex.addItem(diBuilder.getDocItem("str/hex-to-bytebuf"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,84 @@ else if (v1 != Nil || v2 != Nil) {
private static final long serialVersionUID = -1848883965231344442L;
};

public static VncFunction str_align =
new VncFunction(
"str/align",
VncFunction
.meta()
.arglists(
"(str/align width align overflow-mode text)")
.doc(
"Aligns a text to width characters.\n\n" +
"align: :left, :center, :right\n\n" +
"overflow-mode: :clip-left, :clip-right, :ellipsis-left, :ellipsis-right")
.examples(
"(str/align 6 :left :clip-right \"abc\")",
"(str/align 6 :center :clip-right \"abc\")",
"(str/align 6 :right :clip-right \"abc\")",
"(str/align 6 :left :clip-left \"abcdefgh\")",
"(str/align 6 :left :ellipsis-left \"abcdefgh\")",
"(str/align 6 :left :ellipsis-right \"abcdefgh\")")
.seeAlso(
"str/trim-to-nil", "str/trim-left", "str/trim-right")
.build()
) {
@Override
public VncVal apply(final VncList args) {
ArityExceptions.assertArity(this, args, 4);

final int width = Coerce.toVncLong(args.first()).toJavaInteger();
final String align = Coerce.toVncKeyword(args.second()).getSimpleName();
final String overflow = Coerce.toVncKeyword(args.third()).getSimpleName();
final String text = Coerce.toVncString(args.fourth()).getValue().trim();

final int textlen = text.length();

String justified;

switch(overflow) {
case "clip-left":
justified = textlen >= width ? text.substring(textlen-width, textlen) : text;
break;
case "clip-right":
justified = textlen >= width ? text.substring(0, width) : text;
break;
case "ellipsis-left":
justified = textlen >= width-1 ? "…" + text.substring(textlen-width+1, textlen) : text;
break;
case "ellipsis-right":
justified = textlen >= width-1 ? text.substring(0, width-1) + "…" : text;
break;
default:
throw new VncException(String.format(
"Function 'str/align' got undefined overflow-mode :%s.",
overflow));
}

if (justified.length() < width) {
switch(align) {
case "left":
justified = StringUtil.padRight(justified, width);
break;
case "right":
justified = StringUtil.padLeft(justified, width);
break;
case "center":
justified = StringUtil.padCenter(justified, width);
break;
default:
throw new VncException(String.format(
"Function 'str/align' got invalid align mode :%s.",
align));
}
}

return new VncString(justified);
}

private static final long serialVersionUID = -1848883965231344442L;
};

public static VncFunction str_trim =
new VncFunction(
"str/trim",
Expand Down Expand Up @@ -2617,6 +2695,7 @@ else if (Types.isVncSequence(locale)) {
.add(str_trim_left)
.add(str_trim_right)
.add(str_trim_to_nil)
.add(str_align)
.add(str_index_of)
.add(str_last_index_of)
.add(str_replace_first)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -548,9 +548,21 @@ public static String replaceLeadingSpaces(final String text, final char replaceC
}
}

public static String padLeft(final String s, final int len) {
final int padLen = len - s.length();
return padLen > 0 ? repeat(' ', padLen) + s : s;
}

public static String padRight(final String s, final int len) {
final int padLen = len - s.length();
return padLen > 0 ? s + StringUtil.repeat(' ', padLen) : s;
return padLen > 0 ? s + repeat(' ', padLen) : s;
}

public static String padCenter(final String s, final int len) {
final int padLen = len - s.length();
final int padRight = padLen / 2;
final int padLeft = padLen - padRight;
return padLen > 0 ? repeat(' ', padLeft) + s + repeat(' ', padRight) : s;
}

public static String toEscapedUnicode(final char ch) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,49 @@ public void test_str_trim_right() {
assertEquals("", venice.eval("(str/trim-right \" \f\t\r\n \")"));
}

@Test
public void test_str_align() {
final Venice venice = new Venice();

assertEquals(" ", venice.eval("(str/align 6 :left :clip-right \"\")"));
assertEquals(" ", venice.eval("(str/align 6 :center :clip-right \"\")"));
assertEquals(" ", venice.eval("(str/align 6 :right :clip-right \"\")"));

assertEquals("a ", venice.eval("(str/align 6 :left :clip-right \"a\")"));
assertEquals(" a ", venice.eval("(str/align 6 :center :clip-right \"a\")"));
assertEquals(" a", venice.eval("(str/align 6 :right :clip-right \"a\")"));

assertEquals("ab ", venice.eval("(str/align 6 :left :clip-right \"ab\")"));
assertEquals(" ab ", venice.eval("(str/align 6 :center :clip-right \"ab\")"));
assertEquals(" ab", venice.eval("(str/align 6 :right :clip-right \"ab\")"));

assertEquals("abc ", venice.eval("(str/align 6 :left :clip-right \"abc\")"));
assertEquals(" abc ", venice.eval("(str/align 6 :center :clip-right \"abc\")"));
assertEquals(" abc", venice.eval("(str/align 6 :right :clip-right \"abc\")"));

assertEquals("abcd ", venice.eval("(str/align 6 :left :clip-right \"abcd\")"));
assertEquals(" abcd ", venice.eval("(str/align 6 :center :clip-right \"abcd\")"));
assertEquals(" abcd", venice.eval("(str/align 6 :right :clip-right \"abcd\")"));

assertEquals("abcde ", venice.eval("(str/align 6 :left :clip-right \"abcde\")"));
assertEquals(" abcde", venice.eval("(str/align 6 :center :clip-right \"abcde\")"));
assertEquals(" abcde", venice.eval("(str/align 6 :right :clip-right \"abcde\")"));

assertEquals("abcdef", venice.eval("(str/align 6 :left :clip-right \"abcdef\")"));
assertEquals("abcdef", venice.eval("(str/align 6 :center :clip-right \"abcdef\")"));
assertEquals("abcdef", venice.eval("(str/align 6 :right :clip-right \"abcdef\")"));

assertEquals("abcdef", venice.eval("(str/align 6 :left :clip-right \"abcdefg\")"));
assertEquals("bcdefg", venice.eval("(str/align 6 :left :clip-left \"abcdefg\")"));
assertEquals("abcde…", venice.eval("(str/align 6 :left :ellipsis-right \"abcdefg\")"));
assertEquals("…cdefg", venice.eval("(str/align 6 :left :ellipsis-left \"abcdefg\")"));

assertEquals("abcdef", venice.eval("(str/align 6 :left :clip-right \"abcdefgh\")"));
assertEquals("cdefgh", venice.eval("(str/align 6 :left :clip-left \"abcdefgh\")"));
assertEquals("abcde…", venice.eval("(str/align 6 :left :ellipsis-right \"abcdefgh\")"));
assertEquals("…defgh", venice.eval("(str/align 6 :left :ellipsis-left \"abcdefgh\")"));
}

@Test
public void test_str_truncate() {
final Venice venice = new Venice();
Expand Down

0 comments on commit 07f1b74

Please sign in to comment.