Parts now have access to all parts via a EmbeddablePartsMap.

This commit is contained in:
Jesse Brault 2023-02-13 15:08:58 +01:00
parent 25f4b3657d
commit 0e49414db7
6 changed files with 65 additions and 10 deletions

View File

@ -18,12 +18,15 @@ class EmbeddablePart {
@Nullable @Nullable
private final EmbeddableText text private final EmbeddableText text
private final Collection<Part> allParts
String render(Map binding = [:]) { String render(Map binding = [:]) {
def result = part.type.renderer.render( def result = part.type.renderer.render(
this.part, this.part,
binding, binding,
this.globals, this.globals,
this.text this.text,
this.allParts
) )
if (result.v1.size() > 0) { if (result.v1.size() > 0) {
this.onDiagnostics.call(result.v1) this.onDiagnostics.call(result.v1)

View File

@ -20,7 +20,7 @@ class EmbeddablePartsMap {
Objects.requireNonNull(globals) Objects.requireNonNull(globals)
Objects.requireNonNull(onDiagnostics) Objects.requireNonNull(onDiagnostics)
parts.each { parts.each {
this.put(it.path, new EmbeddablePart(it, globals, onDiagnostics, text)) this.put(it.path, new EmbeddablePart(it, globals, onDiagnostics, text, parts))
} }
} }

View File

@ -18,22 +18,30 @@ class GspPartRenderer implements PartRenderer {
Part part, Part part,
Map binding, Map binding,
Map globals, Map globals,
@Nullable EmbeddableText text = null @Nullable EmbeddableText text = null,
Collection<Part> allParts
) { ) {
Objects.requireNonNull(part) Objects.requireNonNull(part)
Objects.requireNonNull(binding) Objects.requireNonNull(binding)
Objects.requireNonNull(globals) Objects.requireNonNull(globals)
Objects.requireNonNull(allParts)
def embeddedPartDiagnostics = []
try { try {
def result = engine.createTemplate(part.text).make([ def result = engine.createTemplate(part.text).make([
binding: binding, binding: binding,
globals: globals, globals: globals,
parts: new EmbeddablePartsMap(allParts, globals, embeddedPartDiagnostics.&addAll, text),
tagBuilder: new DynamicTagBuilder(), tagBuilder: new DynamicTagBuilder(),
text: text text: text
]) ])
new Tuple2<>([], result.toString()) new Tuple2<>([], result.toString())
} catch (Exception e) { } catch (Exception e) {
def diagnostic = new Diagnostic(
"An exception occurred while rendering part ${ part.path }:\n${ e }",
e
)
new Tuple2<>( new Tuple2<>(
[new Diagnostic("An exception occurred while rendering part ${ part.path }:\n${ e }", e)], [diagnostic, *embeddedPartDiagnostics],
'' ''
) )
} }

View File

@ -10,7 +10,8 @@ interface PartRenderer {
Part part, Part part,
Map binding, Map binding,
Map globals, Map globals,
@Nullable EmbeddableText text @Nullable EmbeddableText text,
Collection<Part> allParts
) )
} }

View File

@ -3,7 +3,9 @@ package com.jessebrault.ssg.part
import com.jessebrault.ssg.Diagnostic import com.jessebrault.ssg.Diagnostic
import com.jessebrault.ssg.text.* import com.jessebrault.ssg.text.*
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.mockito.Mock
import static com.jessebrault.ssg.testutil.DiagnosticsUtil.getDiagnosticsMessageSupplier
import static org.junit.jupiter.api.Assertions.assertEquals import static org.junit.jupiter.api.Assertions.assertEquals
import static org.junit.jupiter.api.Assertions.assertTrue import static org.junit.jupiter.api.Assertions.assertTrue
import static org.mockito.ArgumentMatchers.any import static org.mockito.ArgumentMatchers.any
@ -28,7 +30,7 @@ class GspPartRendererTests {
@Test @Test
void rendersWithNoBindingOrGlobals() { void rendersWithNoBindingOrGlobals() {
def part = new Part('', null, 'Hello, World!') def part = new Part('', null, 'Hello, World!')
def r = this.renderer.render(part, [:], [:], null) def r = this.renderer.render(part, [:], [:], null, [part])
assertTrue(r.v1.size() == 0) assertTrue(r.v1.size() == 0)
assertEquals('Hello, World!', r.v2) assertEquals('Hello, World!', r.v2)
} }
@ -36,7 +38,13 @@ class GspPartRendererTests {
@Test @Test
void rendersWithBinding() { void rendersWithBinding() {
def part = new Part('', null, "<%= binding['greeting'] %>") def part = new Part('', null, "<%= binding['greeting'] %>")
def r = this.renderer.render(part, [greeting: 'Hello, World!'], [:], null) def r = this.renderer.render(
part,
[greeting: 'Hello, World!'],
[:],
null,
[part]
)
assertTrue(r.v1.size() == 0) assertTrue(r.v1.size() == 0)
assertEquals('Hello, World!', r.v2) assertEquals('Hello, World!', r.v2)
} }
@ -44,7 +52,13 @@ class GspPartRendererTests {
@Test @Test
void rendersWithGlobals() { void rendersWithGlobals() {
def part = new Part(null, null, "<%= globals['greeting'] %>") def part = new Part(null, null, "<%= globals['greeting'] %>")
def r = this.renderer.render(part, [:], [greeting: 'Hello, World!'], null) def r = this.renderer.render(
part,
[:],
[greeting: 'Hello, World!'],
null,
[part]
)
assertTrue(r.v1.size() == 0) assertTrue(r.v1.size() == 0)
assertEquals('Hello, World!', r.v2) assertEquals('Hello, World!', r.v2)
} }
@ -61,7 +75,8 @@ class GspPartRendererTests {
mockRenderableText('Hello, World!'), mockRenderableText('Hello, World!'),
[:], [:],
{ Collection<Diagnostic> diagnostics -> textDiagnostics.addAll(diagnostics) } { Collection<Diagnostic> diagnostics -> textDiagnostics.addAll(diagnostics) }
) ),
[part]
) )
assertTrue(textDiagnostics.isEmpty()) assertTrue(textDiagnostics.isEmpty())
assertTrue(r.v1.isEmpty()) assertTrue(r.v1.isEmpty())
@ -71,9 +86,19 @@ class GspPartRendererTests {
@Test @Test
void tagBuilderAvailable() { void tagBuilderAvailable() {
def part = new Part('', null, '<%= tagBuilder.test() %>') def part = new Part('', null, '<%= tagBuilder.test() %>')
def r = this.renderer.render(part, [:], [:], null) def r = this.renderer.render(part, [:], [:], null, [part])
assertTrue(r.v1.isEmpty()) assertTrue(r.v1.isEmpty())
assertEquals('<test />', r.v2) assertEquals('<test />', r.v2)
} }
@Test
void allPartsAvailable() {
def partType = new PartType(['.gsp'], this.renderer)
def part0 = new Part('part0.gsp', partType, '<%= parts["part1.gsp"].render() %>')
def part1 = new Part('part1.gsp', partType, 'Hello, World!')
def r = this.renderer.render(part0, [:], [:], null, [part0, part1])
assertTrue(r.v1.isEmpty(), getDiagnosticsMessageSupplier(r.v1))
assertEquals('Hello, World!', r.v2)
}
} }

View File

@ -0,0 +1,18 @@
package com.jessebrault.ssg.testutil
import com.jessebrault.ssg.Diagnostic
class DiagnosticsUtil {
static Closure<String> getDiagnosticsMessageSupplier(Collection<Diagnostic> diagnostics) {
return {
diagnostics.collect {
def writer = new StringWriter()
it.exception.printStackTrace(new PrintWriter(writer))
def stackTrace = writer.toString()
"$it.message\n$stackTrace"
}.join('\n')
}
}
}