Refactoring and updating of Views.

This commit is contained in:
JesseBrault0709 2024-05-05 20:54:33 +02:00
parent 2e454c6f60
commit 7e2e176e6a
6 changed files with 71 additions and 78 deletions

View File

@ -1,34 +0,0 @@
package groowt.view;
import groovy.lang.Closure;
import groovy.lang.GroovyObjectSupport;
import groovy.lang.MetaProperty;
import groovy.lang.Writable;
import org.codehaus.groovy.runtime.typehandling.GroovyCastException;
import java.util.Map;
import java.util.stream.Collectors;
/**
* TODO: create a Map implementation that can access the View for keys/values, or do a metaclass thing
* TODO: get rid of this and just move the asType stuff to GStringTemplateView
*/
public abstract class AbstractView extends GroovyObjectSupport implements View {
@SuppressWarnings("unchecked")
public <T> T asType(Class<T> clazz) {
if (clazz.isAssignableFrom(this.getClass())) {
return (T) this;
} else if (clazz.equals(Writable.class)) {
return (T) this.asWritable();
} else if (clazz.equals(Closure.class)) {
return (T) this.asClosure();
} else if (clazz.equals(Map.class)) {
return (T) this.getMetaClass().getProperties().stream()
.collect(Collectors.toMap(MetaProperty::getName, metaProperty -> metaProperty.getProperty(this)));
} else {
throw new GroovyCastException(this, clazz);
}
}
}

View File

@ -17,7 +17,7 @@ import java.util.Map;
/** /**
* Delegates to self. * Delegates to self.
*/ */
public class GStringTemplateView extends AbstractView { public class GStringTemplateView implements View {
private final GStringTemplateEngine engine; private final GStringTemplateEngine engine;
private final Object src; private final Object src;

View File

@ -7,7 +7,7 @@ import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import java.util.Map; import java.util.Map;
public class GroovyTemplateView extends AbstractView { public class GroovyTemplateView implements View {
private final Template template; private final Template template;

View File

@ -2,6 +2,7 @@ package groowt.view;
import groovy.lang.Closure; import groovy.lang.Closure;
import groovy.lang.Writable; import groovy.lang.Writable;
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
@ -10,28 +11,6 @@ import java.io.Writer;
@FunctionalInterface @FunctionalInterface
public interface View { public interface View {
/**
* TODO: consider making this a (package private?) separate class, perhaps with support for GStringTemplateViews, etc.?
*/
final class ClosureView extends Closure<Object> {
private final View view;
public ClosureView(View view) {
super(view, view);
this.view = view;
}
public void doCall(Writer writer) throws IOException {
this.view.renderTo(writer);
}
public String doCall() {
return this.view.render();
}
}
void renderTo(Writer writer) throws IOException; void renderTo(Writer writer) throws IOException;
default String render() { default String render() {
@ -44,15 +23,37 @@ public interface View {
} }
} }
default Writable asWritable() { @SuppressWarnings("rawtypes")
return writer -> { default Closure asWritable() {
this.renderTo(writer); if (this instanceof Closure) {
return writer; return (Closure) this;
}; } else {
return new WritableClosureView(this);
}
} }
default Closure<Object> asClosure() { @SuppressWarnings("rawtypes")
return new ClosureView(this); default Closure asClosure() {
if (this instanceof Closure) {
return (Closure) this;
} else {
return new WritableClosureView(this);
}
}
@SuppressWarnings("unchecked")
default <T> T asType(Class<T> clazz) {
if (clazz.isInstance(this)) {
return clazz.cast(this);
} else if (clazz.equals(Writable.class)) {
return (T) this.asWritable();
} else if (clazz.equals(Closure.class)) {
return (T) this.asClosure();
} else if (clazz.equals(String.class)) {
return (T) this.render();
} else {
return DefaultGroovyMethods.asType(this, clazz);
}
} }
} }

View File

@ -0,0 +1,37 @@
package groowt.view;
import groovy.lang.Closure;
import groovy.lang.Writable;
import java.io.IOException;
import java.io.Writer;
final class WritableClosureView extends Closure<Object> implements View, Writable {
private final View view;
public WritableClosureView(View view) {
super(view, view);
this.view = view;
}
@Override
public void renderTo(Writer writer) throws IOException {
this.view.renderTo(writer);
}
public void doCall(Writer writer) throws IOException {
this.view.renderTo(writer);
}
public String doCall() {
return this.view.render();
}
@Override
public Writer writeTo(Writer out) throws IOException {
this.view.renderTo(out);
return out;
}
}

View File

@ -14,8 +14,6 @@ public class GStringTemplateViewTests {
private static final class GreetingView extends GStringTemplateView { private static final class GreetingView extends GStringTemplateView {
private final String greeting = "Hello, world!";
public GreetingView(GStringTemplateEngine engine) { public GreetingView(GStringTemplateEngine engine) {
super(Map.of( super(Map.of(
"engine", engine, "engine", engine,
@ -24,7 +22,7 @@ public class GStringTemplateViewTests {
} }
public String getGreeting() { public String getGreeting() {
return this.greeting; return "Hello, world!";
} }
} }
@ -58,19 +56,10 @@ public class GStringTemplateViewTests {
final var view = new GreetingView(this.engine); final var view = new GreetingView(this.engine);
final var writable = view.asWritable(); final var writable = view.asWritable();
final var w = new StringWriter(); final var w = new StringWriter();
writable.writeTo(w); writable.call(w);
assertEquals("Hello, world!", w.toString()); assertEquals("Hello, world!", w.toString());
} }
@SuppressWarnings("unchecked")
@Test
public void coerceToMap() {
final var view = new GreetingView(this.engine);
final Map<String, Object> map = view.asType(Map.class);
assertTrue(map.containsKey("greeting"));
assertEquals("Hello, world!", map.get("greeting"));
}
@Test @Test
public void yieldingViewSimple() { public void yieldingViewSimple() {
final var greetingView = new GreetingView(this.engine); final var greetingView = new GreetingView(this.engine);