Moved from Gradle to bld

This commit is contained in:
Erik C. Thauvin 2023-04-08 10:28:20 -07:00
parent 5df56b7820
commit 630b57b604
108 changed files with 447 additions and 786 deletions

BIN
lib/bld/bld-wrapper.jar Normal file

Binary file not shown.

View file

@ -0,0 +1,6 @@
bld.downloadExtensionJavadoc=false
bld.downloadExtensionSources=true
bld.extension-tests=com.uwyn.rife2:bld-tests-badge:1.0.0
bld.repositories=MAVEN_CENTRAL,RIFE2_RELEASES
rife2.downloadLocation=
rife2.version=1.5.18

View file

@ -1,202 +0,0 @@
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent
import java.net.URI
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse
plugins {
`java-library`
`maven-publish`
pmd
signing
id("com.github.ben-manes.versions") version "0.46.0"
}
val rifeVersion by rootProject.extra { "1.5.6" }
group = "com.uwyn.rife2"
version = "1.1.0"
repositories {
mavenLocal()
mavenCentral()
maven { url = uri("https://s01.oss.sonatype.org/content/repositories/snapshots") } // only needed for SNAPSHOT
}
dependencies {
implementation("com.uwyn.rife2:rife2:${rifeVersion}") {
this.isChanging = true
}
runtimeOnly("com.uwyn.rife2:rife2:${rifeVersion}:agent") {
this.isChanging = true
}
testImplementation(platform("org.junit:junit-bom:5.9.2"))
testImplementation("org.junit.jupiter:junit-jupiter")
testImplementation("org.assertj:assertj-core:3.24.2")
}
configurations {
all {
resolutionStrategy.cacheChangingModulesFor(0, TimeUnit.SECONDS)
}
}
java {
withJavadocJar()
withSourcesJar()
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}
}
pmd {
isIgnoreFailures = true
ruleSetFiles = files("${projectDir}/config/pmd.xml")
isConsoleOutput = true
}
tasks {
withType<JavaCompile> {
options.encoding = "UTF-8"
}
test {
val apiKey = project.properties["testsBadgeApiKey"]
useJUnitPlatform {
if (System.getenv("NO_CI") != null) {
excludeTags("no-ci")
println("Excluded test tags: $excludeTags")
}
}
testLogging {
exceptionFormat = TestExceptionFormat.FULL
events = setOf(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED)
showStandardStreams = true
}
addTestListener(object : TestListener {
override fun beforeTest(p0: TestDescriptor?) = Unit
override fun beforeSuite(p0: TestDescriptor?) = Unit
override fun afterTest(desc: TestDescriptor, result: TestResult) = Unit
override fun afterSuite(desc: TestDescriptor, result: TestResult) {
if (desc.parent != null) {
val output = result.run {
"Results: $resultType (" +
"$testCount tests, " +
"$successfulTestCount successes, " +
"$failedTestCount failures, " +
"$skippedTestCount skipped" +
")"
}
val testResultLine = "| $output |"
val repeatLength = testResultLine.length
val separationLine = "-".repeat(repeatLength)
println()
println(separationLine)
println(testResultLine)
println(separationLine)
}
if (desc.parent == null) {
val passed = result.successfulTestCount
val failed = result.failedTestCount
val skipped = result.skippedTestCount
if (apiKey != null) {
val response: HttpResponse<String> = HttpClient.newHttpClient()
.send(
HttpRequest.newBuilder()
.uri(
URI(
"https://rife2.com/tests-badge/update/com.uwyn.rife2/rife2-renderers?" +
"apiKey=$apiKey&" +
"passed=$passed&" +
"failed=$failed&" +
"skipped=$skipped"
)
)
.POST(HttpRequest.BodyPublishers.noBody())
.build(), HttpResponse.BodyHandlers.ofString()
)
println("RESPONSE: " + response.statusCode())
println(response.body())
}
}
}
})
}
javadoc {
title = "<a href=\"https://rife2.com\">RIFE2</a> Template Renderers"
options {
this as StandardJavadocDocletOptions
keyWords(true)
splitIndex(true)
links("https://rife2.github.io/rife2/")
}
}
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
artifactId = "rife2-renderers"
from(components["java"])
pom {
name.set("RIFE2 Template Renderers")
description.set("Template Renderers for the RIFE2 web framework")
url.set("https://github.com/rife2/rife2-template-renderers")
licenses {
license {
name.set("The Apache License, Version 2.0")
url.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
}
}
developers {
developer {
id.set("ethauvin")
name.set("Erik C. Thauvin")
email.set("erik@thauvin.net")
url.set("https://erik.thauvin.net/")
}
developer {
id.set("gbevin")
name.set("Geert Bevin")
email.set("gbevin@uwyn.com")
url.set("https://github.com/gbevin")
}
}
scm {
connection.set("scm:git:https://github.com/rife2/rife2-template-renderers.git")
developerConnection.set("scm:git:git@github.com:rife2/rife2-template-renderers.git")
url.set("https://github.com/rife2/rife2-template-renderers")
}
}
repositories {
maven {
credentials {
username = System.getenv("SONATYPE_USER")
password = System.getenv("SONATYPE_PASSWORD")
}
val releasesRepoUrl = uri("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/")
val snapshotsRepoUrl = uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")
url = if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl
}
}
}
}
}
signing {
val signingKey: String? by project // ORG_GRADLE_PROJECT_signingKey
val signingPassword: String? by project // ORG_GRADLE_PROJECT_signingPassword
useInMemoryPgpKeys(signingKey, signingPassword)
sign(publishing.publications["mavenJava"])
}

View file

@ -1,112 +0,0 @@
<?xml version="1.0"?>
<ruleset name="erik"
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
<description>Erik's Ruleset</description>
<!-- BEST PRACTICES -->
<rule ref="category/java/bestpractices.xml">
<exclude name="AvoidPrintStackTrace"/>
<exclude name="JUnit4TestShouldUseTestAnnotation"/>
<exclude name="JUnitTestContainsTooManyAsserts"/>
</rule>
<rule ref="category/java/bestpractices.xml/MissingOverride">
<properties>
<property name="violationSuppressXPath"
value="//MethodDeclaration[@Name='hashCode' or @Name='equals' or @Name='toString']"/>
</properties>
</rule>
<!-- CODE STYLE -->
<rule ref="category/java/codestyle.xml">
<exclude name="AtLeastOneConstructor"/>
<exclude name="ClassNamingConventions"/>
<exclude name="CommentDefaultAccessModifier"/>
<exclude name="ConfusingTernary"/>
<exclude name="DefaultPackage"/>
<exclude name="FieldNamingConventions"/>
<exclude name="LocalVariableCouldBeFinal"/>
<exclude name="LongVariable"/>
<exclude name="MethodArgumentCouldBeFinal"/>
<exclude name="OnlyOneReturn"/>
<exclude name="PackageCase"/>
<exclude name="ShortClassName"/>
<exclude name="ShortMethodName"/>
<exclude name="ShortVariable"/>
<exclude name="UselessParentheses"/>
<exclude name="UseUnderscoresInNumericLiterals"/>
</rule>
<!-- DESIGN -->
<rule ref="category/java/design.xml">
<exclude name="AvoidCatchingGenericException"/>
<exclude name="AvoidDeeplyNestedIfStmts"/>
<exclude name="AvoidUncheckedExceptionsInSignatures"/>
<exclude name="CognitiveComplexity"/>
<exclude name="CyclomaticComplexity"/>
<exclude name="ExcessiveClassLength"/>
<exclude name="ExcessiveMethodLength"/>
<exclude name="ExcessiveParameterList"/>
<exclude name="ExcessivePublicCount"/>
<exclude name="GodClass"/>
<exclude name="LawOfDemeter"/>
<exclude name="LoosePackageCoupling"/>
<exclude name="NPathComplexity"/>
<exclude name="NcssCount"/>
<exclude name="TooManyFields"/>
<exclude name="TooManyMethods"/>
<exclude name="UseObjectForClearerAPI"/>
</rule>
<!-- DOCUMENTATION -->
<rule ref="category/java/documentation.xml">
<exclude name="CommentRequired"/>
<exclude name="CommentSize"/>
</rule>
<!-- ERROR PRONE -->
<rule ref="category/java/errorprone.xml">
<exclude name="AssignmentInOperand"/>
<exclude name="AvoidCatchingNPE"/>
<exclude name="AvoidDuplicateLiterals"/>
<exclude name="AvoidFieldNameMatchingMethodName"/>
<exclude name="AvoidFieldNameMatchingTypeName"/>
<exclude name="AvoidLiteralsInIfCondition"/>
<exclude name="EmptyCatchBlock"/>
<exclude name="NullAssignment"/>
</rule>
<rule ref="category/java/errorprone.xml/AssignmentInOperand">
<properties>
<property name="allowWhile" value="true"/>
<property name="allowFor" value="true"/>
<property name="allowIf" value="true"/>
</properties>
</rule>
<rule ref="category/java/errorprone.xml/AvoidDuplicateLiterals">
<properties>
<property name="skipAnnotations" value="true"/>
</properties>
</rule>
<rule ref="category/java/errorprone.xml/EmptyCatchBlock">
<properties>
<property name="allowExceptionNameRegex">
<value>^ignore$</value>
</property>
</properties>
</rule>
<!-- MULTITHREADING -->
<rule ref="category/java/multithreading.xml">
</rule>
<!-- PERFORMANCE -->
<rule ref="category/java/performance.xml">
</rule>
<!-- SECURITY -->
<rule ref="category/java/security.xml">
</rule>
</ruleset>

View file

@ -1,55 +0,0 @@
/*
* 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;
/**
* <p>Abbreviate a template value with ellipses.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.Abbreviate:valueId/--&gt;
* {{v render:rife.render.Abbreviate:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.Abbreviate">rife.render.Abbreviate</a>
* @since 1.0
*/
public class Abbreviate implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
var mark = "...";
var max = -1;
var defaultValue = template.getDefaultValue(valueId);
if (defaultValue != null) {
var properties = RenderUtils.parsePropertiesString(defaultValue);
mark = properties.getProperty("mark", mark);
max = Integer.parseInt(properties.getProperty("max", String.valueOf(max)));
}
return template.getEncoder().encode(
RenderUtils.abbreviate(template.getValueOrAttribute(differentiator), max, mark));
}
}

View file

@ -1,47 +0,0 @@
/*
* 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.time.ZonedDateTime;
/**
* <p>Renders the current time in Swatch Internet (.beat) Time format.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.BeatTime/--&gt;
* {{v render:rife.render.BeatTime/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.BeatTime">rife.render.BeatTime</a>
* @since 1.0
*/
public class BeatTime implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
return template.getEncoder().encode(RenderUtils.beatTime(ZonedDateTime.now()));
}
}

View file

@ -1,46 +0,0 @@
/*
* 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 rife.tools.StringUtils;
/**
* <p>Capitalizes a template value.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.Capitalize:valueId/--&gt;
* {{v render:rife.render.Capitalize:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.Capitalize">rife.render.Capitalize</a>
* @since 1.0
*/
public class Capitalize implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
return template.getEncoder().encode(StringUtils.capitalize(template.getValueOrAttribute(differentiator)));
}
}

View file

@ -1,47 +0,0 @@
/*
* 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.time.ZonedDateTime;
/**
* <p>Return the current date in ISO 8601 format.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.DateIso/--&gt;
* {{v render:rife.render.DateIso/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.DateIso">rife.render.DateIso</a>
* @since 1.0
*/
public class DateIso implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
return template.getEncoder().encode(ZonedDateTime.now().format(RenderUtils.ISO_8601_DATE_FORMATTER));
}
}

View file

@ -1,58 +0,0 @@
/*
* 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.time.ZoneId;
import java.time.ZonedDateTime;
/**
* <p>Return the current date and time in ISO 8601 format.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.DateTimeIso/--&gt;
* {{v render:rife.render.DateTimeIso/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.DateTimeIso">rife.render.DateTimeIso</a>
* @since 1.0
*/
public class DateTimeIso implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
var defaultValue = template.getDefaultValue(valueId);
if (defaultValue != null) {
var properties = RenderUtils.parsePropertiesString(template.getDefaultValue(valueId));
var tz = "tz";
if (properties.containsKey(tz)) {
return ZonedDateTime.now().format(
RenderUtils.ISO_8601_FORMATTER.withZone(ZoneId.of(properties.getProperty(tz))));
}
}
return template.getEncoder().encode(ZonedDateTime.now().format(RenderUtils.ISO_8601_FORMATTER));
}
}

View file

@ -1,47 +0,0 @@
/*
* 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.time.ZonedDateTime;
/**
* <p>Return the current date and time in RFC 2822 format.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.DateTimeRfc2822/--&gt;
* {{v render:rife.render.DateTimeRfc2822/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.DateTimeRfc2822">rife.render.DateTimeRfc2822</a>
* @since 1.0
*/
public class DateTimeRfc2822 implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
return template.getEncoder().encode(ZonedDateTime.now().format(RenderUtils.RFC_2822_FORMATTER));
}
}

View file

@ -1,52 +0,0 @@
/*
* 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 rife.tools.StringUtils;
import java.nio.charset.StandardCharsets;
/**
* <p>Encodes a template value to Base64.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.EncodeBase64:valueId/--&gt;
* {{v render:rife.render.EncodeBase64:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeBase64">rife.render.EncodeBase64</a>
* @see StringUtils#encodeBase64(byte[])
* @since 1.0
*/
public class EncodeBase64 implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
var properties = RenderUtils.parsePropertiesString(template.getDefaultValue(valueId));
return RenderUtils.encode(
StringUtils.encodeBase64(template.getValueOrAttribute(differentiator).getBytes(StandardCharsets.UTF_8)),
properties);
}
}

View file

@ -1,47 +0,0 @@
/*
* 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 rife.tools.StringUtils;
/**
* <p>Encodes a template value to HTML.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.EncodeHtml:valueId/--&gt;
* {{v render:rife.render.EncodeHtml:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeHtml">rife.render.EncodeHtml</a>
* @see StringUtils#encodeHtml(String)
* @since 1.0
*/
public class EncodeHtml implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
return StringUtils.encodeHtml(template.getValueOrAttribute(differentiator));
}
}

View file

@ -1,45 +0,0 @@
/*
* 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;
/**
* <p>Encodes a template value to HTML decimal entities</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.EncodeHtmlEntities:valueId/--&gt;
* {{v render:rife.render.EncodeHtmlEntities:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeHtmlEntities">rife.render.EncodeHtmlEntities</a>
* @since 1.0
*/
public class EncodeHtmlEntities implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
return RenderUtils.htmlEntities(template.getValueOrAttribute(differentiator));
}
}

View file

@ -1,48 +0,0 @@
/*
* 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 rife.tools.StringUtils;
/**
* <p>Encodes a template value to JavaScript/ECMAScript.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.EncodeJs:valueId/--&gt;
* {{v render:rife.render.EncodeJs:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeJs">rife.render.EncodeJs</a>
* @see StringUtils#encodeJson(String)
* @since 1.0
*/
public class EncodeJs implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
var properties = RenderUtils.parsePropertiesString(template.getDefaultValue(valueId));
return RenderUtils.encode(RenderUtils.encodeJs(template.getValueOrAttribute(differentiator)), properties);
}
}

View file

@ -1,48 +0,0 @@
/*
* 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 rife.tools.StringUtils;
/**
* <p>Encodes a template value to JSON.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.EncodeJson:valueId/--&gt;
* {{v render:rife.render.EncodeJson:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeJson">rife.render.EncodeJson</a>
* @see StringUtils#encodeJson(String)
* @since 1.0
*/
public class EncodeJson implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
var properties = RenderUtils.parsePropertiesString(template.getDefaultValue(valueId));
return RenderUtils.encode(StringUtils.encodeJson(template.getValueOrAttribute(differentiator)), properties);
}
}

View file

@ -1,48 +0,0 @@
/*
* 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 rife.tools.StringUtils;
/**
* <p>Encodes a template value to Unicode escape codes.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.EncodeUnicode:valueId/--&gt;
* {{v render:rife.render.EncodeUnicode:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeUnicode">rife.render.EncodeUnicode</a>
* @see StringUtils#encodeUnicode(String)
* @since 1.0
*/
public class EncodeUnicode implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
var properties = RenderUtils.parsePropertiesString(template.getDefaultValue(valueId));
return RenderUtils.encode(StringUtils.encodeUnicode(template.getValueOrAttribute(differentiator)), properties);
}
}

View file

@ -1,48 +0,0 @@
/*
* 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 rife.tools.StringUtils;
/**
* <p>URL-encodes a template value.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.EncodeUrl:valueId/--&gt;
* {{v render:rife.render.EncodeUrl:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeUrl">rife.render.EncodeUrl</a>
* @see StringUtils#encodeUrl(String)
* @since 1.0
*/
public class EncodeUrl implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
var properties = RenderUtils.parsePropertiesString(template.getDefaultValue(valueId));
return RenderUtils.encode(StringUtils.encodeUrl(template.getValueOrAttribute(differentiator)), properties);
}
}

View file

@ -1,47 +0,0 @@
/*
* 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 rife.tools.StringUtils;
/**
* <p>Encodes a template value to XML.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.EncodeXml:valueId/--&gt;
* {{v render:rife.render.EncodeXml:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeXml">rife.render.EncodeXml</a>
* @see StringUtils#encodeXml(String)
* @since 1.0
*/
public class EncodeXml implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
return StringUtils.encodeXml(template.getValueOrAttribute(differentiator));
}
}

View file

@ -1,45 +0,0 @@
/*
* 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;
/**
* Formats a template credit card number value to the last 4 digits.
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.FormatCreditCard:valueId/--&gt;
* {{v render:rife.render.FormatCreditCard:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.FormatCreditCard">rife.render.FormatCreditCard</a>
* @since 1.0
*/
public class FormatCreditCard implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
return template.getEncoder().encode(RenderUtils.formatCreditCard(template.getValueOrAttribute(differentiator)));
}
}

View file

@ -1,50 +0,0 @@
/*
* 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 rife.tools.Localization;
/**
* <p>Converts a template value to lowercase.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.Lowercase:valueId/--&gt;
* {{v render:rife.render.Lowercase:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.Lowercase">rife.render.Lowercase</a>
* @since 1.0
*/
public class Lowercase implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
var value = template.getValueOrAttribute(differentiator);
if (value == null || value.isBlank()) {
return value;
}
return template.getEncoder().encode(value.toLowerCase(Localization.getLocale()));
}
}

View file

@ -1,60 +0,0 @@
/*
* 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;
/**
* <p>Masks characters of a template value.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.Mask:valueId/--&gt;
* {{v render:rife.render.Mask:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.Mask">rife.render.Mask</a>
* @since 1.0
*/
public class Mask implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
var mask = "*";
var unmasked = 0;
var fromStart = false;
var defaultValue = template.getDefaultValue(valueId);
if (defaultValue != null && !defaultValue.isBlank()) {
var properties = RenderUtils.parsePropertiesString(defaultValue);
mask = properties.getProperty("mask", mask);
try {
unmasked = Integer.parseInt(properties.getProperty("unmasked", "0"));
} catch (NumberFormatException ignore) {
// do nothing
}
fromStart = "true".equalsIgnoreCase(properties.getProperty("fromStart", "false"));
}
return template.getEncoder().encode(
RenderUtils.mask(template.getValueOrAttribute(differentiator), mask, unmasked, fromStart));
}
}

View file

@ -1,45 +0,0 @@
/*
* 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;
/**
* <p>Normalizes a template value for inclusion in a URL path.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.Normalize:valueId/--&gt;
* {{v render:rife.render.Normalize:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.Normalize">rife.render.Normalize</a>
* @since 1.0
*/
public class Normalize implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
return template.getEncoder().encode(RenderUtils.normalize(template.getValueOrAttribute(differentiator)));
}
}

View file

@ -1,47 +0,0 @@
/*
* 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;
/**
* <p>Generates an SVG QR Code for a template value using <a href="https://goqr.me/">goQR.me</a>.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.QrCode:valueId/--&gt;
* {{v render:rife.render.QrCode:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.QrCode">rife.render.QrCode</a>
* @since 1.0
*/
public class QrCode implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
var properties = RenderUtils.parsePropertiesString(template.getDefaultValue(valueId));
var size = properties.getProperty("size", "150x150");
return RenderUtils.qrCode(template.getValueOrAttribute(differentiator), size);
}
}

View file

@ -1,602 +0,0 @@
/*
* 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.tools.Localization;
import rife.tools.StringUtils;
import java.io.IOException;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.Normalizer;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Collection of utility-type methods commonly used by the renderers.
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @since 1.0
*/
public final class RenderUtils {
/**
* The encoding property.
*/
public static final String ENCODING_PROPERTY = "encoding";
/**
* ISO 8601 date formatter.
*
* @see <a href="https://en.wikipedia.org/wiki/ISO_8601">ISO 8601</a>
*/
public static final DateTimeFormatter ISO_8601_DATE_FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd").withLocale(Localization.getLocale());
/**
* ISO 8601 date and time formatter.
*
* @see <a href="https://en.wikipedia.org/wiki/ISO_8601">ISO 8601</a>
*/
public static final DateTimeFormatter ISO_8601_FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXXXX").withLocale(Localization.getLocale());
/**
* ISO 8601 time formatter.
*
* @see <a href="https://en.wikipedia.org/wiki/ISO_8601">ISO 8601</a>
*/
public static final DateTimeFormatter ISO_8601_TIME_FORMATTER =
DateTimeFormatter.ofPattern("HH:mm:ss").withLocale(Localization.getLocale());
/**
* ISO 8601 Year formatter.
*
* @see <a href="https://en.wikipedia.org/wiki/ISO_8601">ISO 8601</a>
*/
static public final DateTimeFormatter ISO_8601_YEAR_FORMATTER =
DateTimeFormatter.ofPattern("yyyy").withLocale(Localization.getLocale());
/**
* RFC 2822 date and time formatter.
*
* @see <a href="https://www.rfc-editor.org/rfc/rfc2822">RFC 2822</a>
*/
public static final DateTimeFormatter RFC_2822_FORMATTER =
DateTimeFormatter.ofPattern("EEE, d MMM yyyy HH:mm:ss zzz").withLocale(Localization.getLocale());
private static final String DEFAULT_USER_AGENT =
"Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0";
private final static Logger LOGGER = Logger.getLogger(RenderUtils.class.getName());
private RenderUtils() {
// no-op
}
/**
* Abbreviates a {@code String} to the given length using a replacement marker.
*
* @param src the source {@code String}
* @param max the maximum length of the resulting {@code String}
* @param marker the {@code String} used as a replacement marker
* @return the abbreviated {@code String}
*/
public static String abbreviate(String src, int max, String marker) {
if (src == null || src.isBlank() || marker == null) {
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.
*
* @param zonedDateTime the date and time
* @return the .beat time. (eg.: {@code @248})
*/
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);
return String.format("@%03d", beats);
}
/**
* <p>Encodes the source {@code String} to the specified encoding.</p>
*
* <p>The supported encodings are:</p>
*
* <ul>
* <li>{@code html}</li>
* <li>{@code js}</li>
* <li>{@code json}</li>
* <li>{@code unicode}</li>
* <li>{@code url}</li>
* <li>{@code xml}</li>
* </ul>
*
* @param src the source {@code String} to encode
* @param properties the properties containing the {@link #ENCODING_PROPERTY encoding property}.
* @return the encoded {@code String}
*/
public static String encode(String src, Properties properties) {
if (src == null || src.isBlank() || properties.isEmpty()) {
return src;
}
var encoding = properties.getProperty(ENCODING_PROPERTY, "");
switch (encoding) {
case "html" -> {
return StringUtils.encodeHtml(src);
}
case "js" -> {
return RenderUtils.encodeJs(src);
}
case "json" -> {
return StringUtils.encodeJson(src);
}
case "unicode" -> {
return StringUtils.encodeUnicode(src);
}
case "url" -> {
return StringUtils.encodeUrl(src);
}
case "xml" -> {
return StringUtils.encodeXml(src);
}
default -> {
return src;
}
}
}
/**
* Encodes a {@code String} to JavaScript/ECMAScript.
*
* @param src the source {@code String}
* @return the encoded {@code String}
*/
public static String encodeJs(String src) {
if (src == null || src.isBlank()) {
return src;
}
var len = src.length();
var sb = new StringBuilder(len);
char c;
for (var i = 0; i < len; i++) {
c = src.charAt(i);
switch (c) {
case '\'' -> sb.append("\\'");
case '"' -> sb.append("\\\"");
case '\\' -> sb.append("\\\\");
case '/' -> sb.append("\\/");
default -> sb.append(c);
}
}
return sb.toString();
}
/**
* Fetches the content (body) of a URL.
*
* @param url the URL {@code 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 fetchUrl = new URL(url);
try {
var connection = (HttpURLConnection) fetchUrl.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);
}
} else {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.warning("A " + code + " status code was returned by " + fetchUrl.getHost());
}
}
} catch (IOException ioe) {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.log(Level.WARNING, "An IO error occurred while connecting to " + fetchUrl.getHost(), ioe);
}
}
} catch (MalformedURLException ignore) {
// do nothing
}
return defaultContent;
}
/**
* <p>Returns the last 4 digits a credit card number.</p>
*
* <ul>
* <li>The number must satisfy the Luhn algorithm</li>
* <li>Non-digits are stripped from the number</li>
* </ul>
*
* @param src the credit card number
* @return the last 4 digits of the credit card number or empty
*/
public static String formatCreditCard(String src) {
if (src == null || src.isBlank()) {
return src;
}
var cc = src.replaceAll("[^0-9]", "");
if (validateCreditCard(cc)) {
return cc.substring(cc.length() - 4);
} else {
return "";
}
}
/**
* Converts a text {@code String} to HTML decimal entities.
*
* @param src the {@code String} to convert
* @return the converted {@code String}
*/
@SuppressWarnings("PMD.AvoidReassigningLoopVariables")
public static String htmlEntities(String src) {
if (src == null || src.isEmpty()) {
return src;
}
var len = src.length();
var sb = new StringBuilder(len * 6);
// https://stackoverflow.com/a/6766497/8356718
int codePoint;
for (var i = 0; i < len; i++) {
codePoint = src.codePointAt(i);
// Skip over the second char in a surrogate pair
if (codePoint > 0xffff) {
i++;
}
sb.append(String.format("&#%s;", codePoint));
}
return sb.toString();
}
/**
* Masks characters in a String.
*
* @param src the source {@code String}
* @param mask the {@code String} to mask characters with
* @param unmasked the number of characters to leave unmasked
* @param fromStart to unmask characters from the start of the {@code String}
* @return the masked {@code String}
*/
public static String mask(String src, String mask, int unmasked, boolean fromStart) {
if (src == null || src.isEmpty()) {
return src;
}
var len = src.length();
var buff = new StringBuilder(len);
if (unmasked > 0 && unmasked < len) {
if (fromStart) {
buff.append(src, 0, unmasked);
}
buff.append(mask.repeat(len - unmasked));
if (!fromStart) {
buff.append(src.substring(len - unmasked));
}
} else {
buff.append(mask.repeat(len));
}
return buff.toString();
}
/**
* Normalizes a {@code String} for inclusion in a URL path.
*
* @param src the source {@code String}
* @return the normalized {@code String}
*/
public static String normalize(String src) {
if (src == null || src.isBlank()) {
return src;
}
var normalized = Normalizer.normalize(src.trim(), Normalizer.Form.NFD);
var sb = new StringBuilder(normalized.length());
boolean space = false;
for (var c : normalized.toCharArray()) {
if (c <= '\u007F') { // ascii only
if (!space && c == ' ') {
space = true;
sb.append('-');
} else {
space = false;
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z')) {
sb.append(c);
} else if (c >= 'A' && c <= 'Z') {
sb.append((char) (c + 32)); // lowercase
}
}
}
}
return sb.toString();
}
/**
* Returns a new {@code Properties} containing the properties specified in the given {@code String}.
*
* @param src the {@code} String containing the properties
* @return the new {@code Properties}
*/
public static Properties parsePropertiesString(String src) {
var properties = new Properties();
if (src != null && !src.isBlank()) {
try {
properties.load(new StringReader(src));
} catch (IOException ignore) {
// ignore
}
}
return properties;
}
/**
* Returns the plural form of a word, if count &gt; 1.
*
* @param count the count
* @param word the singular word
* @param plural the plural word
* @return the singular or plural {@code String}
*/
public static String plural(final long count, final String word, final String plural) {
if (count > 1) {
return plural;
} else {
return word;
}
}
/**
* Generates an SVG QR Code from the given {@code String} using <a href="https://goqr.me/">goQR.me</a>.
*
* @param src the data {@code String}
* @param size the QR Code size. (e.g. {@code 150x150})
* @return the QR code
*/
public static String qrCode(String src, String size) {
if (src == null || src.isBlank()) {
return src;
}
return fetchUrl(String.format("https://api.qrserver.com/v1/create-qr-code/?format=svg&size=%s&data=%s",
StringUtils.encodeUrl(size),
StringUtils.encodeUrl(src.trim())),
src);
}
/**
* Translates a {@code String} to/from ROT13.
*
* @param src the source {@code String}
* @return the translated {@code String}
*/
public static String rot13(String src) {
if (src == null || src.isBlank()) {
return src;
}
var len = src.length();
var output = new StringBuilder(len);
for (var i = 0; i < len; i++) {
var inChar = src.charAt(i);
if ((inChar >= 'A') && (inChar <= 'Z')) {
inChar += (char) 13;
if (inChar > 'Z') {
inChar -= (char) 26;
}
}
if ((inChar >= 'a') && (inChar <= 'z')) {
inChar += (char) 13;
if (inChar > 'z') {
inChar -= (char) 26;
}
}
output.append(inChar);
}
return output.toString();
}
/**
* <p>Shortens a URL using <a href="https://is.gd/">is.gid</a>.</p>
*
* <p>The URL {@code String} must be a valid http or https URL.</p>
*
* <p>Based on <a href="https://github.com/ethauvin/isgd-shorten">isgd-shorten</a></p>
*
* @param url the source URL
* @return the short URL
*/
public static String shortenUrl(String url) {
if (url == null || url.isBlank() || !url.matches("^[Hh][Tt][Tt][Pp][Ss]?://\\w.*")) {
return url;
}
return fetchUrl(String.format("https://is.gd/create.php?format=simple&url=%s",
StringUtils.encodeUrl(url.trim())), url);
}
/**
* Swaps the case of a String.
*
* @param src the {@code String} to swap the case of
* @return the modified {@code String} or null
*/
@SuppressWarnings("PMD.AvoidReassigningLoopVariables")
public static String swapCase(String src) {
if (src == null || src.isBlank()) {
return src;
}
int offset = 0;
var len = src.length();
var buff = new int[len];
for (var i = 0; i < len; ) {
int newCodePoint;
var curCodePoint = src.codePointAt(i);
if (Character.isUpperCase(curCodePoint) || Character.isTitleCase(curCodePoint)) {
newCodePoint = Character.toLowerCase(curCodePoint);
} else if (Character.isLowerCase(curCodePoint)) {
newCodePoint = Character.toUpperCase(curCodePoint);
} else {
newCodePoint = curCodePoint;
}
buff[offset++] = newCodePoint;
i += Character.charCount(newCodePoint);
}
return new String(buff, 0, offset);
}
/**
* <p>Returns the formatted server uptime.</p>
*
* <p>The default Properties are:</p>
*
* <pre>
* year=\ year\u29F5u0020
* years=\ years\u29F5u0020
* month=\ month\u29F5u0020
* months=\ months\u29F5u0020
* week=\ week\u29F5u0020
* weeks=\ weeks\u29F5u0020
* day=\ day\u29F5u0020
* days=\ days\u29F5u0020
* hour=\ hour\u29F5u0020
* hours=\ hours\u29F5u0020
* minute=\ minute
* minutes=\ minutes
* </pre>
*
* @param uptime the uptime in milliseconds
* @param properties the format properties
* @return the formatted uptime
*/
@SuppressWarnings("UnnecessaryUnicodeEscape")
public static String uptime(long uptime, Properties properties) {
var sb = new StringBuilder();
var days = TimeUnit.MILLISECONDS.toDays(uptime);
var years = days / 365;
days %= 365;
var months = days / 30;
days %= 30;
var weeks = days / 7;
days %= 7;
var hours = TimeUnit.MILLISECONDS.toHours(uptime) - TimeUnit.DAYS.toHours(TimeUnit.MILLISECONDS.toDays(uptime));
var minutes = TimeUnit.MILLISECONDS.toMinutes(uptime) - TimeUnit.HOURS.toMinutes(
TimeUnit.MILLISECONDS.toHours(uptime));
if (years > 0) {
sb.append(years).append(plural(years, properties.getProperty("year", " year "),
properties.getProperty("years", " years ")));
}
if (months > 0) {
sb.append(months).append(plural(months, properties.getProperty("month", " month "),
properties.getProperty("months", " months ")));
}
if (weeks > 0) {
sb.append(weeks).append(plural(weeks, properties.getProperty("week", " week "),
properties.getProperty("weeks", " weeks ")));
}
if (days > 0) {
sb.append(days).append(plural(days, properties.getProperty("day", " day "),
properties.getProperty("days", " days ")));
}
if (hours > 0) {
sb.append(hours).append(plural(hours, properties.getProperty("hour", " hour "),
properties.getProperty("hours", " hours ")));
}
sb.append(minutes).append(plural(minutes, properties.getProperty("minute", " minute"),
properties.getProperty("minutes", " minutes")));
return sb.toString();
}
/**
* Validates a credit card number using the Luhn algorithm.
*
* @param cc the credit card number
* @return {@code true} if the credit card number is valid
*/
public static boolean validateCreditCard(String cc) {
try {
var len = cc.length();
if (len >= 8 && len <= 19) {
// Luhn algorithm
var sum = 0;
boolean second = false;
int digit;
char c;
for (int i = len - 1; i >= 0; i--) {
c = cc.charAt(i);
if (c >= '0' && c <= '9') {
digit = cc.charAt(i) - '0';
if (second) {
digit = digit * 2;
}
sum += digit / 10;
sum += digit % 10;
second = !second;
}
}
if (sum % 10 == 0) {
return true;
}
}
} catch (NumberFormatException ignore) {
// do nothing
}
return false;
}
}

View file

@ -1,45 +0,0 @@
/*
* 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;
/**
* <p>Translates a template value to/from ROT13.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.Rot13:valueId/--&gt;
* {{v render:rife.render.Rot13:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.Rot13">rife.render.Rot13</a>
* @since 1.0
*/
public class Rot13 implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
return template.getEncoder().encode(RenderUtils.rot13(template.getValueOrAttribute(differentiator)));
}
}

View file

@ -1,47 +0,0 @@
/*
* 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;
/**
* <p>Shortens a template value using <a href="https://is.gd/">is.gid</a>. The value must a valid http or https URL.</p>
*
* <p>Based on <a href="https://github.com/ethauvin/isgd-shorten">isgd-shorten</a></p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.ShortenUrl:valueId/--&gt;
* {{v render:rife.render.ShortenUrl:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.ShortenUrl">rife.render.ShortenUrl</a>
* @since 1.0
*/
public class ShortenUrl implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
return template.getEncoder().encode(RenderUtils.shortenUrl(template.getValueOrAttribute(differentiator)));
}
}

View file

@ -1,46 +0,0 @@
/*
* 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;
/**
* <p>Swap case of a template value.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.SwapCase:valueId/--&gt;
* {{v render:rife.render.SwapCase:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.SwapCase">rife.render.SwapCase</a>
* @since 1.0
*/
public class SwapCase implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
return template.getEncoder().encode(RenderUtils.swapCase(template.getValueOrAttribute(differentiator)));
}
}

View file

@ -1,47 +0,0 @@
/*
* 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.time.ZonedDateTime;
/**
* <p>Return the current time in ISO 8601 format.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.TimeIso/--&gt;
* {{v render:rife.render.TimeIso/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.TimeIso">rife.render.TimeIso</a>
* @since 1.0
*/
public class TimeIso implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
return template.getEncoder().encode(ZonedDateTime.now().format(RenderUtils.ISO_8601_TIME_FORMATTER));
}
}

View file

@ -1,49 +0,0 @@
/*
* 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;
/**
* <p>Removes leading and trailing whitespace from a template value.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.Trim:valueId/--&gt;
* {{v render:rife.render.Trim:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.Trim">rife.render.Trim</a>
* @since 1.0
*/
public class Trim implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
var value = template.getValueOrAttribute(differentiator);
if (value == null || value.isEmpty()) {
return value;
}
return template.getEncoder().encode(value.trim());
}
}

View file

@ -1,46 +0,0 @@
/*
* 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 rife.tools.StringUtils;
/**
* <p>Un-capitalizes a template value.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.Uncapitalize:valueId/--&gt;
* {{v render:rife.render.Uncapitalize:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.Uncapitalize">rife.render.Uncapitalize</a>
* @since 1.0
*/
public class Uncapitalize implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
return template.getEncoder().encode(StringUtils.uncapitalize(template.getValueOrAttribute(differentiator)));
}
}

View file

@ -1,50 +0,0 @@
/*
* 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 rife.tools.Localization;
/**
* <p>Convert a template value to uppercase.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.Uppercase:valueId/--&gt;
* {{v render:rife.render.Uppercase:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* #see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.Uppercase">rife.render.Uppercase</a>
* @since 1.0
*/
public class Uppercase implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
var value = template.getValueOrAttribute(differentiator);
if (value == null || value.isBlank()) {
return value;
}
return template.getEncoder().encode(value.toUpperCase(Localization.getLocale()));
}
}

View file

@ -1,55 +0,0 @@
/*
* 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.lang.management.ManagementFactory;
/**
* Renders the server uptime.
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.Uptime/--&gt;
* {{v render:rife.render.Uptime/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.Uptime">rife.render.Uptime</a>
* @since 1.0
*/
public class Uptime implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
var properties = RenderUtils.parsePropertiesString(template.getDefaultValue(valueId));
String uptime;
if (template.hasAttribute(Uptime.class.getName())) {
uptime = RenderUtils.uptime((long) template.getAttribute(Uptime.class.getName()), properties);
} else {
uptime = RenderUtils.uptime(ManagementFactory.getRuntimeMXBean().getUptime(), properties);
}
return template.getEncoder().encode(uptime);
}
}

View file

@ -1,48 +0,0 @@
/*
* 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.time.ZonedDateTime;
/**
* <p>Renders the current year.</p>
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.Year/--&gt;
* {{v render:rife.render.Year/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.rennder.Year">rife.render.Year</a>
* @since 1.0
*/
public class Year implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
return template.getEncoder().encode(ZonedDateTime.now().format(RenderUtils.ISO_8601_YEAR_FORMATTER));
}
}

View file

@ -1,72 +0,0 @@
/*
* 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 org.junit.jupiter.api.Test;
import rife.template.TemplateFactory;
import rife.tools.Localization;
import static org.assertj.core.api.Assertions.assertThat;
class TestCase {
static final String FOO = "foo";
static final String SAMPLE_TEXT = "This is a test.";
@Test
void testCapitalize() {
var t = TemplateFactory.TXT.get("capitalize");
t.setAttribute(FOO, SAMPLE_TEXT.toLowerCase(Localization.getLocale()));
assertThat(t.getContent()).isEqualTo(SAMPLE_TEXT);
}
@Test
void testLowercase() {
var t = TemplateFactory.TXT.get("lowercase");
var bean = new ValueBean("this IS a TEST.");
t.setBean(bean);
assertThat(t.getContent()).isEqualTo(bean.getValue() + ": this is a test.");
}
@Test
void testSwapCase() {
var t = TemplateFactory.TXT.get("swapCase");
t.setAttribute(FOO, "tHiS iS a TeSt");
assertThat(t.getContent()).isEqualTo("ThIs Is A tEsT");
}
@Test
void testTrim() {
var t = TemplateFactory.TXT.get("trim");
t.setAttribute(FOO, "\t" + SAMPLE_TEXT + " \n");
assertThat(t.getContent()).isEqualTo(SAMPLE_TEXT);
}
@Test
void testUncapitalize() {
var t = TemplateFactory.TXT.get("uncapitalize");
t.setAttribute(FOO, SAMPLE_TEXT);
assertThat(t.getContent()).isEqualTo(SAMPLE_TEXT.toLowerCase(Localization.getLocale()));
}
@Test
void testUppercase() {
var t = TemplateFactory.TXT.get("uppercase");
t.setAttribute("bar", SAMPLE_TEXT);
assertThat(t.getContent()).isEqualTo(SAMPLE_TEXT.toUpperCase(Localization.getLocale()));
}
}

View file

@ -1,72 +0,0 @@
/*
* 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 org.junit.jupiter.api.Test;
import rife.template.TemplateFactory;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
class TestDateTime {
@Test
void testBestTime() {
var t = TemplateFactory.HTML.get("beatTime");
assertThat(t.getContent()).matches("@\\d{3}");
}
@Test
void testDateIso() {
var t = TemplateFactory.HTML.get("dateIso");
assertThatCode(() -> RenderUtils.ISO_8601_DATE_FORMATTER.parse(t.getContent())).doesNotThrowAnyException();
}
@Test
void testDateTimeIso() {
var t = TemplateFactory.HTML.get("dateTimeIso");
assertThatCode(() -> RenderUtils.ISO_8601_FORMATTER.parse(t.getContent())).doesNotThrowAnyException();
}
@Test
void testDateTimeRfc2822() {
var t = TemplateFactory.HTML.get("dateTimeRfc2822");
assertThatCode(() -> RenderUtils.RFC_2822_FORMATTER.parse(t.getContent())).doesNotThrowAnyException();
}
@Test
void testDateTimeUtc() {
var t = TemplateFactory.HTML.get("dateTimeUtc");
var content = t.getContent();
assertThatCode(() -> RenderUtils.ISO_8601_FORMATTER.parse(content)).doesNotThrowAnyException();
assertThat(content).endsWith("Z");
}
@Test
void testTimeIso() {
var t = TemplateFactory.HTML.get("timeIso");
assertThatCode(() -> RenderUtils.ISO_8601_TIME_FORMATTER.parse(t.getContent())).doesNotThrowAnyException();
}
@Test
void testYear() {
var t = TemplateFactory.HTML.get("year");
var year = java.time.Year.now().toString();
assertThat(t.getContent()).isEqualTo(year + "<br>" + year);
}
}

View file

@ -1,121 +0,0 @@
/*
* 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 org.junit.jupiter.api.Test;
import rife.template.TemplateFactory;
import static org.assertj.core.api.Assertions.assertThat;
class TestEncode {
@Test
void testEncodeBase64() {
var t = TemplateFactory.TXT.get("encodeBase64");
t.setValue(TestCase.FOO, TestCase.SAMPLE_TEXT);
assertThat(t.getContent()).isEqualTo(t.getValue(TestCase.FOO) + ": VGhpcyBpcyBhIHRlc3Qu");
t = TemplateFactory.HTML.get("encodeBase64");
t.setValue(TestCase.FOO, TestCase.SAMPLE_TEXT + " URL Encoded.");
assertThat(t.getContent()).as("with URL encoding").contains("VGhpcyBpcyBhIHRlc3QuIFVSTCBFbmNvZGVkLg%3D%3D");
}
@Test
void testEncodeHtml() {
var t = TemplateFactory.HTML.get("encodeHtml");
t.setAttribute(TestCase.FOO, "<a test &>");
assertThat(t.getContent()).isEqualTo("&lt;a test &amp;&gt;");
}
@Test
void testEncodeHtmlEntities() {
var t = TemplateFactory.HTML.get("encodeHtmlEntities");
t.setAttribute(TestCase.FOO, "john@doe.com");
assertThat(t.getContent()).isEqualTo(
"<a href=\"mailto:&#106;&#111;&#104;&#110;&#64;&#100;&#111;&#101;&#46;&#99;&#111;&#109;\">Email</a>");
}
@Test
void testEncodeJs() {
var t = TemplateFactory.TXT.get("encodeJs");
t.setAttribute(TestCase.FOO, "'\"\\/");
assertThat(t.getContent()).isEqualTo("\\'\\\"\\\\\\/");
t = TemplateFactory.HTML.get("encodeJs");
t.setAttribute(TestCase.FOO, '"' + TestCase.SAMPLE_TEXT + '"');
assertThat(t.getContent()).as("with unicode")
.isEqualTo("\\u005C\\u0022\\u0054\\u0068\\u0069\\u0073\\u0020\\u0069\\u0073\\u0020\\u0061\\u0020\\u0074\\u0065\\u0073\\u0074\\u002E\\u005C\\u0022");
}
@Test
void testEncodeJson() {
var t = TemplateFactory.JSON.get("encodeJson");
t.setAttribute(TestCase.FOO, "This is a \"•test\"");
assertThat(t.getContent()).isEqualTo("{\n \"foo\": \"This is a \\\"\\u2022test\\\"\"\n}");
t = TemplateFactory.HTML.get("encodeJson");
t.setAttribute(TestCase.FOO, "\"<test>\"");
assertThat(t.getContent()).as("with html").isEqualTo("\\&quot;&lt;test&gt;\\&quot;");
}
@Test
void testEncodeRot13() {
var t = TemplateFactory.TXT.get("rot13");
var rot13 = "Guvf vf n grfg.";
// Encode
var bean = new ValueBean(TestCase.SAMPLE_TEXT);
t.setBean(bean);
assertThat(t.getContent()).as("encode").isEqualTo(bean.getValue() + ": " + rot13);
// Decode
t.setValue("value", rot13);
assertThat(t.getContent()).as("decode").isEqualTo(rot13 + ": " + TestCase.SAMPLE_TEXT);
}
@Test
void testEncodeUnicode() {
var t = TemplateFactory.TXT.get("encodeUnicode");
t.setAttribute(TestCase.FOO, TestCase.SAMPLE_TEXT);
assertThat(t.getContent()).isEqualTo(
"\\u0054\\u0068\\u0069\\u0073\\u0020\\u0069\\u0073\\u0020\\u0061\\u0020\\u0074\\u0065\\u0073\\u0074\\u002E");
t = TemplateFactory.HTML.get("encodeUnicode");
t.setAttribute(TestCase.FOO, '"' + TestCase.SAMPLE_TEXT + '"');
assertThat(t.getContent()).as("with js")
.contains("'\\\\u0022\\\\u0054\\\\u0068\\\\u0069\\\\u0073\\\\u0020\\\\u0069\\\\u0073\\\\u0020\\\\u0061\\\\u0020\\\\u0074\\\\u0065\\\\u0073\\\\u0074\\\\u002E\\\\u0022'");
}
@Test
void testEncodeUrl() {
var t = TemplateFactory.HTML.get("encodeUrl");
t.setAttribute(TestCase.FOO, "a test &");
assertThat(t.getContent()).isEqualTo("<a href=\"https://example.com/a%20test%20%26\">a test &amp;</a>");
t = TemplateFactory.HTML.get("encodeUrlwithUnicode");
t.setAttribute(TestCase.FOO, "a=test");
assertThat(t.getContent()).as("with unicode")
.contains("https://foo.com/\\u0061\\u0025\\u0033\\u0044\\u0074\\u0065\\u0073\\u0074");
}
@Test
void testEncodeXml() {
var t = TemplateFactory.XML.get("encodeXml");
t.setAttribute(TestCase.FOO, "a test &");
assertThat(t.getContent()).isEqualTo("<test>\n <foo>a test &amp;</foo>\n</test>");
}
}

View file

@ -1,118 +0,0 @@
/*
* 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 org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
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);
assertThat(t.getContent()).as("activate.html").endsWith("&hellip;").hasSize(19);
t = TemplateFactory.TXT.get("abbreviate");
t.setAttribute(TestCase.FOO, TestCase.SAMPLE_TEXT);
assertThat(t.getContent()).as("activate.txt").endsWith("...").hasSize(8);
}
@Test
void testFormatCreditCard() {
var t = TemplateFactory.TXT.get("formatCreditCard");
t.setAttribute(TestCase.FOO, "4342 2565 6244 0179");
assertThat(t.getContent()).as("US VISA").isEqualTo("0179");
t.setAttribute(TestCase.FOO, "5130-3899-9169-8324");
assertThat(t.getContent()).as("FR MASTERCARD").isEqualTo("8324");
t.setAttribute(TestCase.FOO, "374380141731053");
assertThat(t.getContent()).as("UK AMEX").isEqualTo("1053");
t.setAttribute(TestCase.FOO, "000000000000001");
assertThat(t.getContent()).isEmpty();
}
@Test
void testMask() {
var t = TemplateFactory.HTML.get("mask");
var foo = "374380141731053";
t.setAttribute(TestCase.FOO, foo);
assertThat(t.getContent()).as("mask.html")
.isEqualTo("3743&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;");
t = TemplateFactory.TXT.get("mask");
t.setAttribute(TestCase.FOO, foo);
assertThat(t.getContent()).as("mask.txt").isEqualTo("***************");
}
@Test
void testNormalize() {
var t = TemplateFactory.HTML.get("normalize");
var foo = "News for January 6, 2023 (Paris)";
t.setValue(TestCase.FOO, foo);
assertThat(t.getContent()).isEqualTo("<a href=\"news/20230106/news-for-january-6-2023-paris\">"
+ foo + "</a>");
}
@Test
@Tag("no-ci")
void testQrCode() {
var t = TemplateFactory.SVG.get("qrCode");
var foo = "https://example.com/";
t.setAttribute(TestCase.FOO, foo);
assertThat(t.getContent()).startsWith("<?xml").contains("<desc>" + foo + "</desc").contains("width=\"200\"");
}
@Test
@Tag("no-ci")
void testShortenUrl() {
var t = TemplateFactory.HTML.get("shortenUrl");
var url = "https://example.com/";
var shortUrl = "https://is.gd/AG3Hwv";
t.setValue(TestCase.FOO, url);
assertThat(t.getContent()).isEqualTo(String.format("<a href=\"%s\">%s</a>", shortUrl, url));
t.setValue(TestCase.FOO, TestCase.FOO);
assertThat(t.getContent()).isEqualTo("<a href=\"foo\">foo</a>");
}
@Test
void testUptime() {
var t = TemplateFactory.TXT.get("uptime");
assertThat(t.getContent()).as("uptime.txt").isEqualTo("0 minute\n0 minuto\n0 minute");
t = TemplateFactory.HTML.get("uptime");
t.setAttribute(Uptime.class.getName(), 547800300076L);
assertThat(t.getContent()).as("uptime.html")
.isEqualTo("17 ann&eacute;es, 4 mois, 2 semaines, 1 jour, 6 heures, 45 minutes");
t.setAttribute(Uptime.class.getName(), 120000L);
assertThat(t.getContent()).as("uptime.html: 2 min").isEqualTo("2 minutes");
t = TemplateFactory.JSON.get("uptime");
t.setAttribute(Uptime.class.getName(), 5999964460000L);
assertThat(t.getContent()).as("uptime.json")
.isEqualTo("190 years 3 months 4 days 47 minutes");
t.setAttribute(Uptime.class.getName(), 34822860000L);
assertThat(t.getContent()).as("uptime.json: 1 year...")
.isEqualTo("1 year 1 month 1 week 1 day 1 hour 1 minute");
t = TemplateFactory.TXT.get("uptime2");
t.setAttribute(Uptime.class.getName(), 547800388076L);
assertThat(t.getContent()).as("uptime2.txt").isEqualTo("17YRS-4MOS-2WKS-1D-6H-46M");
}
}

View file

@ -1,100 +0,0 @@
/*
* 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 org.junit.jupiter.api.Test;
import java.util.Properties;
import static org.assertj.core.api.Assertions.assertThat;
class TestRenderUtils {
static final String SAMPLE_GERMAN = "Möchten Sie ein paar Äpfel?";
@Test
void testAbbreviate() {
assertThat(RenderUtils.abbreviate(TestCase.SAMPLE_TEXT, 9, "")).as("max=9")
.isEqualTo("This is a");
assertThat(RenderUtils.abbreviate(TestCase.SAMPLE_TEXT, 0, "")).as("max=0").isEmpty();
assertThat(RenderUtils.abbreviate(TestCase.SAMPLE_TEXT, -1, "")).as("max=-1")
.isEqualTo(TestCase.SAMPLE_TEXT);
}
@Test
void testEncode() {
var p = new Properties();
p.put(RenderUtils.ENCODING_PROPERTY, "html");
assertThat(RenderUtils.encode("<a test &>", p)).as("html").isEqualTo("&lt;a test &amp;&gt;");
p.put(RenderUtils.ENCODING_PROPERTY, "js");
assertThat(RenderUtils.encode("\"test'", p)).as("js").isEqualTo("\\\"test\\'");
p.put(RenderUtils.ENCODING_PROPERTY, "unicode");
assertThat(RenderUtils.encode("test", p)).as("unicode").isEqualTo("\\u0074\\u0065\\u0073\\u0074");
p.put(RenderUtils.ENCODING_PROPERTY, "url");
assertThat(RenderUtils.encode("a = test", p)).as("url").isEqualTo("a%20%3D%20test");
p.put(RenderUtils.ENCODING_PROPERTY, "xml");
assertThat(RenderUtils.encode("Joe's Café & Bar", p)).as("xml").isEqualTo("Joe&apos;s Café &amp; Bar");
}
@Test
void testHtmlEntities() {
assertThat(RenderUtils.htmlEntities(SAMPLE_GERMAN))
.isEqualTo("&#77;&#246;&#99;&#104;&#116;&#101;&#110;&#32;&#83;&#105;&#101;&#32;&#101;&#105;&#110;&#32;&#112;&#97;&#97;&#114;&#32;&#196;&#112;&#102;&#101;&#108;&#63;");
}
@Test
void testMask() {
var foo = "4342256562440179";
assertThat(RenderUtils.mask(foo, "?", 4, false)).as("mask=?")
.isEqualTo("????????????0179");
assertThat(RenderUtils.mask(foo, "-", 22, true)).as("unmasked=22")
.isEqualTo("----------------");
assertThat(RenderUtils.mask(foo, "&bull;", -1, false)).as("mask=&bull;")
.isEqualTo("&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;");
}
@Test
void testNormalize() {
assertThat(RenderUtils.normalize(SAMPLE_GERMAN)).isEqualTo("mochten-sie-ein-paar-apfel");
}
@Test
void testRot13() {
var encoded = "Zöpugra Fvr rva cnne Äcsry?";
assertThat(RenderUtils.rot13(SAMPLE_GERMAN)).as("encode").isEqualTo(encoded);
assertThat(RenderUtils.rot13(encoded)).as("decode").isEqualTo(SAMPLE_GERMAN);
}
@Test
void testSwapCase() {
assertThat(RenderUtils.swapCase(SAMPLE_GERMAN)).isEqualTo("mÖCHTEN sIE EIN PAAR äPFEL?");
}
@Test
void testValidateCreditCard() {
assertThat(RenderUtils.validateCreditCard("4505 4672 3366 6430")).as("visa").isTrue();
assertThat(RenderUtils.validateCreditCard("5189-5923-3915-0425")).as("mastercard").isTrue();
assertThat(RenderUtils.validateCreditCard("3433634926643302")).as("amex").isTrue();
assertThat(RenderUtils.validateCreditCard("6011 1076-8252 0629")).as("discover").isTrue();
assertThat(RenderUtils.validateCreditCard("0123456789012345")).as("invalid").isFalse();
}
}

View file

@ -1,34 +0,0 @@
/*
* 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;
public class ValueBean {
private String value;
ValueBean(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

View file

@ -1,4 +0,0 @@
<!--v render:rife.render.Abbreviate:foo-->
mark=…
max=12
<!--/v-->

View file

@ -1,3 +0,0 @@
{{v render:rife.render.Abbreviate:foo}}
max=8
{{/v}}

View file

@ -1 +0,0 @@
<!--v render:rife.render.BeatTime/-->

View file

@ -1 +0,0 @@
{{v render:rife.render.Capitalize:foo/}}

View file

@ -1 +0,0 @@
<!--v render:rife.render.DateIso/-->

View file

@ -1 +0,0 @@
<!--v render:rife.render.DateTimeIso/-->

View file

@ -1 +0,0 @@
<!--v render:rife.render.DateTimeRfc2822/-->

View file

@ -1 +0,0 @@
<!--v render:rife.render.DateTimeIso-->tz=UTC<!--/v-->

View file

@ -1 +0,0 @@
<a href="https://foo.com/{{v render:rife.render.EncodeBase64:foo}}encoding=url{{/v}}"><!--v foo/--></a>

View file

@ -1 +0,0 @@
{{v foo/}}: {{v render:rife.render.EncodeBase64:foo/}}

View file

@ -1 +0,0 @@
<!--v render:rife.render.EncodeHtml:foo/-->

View file

@ -1 +0,0 @@
<a href="mailto:{{v render:rife.render.EncodeHtmlEntities:foo/}}">Email</a>

View file

@ -1 +0,0 @@
<!--v render:rife.render.EncodeJs:foo-->encoding=unicode<!--/v-->

View file

@ -1 +0,0 @@
{{v render:rife.render.EncodeJs:foo/}}

View file

@ -1 +0,0 @@
<!--v render:rife.render.EncodeJson:foo-->encoding=html<!--/v-->

View file

@ -1,3 +0,0 @@
{
"foo": "{{v render:rife.render.EncodeJson:foo/}}"
}

View file

@ -1 +0,0 @@
<script>alert('{{v render:rife.render.EncodeUnicode:foo}}encoding=js{{/v}}');</script>

View file

@ -1 +0,0 @@
{{v render:rife.render.EncodeUnicode:foo/}}

View file

@ -1 +0,0 @@
<a href="https://example.com/{{v render:rife.render.EncodeUrl:foo/}}">{{v render:rife.render.EncodeHtml:foo/}}</a>

View file

@ -1 +0,0 @@
<script>window.open("https://foo.com/{{v render:rife.render.EncodeUrl:foo}}encoding=unicode{{/v}}")</script>

View file

@ -1,3 +0,0 @@
<test>
<foo>{{v render:rife.render.EncodeXml:foo/}}</foo>
</test>

View file

@ -1 +0,0 @@
{{v render:rife.render.FormatCreditCard:foo/}}

View file

@ -1 +0,0 @@
{{v value/}}: {{v render:rife.render.Lowercase:value/}}

View file

@ -1,5 +0,0 @@
<!--v render:rife.render.Mask:foo-->
mask=•
unmasked=4
fromStart=true
<!--/v-->

View file

@ -1 +0,0 @@
{{v render:rife.render.Mask:foo/}}

View file

@ -1 +0,0 @@
<a href="news/20230106/{{v render:rife.render.Normalize:foo/}}"><!--v foo/--></a>

View file

@ -1 +0,0 @@
{{v render:rife.render.QrCode:foo}}size=200x200{{/v}}

View file

@ -1 +0,0 @@
{{v value/}}: {{v render:rife.render.Rot13:value/}}

View file

@ -1 +0,0 @@
<a href="{{v render:rife.render.ShortenUrl:foo/}}"><!--v foo/--></a>

View file

@ -1 +0,0 @@
{{v render:rife.render.SwapCase:foo/}}

View file

@ -1 +0,0 @@
<!--v render:rife.render.TimeIso/-->

View file

@ -1 +0,0 @@
{{v render:rife.render.Trim:foo/}}

View file

@ -1 +0,0 @@
{{v render:rife.render.Uncapitalize:foo/}}

View file

@ -1 +0,0 @@
{{v render:rife.render.Uppercase:bar/}}

View file

@ -1,13 +0,0 @@
<!--v render:rife.render.Uptime-->
year=\ année,\u0020
years=\ années,\u0020
month=\ moi,\u0020
months=\ mois,\u0020
week=\ semaine,\u0020
weeks=\ semaines,\u0020
day=\ jour,\u0020
days=\ jours,\u0020
hour=\ heure,\u0020
hours=\ heures,\u0020
minute=\ minute
minutes=\ minutes<!--/v-->

View file

@ -1 +0,0 @@
{{v render:rife.render.Uptime/}}

View file

@ -1,6 +0,0 @@
{{v render:rife.render.Uptime/}}
{{v render:rife.render.Uptime:spanish}}
minute=\ minuto
minutes=\ minutos
{{/v}}
{{v render:rife.render.Uptime:plain}}{{/v}}

View file

@ -1,14 +0,0 @@
{{v render:rife.render.Uptime}}
year=YR-
years=YRS-
month=M0-
months=MOS-
week=WK-
weeks=WKS-
day=D-
days=D-
hour=H-
hours=H-
minute=M
minutes=M
{{/v}}

View file

@ -1 +0,0 @@
<!--v render:rife.render.Year/--><br>{{v render:rife.render.Year/}}