假设我有这样的DSL
setup {name = "aDSLScript"}
println "this is common groovy code"
doStuff {println "I'm doing dsl stuff"}
通常会有一个实现方法“设置”和“doStuff”的委托类。此外,还可以编写要执行的通用Groovy代码(println...)。
我正在寻找的是一种分两步执行的方法。在第一步中,只应处理setup方法(无论是println还是println)。第二步处理其他部件。
目前,我有两个授权课程。一个实现“setup”,另一个实现“doStuff”。当然,两者都执行println语句。
我找到了一种拆分DSL脚本执行的方法。我使用CompilationCustomizer
从AST中删除除doFirst{}
之外的所有语句。所以第一次运行只会执行doFirst
。第二次运行执行其他所有操作。以下是一些代码:
class DoFirstProcessor {
def doFirst(Closure c) {
c()
}
}
class TheRestProcessor {
def doStuff(Closure c) {
c()
}
def methodMissing(String name, args) {
//nothing to do
}
}
def dsl = "
println 'this is text that will not be printed out in first line!'
doFirst { println 'First things first: e.g. setting up environment' }
doStuff { println 'doing some stuff now' }
println 'That is it!'
"
class HighlanderCustomizer extends CompilationCustomizer {
def methodName
HighlanderCustomizer(def methodName) {
super(CompilePhase.SEMANTIC_ANALYSIS)
this.methodName = methodName
}
@Override
void call(SourceUnit sourceUnit, GeneratorContext generatorContext, ClassNode classNode) throws CompilationFailedException {
def methods = classNode.getMethods()
methods.each { MethodNode m ->
m.code.each { Statement st ->
if (!(st instanceof BlockStatement)) {
return
}
def removeStmts = []
st.statements.each { Statement bst ->
if (bst instanceof ExpressionStatement) {
def ex = bst.expression
if (ex instanceof MethodCallExpression) {
if (!ex.methodAsString.equals(methodName)) {
removeStmts << bst
}
} else {
removeStmts << bst
}
} else {
removeStmts << bst
}
}
st.statements.removeAll(removeStmts)
}
}
}
}
def cc = new CompilerConfiguration()
cc.addCompilationCustomizers new HighlanderCustomizer("doFirst")
cc.scriptBaseClass = DelegatingScript.class.name
def doFirstShell = new GroovyShell(new Binding(), cc)
def doFirstScript = doFirstShell.parse dsl
doFirstScript.setDelegate new DoFirstProcessor()
doFirstScript.run()
cc.compilationCustomizers.clear()
def shell = new GroovyShell(new Binding(), cc)
def script = shell.parse dsl
script.setDelegate new TheRestProcessor()
script.run()
我做了另一个变化,我在一个步骤中执行DSL。查看我的博客帖子:http://hackserei.metacode.de/?p=247
您可以创建一个类来拦截脚本中的方法调用,并让它协调以下方法调用。我是通过反射来完成的,但如果您愿意,您可以采用声明式。这些是模型和脚本类:
class FirstDelegate {
def setup(closure) { "firstDelegate.setup" }
}
class SecondDelegate {
def doStuff(closure) { "secondDelegate.doStuff" }
}
class MethodInterceptor {
def invokedMethods = []
def methodMissing(String method, args) {
invokedMethods << [method: method, args: args]
}
def delegate() {
def lookupCalls = { instance ->
def invokes = instance.metaClass.methods.findResults { method ->
invokedMethods.findResult { invocation ->
invocation.method == method.name ?
[method: method, invocation: invocation] : null
}
}
invokes.collect { invoked ->
invoked.method.invoke(instance, invoked.invocation.args)
}
}
return lookupCalls(new FirstDelegate()) + lookupCalls(new SecondDelegate())
}
}
下面是脚本和断言:
import org.codehaus.groovy.control.CompilerConfiguration
def dsl = '''
setup {name = "aDSLScript"}
println "this is common groovy code"
doStuff {println "Ima doing dsl stuff"}
'''
def compiler = new CompilerConfiguration()
compiler.scriptBaseClass = DelegatingScript.class.name
def shell = new GroovyShell(this.class.classLoader, new Binding(), compiler)
script = shell.parse dsl
interceptor = new MethodInterceptor()
script.setDelegate interceptor
script.run()
assert interceptor.invokedMethods*.method == [ 'setup', 'doStuff' ]
assert interceptor.delegate() ==
['firstDelegate.setup', 'secondDelegate.doStuff']
注意,我没有费心拦截println调用,这是一种默认的groovymethods,因此处理起来有点麻烦。
让类Method odInterceptor
实现方法委托()
也不是一个好主意,因为这允许用户定义的脚本调用它。
我有一个名为< code > globalcexceptionhandler 的类,它由< code>ControllerAdvice注释。它正确处理所有< code > NoHandlerFoundExceptions 。我向添加了一个新方法来处理< code>InternalError异常,但它不处理此类异常;因此,我仍然收到< code>HTTP状态500。 基于此链接,< code>500
我需要创建三个类:客户、产品和订单。我希望我的orders类接受来自客户和产品的实例(即,能够让一个订单包含关于客户和他们正在订购的产品的信息)。在JavaScript中设置这一点的最佳方法是什么?我最初想让我的customer和products类扩展order类,但我是否能够让order同时扩展customer和products类?
JVM如何进行内部管理 如果在两个不同的用户定义的类装入器中装入相同版本的类装入? 2.如果在两个不同的用户定义类加载程序(相同的类名和包)中加载不同版本的类。如果JVM加载了将在我的应用程序中引用的两个类。 我们知道JVM在类、包 我想知道JVM内部如何处理这些情况。
问题内容: 我正在子类化中添加一些功能,例如双击缩放和用于图库目的的image属性。但是为了做图像部分,我的子类必须是自己的委托并实现。 但是,当有人使用我的滚动视图子类时,他们可能还希望获得委托通知,以查看或了解您的情况。 在Swift中,我如何同时获得这两个? 问题答案: 这是此模式的Swift版本: 尽管已在Swift中禁用,但我们仍然可以使用
我正在开发一个仅支持iPhone的iOS 8应用程序。我想只支持iPhone 4S的纵向模式设备。 我有一个图形设计,它采用全屏内容。我使用自动布局来处理视图,并使其适用于所有屏幕。但是,我使用一个小资产来管理从iPhone4S工作的设计。当我在iPhone6S/6看到它时,内容非常小,大量额外的空间被浪费了。 当设备分辨率变大时,我想增加字体大小、图像大小。这个应用程序中有很多屏幕。 例如,我在