Skip to content

Commit

Permalink
Introduce Applicative Validation
Browse files Browse the repository at this point in the history
closes gh-119
  • Loading branch information
making committed May 13, 2021
1 parent 0c65feb commit c057042
Show file tree
Hide file tree
Showing 43 changed files with 2,691 additions and 10 deletions.
124 changes: 124 additions & 0 deletions scripts/generate-applicative.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#!/bin/bash
set -e
n=16

for i in `seq 1 ${n}`;do
class="Function${i}"
file="$(dirname $0)/../src/main/java/am/ik/yavi/fn/${class}.java"
echo $file
cat <<EOF > ${file}
/*
* Copyright (C) 2018-2021 Toshiaki Maki <makingx@gmail.com>
*
* 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 am.ik.yavi.fn;
/**
* Generated by
* https://github.com/making/yavi/blob/develop/scripts/generate-applicative.sh
*
* @since 0.6.0
*/
public interface ${class}<$(echo $(for j in `seq 1 ${i}`;do echo -n "T${j}, ";done) | sed 's/,$//'), R> {
R apply($(echo $(for j in `seq 1 ${i}`;do echo -n "T${j} t${j}, ";done) | sed 's/,$//')) throws Exception;
default $(echo $(for j in `seq 1 ${i}`;do echo -n "Function1<T${j}, ";done)) R$(echo $(for j in `seq 1 ${i}`;do echo -n ">";done)) curried() {
return $(echo $(for j in `seq 1 ${i}`;do echo -n "t${j} -> ";done)) this.apply($(echo $(for j in `seq 1 ${i}`;do echo -n "t${j}, ";done) | sed 's/,$//'));
}
}
EOF
done

for i in `seq 1 ${n}`;do
class="Composing${i}"
file="$(dirname $0)/../src/main/java/am/ik/yavi/fn/${class}.java"
echo $file
cat <<EOF > ${file}
/*
* Copyright (C) 2018-2021 Toshiaki Maki <makingx@gmail.com>
*
* 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 am.ik.yavi.fn;
import java.util.List;
/**
* Generated by
* https://github.com/making/yavi/blob/develop/scripts/generate-applicative.sh
*
* @since 0.6.0
*/
public class ${class}<E, $(echo $(for j in `seq 1 ${i}`;do echo -n "T${j}, ";done) | sed 's/,$//')> {
$(for j in `seq 1 ${i}`;do echo " protected final Validation<E, T${j}> v${j};";echo;done)
public ${class}($(echo $(for j in `seq 1 ${i}`;do echo -n "Validation<E, T${j}> v${j}, ";done) | sed 's/,$//')) {
$(for j in `seq 1 ${i}`;do echo " this.v${j} = v${j};";done)
}
public <R> Validation<List<E>, R> apply(Function${i}<$(echo $(for j in `seq 1 ${i}`;do echo -n "T${j}, ";done) | sed 's/,$//'), R> f) {
return $(echo $(for j in `seq ${i} 1`;do echo -n "v${j}.apply(";done) | sed 's/,$//')Validation.success(f.curried())$(echo $(for j in `seq 1 ${i}`;do echo -n ")";done));
}
$(if [ ${i} -lt ${n} ];then echo;echo " public <T$((${i} + 1))> Composing$((${i} + 1))<E, $(echo $(for j in `seq 1 $((${i} + 1))`;do echo -n "T${j}, ";done) | sed 's/,$//')> compose(Validation<E, T$((${i} + 1))> v$((${i} + 1))) {"; echo " return new Composing$((${i} + 1))<>($(echo $(for j in `seq 1 $((${i} + 1))`;do echo -n "v${j}, ";done) | sed 's/,$//'));"; echo " }"; else echo -n "";fi)
}
EOF
done

class="Validations"
file="$(dirname $0)/../src/main/java/am/ik/yavi/fn/${class}.java"
echo $file
cat <<EOF > ${file}
/*
* Copyright (C) 2018-2021 Toshiaki Maki <makingx@gmail.com>
*
* 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 am.ik.yavi.fn;
import java.util.List;
/**
* Generated by
* https://github.com/making/yavi/blob/develop/scripts/generate-applicative.sh
*
* @since 0.6.0
*/
public class ${class} {
$(for i in `seq 1 ${n}`;do echo " public static <E, $(echo $(for j in `seq 1 ${i}`;do echo -n "T${j}, ";done) | sed 's/,$//')> Composing${i}<E, $(echo $(for j in `seq 1 ${i}`;do echo -n "T${j}, ";done) | sed 's/,$//')> compose($(echo $(for j in `seq 1 ${i}`;do echo -n "Validation<E, T${j}> v${j}, ";done) | sed 's/,$//')) {"; echo " return new Composing${i}<>($(echo $(for j in `seq 1 ${i}`;do echo -n "v${j}, ";done) | sed 's/,$//'));"; echo " }";echo;done)
$(for i in `seq 1 ${n}`;do echo " public static <R, E, $(echo $(for j in `seq 1 ${i}`;do echo -n "T${j}, ";done) | sed 's/,$//')> Validation<List<E>, R> apply($(echo $(for j in `seq 1 ${i}`;do echo -n "Validation<E, T${j}> v${j}, ";done))Function${i}<$(echo $(for j in `seq 1 ${i}`;do echo -n "T${j}, ";done) | sed 's/,$//'), R> f) {"; echo " return compose($(echo $(for j in `seq 1 ${i}`;do echo -n "v${j}, ";done) | sed 's/,$//')).apply(f);"; echo " }";echo;done)
}
EOF
2 changes: 1 addition & 1 deletion src/main/java/am/ik/yavi/builder/ValidatorBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,7 @@ private <N> Consumer<Pair<ConstraintCondition<N>, ValidatorSubset<N>>> appendNes
final ConstraintCondition<T> condition = new NestedConstraintCondition<>(
nested, conditionalValidator.first());
final ValidatorSubset<T> v = new NestedValidatorSubset<>(nested,
conditionalValidator.second(), name + this.messageKeySeparator);
conditionalValidator.second(), name);
this.conditionalValidators.add(new Pair<>(condition, v));
};
}
Expand Down
49 changes: 49 additions & 0 deletions src/main/java/am/ik/yavi/core/ApplicativeValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2018-2021 Toshiaki Maki <makingx@gmail.com>
*
* 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 am.ik.yavi.core;

import java.util.Locale;

import am.ik.yavi.fn.Validation;

/**
* Applicative validator class
* @param <T> Target class
* @since 0.6.0
*/
public final class ApplicativeValidator<T> {
private final Validator<T> validator;

ApplicativeValidator(Validator<T> validator) {
this.validator = validator;
}

public Validation<ConstraintViolations, T> validate(T target) {
return this.validate(target, Locale.getDefault(), ConstraintGroup.DEFAULT);
}

public Validation<ConstraintViolations, T> validate(T target, Locale locale,
ConstraintGroup constraintGroup) {
final ConstraintViolations violations = this.validator.validate(target, locale,
constraintGroup);
if (violations.isValid()) {
return Validation.success(target);
}
else {
return Validation.failure(violations);
}
}
}
33 changes: 32 additions & 1 deletion src/main/java/am/ik/yavi/core/ConstraintViolations.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,38 @@
import java.util.stream.Collectors;

public class ConstraintViolations implements List<ConstraintViolation> {
private final List<ConstraintViolation> delegate = new ArrayList<>();
private final List<ConstraintViolation> delegate;

/**
* Constructs an empty list with an initial capacity of ten.
*/
public ConstraintViolations() {
this.delegate = new ArrayList<>();
}

/**
* Constructs an empty list with the specified initial capacity.
*
* @param initialCapacity the initial capacity of the list
* @throws IllegalArgumentException if the specified initial capacity is negative
* @since 0.6.0
*/
public ConstraintViolations(int initialCapacity) {
this.delegate = new ArrayList<>(initialCapacity);
}

/**
* Concatenate all violations
* @param violations
* @return concatenated violations
* @since 0.6.0
*/
public static ConstraintViolations concat(List<ConstraintViolations> violations) {
final ConstraintViolations constraintViolations = new ConstraintViolations(
violations.stream().mapToInt(ConstraintViolations::size).sum());
violations.forEach(constraintViolations::addAll);
return constraintViolations;
}

/**
* Appends the specified element to the end of this list (optional operation).
Expand Down
19 changes: 14 additions & 5 deletions src/main/java/am/ik/yavi/core/Validator.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@

/**
* Validates the target instances.
*
*
* A <code>Validator</code> instance is immutable and can be used as a singleton.
*
*
* @param <T> the type of the instance to validate
* @author Toshiaki Maki
*/
Expand Down Expand Up @@ -73,12 +73,12 @@ private Validator(String messageKeySeparator,
Validator<T> prefixed(String prefix) {
return new Validator<>(this.messageKeySeparator, this.predicatesList,
this.collectionValidators, this.conditionalValidators,
this.messageFormatter, prefix);
this.messageFormatter, prefix + this.messageKeySeparator);
}

/**
* This method is supposed to be used only internally.
*
*
* @param action callback per <code>ConstraintPredicates</code>.
*/
public void forEachPredicates(Consumer<ConstraintPredicates<T, ?>> action) {
Expand Down Expand Up @@ -121,7 +121,7 @@ public ConstraintViolations validate(T target, ConstraintGroup constraintGroup)
/**
* Validates all constraints on {@code target}.<br>
* {@code ConstraintGroup.DEFAULT} is used as a constraint group.
*
*
* @param target target to validate
* @param locale the locale targeted for the violation messages.
* @return constraint violations
Expand Down Expand Up @@ -158,6 +158,15 @@ public ConstraintViolations validate(T target) {
return this.validate(target, Locale.getDefault(), ConstraintGroup.DEFAULT);
}

/**
* Convert to the applicative validator
* @return applicative validator
* @since 0.6.0
*/
public ApplicativeValidator<T> applicative() {
return new ApplicativeValidator<>(this);
}

/**
* Validates all constraints on {@code target} and returns {@code Either} object that
* has constraint violations on the left or validated object on the right. <br>
Expand Down
40 changes: 40 additions & 0 deletions src/main/java/am/ik/yavi/fn/Composing1.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (C) 2018-2021 Toshiaki Maki <makingx@gmail.com>
*
* 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 am.ik.yavi.fn;

import java.util.List;

/**
* Generated by
* https://github.com/making/yavi/blob/develop/scripts/generate-applicative.sh
*
* @since 0.6.0
*/
public class Composing1<E, T1> {
protected final Validation<E, T1> v1;

public Composing1(Validation<E, T1> v1) {
this.v1 = v1;
}

public <R> Validation<List<E>, R> apply(Function1<T1, R> f) {
return v1.apply(Validation.success(f.curried()));
}

public <T2> Composing2<E, T1, T2> compose(Validation<E, T2> v2) {
return new Composing2<>(v1, v2);
}
}
73 changes: 73 additions & 0 deletions src/main/java/am/ik/yavi/fn/Composing10.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright (C) 2018-2021 Toshiaki Maki <makingx@gmail.com>
*
* 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 am.ik.yavi.fn;

import java.util.List;

/**
* Generated by
* https://github.com/making/yavi/blob/develop/scripts/generate-applicative.sh
*
* @since 0.6.0
*/
public class Composing10<E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> {
protected final Validation<E, T1> v1;

protected final Validation<E, T2> v2;

protected final Validation<E, T3> v3;

protected final Validation<E, T4> v4;

protected final Validation<E, T5> v5;

protected final Validation<E, T6> v6;

protected final Validation<E, T7> v7;

protected final Validation<E, T8> v8;

protected final Validation<E, T9> v9;

protected final Validation<E, T10> v10;

public Composing10(Validation<E, T1> v1, Validation<E, T2> v2, Validation<E, T3> v3,
Validation<E, T4> v4, Validation<E, T5> v5, Validation<E, T6> v6,
Validation<E, T7> v7, Validation<E, T8> v8, Validation<E, T9> v9,
Validation<E, T10> v10) {
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
this.v4 = v4;
this.v5 = v5;
this.v6 = v6;
this.v7 = v7;
this.v8 = v8;
this.v9 = v9;
this.v10 = v10;
}

public <R> Validation<List<E>, R> apply(
Function10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R> f) {
return v10.apply(v9.apply(v8.apply(v7.apply(v6.apply(v5.apply(v4.apply(
v3.apply(v2.apply(v1.apply(Validation.success(f.curried())))))))))));
}

public <T11> Composing11<E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> compose(
Validation<E, T11> v11) {
return new Composing11<>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11);
}
}
Loading

0 comments on commit c057042

Please sign in to comment.