From 7532dcb7bd0f8905391a491d428f195e8d7cbb0e Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 25 May 2024 11:42:22 +0200 Subject: [PATCH 1/6] initial implementation --- .../org/apache/commons/text/CasedString.java | 143 ++++++++++++++++++ .../apache/commons/text/CasedStringTest.java | 47 ++++++ 2 files changed, 190 insertions(+) create mode 100644 src/main/java/org/apache/commons/text/CasedString.java create mode 100644 src/test/java/org/apache/commons/text/CasedStringTest.java diff --git a/src/main/java/org/apache/commons/text/CasedString.java b/src/main/java/org/apache/commons/text/CasedString.java new file mode 100644 index 0000000000..a89cd8626f --- /dev/null +++ b/src/main/java/org/apache/commons/text/CasedString.java @@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.commons.text; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; +import java.util.function.Predicate; + +/** + * Handles converting from one string case to another (e.g. camel case to snake case). + */ +public class CasedString { + private String string; + private StringCase stringCase; + + /** + * A method to join camel string fragments together. + */ + private final static Function camelJoiner = a -> { + StringBuilder sb = new StringBuilder(a[0]); + + for (int i=1;i c =='_', false, a -> String.join("_", a)), + /** + * Kebab case identifies strings like 'kebab-case' + */ + Kebab(c -> c == '-', false, a -> String.join("-", a)), + + /** + * Phrase case identifies phrases of words like 'phrase case' + */ + Phrase(c -> c == ' ', false, a -> String.join(" ", a)), + + /** + * Dot case identifies strings of words like 'dot.case' + */ + Dot(c -> c == '.', false, a -> String.join(".", a)); + + private final Predicate splitter; + private final boolean preserveSplit; + private final Function joiner; + + /** + * Defines a String Case + * @param splitter The predicate that determines when a new word in the cased string begins. + * @param preserveSplit if {@code true} the character that the splitter detected is preserved as the first character of the new word. + * @param joiner The function to merge a list of strings into the cased String. + */ + StringCase(final Predicate splitter, final boolean preserveSplit, final Function joiner) { + this.splitter = splitter; + this.preserveSplit = preserveSplit; + this.joiner = joiner; + } + } + + /** + * A representation of a cased string and the identified case of that string. + * @param stringCase The {@code StringCase} that the {@code string} argument is in. + * @param string The string. + */ + public CasedString(StringCase stringCase, String string) { + this.string = string; + this.stringCase = stringCase; + } + + private String[] split() { + List lst = new ArrayList<>(); + StringBuilder sb = new StringBuilder(); + for (char c : string.toCharArray()) + { + if (stringCase.splitter.test(c)) { + if (sb.length() > 0) { + lst.add(sb.toString()); + sb.setLength(0); + } + if (stringCase.preserveSplit) { + sb.append(c); + } + } else { + sb.append(c); + } + } + if (sb.length() > 0) { + lst.add(sb.toString()); + } + return lst.toArray(new String[0]); + } + + /** + * Converts this cased string into a {@code String} of another format. + * The upper/lower case of the characters within the string are not modified. + * @param stringCase THe fomrat to convert to. + * @return the String current string represented in the new format. + */ + public String toCase(StringCase stringCase) { + if (stringCase == this.stringCase) { + return string; + } + return stringCase.joiner.apply(split()); + } + + /** + * Returns the string representation provided in the constructor. + * @return the string representation. + */ + @Override + public String toString() { + return string; + } +} diff --git a/src/test/java/org/apache/commons/text/CasedStringTest.java b/src/test/java/org/apache/commons/text/CasedStringTest.java new file mode 100644 index 0000000000..14ccc78116 --- /dev/null +++ b/src/test/java/org/apache/commons/text/CasedStringTest.java @@ -0,0 +1,47 @@ +package org.apache.commons.text; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CasedStringTest { + + private static String expectedValue(CasedString.StringCase stringCase) { + switch (stringCase) { + case Camel: + return "HelloWorld"; + case Kebab: + return "Hello-World"; + case Phrase: + return "Hello World"; + case Snake: + return "Hello_World"; + case Dot: + return "Hello.World"; + default: + throw new RuntimeException("Unsupported StringCase: " + stringCase); + } + } + + @ParameterizedTest + @MethodSource("conversionProvider") + public void testConversions(CasedString underTest) { + for (CasedString.StringCase stringCase : CasedString.StringCase.values()) { + assertEquals(expectedValue(stringCase), underTest.toCase(stringCase), () -> "failed converting to " + stringCase); + } + } + + private static Stream conversionProvider() { + List lst = new ArrayList<>(); + for (CasedString.StringCase stringCase : CasedString.StringCase.values()) { + lst.add(Arguments.of(new CasedString(stringCase, expectedValue(stringCase)))); + } + return lst.stream(); + } +} From 306a3d370b8683580ad284e21e6240a693c890f8 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 25 May 2024 11:53:33 +0200 Subject: [PATCH 2/6] added licence header and since tag --- .../org/apache/commons/text/CasedString.java | 1 + .../apache/commons/text/CasedStringTest.java | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/main/java/org/apache/commons/text/CasedString.java b/src/main/java/org/apache/commons/text/CasedString.java index a89cd8626f..2a5c6e55a0 100644 --- a/src/main/java/org/apache/commons/text/CasedString.java +++ b/src/main/java/org/apache/commons/text/CasedString.java @@ -25,6 +25,7 @@ /** * Handles converting from one string case to another (e.g. camel case to snake case). + * @since 1.13.0 */ public class CasedString { private String string; diff --git a/src/test/java/org/apache/commons/text/CasedStringTest.java b/src/test/java/org/apache/commons/text/CasedStringTest.java index 14ccc78116..66fce092f5 100644 --- a/src/test/java/org/apache/commons/text/CasedStringTest.java +++ b/src/test/java/org/apache/commons/text/CasedStringTest.java @@ -1,3 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ package org.apache.commons.text; import org.junit.jupiter.params.ParameterizedTest; From 2ca406408c81c991d355bf60dcb10c4d88082dfe Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 25 May 2024 12:03:51 +0200 Subject: [PATCH 3/6] fixed checkstyle issues --- .../org/apache/commons/text/CasedString.java | 34 +++++++++++-------- .../apache/commons/text/CasedStringTest.java | 8 ++--- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/apache/commons/text/CasedString.java b/src/main/java/org/apache/commons/text/CasedString.java index 2a5c6e55a0..5d1153a5c6 100644 --- a/src/main/java/org/apache/commons/text/CasedString.java +++ b/src/main/java/org/apache/commons/text/CasedString.java @@ -28,16 +28,18 @@ * @since 1.13.0 */ public class CasedString { - private String string; - private StringCase stringCase; + /** the string the the cased format. */ + private final String string; + /** the case of the string. */ + private final StringCase stringCase; /** * A method to join camel string fragments together. */ - private final static Function camelJoiner = a -> { + private static final Function CAMEL_JOINER = a -> { StringBuilder sb = new StringBuilder(a[0]); - for (int i=1;i c =='_', false, a -> String.join("_", a)), + Snake(c -> c == '_', false, a -> String.join("_", a)), /** - * Kebab case identifies strings like 'kebab-case' + * Kebab case identifies strings like 'kebab-case'. */ Kebab(c -> c == '-', false, a -> String.join("-", a)), /** - * Phrase case identifies phrases of words like 'phrase case' + * Phrase case identifies phrases of words like 'phrase case'. */ Phrase(c -> c == ' ', false, a -> String.join(" ", a)), /** - * Dot case identifies strings of words like 'dot.case' + * Dot case identifies strings of words like 'dot.case'. */ Dot(c -> c == '.', false, a -> String.join(".", a)); + /** test for split position character. */ private final Predicate splitter; + /** if {@code true} split position character will be preserved in following segment. */ private final boolean preserveSplit; - private final Function joiner; + /** a function to joing the segments into this case type. */ + private final Function joiner; /** - * Defines a String Case + * Defines a String Case. * @param splitter The predicate that determines when a new word in the cased string begins. * @param preserveSplit if {@code true} the character that the splitter detected is preserved as the first character of the new word. * @param joiner The function to merge a list of strings into the cased String. */ - StringCase(final Predicate splitter, final boolean preserveSplit, final Function joiner) { + StringCase(final Predicate splitter, final boolean preserveSplit, final Function joiner) { this.splitter = splitter; this.preserveSplit = preserveSplit; this.joiner = joiner; @@ -100,8 +105,7 @@ public CasedString(StringCase stringCase, String string) { private String[] split() { List lst = new ArrayList<>(); StringBuilder sb = new StringBuilder(); - for (char c : string.toCharArray()) - { + for (char c : string.toCharArray()) { if (stringCase.splitter.test(c)) { if (sb.length() > 0) { lst.add(sb.toString()); diff --git a/src/test/java/org/apache/commons/text/CasedStringTest.java b/src/test/java/org/apache/commons/text/CasedStringTest.java index 66fce092f5..f0c0007b3d 100644 --- a/src/test/java/org/apache/commons/text/CasedStringTest.java +++ b/src/test/java/org/apache/commons/text/CasedStringTest.java @@ -18,15 +18,15 @@ */ package org.apache.commons.text; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; public class CasedStringTest { From 0ce19d0c1da822201d3d2500166facc024a82e0c Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 25 May 2024 16:20:53 +0200 Subject: [PATCH 4/6] Added javadoc and significant test cases --- .../org/apache/commons/text/CasedString.java | 112 ++++++++++----- .../apache/commons/text/CasedStringTest.java | 129 +++++++++++++++--- 2 files changed, 187 insertions(+), 54 deletions(-) diff --git a/src/main/java/org/apache/commons/text/CasedString.java b/src/main/java/org/apache/commons/text/CasedString.java index 5d1153a5c6..34418cfbe0 100644 --- a/src/main/java/org/apache/commons/text/CasedString.java +++ b/src/main/java/org/apache/commons/text/CasedString.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.function.Function; import java.util.function.Predicate; @@ -37,46 +38,56 @@ public class CasedString { * A method to join camel string fragments together. */ private static final Function CAMEL_JOINER = a -> { - StringBuilder sb = new StringBuilder(a[0]); + StringBuilder sb = new StringBuilder(a[0].toLowerCase(Locale.ROOT)); for (int i = 1; i < a.length; i++) { - sb.append(WordUtils.capitalize(a[i])); + sb.append(WordUtils.capitalize(a[i].toLowerCase(Locale.ROOT))); } return sb.toString(); }; /** - * An enumeration of supported string cases. + * An enumeration of supported string cases. These cases tag strings as having a specific format. */ public enum StringCase { /** - * Camel case identifies strings like 'CamelCase'. + * Camel case tags strings like 'CamelCase' or 'camelCase'. This conversion forces the first character to + * lower case. If specific capitalization rules are required use {@code WordUtils.capitalize()} to set the first + * character of the string. */ - Camel(Character::isUpperCase, true, CAMEL_JOINER), + CAMEL(Character::isUpperCase, true, CAMEL_JOINER), /** - * Snake case identifies strings like 'Snake_Case'. + * Snake case tags strings like 'Snake_Case'. This conversion does not change the capitalization of any characters + * in the string. If specific capitalization is required use {@code String.upperCase}, {@code String.upperCase}, + * {@code WordUtils.capitalize()}, or {@code WordUtils.uncapitalize()} as required. */ - Snake(c -> c == '_', false, a -> String.join("_", a)), + SNAKE(c -> c == '_', false, a -> String.join("_", a)), /** - * Kebab case identifies strings like 'kebab-case'. + * Kebab case tags strings like 'kebab-case'. This conversion does not change the capitalization of any characters + * in the string. If specific capitalization is required use {@code String.upperCase}, {@code String.upperCase}, + * {@code WordUtils.capitalize()}, or {@code WordUtils.uncapitalize()} as required. */ - Kebab(c -> c == '-', false, a -> String.join("-", a)), + KEBAB(c -> c == '-', false, a -> String.join("-", a)), /** - * Phrase case identifies phrases of words like 'phrase case'. + * Phrase case tags phrases of words like 'phrase case'. This conversion does not change the capitalization of any characters + * in the string. If specific capitalization is required use {@code String.upperCase}, {@code String.upperCase}, + * {@code WordUtils.capitalize()}, or {@code WordUtils.uncapitalize()} as required. */ - Phrase(c -> c == ' ', false, a -> String.join(" ", a)), + PHRASE(Character::isWhitespace, false, a -> String.join(" ", a)), /** - * Dot case identifies strings of words like 'dot.case'. + * Dot case tags phrases of words like 'phrase.case'. This conversion does not change the capitalization of any characters + * in the string. If specific capitalization is required use {@code String.upperCase}, {@code String.upperCase}, + * {@code WordUtils.capitalize()}, or {@code WordUtils.uncapitalize()} as required. */ - Dot(c -> c == '.', false, a -> String.join(".", a)); + DOT(c -> c == '.', false, a -> String.join(".", a)); /** test for split position character. */ private final Predicate splitter; /** if {@code true} split position character will be preserved in following segment. */ private final boolean preserveSplit; - /** a function to joing the segments into this case type. */ + /** a function to joining the segments into this case type. */ private final Function joiner; /** @@ -90,6 +101,48 @@ public enum StringCase { this.preserveSplit = preserveSplit; this.joiner = joiner; } + + /** + * Creates a cased string from a collection of segments. + * @param segments the segments to create the CasedString from. + * @return a CasedString + */ + public String assemble(String[] segments) { + return segments.length == 0 ? null : this.joiner.apply(segments); + } + + /** + * Returns an array of each of the segments in this CasedString. Segments are defined as the strings between + * the separators in the CasedString. for the CAMEL case the segments are determined by the presence of a capital letter. + * @return the array of Strings that are segments of the cased string. + */ + public String[] getSegments(String string) { + if (string == null) { + return new String[0]; + } + if (string.isEmpty()) { + return new String[]{""}; + } + List lst = new ArrayList<>(); + StringBuilder sb = new StringBuilder(); + for (char c : string.toCharArray()) { + if (splitter.test(c)) { + if (sb.length() > 0) { + lst.add(sb.toString()); + sb.setLength(0); + } + if (preserveSplit) { + sb.append(c); + } + } else { + sb.append(c); + } + } + if (sb.length() > 0) { + lst.add(sb.toString()); + } + return lst.toArray(new String[0]); + } } /** @@ -98,30 +151,17 @@ public enum StringCase { * @param string The string. */ public CasedString(StringCase stringCase, String string) { - this.string = string; + this.string = string == null ? null : stringCase.assemble(stringCase.getSegments(string.trim())); this.stringCase = stringCase; } - private String[] split() { - List lst = new ArrayList<>(); - StringBuilder sb = new StringBuilder(); - for (char c : string.toCharArray()) { - if (stringCase.splitter.test(c)) { - if (sb.length() > 0) { - lst.add(sb.toString()); - sb.setLength(0); - } - if (stringCase.preserveSplit) { - sb.append(c); - } - } else { - sb.append(c); - } - } - if (sb.length() > 0) { - lst.add(sb.toString()); - } - return lst.toArray(new String[0]); + /** + * Returns an array of each of the segments in this CasedString. Segments are defined as the strings between + * the separators in the CasedString. for the CAMEL case the segments are determined by the presence of a capital letter. + * @return the array of Strings that are segments of the cased string. + */ + public String[] getSegments() { + return stringCase.getSegments(string); } /** @@ -134,7 +174,7 @@ public String toCase(StringCase stringCase) { if (stringCase == this.stringCase) { return string; } - return stringCase.joiner.apply(split()); + return string == null ? null : stringCase.joiner.apply(getSegments()); } /** diff --git a/src/test/java/org/apache/commons/text/CasedStringTest.java b/src/test/java/org/apache/commons/text/CasedStringTest.java index f0c0007b3d..106a93aae5 100644 --- a/src/test/java/org/apache/commons/text/CasedStringTest.java +++ b/src/test/java/org/apache/commons/text/CasedStringTest.java @@ -18,48 +18,141 @@ */ package org.apache.commons.text; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; +import org.apache.commons.text.CasedString.StringCase; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; public class CasedStringTest { - private static String expectedValue(CasedString.StringCase stringCase) { + private static String helloWorldValue(StringCase stringCase) { switch (stringCase) { - case Camel: - return "HelloWorld"; - case Kebab: - return "Hello-World"; - case Phrase: - return "Hello World"; - case Snake: - return "Hello_World"; - case Dot: - return "Hello.World"; + case CAMEL: + return "helloWorld"; + case KEBAB: + return "hello-World"; + case PHRASE: + return "hello World"; + case SNAKE: + return "hello_World"; + case DOT: + return "hello.World"; default: - throw new RuntimeException("Unsupported StringCase: " + stringCase); + fail("Unsupported StringCase: " + stringCase); } + return null; // keeps compiler happy } + private static final CasedString CAMEL = new CasedString(StringCase.CAMEL, "aCamelString"); + private static final CasedString PHRASE = new CasedString(StringCase.PHRASE, "A test PhrAse"); + private static final CasedString KEBAB = new CasedString(StringCase.KEBAB, "A-kebAb-string"); + private static final CasedString SNAKE = new CasedString(StringCase.SNAKE, "A_snaKE_string"); + private static final CasedString DOT = new CasedString(StringCase.DOT, "A.dOt.string"); + private static final CasedString ABCDEF = new CasedString(StringCase.PHRASE, "a b c @def"); + /** + * tests the conversion from each Cased string type to every other type. + * @param underTest the CasedString being tested. + */ @ParameterizedTest @MethodSource("conversionProvider") - public void testConversions(CasedString underTest) { - for (CasedString.StringCase stringCase : CasedString.StringCase.values()) { - assertEquals(expectedValue(stringCase), underTest.toCase(stringCase), () -> "failed converting to " + stringCase); + public void testCrossProductConversions(CasedString underTest) { + for (StringCase stringCase : StringCase.values()) { + assertEquals(helloWorldValue(stringCase), underTest.toCase(stringCase), () -> "failed converting to " + stringCase); } } - + /* generates the hello world Cased String for every StringCase */ private static Stream conversionProvider() { List lst = new ArrayList<>(); - for (CasedString.StringCase stringCase : CasedString.StringCase.values()) { - lst.add(Arguments.of(new CasedString(stringCase, expectedValue(stringCase)))); + for (StringCase stringCase : StringCase.values()) { + lst.add(Arguments.of(new CasedString(stringCase, helloWorldValue(stringCase)))); } return lst.stream(); } + + @Test + public void testNullConstructor() { + for (StringCase stringCase : StringCase.values()) { + CasedString underTest = new CasedString(stringCase, null); + assertThat(underTest.toString()).isNull(); + assertThat(underTest.getSegments()).isEmpty(); + // test a null underTest can convert to all others types. + for (CasedString.StringCase otherCase : StringCase.values()) { + assertThat(underTest.toCase(otherCase)).isNull(); + } + } + } + + @Test + public void testToCamelCase() { + assertThat(new CasedString(StringCase.CAMEL, "").toString()).isEqualTo(""); + assertThat(new CasedString(StringCase.CAMEL, " ").toString()).isEqualTo(""); + assertThat(new CasedString(StringCase.CAMEL, "Tocamelcase").toString()).isEqualTo("tocamelcase"); + assertThat(new CasedString(StringCase.PHRASE, "\uD800\uDF00 \uD800\uDF02").toCase(StringCase.CAMEL)).isEqualTo("\uD800\uDF00\uD800\uDF02"); + assertThat(ABCDEF.toCase(StringCase.CAMEL)).isEqualTo("aBC@def"); + assertThat(CAMEL.toCase(StringCase.CAMEL)).isEqualTo("aCamelString"); + assertThat(PHRASE.toCase(StringCase.CAMEL)).isEqualTo("aTestPhrase"); + assertThat(KEBAB.toCase(StringCase.CAMEL)).isEqualTo("aKebabString"); + assertThat(SNAKE.toCase(StringCase.CAMEL)).isEqualTo("aSnakeString"); + assertThat(DOT.toCase(StringCase.CAMEL)).isEqualTo("aDotString"); + assertThat(new CasedString(StringCase.PHRASE, "TO CAMEL CASE").toCase(StringCase.CAMEL)).isEqualTo("toCamelCase"); + assertThat(new CasedString(StringCase.KEBAB, " to-CAMEL-cASE").toCase(StringCase.CAMEL)).isEqualTo("toCamelCase"); + assertThat(new CasedString(StringCase.DOT, "To.Camel.Case").toCase(StringCase.CAMEL)).isEqualTo("toCamelCase"); + } + + @Test + public void testToPhraseTest() { + assertThat(new CasedString(StringCase.PHRASE, "").toString()).isEqualTo(""); + assertThat(new CasedString(StringCase.PHRASE, " ").toString()).isEqualTo(""); + assertThat(ABCDEF.toCase(StringCase.PHRASE)).isEqualTo("a b c @def"); + assertThat(CAMEL.toCase(StringCase.PHRASE)).isEqualTo("a Camel String"); + assertThat(PHRASE.toCase(StringCase.PHRASE)).isEqualTo("A test PhrAse"); + assertThat(KEBAB.toCase(StringCase.PHRASE)).isEqualTo("A kebAb string"); + assertThat(SNAKE.toCase(StringCase.PHRASE)).isEqualTo("A snaKE string"); + assertThat(DOT.toCase(StringCase.PHRASE)).isEqualTo("A dOt string"); + } + + @Test + public void testToKebabTest() { + assertThat(new CasedString(StringCase.KEBAB, "").toString()).isEqualTo(""); + assertThat(new CasedString(StringCase.KEBAB, " ").toString()).isEqualTo(""); + assertThat(ABCDEF.toCase(StringCase.KEBAB)).isEqualTo("a-b-c-@def"); + assertThat(CAMEL.toCase(StringCase.KEBAB)).isEqualTo("a-Camel-String"); + assertThat(PHRASE.toCase(StringCase.KEBAB)).isEqualTo("A-test-PhrAse"); + assertThat(KEBAB.toCase(StringCase.KEBAB)).isEqualTo("A-kebAb-string"); + assertThat(SNAKE.toCase(StringCase.KEBAB)).isEqualTo("A-snaKE-string"); + assertThat(DOT.toCase(StringCase.KEBAB)).isEqualTo("A-dOt-string"); + } + + @Test + public void testToSnakeTest() { + assertThat(new CasedString(StringCase.SNAKE, "").toString()).isEqualTo(""); + assertThat(new CasedString(StringCase.SNAKE, " ").toString()).isEqualTo(""); + assertThat(ABCDEF.toCase(StringCase.SNAKE)).isEqualTo("a_b_c_@def"); + assertThat(CAMEL.toCase(StringCase.SNAKE)).isEqualTo("a_Camel_String"); + assertThat(PHRASE.toCase(StringCase.SNAKE)).isEqualTo("A_test_PhrAse"); + assertThat(KEBAB.toCase(StringCase.SNAKE)).isEqualTo("A_kebAb_string"); + assertThat(SNAKE.toCase(StringCase.SNAKE)).isEqualTo("A_snaKE_string"); + assertThat(DOT.toCase(StringCase.SNAKE)).isEqualTo("A_dOt_string"); + } + + @Test + public void testToDotTest() { + assertThat(new CasedString(StringCase.DOT, "").toString()).isEqualTo(""); + assertThat(new CasedString(StringCase.DOT, " ").toString()).isEqualTo(""); + assertThat(ABCDEF.toCase(StringCase.DOT)).isEqualTo("a.b.c.@def"); + assertThat(CAMEL.toCase(StringCase.DOT)).isEqualTo("a.Camel.String"); + assertThat(PHRASE.toCase(StringCase.DOT)).isEqualTo("A.test.PhrAse"); + assertThat(KEBAB.toCase(StringCase.DOT)).isEqualTo("A.kebAb.string"); + assertThat(SNAKE.toCase(StringCase.DOT)).isEqualTo("A.snaKE.string"); + assertThat(DOT.toCase(StringCase.DOT)).isEqualTo("A.dOt.string"); + } } From 81e954c2924e26b5ab03ee272ef3e86c7e87a033 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 25 May 2024 16:26:25 +0200 Subject: [PATCH 5/6] fixed typo --- src/main/java/org/apache/commons/text/CasedString.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/apache/commons/text/CasedString.java b/src/main/java/org/apache/commons/text/CasedString.java index 34418cfbe0..d6655d4e31 100644 --- a/src/main/java/org/apache/commons/text/CasedString.java +++ b/src/main/java/org/apache/commons/text/CasedString.java @@ -29,7 +29,7 @@ * @since 1.13.0 */ public class CasedString { - /** the string the the cased format. */ + /** the string of the cased format. */ private final String string; /** the case of the string. */ private final StringCase stringCase; From 72bb83b63dfd4649e5b4346c46a8faa52a115264 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Mon, 27 May 2024 17:55:12 +0200 Subject: [PATCH 6/6] updates as per review --- .../org/apache/commons/text/CasedString.java | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/apache/commons/text/CasedString.java b/src/main/java/org/apache/commons/text/CasedString.java index d6655d4e31..f298e121e2 100644 --- a/src/main/java/org/apache/commons/text/CasedString.java +++ b/src/main/java/org/apache/commons/text/CasedString.java @@ -29,9 +29,9 @@ * @since 1.13.0 */ public class CasedString { - /** the string of the cased format. */ + /** The string of the cased format. */ private final String string; - /** the case of the string. */ + /** The case of the string. */ private final StringCase stringCase; /** @@ -51,9 +51,8 @@ public class CasedString { */ public enum StringCase { /** - * Camel case tags strings like 'CamelCase' or 'camelCase'. This conversion forces the first character to - * lower case. If specific capitalization rules are required use {@code WordUtils.capitalize()} to set the first - * character of the string. + * Camel case tags strings like 'camelCase'. This conversion forces the first character to of the result to be + * lower case. Other than the upper case separating character all other characters are lower cased. */ CAMEL(Character::isUpperCase, true, CAMEL_JOINER), /** @@ -83,16 +82,22 @@ public enum StringCase { */ DOT(c -> c == '.', false, a -> String.join(".", a)); - /** test for split position character. */ + /** The segment representation of a null String. */ + private static final String[] NULL_STRING = new String[0]; + /** The segment representation of an empty String. */ + private static final String[] EMPTY_STRING = new String[]{""}; + + /** Tests for split position character. */ private final Predicate splitter; - /** if {@code true} split position character will be preserved in following segment. */ + /** If {@code true} split position character will be preserved in following segment. */ private final boolean preserveSplit; - /** a function to joining the segments into this case type. */ + /** A function to joining the segments into this case type. */ private final Function joiner; /** * Defines a String Case. - * @param splitter The predicate that determines when a new word in the cased string begins. + * @param splitter The predicate that determines when a new word in the cased string begins. This function will never receive + * {@code null} argument. * @param preserveSplit if {@code true} the character that the splitter detected is preserved as the first character of the new word. * @param joiner The function to merge a list of strings into the cased String. */ @@ -104,11 +109,11 @@ public enum StringCase { /** * Creates a cased string from a collection of segments. - * @param segments the segments to create the CasedString from. - * @return a CasedString + * @param segments the segments to create the CasedString from. A {@code null} or zero length argument will result in an empty string. + * @return a string that is formatted for this Cased type. */ public String assemble(String[] segments) { - return segments.length == 0 ? null : this.joiner.apply(segments); + return segments == null || segments.length == 0 ? null : this.joiner.apply(segments); } /** @@ -118,10 +123,10 @@ public String assemble(String[] segments) { */ public String[] getSegments(String string) { if (string == null) { - return new String[0]; + return NULL_STRING; } if (string.isEmpty()) { - return new String[]{""}; + return EMPTY_STRING; } List lst = new ArrayList<>(); StringBuilder sb = new StringBuilder();