From 1aa2bc268124e4abc21e5513d29c87455099e057 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 19 Mar 2023 15:11:07 -0700 Subject: [PATCH] Added Abbreviate renderers --- README.md | 1 + lib/src/main/java/rife/render/Abbreviate.java | 61 ++++++++ lib/src/main/java/rife/render/Mask.java | 2 +- .../main/java/rife/render/RenderUtils.java | 139 +++++++----------- lib/src/test/java/rife/render/TestFormat.java | 12 ++ .../test/resources/templates/abbreviate.html | 4 + .../test/resources/templates/abbreviate.txt | 3 + .../test/resources/templates/dateTimeUtc.html | 4 +- 8 files changed, 139 insertions(+), 87 deletions(-) create mode 100644 lib/src/main/java/rife/render/Abbreviate.java create mode 100644 lib/src/test/resources/templates/abbreviate.html create mode 100644 lib/src/test/resources/templates/abbreviate.txt diff --git a/README.md b/README.md index 012b23c..544bbfc 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ This project provides a collection of useful template renderers. | Renderer | Description | |:--------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------| +| [rife.render.Abbreviate](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.Abbreviate) | Abbreviates a template value | | [rife.render.formatCreditcard](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.FormatCreditCard) | Formats a template credit card number value to the last 4 digits | | [rife.render.Mask](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.Mask) | Masks characters of a template value | | [rife.render.Normalize](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.Normalize) | Normalizes a template value for inclusion in a URL path | diff --git a/lib/src/main/java/rife/render/Abbreviate.java b/lib/src/main/java/rife/render/Abbreviate.java new file mode 100644 index 0000000..d27a1a7 --- /dev/null +++ b/lib/src/main/java/rife/render/Abbreviate.java @@ -0,0 +1,61 @@ +/* + * Copyright 2023 the original author or authors. + * + * 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 + * + * https://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. + * + */ + +package rife.render; + +import rife.template.Template; +import rife.template.ValueRenderer; + +import java.io.IOException; +import java.io.StringReader; +import java.util.Properties; + +/** + *

Abbreviate a template value with ellipses.

+ * + *

Usage:

+ * + *
+ *   <!--v render:rife.render.Abbreviate:valueId/-->
+ *   {{v render:rife.render.Abbreviate:valueId/}}
+ * 
+ * + * @author Erik C. Thauvin + * @see rife.render.Abbreviate + * @since 1.0 + */ +public class Abbreviate implements ValueRenderer { + /** + * {@inheritDoc} + */ + @Override + public String render(Template template, String valueId, String differentiator) { + var mark = "..."; + var max = 0; + if (template.hasDefaultValue(valueId)) { + var properties = new Properties(); + try { + properties.load(new StringReader(template.getDefaultValue(valueId))); + mark = properties.getProperty("mark", mark); + max = Integer.parseInt(properties.getProperty("max", String.valueOf(max))); + } catch (IOException | NumberFormatException ignore) { + // do nothing + } + } + return RenderUtils.abbreviate(template.getValueOrAttribute(differentiator), max, mark); + } +} diff --git a/lib/src/main/java/rife/render/Mask.java b/lib/src/main/java/rife/render/Mask.java index 8697425..b9d8d78 100644 --- a/lib/src/main/java/rife/render/Mask.java +++ b/lib/src/main/java/rife/render/Mask.java @@ -25,7 +25,7 @@ import java.io.StringReader; import java.util.Properties; /** - *

Masks characters of a template value. + *

Masks characters of a template value.

* *

Usage:

* diff --git a/lib/src/main/java/rife/render/RenderUtils.java b/lib/src/main/java/rife/render/RenderUtils.java index 3783d03..7da211e 100644 --- a/lib/src/main/java/rife/render/RenderUtils.java +++ b/lib/src/main/java/rife/render/RenderUtils.java @@ -17,7 +17,6 @@ package rife.render; -import rife.tools.Localization; import rife.tools.StringUtils; import java.io.IOException; @@ -33,14 +32,40 @@ import java.util.concurrent.TimeUnit; /** * Collection of utility-type methods commonly used by the renderers. + * + * @author Erik C. Thauvin + * @since 1.0 */ public final class RenderUtils { - private static final String DEFAULT_USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0"; + private static final String DEFAULT_USER_AGENT = + "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0"; private RenderUtils() { // no-op } + /** + * Abbreviates a String to the given length using a replacement marker. + * + * @param src the source String + * @param max the maximum length of the resulting String + * @param marker the String used as a replacement marker + * @return the abbreviated String + */ + public static String abbreviate(String src, int max, String marker) { + if (src == null || src.isBlank()) { + return src; + } + + var len = src.length(); + + if (len <= max || max < 0) { + return src; + } + + return src.substring(0, max - marker.length()) + marker; + } + /** * Returns the Swatch Internet (.beat) Time for the give date-time. * @@ -49,7 +74,8 @@ public final class RenderUtils { */ public static String beatTime(ZonedDateTime zonedDateTime) { var zdt = zonedDateTime.withZoneSameInstant(ZoneId.of("UTC+01:00")); - var beats = (int) ((zdt.get(ChronoField.SECOND_OF_MINUTE) + (zdt.get(ChronoField.MINUTE_OF_HOUR) * 60) + (zdt.get(ChronoField.HOUR_OF_DAY) * 3600)) / 86.4); + var beats = (int) ((zdt.get(ChronoField.SECOND_OF_MINUTE) + (zdt.get(ChronoField.MINUTE_OF_HOUR) * 60) + + (zdt.get(ChronoField.HOUR_OF_DAY) * 3600)) / 86.4); return String.format("@%03d", beats); } @@ -81,6 +107,29 @@ public final class RenderUtils { return sb.toString(); } + /** + * Fetches the content (body) of a URL. + * + * @param url the URL string. + * @param defaultContent the default content to return if none fetched. + * @return the url content, or empty. + */ + public static String fetchUrl(String url, String defaultContent) { + try { + var connection = (HttpURLConnection) new URL(url).openConnection(); + connection.setRequestProperty("User-Agent", DEFAULT_USER_AGENT); + var code = connection.getResponseCode(); + if (code >= 200 && code <= 399) { + try (var inputStream = connection.getInputStream()) { + return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); + } + } + } catch (IOException ignore) { + // do nothing + } + return defaultContent; + } + /** * Returns the last 4 digits a credit card number. The number must satisfy the Luhn algorithm. * Non-digits are stripped from the number. @@ -204,23 +253,8 @@ public final class RenderUtils { if (src == null || src.isBlank()) { return src; } - - var svg = src; - try { - var connection = (HttpURLConnection) new URL( - String.format("https://api.qrserver.com/v1/create-qr-code/?format=svg&size=%s&data=%s", size, - StringUtils.encodeUrl(src.trim()))) - .openConnection(); - connection.setRequestProperty("User-Agent", DEFAULT_USER_AGENT); - if (validResponseCode(connection.getResponseCode())) { - try (var inputStream = connection.getInputStream()) { - svg = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); - } - } - } catch (IOException ignore) { - // do nothing - } - return svg; + return fetchUrl(String.format("https://api.qrserver.com/v1/create-qr-code/?format=svg&size=%s&data=%s", size, + StringUtils.encodeUrl(src.trim())), src); } /** @@ -274,22 +308,8 @@ public final class RenderUtils { if (url == null || url.isBlank() || !url.matches("^[Hh][Tt][Tt][Pp][Ss]?://\\w.*")) { return url; } - - var shorten = url; - try { - var connection = (HttpURLConnection) new URL( - String.format("https://is.gd/create.php?format=simple&url=%s", StringUtils.encodeUrl(url.trim()))) - .openConnection(); - connection.setRequestProperty("User-Agent", DEFAULT_USER_AGENT); - if (validResponseCode(connection.getResponseCode())) { - try (var inputStream = connection.getInputStream()) { - shorten = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); - } - } - } catch (IOException ignore) { - // do nothing - } - return shorten; + return fetchUrl(String.format("https://is.gd/create.php?format=simple&url=%s", + StringUtils.encodeUrl(url.trim())), url); } /** @@ -351,43 +371,6 @@ public final class RenderUtils { return sb.toString(); } - /** - * Converts the given String to a quoted-printable string. - * - * @param src the source String - * @return the quoted-printable String - */ - public static String toQuotedPrintable(String src) { - if (src == null || src.isEmpty()) { - return src; - } - - var len = src.length(); - var buff = new StringBuilder(len); - - char c; - String hex; - for (var i = 0; i < len; i++) { - c = src.charAt(i); - - if (((c > 47) && (c < 58)) || ((c > 64) && (c < 91)) || ((c > 96) && (c < 123))) { - buff.append(c); - } else { - hex = Integer.toString(c, 16); - - buff.append('='); - - if (hex.length() == 1) { - buff.append('0'); - } - - buff.append(hex.toUpperCase(Localization.getLocale())); - } - } - - return buff.toString(); - } - /** * Returns the formatted server uptime. * @@ -439,14 +422,4 @@ public final class RenderUtils { return sb.toString(); } - - /** - * Checks whether the specified HTTP response code is valid. - * - * @param code the HTTP response code. - * @return {@code true} if the response code is valid. - */ - public static boolean validResponseCode(int code) { - return code >= 200 && code <= 399; - } } \ No newline at end of file diff --git a/lib/src/test/java/rife/render/TestFormat.java b/lib/src/test/java/rife/render/TestFormat.java index e7fa330..82cd8b0 100644 --- a/lib/src/test/java/rife/render/TestFormat.java +++ b/lib/src/test/java/rife/render/TestFormat.java @@ -23,6 +23,18 @@ import rife.template.TemplateFactory; import static org.assertj.core.api.Assertions.assertThat; class TestFormat { + @Test + void testAbbreviate() { + var t = TemplateFactory.HTML.get("abbreviate"); + t.setAttribute(TestCase.FOO, TestCase.SAMPLE_TEXT); + System.out.println(t.getContent()); + assertThat(t.getContent()).as("max=12").endsWith("…").hasSize(12); + + t = TemplateFactory.TXT.get("abbreviate"); + t.setAttribute(TestCase.FOO, TestCase.SAMPLE_TEXT); + assertThat(t.getContent()).as("max=8").endsWith("...").hasSize(8); + } + @Test void testFormatCreditCard() { var t = TemplateFactory.TXT.get("formatCreditCard"); diff --git a/lib/src/test/resources/templates/abbreviate.html b/lib/src/test/resources/templates/abbreviate.html new file mode 100644 index 0000000..3cc9bef --- /dev/null +++ b/lib/src/test/resources/templates/abbreviate.html @@ -0,0 +1,4 @@ + +mark=… +max=12 + \ No newline at end of file diff --git a/lib/src/test/resources/templates/abbreviate.txt b/lib/src/test/resources/templates/abbreviate.txt new file mode 100644 index 0000000..267a1d7 --- /dev/null +++ b/lib/src/test/resources/templates/abbreviate.txt @@ -0,0 +1,3 @@ +{{v render:rife.render.Abbreviate:foo}} +max=8 +{{/v}} \ No newline at end of file diff --git a/lib/src/test/resources/templates/dateTimeUtc.html b/lib/src/test/resources/templates/dateTimeUtc.html index 0cf020c..378c0e0 100644 --- a/lib/src/test/resources/templates/dateTimeUtc.html +++ b/lib/src/test/resources/templates/dateTimeUtc.html @@ -1,3 +1 @@ - -tz=UTC - \ No newline at end of file +tz=UTC \ No newline at end of file