Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,60 +61,6 @@ public abstract class AbstractModelloGenerator implements ModelloGenerator {

private static final Map<String, String> PLURAL_EXCEPTIONS = new HashMap<>();

static {
// Irregular names
PLURAL_EXCEPTIONS.put("children", "child");
PLURAL_EXCEPTIONS.put("feet", "foot");
PLURAL_EXCEPTIONS.put("geese", "goose");
PLURAL_EXCEPTIONS.put("indices", "index");
PLURAL_EXCEPTIONS.put("men", "man");
PLURAL_EXCEPTIONS.put("mice", "mouse");
PLURAL_EXCEPTIONS.put("people", "person");
PLURAL_EXCEPTIONS.put("teeth", "tooth");
PLURAL_EXCEPTIONS.put("women", "woman");

// Invariant names
PLURAL_EXCEPTIONS.put("aircraft", "aircraft");
PLURAL_EXCEPTIONS.put("bison", "bison");
PLURAL_EXCEPTIONS.put("deer", "deer");
PLURAL_EXCEPTIONS.put("elk", "elk");
PLURAL_EXCEPTIONS.put("fish", "fish");
PLURAL_EXCEPTIONS.put("series", "series");
PLURAL_EXCEPTIONS.put("sheep", "sheep");
PLURAL_EXCEPTIONS.put("species", "species");

// Special "oes" exceptions
PLURAL_EXCEPTIONS.put("buffaloes", "buffalo");
PLURAL_EXCEPTIONS.put("cargoes", "cargo");
PLURAL_EXCEPTIONS.put("echoes", "echo");
PLURAL_EXCEPTIONS.put("goes", "go");
PLURAL_EXCEPTIONS.put("haloes", "halo");
PLURAL_EXCEPTIONS.put("heroes", "hero");
PLURAL_EXCEPTIONS.put("mosquitoes", "mosquito");
PLURAL_EXCEPTIONS.put("noes", "no");
PLURAL_EXCEPTIONS.put("potatoes", "potato");
PLURAL_EXCEPTIONS.put("tomatoes", "tomato");
PLURAL_EXCEPTIONS.put("torpedoes", "torpedo");
PLURAL_EXCEPTIONS.put("vetoes", "veto");
PLURAL_EXCEPTIONS.put("volcanoes", "volcano");

// Special "ses" exceptions
PLURAL_EXCEPTIONS.put("horses", "horse");
PLURAL_EXCEPTIONS.put("licenses", "license");
PLURAL_EXCEPTIONS.put("phases", "phase");

// Special "zzes" exceptions
PLURAL_EXCEPTIONS.put("fezzes", "fez");
PLURAL_EXCEPTIONS.put("whizzes", "whiz");

// Special "ies" exceptions
PLURAL_EXCEPTIONS.put("movies", "movie");

// Special "ves" exceptions
PLURAL_EXCEPTIONS.put("archives", "archive");
PLURAL_EXCEPTIONS.put("relatives", "relative");
}

private Model model;

private File outputDirectory;
Expand Down Expand Up @@ -257,67 +203,27 @@ protected String capitalise(String str) {
}

public static String singular(String name) {
if (name == null || name.isEmpty()) return name;

String lower = name.toLowerCase();

if (!lower.equals(name)) {
// we can have a case like otherArchives
String[] split = splitByUpperCase(name);
if (split != null && PLURAL_EXCEPTIONS.containsKey(split[1])) {
String plural = PLURAL_EXCEPTIONS.get(split[1]);
return split[0] + Character.toUpperCase(plural.charAt(0)) + plural.substring(1);
}
if (StringUtils.isEmpty(name)) {
return name;
}

if (PLURAL_EXCEPTIONS.containsKey(lower)) {
return PLURAL_EXCEPTIONS.get(lower);
if (PLURAL_EXCEPTIONS.containsKey(name)) {
return PLURAL_EXCEPTIONS.get(name);
}

// Suffix-based rules
if (lower.endsWith("ies") && name.length() > 3) {
if (name.endsWith("ies")) {
return name.substring(0, name.length() - 3) + "y";
}
if (lower.endsWith("aves") || lower.endsWith("lves") || lower.endsWith("rves")) {
return name.substring(0, name.length() - 3) + "f";
}
if (lower.endsWith("ves") && !lower.endsWith("fves")) {
return name.substring(0, name.length() - 3) + "fe";
}
if (lower.endsWith("zzes")) {
return name.substring(0, name.length() - 2);
}
if (lower.endsWith("sses")) {
return name.substring(0, name.length() - 2);
}
if (lower.endsWith("ses")) {
return name.substring(0, name.length() - 2);
}
if (lower.endsWith("ches") || lower.endsWith("shes")) {
} else if (name.endsWith("es") && name.endsWith("ches")) {
return name.substring(0, name.length() - 2);
}
if (lower.endsWith("xes")) {
} else if (name.endsWith("xes")) {
return name.substring(0, name.length() - 2);
}
if (lower.endsWith("oes")) {
return name.substring(0, name.length() - 1);
}
if (lower.endsWith("s") && name.length() > 1) {
} else if (name.endsWith("s") && (name.length() != 1)) {
return name.substring(0, name.length() - 1);
}

return name;
}

private static String[] splitByUpperCase(String name) {
for (int i = name.length() - 1; i >= 0; i--) {
if (Character.isUpperCase(name.charAt(i))) {
return new String[] {name.substring(0, i), name.substring(i).toLowerCase()};
}
}
return null;
}

public static String uncapitalise(String str) {
if (StringUtils.isEmpty(str)) {
return str;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,10 @@ class AbstractModelloGeneratorTest {
"s,s",

// Known exceptions
"men, man",
"women, woman",
"children,child",
"mice, mouse",
"people, person",
"teeth, tooth",
"feet, foot",
"geese, goose",
"series, series",
"species, species",
"sheep, sheep",
"fish, fish",
"deer, deer",
"aircraft, aircraft",
"heroes, hero",
"potatoes, potato",
"tomatoes, tomato",
"echoes, echo",
"vetoes, veto",
"torpedoes, torpedo",
"cargoes, cargo",
"haloes, halo",
"mosquitoes, mosquito",
"buffaloes, buffalo",
"bison, bison",
"elk, elk",

Expand All @@ -47,70 +27,44 @@ class AbstractModelloGeneratorTest {
"toes, toe",
"foes, foe",
"oboes, oboe",
"noes, no",
"boxes, box",
"wishes, wish",
"dishes, dish",
"brushes, brush",
"classes, class",
"buzzes, buzz",
"cars, car",
"dogs, dog",
"cats, cat",
"horses, horse",
"fezzes, fez",
"whizzes, whiz",
"foxes, fox",

// Some test cases with different rules
"archives, archive",
"otherArchives, otherArchive",
"Archives, Archive",
"wolves, wolf",
"knives, knife",
"leaves, leaf",
"wives, wife",
"lives, life",
"babies, baby",
"parties, party",
"cities, city",
"buses, bus",
"boxes, box",
"churches, church",
"matches, match",
"watches, watch",
"riches, rich",
"dresses, dress",
"crosses, cross",
"lunches, lunch",
"relatives, relative",

// More edge cases
"heroes, hero",
"vetoes, veto",
"torpedoes, torpedo",
"tomatoes, tomato",
"potatoes, potato",
"echoes, echo",
"mosquitoes, mosquito",
"buffaloes, buffalo",
"volcanoes, volcano",
"goes, go",
"indices, index",
"phases, phase",
"kisses, kiss",
"movies, movie",
"shoes, shoe",

// other examples
"aliases, alias",
"ids, id",
"licenses, license",
"repositories, repository",
"roles, role",

// existing non grammar conversions
"superclasses, superclasse",
"classes, classe"
})
@ParameterizedTest
public void testSingular(String plural, String singular) {
void testSingular(String plural, String singular) {
assertEquals(
singular,
AbstractModelloGenerator.singular(plural),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,9 @@ public abstract class AbstractModelloGeneratorMojo extends AbstractMojo {
/**
* Additional exceptions to the singularization rules, changing plural noun to singular.
* <p>
* As a kay we provide plural noun and as value we provide singular noun, eg:
* As a key we provide plural noun and as value we provide singular noun, example:
* <pre>
* <kisses>kiss</kisses>
* &lt;kisses&gt;kiss&lt;/kisses&gt;
* </pre>
*
* @since 2.5.0
Expand Down Expand Up @@ -193,7 +193,7 @@ public void execute() throws MojoExecutionException {

parameters.put(ModelloParameterConstants.PACKAGE_WITH_VERSION, Boolean.toString(packageWithVersion));

parameters.put(ModelloParameterConstants.PLURAL_EXCEPTIONS, keysToLower(pluralExceptions));
parameters.put(ModelloParameterConstants.PLURAL_EXCEPTIONS, pluralExceptions);

if (!packagedVersions.isEmpty()) {
parameters.put(ModelloParameterConstants.ALL_VERSIONS, StringUtils.join(packagedVersions.iterator(), ","));
Expand Down Expand Up @@ -239,13 +239,6 @@ public void execute() throws MojoExecutionException {
}
}

private Object keysToLower(Map<String, String> maps) {
if (maps == null) {
return null;
}
return maps.entrySet().stream().collect(Collectors.toMap(e -> e.getKey().toLowerCase(), Map.Entry::getValue));
}

/**
* Performs execute on a single specified model.
*/
Expand Down