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
import com.jessebrault.ssg.util.Monoid
import groovy.transform.EqualsAndHashCode
import groovy.transform.NullCheck
import groovy.transform.TupleConstructor
@ -9,6 +10,11 @@ import groovy.transform.TupleConstructor
@EqualsAndHashCode
final class SiteSpec {
static final Monoid<SiteSpec> defaultSemiGroup = new Monoid<>(
SiteSpec::concat,
SiteSpec::getBlank
)
static SiteSpec getBlank() {
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
import com.jessebrault.ssg.util.Monoid
final class Properties {
static <T> Property<T> get() {
new SimpleProperty<>()
static <T> Property<T> get(Monoid<T> semiGroup) {
new SimpleProperty<>(semiGroup)
}
static <T> Property<T> get(T convention) {
new SimpleProperty<>(convention)
static <T> Property<T> get(Monoid<T> semiGroup, T convention) {
new SimpleProperty<>(semiGroup, convention)
}
static <T> Property<T> get(T convention, T t) {
new SimpleProperty<>(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)
static <T> Property<T> get(Monoid<T> semiGroup, T convention, T t) {
new SimpleProperty<>(semiGroup, convention, t)
}
private Properties() {}

View File

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

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

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