All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.speedment.generator.translator.util.Pluralis Maven / Gradle / Ivy

Go to download

A Speedment bundle that shades all dependencies into one jar. This is useful when deploying an application on a server.

The newest version!
/*
 *
 * Copyright (c) 2006-2019, Speedment, Inc. All Rights Reserved.
 *
 * 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:
 *
 * 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 com.speedment.generator.translator.util;

import static com.speedment.common.codegen.internal.util.NullUtil.requireNonNullElements;
import static com.speedment.common.codegen.internal.util.NullUtil.requireNonNulls;
import com.speedment.generator.translator.namer.JavaLanguageNamer;
import java.util.*;
import static java.util.Objects.requireNonNull;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;

/**
 *
 * @author  Per Minborg
 * @since   2.1.0
 */

public enum Pluralis {

    INSTANCE;

    private final List rules;
    private final Set uncountables;
    private final Map irregulars;

    private Pluralis() {
        rules = new ArrayList<>();
        uncountables = new HashSet<>();
        irregulars = new HashMap<>();
        init();
        Collections.reverse(rules); // Search the general rules last
    }

    public String pluralizeJavaIdentifier(String javaIdentifier, JavaLanguageNamer javaLanguageNamer) {
        requireNonNull(javaIdentifier);
        int lastCapitalCharacter = -1;
        for (int i = 0; i < javaIdentifier.length(); i++) {
            if (Character.isUpperCase(javaIdentifier.charAt(i))) {
                lastCapitalCharacter = i;
            }
        }
        if (lastCapitalCharacter == -1) {
            return pluralize(javaIdentifier);
        } else {
            final String firstPartOfWord = javaIdentifier.substring(0, lastCapitalCharacter);
            final String lastPartOfWord = javaIdentifier.substring(lastCapitalCharacter);
            final String pluralOflastPartOfWord = pluralize(lastPartOfWord);
            return firstPartOfWord + javaLanguageNamer.javaTypeName(pluralOflastPartOfWord);
        }
    }

    /**
     * Returns a plural version in normalized form of the given word.
     *
     * @param word the given singular word form
     * @return a plural version in normalized form of the given word
     */
    public String pluralize(String word) {
        requireNonNull(word);
        final String normalized = normalize(word);
        if (normalized.length() == 0) {
            return normalized;
        }
        if (isUncountable(normalized)) {
            return normalized;
        }
        if (isIrregular(word)) {
            return irregulars.get(normalized);
        }

        for (Rule rule : rules) {
            final Optional result = rule.apply(normalized);
            if (result.isPresent()) {
                return result.get();
            }
        }
        return normalized;
    }

    /**
     * Returns a textual representation of an ordinal. 1 = 1st, 2 = 2nd, 101
     * = 101st, 111 = 111th
     *
     * @param number the ordinal number
     * @return a textual representation of an ordinal
     */
    public String ordinalize(final int number) {
        final int remainder = Math.abs(number % 100);
        final String numberStr = Integer.toString(number);
        if (remainder < 10) {
            if (remainder == 1) {
                return numberStr + "st";
            }
            if (remainder == 2) {
                return numberStr + "nd";
            }
            if (remainder == 3) {
                return numberStr + "rd";
            }
        }
        return numberStr + "th";
    }

    /**
     * Returns if the provided word is considered as an uncountable.
     *
     * @param word to check
     * @return if the provided word is considered as an uncountable
     */
    public boolean isUncountable(String word) {
        requireNonNull(word);
        return uncountables.contains(normalize(word));
    }

    public boolean isIrregular(String word) {
        requireNonNull(word);
        return irregulars.containsKey(normalize(word));
    }

    protected void addRule(String rule, String replacement) {
        requireNonNulls(rule, replacement);
        rules.add(new Rule(rule, replacement));
    }

    protected void addIrregular(String singular, String plural) {
        requireNonNulls(singular, plural);
        irregulars.put(normalize(singular), normalize(plural));
    }

    protected void addUncountable(String... words) {
        requireNonNullElements(words);
        Stream.of(words).map(normalizeMapper()).forEach(uncountables::add);
    }

    private String normalize(String input) {
        requireNonNull(input);
        return normalizeMapper().apply(input);
    }

    public Function normalizeMapper() {
        return s -> Optional.ofNullable(s).orElse("").trim().toLowerCase();
    }

    private void init() {
        addRule("$", "s");
        addRule("(.+)s$", "$1ses");
        addRule("(ax|test)is$", "$1es");
        addRule("(octop)us$", "$1i");
        addRule("(octop|vir)i$", "$1i");
        addRule("(alias|status)$", "$1es");
        addRule("(bu)s$", "$1ses");
        addRule("(buffal|tomat)o$", "$1oes");
        addRule("([ti])um$", "$1a");
        addRule("([ti])a$", "$1a");
        addRule("sis$", "ses");
        addRule("(?:([^f])fe|([lr])f)$", "$1$2ves");
        addRule("(hive)$", "$1s");
        addRule("([^aeiouy]|qu)y$", "$1ies");
        addRule("(x|ch|ss|sh)$", "$1es");
        addRule("(matr|vert|ind)ix|ex$", "$1ices");
        addRule("([m|l])ouse$", "$1ice");
        addRule("([m|l])ice$", "$1ice");
        addRule("^(ox)$", "$1en");
        addRule("(quiz)$", "$1zes");

        addIrregular("woman", "women");
        addIrregular("man", "men");
        addIrregular("child", "children");
        addIrregular("sex", "sexes");
        addIrregular("person", "people");

        addUncountable("furniture", "equipment", "information", "rice", "money", "species", "series", "fish", "sheep", "data");
    }

    private static final class Rule implements Function> {

        private final String expression;
        private final Pattern expressionPattern;
        private final String replacement;

        private Rule(final String expression, final String replacement) {
            this.expression = requireNonNull(expression);
            this.replacement =requireNonNull(replacement);
            this.expressionPattern = Pattern.compile(expression, Pattern.CASE_INSENSITIVE);
        }

        /**
         * Apply the rule against the input string, returning the modified
         * string or null if the rule didn't apply (and no modifications were
         * made)
         *
         * @param input the input string
         * @return the modified string if this rule applied, or null if the
         * input was not modified by this rule
         */
        @Override
        public Optional apply(String input) {
            final Matcher matcher = expressionPattern.matcher(input);
            if (!matcher.find()) {
                return Optional.empty();
            }
            return Optional.ofNullable(matcher.replaceAll(replacement));
        }

        @Override
        public int hashCode() {
            int hash = 3;
            hash = 41 * hash + Objects.hashCode(expression);
            hash = 41 * hash + Objects.hashCode(replacement);
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final Rule other = (Rule) obj;
            if (!Objects.equals(this.expression, other.expression)) {
                return false;
            }
            return Objects.equals(this.replacement, other.replacement);
        }

        @Override
        public String toString() {
            return expression + " -> " + replacement;
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy