Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.github.underscore.Underscore Maven / Gradle / Ivy
/*
* The MIT License (MIT)
*
* Copyright 2015-2024 Valentyn Kolesnikov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.github.underscore;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
/**
* Underscore-java17 is a java port of Underscore.js.
*
* @author Valentyn Kolesnikov
*/
@SuppressWarnings({
"java:S106",
"java:S2189",
"java:S2272",
"java:S2789",
"java:S3740",
"java:S5852"
})
public class Underscore {
private static final Map> FUNCTIONS = new LinkedHashMap<>();
private static final Map TEMPLATE_SETTINGS = new HashMap<>();
private static final int MIN_PASSWORD_LENGTH_8 = 8;
private static final long CAPACITY_SIZE_5 = 5L;
private static final long CAPACITY_COEFF_2 = 2L;
private static final long CAPACITY_SIZE_16 = 16L;
private static final java.util.concurrent.atomic.AtomicInteger UNIQUE_ID =
new java.util.concurrent.atomic.AtomicInteger(0);
private static final String ALL_SYMBOLS = "([\\s\\S]+?)";
private static final String EVALUATE = "evaluate";
private static final String INTERPOLATE = "interpolate";
private static final String ESCAPE = "escape";
private static final String S_Q = "\\s*\\Q";
private static final String E_S = "\\E\\s*";
private static final java.util.regex.Pattern FORMAT_PATTERN =
java.util.regex.Pattern.compile("\\{\\s*(\\d*)\\s*\\}");
private static final Map ESCAPES = new HashMap<>();
private final Iterable iterable;
private final Optional string;
static {
TEMPLATE_SETTINGS.put(EVALUATE, "<%([\\s\\S]+?)%>");
TEMPLATE_SETTINGS.put(INTERPOLATE, "<%=([\\s\\S]+?)%>");
TEMPLATE_SETTINGS.put(ESCAPE, "<%-([\\s\\S]+?)%>");
ESCAPES.put('&', "&");
ESCAPES.put('<', "<");
ESCAPES.put('>', ">");
ESCAPES.put('"', """);
ESCAPES.put('\'', "'");
ESCAPES.put('`', "`");
}
public Underscore(final Iterable iterable) {
this.iterable = iterable;
this.string = Optional.empty();
}
public Underscore(final String string) {
this.iterable = null;
this.string = Optional.of(string);
}
private static void setTemplateKey(
final Map templateSettings, final String key) {
if (templateSettings.containsKey(key) && templateSettings.get(key).contains(ALL_SYMBOLS)) {
TEMPLATE_SETTINGS.put(key, templateSettings.get(key));
}
}
public static void templateSettings(final Map templateSettings) {
setTemplateKey(templateSettings, EVALUATE);
setTemplateKey(templateSettings, INTERPOLATE);
setTemplateKey(templateSettings, ESCAPE);
}
private static final class WherePredicate implements Predicate {
private final List> properties;
private WherePredicate(List> properties) {
this.properties = properties;
}
@Override
public boolean test(final E elem) {
for (Map.Entry prop : properties) {
try {
if (!elem.getClass()
.getField(prop.getKey())
.get(elem)
.equals(prop.getValue())) {
return false;
}
} catch (Exception ex) {
try {
if (!elem.getClass()
.getMethod(prop.getKey())
.invoke(elem)
.equals(prop.getValue())) {
return false;
}
} catch (Exception ignored) {
// ignored
}
}
}
return true;
}
}
private static final class TemplateImpl implements Template> {
private final String template;
private TemplateImpl(String template) {
this.template = template;
}
@Override
public String apply(Map value) {
final String evaluate = TEMPLATE_SETTINGS.get(EVALUATE);
final String interpolate = TEMPLATE_SETTINGS.get(INTERPOLATE);
final String escape = TEMPLATE_SETTINGS.get(ESCAPE);
String result = template;
for (final Map.Entry element : value.entrySet()) {
final String value1 =
String.valueOf(element.getValue())
.replace("\\", "\\\\")
.replace("$", "\\$");
result =
java.util.regex.Pattern.compile(
interpolate.replace(
ALL_SYMBOLS, S_Q + element.getKey() + E_S))
.matcher(result)
.replaceAll(value1);
result =
java.util.regex.Pattern.compile(
escape.replace(ALL_SYMBOLS, S_Q + element.getKey() + E_S))
.matcher(result)
.replaceAll(escape(value1));
result =
java.util.regex.Pattern.compile(
evaluate.replace(ALL_SYMBOLS, S_Q + element.getKey() + E_S))
.matcher(result)
.replaceAll(value1);
}
return result;
}
@Override
public List check(Map value) {
final String evaluate = TEMPLATE_SETTINGS.get(EVALUATE);
final String interpolate = TEMPLATE_SETTINGS.get(INTERPOLATE);
final String escape = TEMPLATE_SETTINGS.get(ESCAPE);
String result = template;
final List notFound = new ArrayList<>();
final List valueKeys = new ArrayList<>();
for (final Map.Entry element : value.entrySet()) {
final String key = "" + element.getKey();
java.util.regex.Matcher matcher =
java.util.regex.Pattern.compile(
interpolate.replace(ALL_SYMBOLS, S_Q + key + E_S))
.matcher(result);
boolean isFound = matcher.find();
result = matcher.replaceAll(String.valueOf(element.getValue()));
matcher =
java.util.regex.Pattern.compile(
escape.replace(ALL_SYMBOLS, S_Q + key + E_S))
.matcher(result);
isFound |= matcher.find();
result = matcher.replaceAll(escape(String.valueOf(element.getValue())));
matcher =
java.util.regex.Pattern.compile(
evaluate.replace(ALL_SYMBOLS, S_Q + key + E_S))
.matcher(result);
isFound |= matcher.find();
result = matcher.replaceAll(String.valueOf(element.getValue()));
if (!isFound) {
notFound.add(key);
}
valueKeys.add(key);
}
final List templateVars = new ArrayList<>();
java.util.regex.Matcher matcher =
java.util.regex.Pattern.compile(interpolate).matcher(result);
while (matcher.find()) {
templateVars.add(matcher.group(1).trim());
}
result = matcher.replaceAll("");
matcher = java.util.regex.Pattern.compile(escape).matcher(result);
while (matcher.find()) {
templateVars.add(matcher.group(1).trim());
}
result = matcher.replaceAll("");
matcher = java.util.regex.Pattern.compile(evaluate).matcher(result);
while (matcher.find()) {
templateVars.add(matcher.group(1).trim());
}
notFound.addAll(difference(templateVars, valueKeys));
return notFound;
}
}
private static final class MyIterable implements Iterable {
private final UnaryOperator unaryOperator;
private boolean firstRun = true;
private T value;
MyIterable(final T seed, final UnaryOperator unaryOperator) {
this.value = seed;
this.unaryOperator = unaryOperator;
}
public Iterator iterator() {
return new Iterator<>() {
@Override
public boolean hasNext() {
return true;
}
@Override
public T next() {
if (firstRun) {
firstRun = false;
} else {
value = unaryOperator.apply(value);
}
return value;
}
@Override
public void remove() {
// ignored
}
};
}
}
public static Function, V> iteratee(final K key) {
return item -> item.get(key);
}
/*
* Documented, #each
*/
public static void each(final Iterable iterable, final Consumer super T> func) {
for (T element : iterable) {
func.accept(element);
}
}
public static void eachIndexed(
final Iterable iterable, final BiConsumer func) {
int index = 0;
for (T element : iterable) {
func.accept(index, element);
index += 1;
}
}
public void each(final Consumer super T> func) {
each(iterable, func);
}
public static void eachRight(final Iterable iterable, final Consumer super T> func) {
each(reverse(iterable), func);
}
public void eachRight(final Consumer super T> func) {
eachRight(iterable, func);
}
public static void forEach(final Iterable iterable, final Consumer super T> func) {
each(iterable, func);
}
public static void forEachIndexed(
final Iterable iterable, final BiConsumer func) {
eachIndexed(iterable, func);
}
public void forEach(final Consumer super T> func) {
each(iterable, func);
}
public void forEachIndexed(final BiConsumer func) {
eachIndexed(iterable, func);
}
public static void forEachRight(
final Iterable iterable, final Consumer super T> func) {
eachRight(iterable, func);
}
public void forEachRight(final Consumer super T> func) {
eachRight(iterable, func);
}
/*
* Documented, #map
*/
public static List map(final List list, final Function super E, T> func) {
final List transformed = newArrayListWithExpectedSize(list.size());
for (E element : list) {
transformed.add(func.apply(element));
}
return transformed;
}
public static List mapMulti(
final List list, final BiConsumer super E, ? super Consumer> mapper) {
final List transformed = newArrayListWithExpectedSize(list.size());
for (E element : list) {
Consumer value = transformed::add;
mapper.accept(element, value);
}
return transformed;
}
public List map(final Function super T, F> func) {
return map(newArrayList(iterable), func);
}
public static List map(final int[] array, final Function super Integer, T> func) {
final List transformed = newArrayListWithExpectedSize(array.length);
for (int element : array) {
transformed.add(func.apply(element));
}
return transformed;
}
public static Set map(final Set set, final Function super E, T> func) {
final Set transformed = newLinkedHashSetWithExpectedSize(set.size());
for (E element : set) {
transformed.add(func.apply(element));
}
return transformed;
}
public static List mapIndexed(
final List list, final BiFunction func) {
final List transformed = newArrayListWithExpectedSize(list.size());
int index = 0;
for (E element : list) {
transformed.add(func.apply(index, element));
index += 1;
}
return transformed;
}
public static List replace(
final Iterable iter, final Predicate pred, final T value) {
List list = newArrayList(iter);
if (pred == null) {
return list;
}
ListIterator itera = list.listIterator();
while (itera.hasNext()) {
if (pred.test(itera.next())) {
itera.set(value);
}
}
return list;
}
public List replace(final Predicate pred, final T value) {
return replace(value(), pred, value);
}
public static List replaceIndexed(
final Iterable iter, final PredicateIndexed pred, final T value) {
List list = newArrayList(iter);
if (pred == null) {
return list;
}
ListIterator itera = list.listIterator();
int index = 0;
while (itera.hasNext()) {
if (pred.test(index, itera.next())) {
itera.set(value);
}
index++;
}
return list;
}
public List replaceIndexed(final PredicateIndexed pred, final T value) {
return replaceIndexed(value(), pred, value);
}
public List mapIndexed(final BiFunction func) {
return mapIndexed(newArrayList(iterable), func);
}
public static List collect(final List list, final Function super E, T> func) {
return map(list, func);
}
public static Set collect(final Set set, final Function super E, T> func) {
return map(set, func);
}
/*
* Documented, #reduce
*/
public static E reduce(
final Iterable iterable, final BiFunction func, final E zeroElem) {
E accum = zeroElem;
for (T element : iterable) {
accum = func.apply(accum, element);
}
return accum;
}
public static Optional reduce(final Iterable iterable, final BinaryOperator func) {
boolean foundAny = false;
T accum = null;
for (T element : iterable) {
if (foundAny) {
accum = func.apply(accum, element);
} else {
foundAny = true;
accum = element;
}
}
return foundAny ? Optional.of(accum) : Optional.empty();
}
public static E reduce(
final int[] array, final BiFunction func, final E zeroElem) {
E accum = zeroElem;
for (int element : array) {
accum = func.apply(accum, element);
}
return accum;
}
public static E reduce(
final T[] array, final BiFunction func, final E zeroElem) {
E accum = zeroElem;
for (T element : array) {
accum = func.apply(accum, element);
}
return accum;
}
public static E foldl(
final Iterable iterable, final BiFunction func, final E zeroElem) {
return reduce(iterable, func, zeroElem);
}
public static E inject(
final Iterable iterable, final BiFunction func, final E zeroElem) {
return reduce(iterable, func, zeroElem);
}
/*
* Documented, #reduceRight
*/
public static E reduceRight(
final Iterable iterable, final BiFunction func, final E zeroElem) {
return reduce(reverse(iterable), func, zeroElem);
}
public static Optional reduceRight(
final Iterable iterable, final BinaryOperator func) {
return reduce(reverse(iterable), func);
}
public static E reduceRight(
final int[] array, final BiFunction func, final E zeroElem) {
E accum = zeroElem;
for (Integer element : reverse(array)) {
accum = func.apply(accum, element);
}
return accum;
}
public static E reduceRight(
final T[] array, final BiFunction func, final E zeroElem) {
return reduce(reverse(array), func, zeroElem);
}
public static E foldr(
final Iterable iterable, final BiFunction func, final E zeroElem) {
return reduceRight(iterable, func, zeroElem);
}
/*
* Documented, #find
*/
public static Optional find(final Iterable iterable, final Predicate pred) {
for (E element : iterable) {
if (pred.test(element)) {
return isNull(element) ? null : Optional.of(element);
}
}
return Optional.empty();
}
public static Optional detect(final Iterable iterable, final Predicate pred) {
return find(iterable, pred);
}
public static Optional findLast(final Iterable iterable, final Predicate pred) {
return find(reverse(iterable), pred);
}
/*
* Documented, #filter
*/
public static List filter(final Iterable iterable, final Predicate pred) {
final List filtered = new ArrayList<>();
for (E element : iterable) {
if (pred.test(element)) {
filtered.add(element);
}
}
return filtered;
}
public static List filter(final List list, final Predicate pred) {
final List filtered = new ArrayList<>();
for (E element : list) {
if (pred.test(element)) {
filtered.add(element);
}
}
return filtered;
}
public List filter(final Predicate pred) {
final List filtered = new ArrayList<>();
for (final T element : value()) {
if (pred.test(element)) {
filtered.add(element);
}
}
return filtered;
}
public static List filterIndexed(final List list, final PredicateIndexed pred) {
final List filtered = new ArrayList<>();
int index = 0;
for (E element : list) {
if (pred.test(index, element)) {
filtered.add(element);
}
index += 1;
}
return filtered;
}
public static Set filter(final Set set, final Predicate pred) {
final Set filtered = new LinkedHashSet<>();
for (E element : set) {
if (pred.test(element)) {
filtered.add(element);
}
}
return filtered;
}
public static List select(final List list, final Predicate pred) {
return filter(list, pred);
}
public static Set select(final Set set, final Predicate pred) {
return filter(set, pred);
}
/*
* Documented, #reject
*/
public static List reject(final List list, final Predicate pred) {
return filter(list, input -> !pred.test(input));
}
public List reject(final Predicate pred) {
return filter(input -> !pred.test(input));
}
public static List rejectIndexed(final List list, final PredicateIndexed pred) {
return filterIndexed(list, (index, input) -> !pred.test(index, input));
}
public static Set reject(final Set set, final Predicate pred) {
return filter(set, input -> !pred.test(input));
}
public static List filterFalse(final List list, final Predicate pred) {
return reject(list, pred);
}
public List filterFalse(final Predicate pred) {
return reject(pred);
}
public static Set filterFalse(final Set set, final Predicate pred) {
return reject(set, pred);
}
public static boolean every(final Iterable iterable, final Predicate pred) {
for (E item : iterable) {
if (!pred.test(item)) {
return false;
}
}
return true;
}
public boolean every(final Predicate pred) {
return every(iterable, pred);
}
/*
* Documented, #all
*/
public static boolean all(final Iterable iterable, final Predicate pred) {
return every(iterable, pred);
}
public boolean all(final Predicate pred) {
return every(iterable, pred);
}
public static boolean some(final Iterable iterable, final Predicate pred) {
Optional optional = find(iterable, pred);
return optional == null || optional.isPresent();
}
public boolean some(final Predicate pred) {
return some(iterable, pred);
}
/*
* Documented, #any
*/
public static boolean any(final Iterable iterable, final Predicate pred) {
return some(iterable, pred);
}
public boolean any(final Predicate pred) {
return some(iterable, pred);
}
public static int count(final Iterable iterable, final Predicate pred) {
int result = 0;
for (E item : iterable) {
if (pred.test(item)) {
result += 1;
}
}
return result;
}
public int count(final Predicate pred) {
return count(iterable, pred);
}
public static boolean contains(final Iterable iterable, final E elem) {
return some(iterable, e -> Objects.equals(elem, e));
}
public boolean contains(final T elem) {
return contains(iterable, elem);
}
public static boolean containsWith(final Iterable iterable, final E elem) {
return some(
iterable,
e -> elem == null ? e == null : String.valueOf(e).contains(String.valueOf(elem)));
}
public boolean containsWith(final T elem) {
return containsWith(iterable, elem);
}
public static boolean contains(
final Iterable iterable, final E elem, final int fromIndex) {
final List list = newArrayList(iterable);
return contains(list.subList(fromIndex, list.size()), elem);
}
public boolean containsAtLeast(final T value, final int count) {
return Underscore.containsAtLeast(this.iterable, value, count);
}
public boolean containsAtMost(final T value, final int count) {
return Underscore.containsAtMost(this.iterable, value, count);
}
public static boolean containsAtLeast(
final Iterable iterable, final E value, final int count) {
int foundItems = 0;
for (E element : iterable) {
if (Objects.equals(element, value)) {
foundItems += 1;
}
if (foundItems >= count) {
break;
}
}
return foundItems >= count;
}
public static boolean containsAtMost(
final Iterable iterable, final E value, final int count) {
int foundItems = size(iterable);
for (E element : iterable) {
if (!(Objects.equals(element, value))) {
foundItems -= 1;
}
if (foundItems <= count) {
break;
}
}
return foundItems <= count;
}
/*
* Documented, #include
*/
public static boolean include(final Iterable iterable, final E elem) {
return contains(iterable, elem);
}
/*
* Documented, #invoke
*/
@SuppressWarnings("unchecked")
public static List invoke(
final Iterable iterable, final String methodName, final List args) {
final List result = new ArrayList<>();
final List> argTypes = map(args, Object::getClass);
try {
final Method method =
iterable.iterator()
.next()
.getClass()
.getMethod(methodName, argTypes.toArray(new Class[0]));
for (E arg : iterable) {
doInvoke(args, result, method, arg);
}
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException(e);
}
return result;
}
@SuppressWarnings("unchecked")
private static void doInvoke(List args, List result, Method method, E arg) {
try {
result.add((E) method.invoke(arg, args.toArray(new Object[0])));
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
}
public List invoke(final String methodName, final List args) {
return invoke(iterable, methodName, args);
}
public static List invoke(final Iterable iterable, final String methodName) {
return invoke(iterable, methodName, Collections.emptyList());
}
public List invoke(final String methodName) {
return invoke(iterable, methodName);
}
/*
* Documented, #pluck
*/
public static List pluck(final List list, final String propertyName) {
if (list.isEmpty()) {
return Collections.emptyList();
}
return map(
list,
elem -> {
try {
return elem.getClass().getField(propertyName).get(elem);
} catch (Exception e) {
try {
return elem.getClass().getMethod(propertyName).invoke(elem);
} catch (Exception ex) {
throw new IllegalArgumentException(ex);
}
}
});
}
public List pluck(final String propertyName) {
return pluck(newArrayList(iterable), propertyName);
}
public static Set pluck(final Set set, final String propertyName) {
if (set.isEmpty()) {
return Collections.emptySet();
}
return map(
set,
elem -> {
try {
return elem.getClass().getField(propertyName).get(elem);
} catch (Exception e) {
try {
return elem.getClass().getMethod(propertyName).invoke(elem);
} catch (Exception ex) {
throw new IllegalArgumentException(ex);
}
}
});
}
/*
* Documented, #where
*/
public static List where(
final List