Imports in gsp/gst files now working.

This commit is contained in:
JesseBrault0709 2023-06-12 08:35:56 +02:00
parent bc28a00cfc
commit 956642339c
18 changed files with 218 additions and 45 deletions

View File

@ -23,6 +23,8 @@ import java.util.function.Consumer
final class DefaultBuildScriptConfiguratorFactory implements BuildScriptConfiguratorFactory {
private final File baseDir
private final ClassLoader classLoader
private final Collection<URL> scriptBaseUrls
@Override
Consumer<BuildScriptBase> get() {
@ -34,9 +36,9 @@ final class DefaultBuildScriptConfiguratorFactory implements BuildScriptConfigur
types {
textTypes << TextTypes.MARKDOWN
pageTypes << PageTypes.GSP
templateTypes << TemplateTypes.GSP
partTypes << PartTypes.GSP
pageTypes << PageTypes.getGsp(['.gsp', '.ssg.gst'], this.classLoader, this.scriptBaseUrls)
templateTypes << TemplateTypes.getGsp(['.gsp', '.ssg.gst'], this.classLoader, this.scriptBaseUrls)
partTypes << PartTypes.getGsp(['.gsp', '.ssg.gst'], this.classLoader, this.scriptBaseUrls)
}
sources { base, types ->

View File

@ -11,7 +11,11 @@ import groovy.transform.NullCheck
@EqualsAndHashCode
final class GspPageRenderer implements PageRenderer {
private final StandardGspRenderer gspRenderer = new StandardGspRenderer(this.class.classLoader)
private final StandardGspRenderer gspRenderer
GspPageRenderer(ClassLoader classLoader, Collection<URL> urls) {
this.gspRenderer = new StandardGspRenderer(classLoader, urls)
}
@Override
Result<String> render(

View File

@ -2,7 +2,12 @@ package com.jessebrault.ssg.page
final class PageTypes {
static final PageType GSP = new PageType(['.gsp'], new GspPageRenderer())
@Deprecated
static final PageType GSP = new PageType(['.gsp'], new GspPageRenderer(PageTypes.classLoader, []))
static PageType getGsp(Collection<String> extensions, ClassLoader classLoader, Collection<URL> urls) {
new PageType(extensions, new GspPageRenderer(classLoader, urls))
}
private PageTypes() {}

View File

@ -13,7 +13,11 @@ import static java.util.Objects.requireNonNull
@EqualsAndHashCode
final class GspPartRenderer implements PartRenderer {
private final StandardGspRenderer gspRenderer = new StandardGspRenderer(this.class.classLoader)
private final StandardGspRenderer gspRenderer
GspPartRenderer(ClassLoader classLoader, Collection<URL> urls) {
this.gspRenderer = new StandardGspRenderer(classLoader, urls)
}
@Override
Result<String> render(

View File

@ -2,7 +2,12 @@ package com.jessebrault.ssg.part
final class PartTypes {
static final PartType GSP = new PartType(['.gsp'], new GspPartRenderer())
@Deprecated
static final PartType GSP = new PartType(['.gsp'], new GspPartRenderer(PartTypes.classLoader, []))
static PartType getGsp(Collection<String> extensions, ClassLoader classLoader, Collection<URL> scriptBaseUrls) {
new PartType(extensions, new GspPartRenderer(classLoader, scriptBaseUrls))
}
private PartTypes() {}

View File

@ -13,8 +13,8 @@ final class StandardGspRenderer {
private final TemplateCreator templateCreator
StandardGspRenderer(ClassLoader parentClassLoader) {
this.templateCreator = new GroovyTemplateCreator(ExtendedGstParser::new, [], parentClassLoader, true)
StandardGspRenderer(ClassLoader parentClassLoader, Collection<URL> urls) {
this.templateCreator = new GroovyTemplateCreator(ExtendedGstParser::new, urls, parentClassLoader, true)
}
Result<String> render(

View File

@ -12,7 +12,11 @@ import groovy.transform.NullCheck
@EqualsAndHashCode
final class GspTemplateRenderer implements TemplateRenderer {
private final StandardGspRenderer gspRenderer = new StandardGspRenderer(this.class.classLoader)
private final StandardGspRenderer gspRenderer
GspTemplateRenderer(ClassLoader parentClassLoader, Collection<URL> urls) {
this.gspRenderer = new StandardGspRenderer(parentClassLoader, urls)
}
@Override
Result<String> render(

View File

@ -2,7 +2,16 @@ package com.jessebrault.ssg.template
final class TemplateTypes {
static final TemplateType GSP = new TemplateType(['.gsp'], new GspTemplateRenderer())
@Deprecated
static final TemplateType GSP = new TemplateType(['.gsp'], new GspTemplateRenderer(TemplateTypes.classLoader, []))
static TemplateType getGsp(
Collection<String> extensions,
ClassLoader classLoader,
Collection<URL> scriptBaseUrls
) {
new TemplateType(extensions, new GspTemplateRenderer(classLoader, scriptBaseUrls))
}
private TemplateTypes() {}

View File

@ -6,12 +6,15 @@ import com.jessebrault.ssg.util.Result
final class GspPageRendererTests implements StandardDslConsumerTests {
private final PageRenderer renderer = new GspPageRenderer()
private static GspPageRenderer getRenderer(ClassLoader classLoader, Collection<URL> urls) {
new GspPageRenderer(classLoader, urls)
}
@Override
Result<String> render(String scriptlet, RenderContext context) {
this.renderer.render(
new Page('', new PageType([], this.renderer), scriptlet),
Result<String> render(String scriptlet, RenderContext context, ClassLoader classLoader, Collection<URL> urls) {
def renderer = getRenderer(classLoader, urls)
renderer.render(
new Page('', new PageType([], renderer), scriptlet),
context
)
}

View File

@ -4,6 +4,7 @@ import com.jessebrault.ssg.dsl.StandardDslConsumerTests
import com.jessebrault.ssg.render.RenderContext
import com.jessebrault.ssg.text.Text
import com.jessebrault.ssg.util.Result
import org.jetbrains.annotations.Nullable
import org.junit.jupiter.api.Test
import static com.jessebrault.ssg.text.TextMocks.renderableText
@ -13,16 +14,24 @@ import static org.junit.jupiter.api.Assertions.assertTrue
final class GspPartRendererTests implements StandardDslConsumerTests {
private final PartRenderer renderer = new GspPartRenderer()
private static GspPartRenderer getRenderer(
ClassLoader classLoader = GspPartRendererTests.classLoader,
Collection<URL> urls = []
) {
new GspPartRenderer(classLoader, urls)
}
private Result<String> doRender(
private static Result<String> doRender(
String scriptlet,
RenderContext context,
Map binding = [:],
Text text = null
@Nullable Text text = null,
ClassLoader classLoader = GspPartRendererTests.classLoader,
Collection<URL> urls = []
) {
this.renderer.render(
new Part('', new PartType([], this.renderer), scriptlet),
def renderer = getRenderer(classLoader, urls)
renderer.render(
new Part('', new PartType([], renderer), scriptlet),
binding,
context,
text
@ -30,22 +39,23 @@ final class GspPartRendererTests implements StandardDslConsumerTests {
}
@Override
Result<String> render(String scriptlet, RenderContext context) {
this.doRender(scriptlet, context)
Result<String> render(String scriptlet, RenderContext context, ClassLoader classLoader, Collection<URL> urls) {
doRender(scriptlet, context, [:], null, classLoader, urls)
}
@Test
void rendersWithBinding() {
this.checkResult(
'Hello, World!',
this.doRender('<%= binding.greeting %>', new RenderContext(), [greeting: 'Hello, World!'])
doRender('<%= binding.greeting %>', new RenderContext(), [greeting: 'Hello, World!'])
)
}
@Test
void textAvailable() {
this.checkResult('Hello, World!', this.renderer.render(
new Part('', new PartType([], this.renderer), '<%= text.render() %>'),
def renderer = getRenderer()
this.checkResult('Hello, World!', renderer.render(
new Part('', new PartType([], renderer), '<%= text.render() %>'),
[:],
new RenderContext(),
renderableText('Hello, World!')
@ -54,7 +64,8 @@ final class GspPartRendererTests implements StandardDslConsumerTests {
@Test
void nestedPartDiagnosticBubblesUp() {
def partType = new PartType([], this.renderer)
def renderer = getRenderer()
def partType = new PartType([], renderer)
def nestedProblemPart = new Part(
'nestedProblem.gsp',
partType,
@ -65,7 +76,7 @@ final class GspPartRendererTests implements StandardDslConsumerTests {
partType,
'<% parts["nestedProblem.gsp"].render() %>'
)
def r = this.renderer.render(
def r = renderer.render(
callerPart,
[:],
new RenderContext(parts: [nestedProblemPart]),
@ -79,7 +90,8 @@ final class GspPartRendererTests implements StandardDslConsumerTests {
@Test
void nestedPartIsBlankWhenThrowingExceptionButCallerRendered() {
def partType = new PartType([], this.renderer)
def renderer = getRenderer()
def partType = new PartType([], renderer)
def nestedProblemPart = new Part(
'nestedProblem.gsp',
partType,
@ -90,7 +102,7 @@ final class GspPartRendererTests implements StandardDslConsumerTests {
partType,
'Hello, World!<% parts["nestedProblem.gsp"].render() %>'
)
def r = this.renderer.render(
def r = renderer.render(
callerPart,
[:],
new RenderContext(parts: [nestedProblemPart]),

View File

@ -13,21 +13,34 @@ import static org.junit.jupiter.api.Assertions.assertEquals
final class GspTemplateRendererTests implements StandardDslConsumerTests {
private final TemplateRenderer renderer = new GspTemplateRenderer()
private static TemplateRenderer getRenderer(
ClassLoader classLoader = GspTemplateRendererTests.classLoader,
Collection<URL> urls = []
) {
new GspTemplateRenderer(classLoader, urls)
}
private Result<String> doRender(String scriptlet, Text text, RenderContext context) {
this.renderer.render(new Template('', new TemplateType([], this.renderer), scriptlet), text, context)
private static Result<String> doRender(
String scriptlet,
Text text,
RenderContext context,
ClassLoader classLoader,
Collection<URL> urls
) {
def renderer = getRenderer(classLoader, urls)
renderer.render(new Template('', new TemplateType([], renderer), scriptlet), text, context)
}
@Override
Result<String> render(String scriptlet, RenderContext context) {
this.doRender(scriptlet, blankText(), context)
Result<String> render(String scriptlet, RenderContext context, ClassLoader classLoader, Collection<URL> urls) {
doRender(scriptlet, blankText(), context, classLoader, urls)
}
@Test
void textAvailableToRender() {
def template = new Template('', new TemplateType([], this.renderer), '<%= text.render() %>')
def r = this.renderer.render(
def renderer = getRenderer()
def template = new Template('', new TemplateType([], renderer), '<%= text.render() %>')
def r = renderer.render(
template,
renderableText('Hello, World!'),
new RenderContext()

View File

@ -33,21 +33,32 @@ import static org.mockito.Mockito.*
@ExtendWith(MockitoExtension)
interface StandardDslConsumerTests {
Result<String> render(String scriptlet, RenderContext context)
Result<String> render(String scriptlet, RenderContext context, ClassLoader classLoader, Collection<URL> urls)
default void checkResult(String expected, Result<String> result) {
assertEmptyDiagnostics(result)
assertEquals(expected, result.get())
}
default void doDslRenderTest(String expected, String scriptlet, RenderContext context = null) {
this.checkResult(expected, this.render(scriptlet, context ?: new RenderContext()))
default void doDslRenderTest(
String expected,
String scriptlet,
RenderContext context = new RenderContext(),
ClassLoader classLoader = this.class.classLoader,
Collection<URL> urls = []
) {
this.checkResult(expected, this.render(scriptlet, context, classLoader, urls))
}
default void doDslAssertionTest(String scriptlet, RenderContext context = null) {
default void doDslAssertionTest(
String scriptlet,
RenderContext context = new RenderContext(),
ClassLoader classLoader = this.class.classLoader,
Collection<URL> urls = []
) {
Result<String> result = null
try {
result = this.render(scriptlet, context ?: new RenderContext())
result = this.render(scriptlet, context, classLoader, urls)
} catch (Throwable e) {
fail(e)
}
@ -242,4 +253,39 @@ interface StandardDslConsumerTests {
)
}
@Test
default void importFromClasspath() {
this.doDslAssertionTest('<%@ import com.jessebrault.ssg.dsl.Greeter %><% assert Greeter %>')
}
@Test
default void importFromClasspathIsClass() {
this.doDslAssertionTest(
'<%@ import com.jessebrault.ssg.dsl.Greeter %><% assert Greeter instanceof Class %>'
)
}
@Test
default void withConfiguredUrls() {
def parentClassLoader = this.class.classLoader
def greeterText = StandardDslConsumerTestsUtil.readResource(
'com/jessebrault/ssg/dsl/TmpGreeter.groovy', parentClassLoader
)
if (greeterText == null) {
fail('Could not load greeterText')
}
def greeterBaseUrl = StandardDslConsumerTestsUtil.writeGroovyClass(
'TmpGreeter',
['com', 'jessebrault', 'ssg', 'tmp'],
greeterText
)
this.doDslRenderTest(
"Hello, World!",
"<%@ import com.jessebrault.ssg.tmp.TmpGreeter %><%= new TmpGreeter().greet() %>",
new RenderContext(),
parentClassLoader,
[greeterBaseUrl]
)
}
}

View File

@ -0,0 +1,33 @@
package com.jessebrault.ssg.dsl
import org.jetbrains.annotations.Nullable
final class StandardDslConsumerTestsUtil {
static @Nullable String readResource(String name, ClassLoader classLoader) {
def resource = classLoader.getResourceAsStream(name)
if (resource != null) {
def writer = new StringWriter()
resource.withReader {
it.transferTo(writer)
}
writer.toString()
} else {
null
}
}
static URL writeGroovyClass(String name, List<String> packageParts, String text) {
def tmpDir = File.createTempDir("standardDslConsumerTestsUtil")
def packageFile = new File(tmpDir, (packageParts.inject('') { acc, part ->
acc + File.separator + part
}) as String)
def classFile = new File(packageFile, "${ name }.groovy")
classFile.createParentDirectories()
classFile.write(text)
tmpDir.toURI().toURL()
}
private StandardDslConsumerTestsUtil() {}
}

View File

@ -0,0 +1,11 @@
package com.jessebrault.ssg.dsl
@SuppressWarnings('unused')
class Greeter {
@SuppressWarnings('GrMethodMayBeStatic')
String greet() {
'Hello, World!'
}
}

View File

@ -0,0 +1,12 @@
//file:noinspection GrPackage
package com.jessebrault.ssg.tmp
@SuppressWarnings('unused')
class TmpGreeter {
@SuppressWarnings('GrMethodMayBeStatic')
String greet() {
'Hello, World!'
}
}

View File

@ -47,7 +47,9 @@ abstract class AbstractBuildCommand extends AbstractSubCommand {
new File('.'),
this.buildScript,
this.buildSrcDirs,
this.scriptArgs
this.scriptArgs,
this.class.classLoader,
this.buildSrcDirs.collect { it.toURI().toURL() }
)
}

View File

@ -13,6 +13,8 @@ final class CliBasedStaticSiteGenerator implements StaticSiteGenerator {
private final File buildScript
private final Collection<File> buildSrcDirs
private final Map<String, String> scriptArgs
private final ClassLoader classLoader
private final Collection<URL> scriptBaseUrls
private StaticSiteGenerator staticSiteGenerator
@ -20,19 +22,23 @@ final class CliBasedStaticSiteGenerator implements StaticSiteGenerator {
File baseDir,
File buildScript,
Collection<File> buildSrcDirs,
Map<String, String> scriptArgs
Map<String, String> scriptArgs,
ClassLoader classLoader,
Collection<URL> scriptBaseUrls
) {
this.baseDir = baseDir
this.buildScript = buildScript
this.buildSrcDirs = buildSrcDirs
this.scriptArgs = scriptArgs
this.classLoader = classLoader
this.scriptBaseUrls = scriptBaseUrls
}
@Override
boolean doBuild(String buildName, Consumer<Collection<Diagnostic>> diagnosticsConsumer) {
if (this.staticSiteGenerator == null) {
this.staticSiteGenerator = new BuildScriptBasedStaticSiteGenerator(
[new DefaultBuildScriptConfiguratorFactory(this.baseDir)],
[new DefaultBuildScriptConfiguratorFactory(this.baseDir, this.classLoader, this.scriptBaseUrls)],
this.buildScript == new File('ssgBuilds.groovy') || this.buildScript.exists()
? new File(this.baseDir, this.buildScript.path)
: null,

View File

@ -18,7 +18,9 @@ final class CliBasedStaticSiteGeneratorTests {
tempDir,
new File('ssgBuilds.groovy'),
[new File('buildSrc')],
[:]
[:],
this.class.classLoader,
[new File(tempDir, 'buildSrc').toURI().toURL()]
)
def diagnostics = [] as Collection<Diagnostic>
assertTrue(ssg.doBuild('production', diagnostics.&addAll))