问题
I am working under some DSL using Groovy categories and I would like to find a way to use my DSL with groovy shell without explicitly writing use(MyCategory){ myObject.doSomething() }
for each command.
For example, suppose I have the following toy category:
class MyCategory {
static Integer plus(Integer integer, String string){
return integer + Integer.valueOf(string)
}
}
Then, I can use this category in groovysh
in the following way:
groovy> use(MyCategory){ 2 + '3' } //gives 5
So, is there any way to set up MyCategory
globally for all groovysh
commands, so it will not be necessary to each time wrap my commands in use(MyCategory) { ... }
? For example:
groovy> useGlobally(MyCategory); //call something like this only once
groovy> 2 + '3' //automatically uses MyCategory and gives 5
回答1:
The idea of the category is to close the scope of metaprogramming. Why not use metaClass
in this case?
groovy:000> class MyCategory {
groovy:001> static Integer plus(Integer integer, String string){
groovy:002> return integer + Integer.valueOf(string)
groovy:003> }
groovy:004> }
===> true
groovy:000> Integer.metaClass.mixin MyCategory
===> null
groovy:MyCategory@131fa4b> 2 + '4'
===> 6
groovy:MyCategory@131fa4b>
Update: With a lot of methods, you can iterate through the first parameters of the static methods and mixin them into the respective parameter type class.
class MyCategory {
static global() {
MyCategory.metaClass.methods
.findAll { it.isStatic() && !it.name.startsWith("__") && it.name != "global" }
.each { it.nativeParameterTypes[0].mixin MyCategory }
}
static Integer plus(Integer integer, String string){
return integer + Integer.valueOf(string)
}
static String yell(String a, times) {
a.toUpperCase() * times + "!!!"
}
}
MyCategory.global()
assert "a".yell(3) == "AAA!!!"
assert 2+'3' == 5
来源:https://stackoverflow.com/questions/23894653/use-groovy-category-in-groovy-shell