Changing Closures to various functional interfaces.

This commit is contained in:
JesseBrault0709 2023-04-26 10:00:15 +02:00
parent a8c6955ca8
commit 2ce269bbdc
15 changed files with 100 additions and 119 deletions

View File

@ -38,7 +38,7 @@ final class DefaultBuildScriptConfiguratorFactory implements BuildScriptConfigur
taskFactories { sourceProviders -> taskFactories { sourceProviders ->
register('textToHtml', TextToHtmlTaskFactory::new) { register('textToHtml', TextToHtmlTaskFactory::new) {
it.specProvider += CollectionProviders.from { it.specProvider += CollectionProviders.fromSupplier {
def templates = sourceProviders.templatesProvider.provide() def templates = sourceProviders.templatesProvider.provide()
sourceProviders.textsProvider.provide().collect { sourceProviders.textsProvider.provide().collect {
def frontMatterResult = it.type.frontMatterGetter.get(it) def frontMatterResult = it.type.frontMatterGetter.get(it)

View File

@ -1,10 +1,6 @@
package com.jessebrault.ssg.model package com.jessebrault.ssg.model
import groovy.io.FileType import java.util.function.Supplier
import groovy.transform.stc.ClosureParams
import groovy.transform.stc.FromString
import java.nio.file.Path
final class Models { final class Models {
@ -12,33 +8,8 @@ final class Models {
new SimpleModel<>(name, t) new SimpleModel<>(name, t)
} }
static <T> Model<T> from(String name, Closure<T> tClosure) { static <T> Model<T> fromSupplier(String name, Supplier<T> tClosure) {
new ClosureBasedModel<>(name, tClosure) new SupplierBasedModel<>(name, tClosure)
}
/**
* Takes a directory and iterates recursively through all files present in the directory and sub-directories,
* supplying each File along with a String representing that File's path relative to the base Directory to the
* given Closure, which then returns a Model containing T, all of which are collected and then returned together.
*
* @param directory The base directory in which to search for Files to process.
* @param fileToModelClosure A Closure which receives two params: the File being processed,
* and a String representing the path of that File relative to the base directory. Must return
* a Model containing T.
* @return A Collection of Models containing Ts.
*/
static <T> Collection<Model<T>> fromDirectory(
File directory,
@ClosureParams(value = FromString, options = ['java.io.File, java.lang.String'])
Closure<Model<T>> fileToModelClosure
) {
final Collection<Model<T>> models = []
def directoryPath = Path.of(directory.path)
directory.eachFileRecurse(FileType.FILES) {
def relativePath = directoryPath.relativize(Path.of(it.path)).toString()
models << fileToModelClosure(it, relativePath)
}
models
} }
private Models() {} private Models() {}

View File

@ -5,18 +5,20 @@ import groovy.transform.NullCheck
import groovy.transform.PackageScope import groovy.transform.PackageScope
import groovy.transform.TupleConstructor import groovy.transform.TupleConstructor
import java.util.function.Supplier
@PackageScope @PackageScope
@TupleConstructor(includeFields = true, defaults = false) @TupleConstructor(includeFields = true, defaults = false)
@NullCheck(includeGenerated = true) @NullCheck(includeGenerated = true)
@EqualsAndHashCode(includeFields = true) @EqualsAndHashCode(includeFields = true)
final class ClosureBasedModel<T> implements Model<T> { final class SupplierBasedModel<T> implements Model<T> {
final String name final String name
private final Closure<T> tClosure private final Supplier<T> supplier
@Override @Override
T get() { T get() {
this.tClosure() this.supplier.get()
} }
} }

View File

@ -3,7 +3,6 @@ package com.jessebrault.ssg.page
import com.jessebrault.ssg.provider.CollectionProvider import com.jessebrault.ssg.provider.CollectionProvider
import com.jessebrault.ssg.provider.CollectionProviders import com.jessebrault.ssg.provider.CollectionProviders
import com.jessebrault.ssg.util.ExtensionUtil import com.jessebrault.ssg.util.ExtensionUtil
import com.jessebrault.ssg.util.PathUtil
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
@ -12,14 +11,19 @@ final class PagesProviders {
private static final Logger logger = LoggerFactory.getLogger(PagesProviders) private static final Logger logger = LoggerFactory.getLogger(PagesProviders)
static CollectionProvider<Page> from(File pagesDirectory, Collection<PageType> pageTypes) { static CollectionProvider<Page> from(File pagesDirectory, Collection<PageType> pageTypes) {
CollectionProviders.from(pagesDirectory) { CollectionProviders.fromDirectory(pagesDirectory) { file, relativePath ->
def extension = ExtensionUtil.getExtension(it.path) def extension = ExtensionUtil.getExtension(relativePath)
def pageType = pageTypes.find { it.ids.contains(extension) } if (extension) {
if (!pageType) { def pageType = pageTypes.find { it.ids.contains(extension) }
logger.warn('there is no PageType for file {}; skipping', it) if (!pageType) {
null logger.debug('there is no PageType for file {}; skipping', file)
return null
} else {
return new Page(relativePath, pageType, file.getText())
}
} else { } else {
new Page(PathUtil.relative(pagesDirectory.path, it.path), pageType, it.getText()) logger.debug('there is no extension for file {}; skipping', file)
return null
} }
} }
} }

View File

@ -3,7 +3,6 @@ package com.jessebrault.ssg.part
import com.jessebrault.ssg.provider.CollectionProvider import com.jessebrault.ssg.provider.CollectionProvider
import com.jessebrault.ssg.provider.CollectionProviders import com.jessebrault.ssg.provider.CollectionProviders
import com.jessebrault.ssg.util.ExtensionUtil import com.jessebrault.ssg.util.ExtensionUtil
import com.jessebrault.ssg.util.PathUtil
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
@ -12,14 +11,19 @@ final class PartsProviders {
private static final Logger logger = LoggerFactory.getLogger(PartsProviders) private static final Logger logger = LoggerFactory.getLogger(PartsProviders)
static CollectionProvider<Part> of(File partsDir, Collection<PartType> partTypes) { static CollectionProvider<Part> of(File partsDir, Collection<PartType> partTypes) {
CollectionProviders.from(partsDir) { CollectionProviders.fromDirectory(partsDir) { file, relativePath ->
def extension = ExtensionUtil.getExtension(it.path) def extension = ExtensionUtil.getExtension(relativePath)
def partType = partTypes.find { it.ids.contains(extension) } if (extension) {
if (!partType) { def partType = partTypes.find { it.ids.contains(extension) }
logger.warn('there is no PartType for file {}; skipping', it) if (!partType) {
null logger.debug('there is no PartType for file {}; skipping', file)
return null
} else {
return new Part(relativePath, partType, file.getText())
}
} else { } else {
new Part(PathUtil.relative(partsDir.path, it.path), partType, it.getText()) logger.debug('there is no extension for file {}; skipping', file)
return null
} }
} }
} }

View File

@ -6,7 +6,7 @@ abstract class AbstractCollectionProvider<T> implements CollectionProvider<T> {
CollectionProvider<T> cp0, CollectionProvider<T> cp0,
CollectionProvider<T> cp1 CollectionProvider<T> cp1
) { ) {
ClosureBasedCollectionProvider.get { SupplierBasedCollectionProvider.get {
cp0.provide() + cp1.provide() cp0.provide() + cp1.provide()
} }
} }

View File

@ -6,7 +6,7 @@ abstract class AbstractProvider<T> implements Provider<T> {
Provider<T> p0, Provider<T> p0,
Provider<T> p1 Provider<T> p1
) { ) {
ClosureBasedCollectionProvider.get { SupplierBasedCollectionProvider.get {
[p0.provide(), p1.provide()] [p0.provide(), p1.provide()]
} }
} }
@ -18,7 +18,7 @@ abstract class AbstractProvider<T> implements Provider<T> {
@Override @Override
CollectionProvider<T> asType(Class<CollectionProvider> collectionProviderClass) { CollectionProvider<T> asType(Class<CollectionProvider> collectionProviderClass) {
ClosureBasedCollectionProvider.get { SupplierBasedCollectionProvider.get {
[this.provide() as T] [this.provide() as T]
} }
} }

View File

@ -1,29 +1,29 @@
package com.jessebrault.ssg.provider package com.jessebrault.ssg.provider
import groovy.transform.stc.ClosureParams
import groovy.transform.stc.FromString
import org.jetbrains.annotations.Nullable import org.jetbrains.annotations.Nullable
import java.util.function.BiFunction
import java.util.function.Supplier
final class CollectionProviders { final class CollectionProviders {
static <T> CollectionProvider<T> getEmpty() { static <T> CollectionProvider<T> getEmpty() {
new SimpleCollectionProvider<>([]) new SimpleCollectionProvider<>([])
} }
static <T> CollectionProvider<T> of(Collection<T> ts) { static <T> CollectionProvider<T> fromCollection(Collection<T> ts) {
new SimpleCollectionProvider<T>(ts) new SimpleCollectionProvider<T>(ts)
} }
static <T> CollectionProvider<T> from(Closure<Collection<T>> closure) { static <T> CollectionProvider<T> fromSupplier(Supplier<Collection<T>> supplier) {
ClosureBasedCollectionProvider.get(closure) new SupplierBasedCollectionProvider<>(supplier)
} }
static <T> CollectionProvider<T> from( static <T> CollectionProvider<T> fromDirectory(
File dir, File baseDirectory,
@ClosureParams(value = FromString, options = 'java.io.File') BiFunction<File, String, @Nullable T> elementFunction
Closure<@Nullable T> fileToElementClosure
) { ) {
new FileBasedCollectionProvider<>(dir, fileToElementClosure) new FileBasedCollectionProvider<>(baseDirectory, elementFunction)
} }
private CollectionProviders() {} private CollectionProviders() {}

View File

@ -1,43 +1,37 @@
package com.jessebrault.ssg.provider package com.jessebrault.ssg.provider
import com.jessebrault.ssg.util.PathUtil
import groovy.io.FileType import groovy.io.FileType
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 groovy.transform.stc.ClosureParams import groovy.transform.TupleConstructor
import groovy.transform.stc.FromString
import org.jetbrains.annotations.Nullable import org.jetbrains.annotations.Nullable
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.util.function.BiFunction
@PackageScope @PackageScope
@NullCheck @TupleConstructor(includeFields = true, defaults = false)
@NullCheck(includeGenerated = true)
@EqualsAndHashCode(includeFields = true) @EqualsAndHashCode(includeFields = true)
final class FileBasedCollectionProvider<T> extends AbstractCollectionProvider<T> { final class FileBasedCollectionProvider<T> extends AbstractCollectionProvider<T> {
private static final Logger logger = LoggerFactory.getLogger(FileBasedCollectionProvider) private static final Logger logger = LoggerFactory.getLogger(FileBasedCollectionProvider)
private final File dir private final File baseDirectory
private final Closure<@Nullable T> fileToElementClosure private final BiFunction<File, String, @Nullable T> elementFunction
FileBasedCollectionProvider(
File dir,
@ClosureParams(value = FromString, options = 'java.io.File')
Closure<@Nullable T> fileToElementClosure
) {
this.dir = dir
this.fileToElementClosure = fileToElementClosure
}
@Override @Override
Collection<T> provide() { Collection<T> provide() {
if (!this.dir.isDirectory()) { if (!this.baseDirectory.isDirectory()) {
logger.error('{} does not exist or is not a directory; returning empty collection', this.dir) logger.error('{} does not exist or is not a directory; returning empty collection', this.baseDirectory)
[] []
} else { } else {
def ts = [] final Collection<T> ts = []
this.dir.eachFileRecurse(FileType.FILES) { this.baseDirectory.eachFileRecurse(FileType.FILES) {
def t = this.fileToElementClosure(it) def t = this.elementFunction.apply(it, PathUtil.relative(this.baseDirectory.path, it.path)) as T
if (t) { if (t) {
ts << t ts << t
} }

View File

@ -1,6 +1,6 @@
package com.jessebrault.ssg.provider package com.jessebrault.ssg.provider
import org.codehaus.groovy.runtime.InvokerHelper import java.util.function.Supplier
final class Providers { final class Providers {
@ -8,8 +8,8 @@ final class Providers {
new SimpleProvider<>(t) new SimpleProvider<>(t)
} }
static <T> Provider<T> from(Closure<T> closure) { static <T> Provider<T> fromSupplier(Supplier<T> supplier) {
ClosureBasedProvider.of(closure) new SupplierBasedProvider<>(supplier)
} }
static <T> CollectionProvider<T> concat(Provider<T> ...providers) { static <T> CollectionProvider<T> concat(Provider<T> ...providers) {

View File

@ -5,21 +5,19 @@ import groovy.transform.NullCheck
import groovy.transform.PackageScope import groovy.transform.PackageScope
import groovy.transform.TupleConstructor import groovy.transform.TupleConstructor
import java.util.function.Supplier
@PackageScope @PackageScope
@TupleConstructor(defaults = false, includeFields = true) @TupleConstructor(defaults = false, includeFields = true)
@NullCheck(includeGenerated = true) @NullCheck(includeGenerated = true)
@EqualsAndHashCode(includeFields = true) @EqualsAndHashCode(includeFields = true)
final class ClosureBasedCollectionProvider<T> extends AbstractCollectionProvider<T> { final class SupplierBasedCollectionProvider<T> extends AbstractCollectionProvider<T> {
static <T> CollectionProvider<T> get(Closure<Collection<T>> closure) { private final Supplier<Collection<T>> supplier
new ClosureBasedCollectionProvider<>(closure)
}
private final Closure<Collection<T>> closure
@Override @Override
Collection<T> provide() { Collection<T> provide() {
this.closure() this.supplier.get()
} }
} }

View File

@ -5,21 +5,19 @@ import groovy.transform.NullCheck
import groovy.transform.PackageScope import groovy.transform.PackageScope
import groovy.transform.TupleConstructor import groovy.transform.TupleConstructor
import java.util.function.Supplier
@PackageScope @PackageScope
@TupleConstructor(includeFields = true, defaults = false) @TupleConstructor(includeFields = true, defaults = false)
@NullCheck(includeGenerated = true) @NullCheck(includeGenerated = true)
@EqualsAndHashCode(includeFields = true) @EqualsAndHashCode(includeFields = true)
final class ClosureBasedProvider<T> extends AbstractProvider<T> { final class SupplierBasedProvider<T> extends AbstractProvider<T> {
static <T> Provider<T> of(Closure<T> closure) { private final Supplier<T> supplier
new ClosureBasedProvider<>(closure)
}
private final Closure<T> closure
@Override @Override
T provide() { T provide() {
this.closure() this.supplier.get()
} }
} }

View File

@ -3,7 +3,6 @@ package com.jessebrault.ssg.template
import com.jessebrault.ssg.provider.CollectionProvider import com.jessebrault.ssg.provider.CollectionProvider
import com.jessebrault.ssg.provider.CollectionProviders import com.jessebrault.ssg.provider.CollectionProviders
import com.jessebrault.ssg.util.ExtensionUtil import com.jessebrault.ssg.util.ExtensionUtil
import com.jessebrault.ssg.util.PathUtil
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
@ -12,14 +11,19 @@ final class TemplatesProviders {
private static final Logger logger = LoggerFactory.getLogger(TemplatesProviders) private static final Logger logger = LoggerFactory.getLogger(TemplatesProviders)
static CollectionProvider<Template> from(File templatesDir, Collection<TemplateType> templateTypes) { static CollectionProvider<Template> from(File templatesDir, Collection<TemplateType> templateTypes) {
CollectionProviders.from(templatesDir) { CollectionProviders.fromDirectory(templatesDir) { file, relativePath ->
def extension = ExtensionUtil.getExtension(it.path) def extension = ExtensionUtil.getExtension(relativePath)
def templateType = templateTypes.find { it.ids.contains(extension) } if (extension) {
if (!templateType) { def templateType = templateTypes.find { it.ids.contains(extension) }
logger.warn('there is no TemplateType for file {}; skipping', it) if (!templateType) {
null logger.debug('there is no TemplateType for file {}; skipping', file)
return null
} else {
return new Template(relativePath, templateType, file.getText())
}
} else { } else {
new Template(PathUtil.relative(templatesDir.path, it.path), templateType, it.getText()) logger.debug('there is no extension for file {}; skipping', file)
return null
} }
} }
} }

View File

@ -3,7 +3,6 @@ package com.jessebrault.ssg.text
import com.jessebrault.ssg.provider.CollectionProvider import com.jessebrault.ssg.provider.CollectionProvider
import com.jessebrault.ssg.provider.CollectionProviders import com.jessebrault.ssg.provider.CollectionProviders
import com.jessebrault.ssg.util.ExtensionUtil import com.jessebrault.ssg.util.ExtensionUtil
import com.jessebrault.ssg.util.PathUtil
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
@ -12,14 +11,19 @@ final class TextsProviders {
private static final Logger logger = LoggerFactory.getLogger(TextsProviders) private static final Logger logger = LoggerFactory.getLogger(TextsProviders)
static CollectionProvider<Text> from(File textsDir, Collection<TextType> types) { static CollectionProvider<Text> from(File textsDir, Collection<TextType> types) {
CollectionProviders.from(textsDir) { CollectionProviders.fromDirectory(textsDir) { file, relativePath ->
def extension = ExtensionUtil.getExtension(it.path) def extension = ExtensionUtil.getExtension(relativePath)
def textType = types.find { it.ids.contains(extension) } if (extension) {
if (!textType) { def textType = types.find { it.ids.contains(extension) }
logger.warn('there is no TextType for file {}; skipping', it) if (!textType) {
null logger.warn('there is no TextType for file {}; skipping', file)
return null
} else {
return new Text(relativePath, textType, file.getText())
}
} else { } else {
new Text(PathUtil.relative(textsDir.path, it.path), textType, it.text) logger.debug('there is no extension for file {}; skipping', file)
return null
} }
} }
} }

View File

@ -1,5 +1,7 @@
package com.jessebrault.ssg.util package com.jessebrault.ssg.util
import org.jetbrains.annotations.Nullable
import java.util.regex.Pattern import java.util.regex.Pattern
final class ExtensionUtil { final class ExtensionUtil {
@ -12,12 +14,12 @@ final class ExtensionUtil {
m.matches() ? m.group(1) : path m.matches() ? m.group(1) : path
} }
static String getExtension(String path) { static @Nullable String getExtension(String path) {
def m = getExtensionPattern.matcher(path) def m = getExtensionPattern.matcher(path)
if (m.matches()) { if (m.matches()) {
m.group(1) m.group(1)
} else { } else {
throw new IllegalArgumentException("cannot get extension for path: ${ path }") null
} }
} }