diff --git a/CHANGELOG.md b/CHANGELOG.md index 2869970..06469c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## Unreleased +### Fixed + +- array functions should use `List`, not `[]` + ## [0.7.3] - 2022-03-29 ### Fixed + - Implementation mappings in `grel_java_mapping.ttl` used class `fnoi:Mapping` instead of `fno:Mapping` (see [GitLab issue #2](https://gitlab.ilabt.imec.be/fno/lib/grel-functions-java/-/issues/2)) ## [0.7.2] - 2022-03-24 diff --git a/README.MD b/README.MD index 22b1f3d..704ff6a 100644 --- a/README.MD +++ b/README.MD @@ -33,5 +33,11 @@ So `Integer` instead of `int`, etc. > The Function Handler for the moment only handles Classes, not primitives. +### Use JAVA Lists, not Arrays + +So `List` instead of `Object[]`, etc. + +> The Function Handler for the moment only handles Lists, not Arrays. + [FnO]: https://fno.io/spec/ [GREL]: https://docs.openrefine.org/manual/grelfunctions diff --git a/src/main/java/io/fno/grel/ArrayFunctions.java b/src/main/java/io/fno/grel/ArrayFunctions.java index 88dadf1..bf306c5 100644 --- a/src/main/java/io/fno/grel/ArrayFunctions.java +++ b/src/main/java/io/fno/grel/ArrayFunctions.java @@ -1,9 +1,11 @@ package io.fno.grel; -import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; -import java.util.*; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; public class ArrayFunctions { @@ -72,39 +74,37 @@ public static String join(List a, String sep) { return StringUtils.join(a, sep); } - // TO-DO these functions are untested and need docstrings - // (brought over from commit 98360fe7f7c13dcbd51c14db12218b605bd86c16) - - public static Integer length(Object[] a) { - return a.length; + // TODO these functions need docstrings + public static Integer length(List a) { + return a.size(); } - public static Object[] slice(Object[] a, Integer from, Integer to) { - return Arrays.copyOfRange(a, from, to + 1); + public static List slice(List a, Integer from, Integer to) { + return a.subList(from, to + 1); } - public static Object[] slice(Object[] a, Integer from) { - return slice(a, from, a.length); + public static List slice(List a, Integer from) { + return slice(a, from, length(a)); } // see get of strings - public static Object[] reverse(Object[] a) { - ArrayUtils.reverse(a); + public static List reverse(List a) { + Collections.reverse(a); return a; } - public static Object[] sort(Object[] a) { - Arrays.sort(a); - return a; + public static Integer sum(List a) { + return a.stream().reduce(0, Integer::sum); } - public static Integer sum(Integer[] a) { - return Arrays.stream(a).mapToInt(Integer::intValue).sum(); + // TODO how to do this sort? + public static List sort(List a) { + // a.sort(); + return a; } - public static Object[] uniques(Object[] a) { - SortedSet set = new TreeSet<>(Arrays.asList(a)); - return set.toArray(new Object[0]); + public static List uniques(List a) { + return a.stream().distinct().collect(Collectors.toList()); } diff --git a/src/main/java/io/fno/grel/StringFunctions.java b/src/main/java/io/fno/grel/StringFunctions.java index 16297bc..b968ede 100644 --- a/src/main/java/io/fno/grel/StringFunctions.java +++ b/src/main/java/io/fno/grel/StringFunctions.java @@ -305,14 +305,14 @@ public static String replaceChars(String s, String f, String r) throws Exception * @param p regex pattern * @return Array of pattern matches */ - public static String[] match(String s, String p) { + public static List match(String s, String p) { List allMatches = new ArrayList(); Matcher m = Pattern.compile(p) .matcher(s); while (m.find()) { allMatches.add(m.group()); } - return (String[]) allMatches.toArray(); + return allMatches; } // NOTE: this was implemented in commit 5161c959985daabc90a53520b00752cc9c69b94d, @@ -359,14 +359,14 @@ public static List split(String s, String sep) { * @param numbers lengths of subsequent substrings to be extracted * @return Array of strings after splitting */ - public static String[] splitByLengths(String s, int... numbers) { + public static List splitByLengths(String s, int... numbers) { List output = new ArrayList<>(); int i = 0; for (int n : numbers) { output.add(s.substring(i, i + n)); i += n; } - return output.toArray(new String[0]); + return output; } // TODO https://github.com/OpenRefine/OpenRefine/wiki/GREL-String-Functions#splitbylengthsstring-s-number-n1-number-n2- @@ -377,7 +377,7 @@ public static String[] splitByLengths(String s, int... numbers) { * Guesses tab or comma separator if sep is not given. * Also, value.escape('javascript') is useful for previewing unprintable chars prior to using smartSplit. */ - public static String[] smartSplit(String s) { + public static List smartSplit(String s) { String sep; if (StringUtils.countMatches(s, "\t") < StringUtils.countMatches(s, ",")) { sep = ","; @@ -387,8 +387,8 @@ public static String[] smartSplit(String s) { return smartSplit(s, sep); } - public static String[] smartSplit(String s, String sep) { - return s.split(sep); + public static List smartSplit(String s, String sep) { + return Arrays.asList(s.split(sep)); } /** @@ -398,11 +398,11 @@ public static String[] smartSplit(String s, String sep) { * will result in an array of [ "H", "enry", "CT", "aylor" ]. It is useful for separating letters * and numbers: "BE1A3E".splitByCharType() will result in [ "BE", "1", "A", "3", "E" ]. */ - public static String[] splitByCharType(String value) { - return StringUtils.splitByCharacterType(value); + public static List splitByCharType(String value) { + return Arrays.asList(StringUtils.splitByCharacterType(value)); } - public static String[] _partition(String s, String frag, Boolean omitFragment, Boolean last) { + public static List _partition(String s, String frag, Boolean omitFragment, Boolean last) { List output = new ArrayList<>(); int offset = 0; int index; @@ -412,7 +412,7 @@ public static String[] _partition(String s, String frag, Boolean omitFragment, B index = s.lastIndexOf(frag); } if (index == -1) { - return new String[]{s, "", ""}; + return Arrays.asList(s, "", ""); } output.add(s.substring(0, index)); if (! omitFragment) { @@ -420,7 +420,7 @@ public static String[] _partition(String s, String frag, Boolean omitFragment, B offset += frag.length(); } output.add(s.substring(index + offset)); - return output.toArray(new String[0]); + return output; } /** @@ -433,7 +433,7 @@ public static String[] _partition(String s, String frag, Boolean omitFragment, B * [ "inter", "nation", "alization" ]. If s does not contain fragment, it returns an array of * [ s, "", "" ] (the original unpartitioned string, and two empty strings). */ - public static String[] partition(String s, String frag) { + public static List partition(String s, String frag) { return partition(s, frag, false); } @@ -450,7 +450,7 @@ public static String[] partition(String s, String frag) { * If the omitFragment boolean is true, for example with "internationalization".partition("nation", true), * the fragment is not returned. The output is [ "inter", "alization" ]. */ - public static String[] partition(String s, String frag, Boolean omitFragment) { + public static List partition(String s, String frag, Boolean omitFragment) { return _partition(s, frag, omitFragment, false); } @@ -463,7 +463,7 @@ public static String[] partition(String s, String frag, Boolean omitFragment) { * For example, "parallel".rpartition("a") returns 3 strings: * [ "par", "a", "llel" ]. Otherwise works identically to partition(). */ - public static String[] rpartition(String s, String frag) { + public static List rpartition(String s, String frag) { return rpartition(s, frag, false); } @@ -476,7 +476,7 @@ public static String[] rpartition(String s, String frag) { * For example, "parallel".rpartition("a") returns 3 strings: * [ "par", "a", "llel" ]. Otherwise works identically to partition(). */ - public static String[] rpartition(String s, String frag, Boolean omitFragment) { + public static List rpartition(String s, String frag, Boolean omitFragment) { return _partition(s, frag, omitFragment, true); } @@ -606,11 +606,11 @@ public static String reinterpret(String s, String encoder) { // https://docs.openrefine.org/manual/grelfunctions#unicodes // TODO add docstring and write unit test - public static String[] unicode(String s) { + public static List unicode(String s) { return s.chars() .mapToObj(c -> (char) c) .map(c -> encodeURIComponent(String.valueOf(c))) - .toArray(String[]::new); + .toList(); } // TODO https://github.com/OpenRefine/OpenRefine/wiki/GREL-String-Functions#unicodetypestring-s diff --git a/src/test/java/io/fno/grel/ArrayFunctions_Test.java b/src/test/java/io/fno/grel/ArrayFunctions_Test.java index 17af04b..ad2f3a3 100644 --- a/src/test/java/io/fno/grel/ArrayFunctions_Test.java +++ b/src/test/java/io/fno/grel/ArrayFunctions_Test.java @@ -5,6 +5,7 @@ import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -39,9 +40,19 @@ public void join() { @Test public void unique() { + List input = Arrays.asList("1","2","2","3"); assertArrayEquals( - new String[]{"1", "2", "3"}, - ArrayFunctions.uniques(new String[]{"1", "2", "2", "3"}) + new String[]{"1","2","3"}, + ArrayFunctions.uniques(new ArrayList(input)).toArray() ); } + + @Test + public void sum() { + List input = new ArrayList<>(); + input.add(2); + input.add(3); + Integer output = ArrayFunctions.sum(input); + assertEquals(Integer.valueOf(5), output); + } } diff --git a/src/test/java/io/fno/grel/StringFunctions_Test.java b/src/test/java/io/fno/grel/StringFunctions_Test.java index 02cceba..a26f40a 100644 --- a/src/test/java/io/fno/grel/StringFunctions_Test.java +++ b/src/test/java/io/fno/grel/StringFunctions_Test.java @@ -14,6 +14,13 @@ public void length() { assertEquals(Integer.valueOf(3), output); } + @Test + public void toStringTest() { + Integer input = 5; + String output = StringFunctions.toString(input); + assertEquals("5", output); + } + @Test public void startsWith() { String input = "one"; @@ -63,6 +70,12 @@ public void trim() { assertEquals("Ones", output); } + @Test + public void strip() { + String input = " Ones "; + String output = StringFunctions.strip(input); + assertEquals("Ones", output); + } @Test public void chomp() { @@ -77,6 +90,34 @@ public void substring() { assertEquals("nes", output); } + @Test + public void substring2() { + String input = "Ones"; + String output = StringFunctions.substring(input, 1, 3); + assertEquals("ne", output); + } + + @Test + public void slice() { + String input = "Ones"; + String output = StringFunctions.slice(input, 1); + assertEquals("nes", output); + } + + @Test + public void get() { + String input = "Ones"; + String output = StringFunctions.slice(input, 1); + assertEquals("nes", output); + } + + @Test + public void indexOf() { + String input = "Ononones"; + Integer output = StringFunctions.indexOf(input, "on"); + assertSame(2, output); + } + @Test public void lastIndexOf() { String input = "Ononones"; @@ -85,10 +126,31 @@ public void lastIndexOf() { } @Test - public void testSubstring() { - String input = "Ones"; - String output = StringFunctions.substring(input, 1, 3); - assertEquals("ne", output); + public void replace() { + String input = "Ononones"; + String output = StringFunctions.replace(input, "no", "mi"); + assertEquals("Omimines", output); + } + + @Test + public void replaceChars() throws Exception { + String input = "Ononones"; + String output = StringFunctions.replaceChars(input, "no", "mi"); + assertEquals("Omimimes", output); + } + + @Test + public void match() { + String input = "Ononones"; + List output = StringFunctions.match(input, "n."); + assertArrayEquals(new String[] { "no", "no", "ne" }, output.toArray()); + } + + @Test + public void toNumber() throws Exception { + String input = "4"; + Integer output = StringFunctions.toNumber(input); + assertEquals(Integer.valueOf(4), output); } @Test @@ -101,35 +163,37 @@ public void split() { @Test public void splitByLengths() { assertArrayEquals( - new String[]{"inter", "nation", "ali"}, - StringFunctions.splitByLengths("internationalization", 5, 6, 3) - ); + new String[] { "inter", "nation", "ali" }, + StringFunctions.splitByLengths("internationalization", 5, 6, 3).toArray()); } + // TODO smartSplit + + // TODO splitByCharType + @Test public void partition() { assertArrayEquals( - new String[]{"inter", "nation", "alization"}, - StringFunctions.partition("internationalization", "nation") - ); + new String[] { "inter", "nation", "alization" }, + StringFunctions.partition("internationalization", "nation").toArray()); } @Test public void rpartition() { assertArrayEquals( - new String[]{"par", "a", "llel"}, - StringFunctions.partition("parallel", "a") - ); + new String[] { "par", "a", "llel" }, + StringFunctions.partition("parallel", "a").toArray()); } @Test public void rpartition_empty() { assertArrayEquals( - new String[]{"lollipop", "", ""}, - StringFunctions.partition("lollipop", "a") - ); + new String[] { "lollipop", "", "" }, + StringFunctions.partition("lollipop", "a").toArray()); } + // TODO diff + @Test public void escape() { String input = "On&es"; @@ -140,6 +204,8 @@ public void escape() { assertEquals("On%20es", output); } + // TODO unescape + @Test public void md5() { String input = "One"; @@ -153,4 +219,10 @@ public void sha1() { String output = StringFunctions.sha1(input); assertEquals("b58b5a8ced9db48b30e008b148004c1065ce53b1", output); } + + // TODO phonetic + + // TODO reinterpret + + // TODO unicode }