Scripting: implement support for user-defined execution wrapper
This commit is contained in:
@@ -96,6 +96,24 @@ val ScriptEvaluationConfigurationKeys.hostConfiguration by PropertiesCollection.
|
|||||||
*/
|
*/
|
||||||
val ScriptEvaluationConfigurationKeys.refineConfigurationBeforeEvaluate by PropertiesCollection.key<List<RefineEvaluationConfigurationData>>(isTransient = true)
|
val ScriptEvaluationConfigurationKeys.refineConfigurationBeforeEvaluate by PropertiesCollection.key<List<RefineEvaluationConfigurationData>>(isTransient = true)
|
||||||
|
|
||||||
|
interface ScriptExecutionWrapper<T> {
|
||||||
|
fun invoke(block: () -> T): T
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An optional user-defined wrapper which is called with the code that actually executes script body
|
||||||
|
*/
|
||||||
|
val ScriptEvaluationConfigurationKeys.scriptExecutionWrapper by PropertiesCollection.key<ScriptExecutionWrapper<*>>(isTransient = true)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper to enable passing lambda directly to the scriptExecutionWrapper "keyword"
|
||||||
|
*/
|
||||||
|
fun <T> ScriptEvaluationConfiguration.Builder.scriptExecutionWrapper(wrapper: (() -> T) -> T) {
|
||||||
|
ScriptEvaluationConfiguration.scriptExecutionWrapper.put(object : ScriptExecutionWrapper<T> {
|
||||||
|
override fun invoke(block: () -> T): T = wrapper(block)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper to enable scriptsInstancesSharingMap with default implementation
|
* A helper to enable scriptsInstancesSharingMap with default implementation
|
||||||
*/
|
*/
|
||||||
|
|||||||
+25
-1
@@ -290,6 +290,31 @@ class ScriptingHostTest : TestCase() {
|
|||||||
Assert.assertEquals(greeting, output)
|
Assert.assertEquals(greeting, output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testEvalWithWrapper() {
|
||||||
|
val greeting = "Hello from script!"
|
||||||
|
var output = ""
|
||||||
|
BasicJvmScriptingHost().evalWithTemplate<SimpleScriptTemplate>(
|
||||||
|
"println(\"$greeting\")".toScriptSource(),
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
scriptExecutionWrapper {
|
||||||
|
val outStream = ByteArrayOutputStream()
|
||||||
|
val prevOut = System.out
|
||||||
|
System.setOut(PrintStream(outStream))
|
||||||
|
try {
|
||||||
|
it()
|
||||||
|
} finally {
|
||||||
|
System.out.flush()
|
||||||
|
System.setOut(prevOut)
|
||||||
|
output = outStream.toString().trim()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).throwOnFailure()
|
||||||
|
Assert.assertEquals(greeting, output)
|
||||||
|
}
|
||||||
|
|
||||||
private fun doDiamondImportTest(evaluationConfiguration: ScriptEvaluationConfiguration? = null): List<String> {
|
private fun doDiamondImportTest(evaluationConfiguration: ScriptEvaluationConfiguration? = null): List<String> {
|
||||||
val mainScript = "sharedVar += 1\nprintln(\"sharedVar == \$sharedVar\")".toScriptSource("main.kts")
|
val mainScript = "sharedVar += 1\nprintln(\"sharedVar == \$sharedVar\")".toScriptSource("main.kts")
|
||||||
val middleScript = File(TEST_DATA_DIR, "importTest/diamondImportMiddle.kts").toScriptSource()
|
val middleScript = File(TEST_DATA_DIR, "importTest/diamondImportMiddle.kts").toScriptSource()
|
||||||
@@ -582,4 +607,3 @@ internal fun captureOutAndErr(body: () -> Unit): Pair<String, String> {
|
|||||||
}
|
}
|
||||||
return outStream.toString().trim() to errStream.toString().trim()
|
return outStream.toString().trim() to errStream.toString().trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+9
-1
@@ -94,10 +94,18 @@ open class BasicJvmScriptEvaluator : ScriptEvaluator {
|
|||||||
|
|
||||||
val ctor = java.constructors.single()
|
val ctor = java.constructors.single()
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
val wrapper: ScriptExecutionWrapper<Any>? =
|
||||||
|
refinedEvalConfiguration[ScriptEvaluationConfiguration.scriptExecutionWrapper] as ScriptExecutionWrapper<Any>?
|
||||||
|
|
||||||
val saveClassLoader = Thread.currentThread().contextClassLoader
|
val saveClassLoader = Thread.currentThread().contextClassLoader
|
||||||
Thread.currentThread().contextClassLoader = this.java.classLoader
|
Thread.currentThread().contextClassLoader = this.java.classLoader
|
||||||
return try {
|
return try {
|
||||||
ctor.newInstance(*args.toArray())
|
if (wrapper == null) {
|
||||||
|
ctor.newInstance(*args.toArray())
|
||||||
|
} else wrapper.invoke {
|
||||||
|
ctor.newInstance(*args.toArray())
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
Thread.currentThread().contextClassLoader = saveClassLoader
|
Thread.currentThread().contextClassLoader = saveClassLoader
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user