Experimenting with Monoid, etc.

This commit is contained in:
JesseBrault0709 2023-05-05 11:31:29 +02:00
parent 4fa2ba0ac9
commit c74d80a69e
11 changed files with 135 additions and 233 deletions

View File

@ -1,5 +1,6 @@
package com.jessebrault.ssg package com.jessebrault.ssg
import com.jessebrault.ssg.util.Monoid
import groovy.transform.EqualsAndHashCode import groovy.transform.EqualsAndHashCode
import groovy.transform.NullCheck import groovy.transform.NullCheck
import groovy.transform.TupleConstructor import groovy.transform.TupleConstructor
@ -9,6 +10,11 @@ import groovy.transform.TupleConstructor
@EqualsAndHashCode @EqualsAndHashCode
final class SiteSpec { final class SiteSpec {
static final Monoid<SiteSpec> defaultSemiGroup = new Monoid<>(
SiteSpec::concat,
SiteSpec::getBlank
)
static SiteSpec getBlank() { static SiteSpec getBlank() {
new SiteSpec('', '') new SiteSpec('', '')
} }

View File

@ -0,0 +1,29 @@
package com.jessebrault.ssg.buildscript.domain
import com.jessebrault.ssg.property.Properties
import com.jessebrault.ssg.property.Property
import com.jessebrault.ssg.util.Monoid
final class MutableSiteSpec {
private static final Monoid<String> nameAndBaseUrlMonoid = new Monoid<>(
{ s0, s1 -> s1 },
{ '' }
)
static final Monoid<MutableSiteSpec> MONOID = new Monoid<>(
MutableSiteSpec::concat,
MutableSiteSpec::new
)
private static MutableSiteSpec concat(MutableSiteSpec ms0, MutableSiteSpec ms1) {
new MutableSiteSpec().tap {
name.set(ms1.name.get())
baseUrl.set(ms1.baseUrl.get())
}
}
final Property<String> name = Properties.get(nameAndBaseUrlMonoid)
final Property<String> baseUrl = Properties.get(nameAndBaseUrlMonoid)
}

View File

@ -1,5 +0,0 @@
package com.jessebrault.ssg.property
interface CollectionProperty<T> extends Property<T> {
// TODO
}

View File

@ -1,7 +0,0 @@
package com.jessebrault.ssg.property
interface MapProperty<K, V> extends Property<Map<K, V>> {
V get(K key)
void put(K key, V value)
void putAll(Map<? extends K, ? extends V> map)
}

View File

@ -1,32 +1,19 @@
package com.jessebrault.ssg.property package com.jessebrault.ssg.property
import com.jessebrault.ssg.util.Monoid
final class Properties { final class Properties {
static <T> Property<T> get() { static <T> Property<T> get(Monoid<T> semiGroup) {
new SimpleProperty<>() new SimpleProperty<>(semiGroup)
} }
static <T> Property<T> get(T convention) { static <T> Property<T> get(Monoid<T> semiGroup, T convention) {
new SimpleProperty<>(convention) new SimpleProperty<>(semiGroup, convention)
} }
static <T> Property<T> get(T convention, T t) { static <T> Property<T> get(Monoid<T> semiGroup, T convention, T t) {
new SimpleProperty<>(convention, t) new SimpleProperty<>(semiGroup, convention, t)
}
static <K, V> MapProperty<K, V> getMap() {
new SimpleMapProperty<K, V>()
}
static <K, V> MapProperty<K, V> getMap(Map<? extends K, ? extends V> convention) {
new SimpleMapProperty<K, V>(convention)
}
static <K, V> MapProperty<K, V> getMap(
Map<? extends K, ? extends V> convention,
Map<? extends K, ? extends V> value
) {
new SimpleMapProperty<K, V>(convention, value)
} }
private Properties() {} private Properties() {}

View File

@ -1,38 +1,19 @@
package com.jessebrault.ssg.property package com.jessebrault.ssg.property
import com.jessebrault.ssg.provider.Provider
import java.util.function.Function
import java.util.function.UnaryOperator import java.util.function.UnaryOperator
interface Property<T> extends Provider<T> { interface Property<T> {
T get()
void set(T t) void set(T t)
void set(Provider<T> provider)
void unset() void unset()
default void leftShift(T t) {
this.set(t)
}
default void leftShift(Provider<T> provider) {
this.set(provider)
}
T getConvention() T getConvention()
void setConvention(T t) void setConvention(T t)
void setConvention(Provider<T> provider)
void unsetConvention() void unsetConvention()
void map(UnaryOperator<T> operator) void map(UnaryOperator<T> mapper)
void flatMap(Function<T, Provider<T>> function) void merge(
@DelegatesTo(type = 'T', strategy = Closure.DELEGATE_FIRST)
default void rightShift(UnaryOperator<T> operator) { Closure<?> configurator
this.map(operator) )
}
default void rightShift(Function<T, Provider<T>> function) {
this.flatMap(function)
}
} }

View File

@ -1,122 +0,0 @@
package com.jessebrault.ssg.property
import com.jessebrault.ssg.provider.CollectionProvider
import com.jessebrault.ssg.provider.Provider
import groovy.transform.EqualsAndHashCode
import groovy.transform.NullCheck
import groovy.transform.PackageScope
import java.util.function.Function
import java.util.function.UnaryOperator
@PackageScope
@NullCheck
@EqualsAndHashCode(includeFields = true)
final class SimpleMapProperty<K, V> implements MapProperty<K, V> {
private final Map<K, V> convention = [:]
private final Map<K, V> m = [:]
SimpleMapProperty(
Map<? extends K, ? extends V> convention,
Map<? extends K, ? extends V> m
) {
this.convention.putAll(convention)
this.m.putAll(m)
}
SimpleMapProperty(Map<? extends K, ? extends V> convention) {
this(convention, [:] as Map<K, V>)
}
SimpleMapProperty() {}
@Override
V get(K key) {
if (m[key] != null) {
m[key]
} else if (convention[key] != null) {
convention[key]
} else {
throw new NullPointerException("no such key: ${ key }")
}
}
@Override
void put(K key, V value) {
this.m.put(key, value)
}
@Override
void putAll(Map<? extends K, ? extends V> map) {
this.m.putAll(map)
}
@Override
void set(Map<K, V> kvMap) {
this.m.clear()
this.m.putAll(kvMap)
}
@Override
void set(Provider<Map<K, V>> provider) {
// TODO
}
@Override
void unset() {
this.m.clear()
}
@Override
Map<K, V> getConvention() {
this.convention
}
@Override
void setConvention(Map<K, V> kvMap) {
this.convention.clear()
this.convention.putAll(kvMap)
}
@Override
void setConvention(Provider<Map<K, V>> provider) {
// TODO
}
@Override
void unsetConvention() {
this.convention.clear()
}
@Override
void map(UnaryOperator<Map<K, V>> operator) {
this.m.putAll(operator.apply(this.convention + this.m))
}
@Override
void flatMap(Function<Map<K, V>, Provider<Map<K, V>>> function) {
// TODO
}
@Override
Map<K, V> provide() {
this.convention + this.m
}
@Override
CollectionProvider<Map<K, V>> plus(Provider<Map<K, V>> other) {
// TODO
}
@Override
CollectionProvider<Map<K, V>> asType(Class<CollectionProvider> collectionProviderClass) {
// TODO
}
@Override
boolean isEmpty() {
return false
}
}

View File

@ -1,93 +1,85 @@
package com.jessebrault.ssg.property package com.jessebrault.ssg.property
import com.jessebrault.ssg.provider.AbstractProvider import com.jessebrault.ssg.util.Monoid
import com.jessebrault.ssg.provider.Provider
import com.jessebrault.ssg.provider.Providers
import groovy.transform.EqualsAndHashCode import groovy.transform.EqualsAndHashCode
import groovy.transform.NullCheck import groovy.transform.NullCheck
import groovy.transform.PackageScope import groovy.transform.PackageScope
import java.util.function.Function
import java.util.function.UnaryOperator import java.util.function.UnaryOperator
import static java.util.Objects.requireNonNull
@PackageScope @PackageScope
@NullCheck @NullCheck(includeGenerated = true)
@EqualsAndHashCode(includeFields = true) @EqualsAndHashCode(includeFields = true)
final class SimpleProperty<T> extends AbstractProvider<T> implements Property<T> { final class SimpleProperty<T> implements Property<T> {
private Provider<T> convention = Providers.getEmpty() private final Monoid<T> monoid
private Provider<T> tProvider = Providers.getEmpty()
SimpleProperty(T convention) { private T t
this.convention = Providers.of(convention) private T convention
SimpleProperty(Monoid<T> monoid) {
this.monoid = monoid
this.convention = this.monoid.empty.get()
} }
SimpleProperty(T convention, T t) { SimpleProperty(Monoid<T> monoid, T convention) {
this.convention = Providers.of(convention) this.monoid = monoid
this.tProvider = Providers.of(t) this.convention = convention
} }
SimpleProperty() {} SimpleProperty(Monoid<T> monoid, T convention, T t) {
this.monoid = monoid
this.t = t
this.convention = convention
}
@Override @Override
T provide() { T get() {
this.tProvider.present ? this.tProvider.provide() : this.convention.provide() this.t != null ? this.t : requireNonNull(this.convention)
} }
@Override @Override
void set(T t) { void set(T t) {
this.tProvider = Providers.of(t) this.t = t
}
@Override
void set(Provider<T> provider) {
this.tProvider = provider
} }
@Override @Override
void unset() { void unset() {
this.tProvider = Providers.getEmpty() this.t = null
} }
@Override @Override
T getConvention() { T getConvention() {
this.convention.provide() requireNonNull(this.convention)
} }
@Override @Override
void setConvention(T t) { void setConvention(T t) {
this.convention = Providers.of(t) this.convention = t
}
@Override
void setConvention(Provider<T> provider) {
this.convention = provider
} }
@Override @Override
void unsetConvention() { void unsetConvention() {
this.convention = Providers.getEmpty() this.t = null
} }
@Override @Override
void map(UnaryOperator<T> operator) { void map(UnaryOperator<T> mapper) {
def oldTProvider = this.tProvider this.t = requireNonNull(mapper.apply(this.t))
this.tProvider = Providers.fromSupplier {
operator.apply(oldTProvider.provide())
}
} }
@Override @Override
void flatMap(Function<T, Provider<T>> function) { void merge(
def oldTProvider = this.tProvider @DelegatesTo(type = 'T', strategy = Closure.DELEGATE_FIRST)
this.tProvider = Providers.fromSupplier { Closure<?> configurator
function.apply(oldTProvider.provide()).provide() ) {
} def d = requireNonNull(this.monoid.empty.get())
} configurator.delegate = d
configurator.resolveStrategy = Closure.DELEGATE_FIRST
@Override configurator()
String toString() { this.t = requireNonNull(this.monoid.concat.apply(this.t != null ? this.t : this.monoid.empty.get(), d))
"SimpleProperty(convention: ${ this.convention }, tProvider: ${ this.tProvider })"
} }
} }

View File

@ -0,0 +1,16 @@
package com.jessebrault.ssg.util
import groovy.transform.EqualsAndHashCode
import groovy.transform.NullCheck
import groovy.transform.TupleConstructor
import java.util.function.BinaryOperator
import java.util.function.Supplier
@TupleConstructor(defaults = false)
@NullCheck(includeGenerated = true)
@EqualsAndHashCode
final class Monoid<T> {
final BinaryOperator<T> concat
final Supplier<T> empty
}

View File

@ -0,0 +1,24 @@
package com.jessebrault.ssg.property
import com.jessebrault.ssg.buildscript.domain.MutableSiteSpec
import org.junit.jupiter.api.Test
import static org.junit.jupiter.api.Assertions.assertEquals
final class SimplePropertyTests {
@Test
void merge() {
def p = Properties.get(MutableSiteSpec.MONOID)
p.merge {
name.set('Hello')
}
p.map {
it.name.map { it + ', World!' }
it
}
def ms = p.get()
assertEquals('Hello, World!', ms.name.get())
}
}

View File

@ -1,16 +1,17 @@
abstractBuild(name: 'redDogAll', extends: 'default') { abstractBuild(name: 'redDogAll', extends: 'default') {
siteSpec.merge { // siteSpec(Closure) is short for siteSpec.merge(Closure)
siteSpec {
name = 'Red Dog Ensemble' name = 'Red Dog Ensemble'
baseUrl = 'https://reddogensemble.com' baseUrl = 'https://reddogensemble.com'
} }
globals.merge { globals {
greeting = 'Say hello to good music!' greeting = 'Say hello to good music!'
} }
sources { types -> sources { types ->
models.map { acc -> models.map { acc ->
old + someMethodThatGetsEventModels() acc + someMethodThatGetsEventModels()
} }
} }
@ -26,11 +27,11 @@ abstractBuild(name: 'redDogAll', extends: 'default') {
} }
build(name: 'preview', extends: 'redDogAll') { build(name: 'preview', extends: 'redDogAll') {
siteSpec.merge { siteSpec { base ->
baseUrl += '/preview' // if possible baseUrl = base.baseUrl + '/preview' // if possible
} }
globals.merge { globals {
greeting = 'Hello from preview!' greeting = 'Hello from preview!'
} }
} }