- common
- multiple assignment
- Boolean
- get the first item if exists or null if empty
- split and trim in string
indices
&indexed()
- elegant way to merge Map<String, List<String>> structure by using groovy
- fuzzy search and merge
Map<String, Map<String, Map<String, String>>>
- groupBy
- get object id (
python -c 'id('abc')
) - loop if not empty
- getField()
- generate the random String
- dynamic method names
instanceof
- run groovy from docker
- MetaClass
- others
- load groovy file
common
multiple assignment
[!TIP] references:
'''1;Joe Doe;joedoe@example.com
2;Mark Doe
3;Clark Doe;clarkdoe@example.com;2
'''.eachLine{ line ->
def (id, name, email, sibling) = line.tokenize(';')
println """
id : ${id}
name : ${name}
email : ${email}
sibling : ${sibling}
"""
}
result
id : 1 name : Joe Doe email : joedoe@example.com sibling : null id : 2 name : Mark Doe email : null sibling : null id : 3 name : Clark Doe email : clarkdoe@example.com sibling : 2
Boolean
usage scenarios:
Boolean doMap( Map m ) { return true|false } if ( map ) { doMap( map ) } else { return true } ==> map ? doMap(map) : true ==> ! map || doMap(map)
assert ( true ? foo() : true ) == ( ! true || foo() )
substring for integers
String str = 'abc12'
assert 'abc' == "${str - ~/\d+\s*/}"
get the first item if exists or null if empty
assert [:]?.find{true} == null
assert []?.find{true} == null
assert ['a']?.find{true} == 'a'
['a': '1'].find{ true }.each { println it.key + ' ~> ' + it.value }
println (['a': '1'].find{ true }.getClass())
// result
// a ~> 1
// class java.util.LinkedHashMap$Entry
split and trim in string
spread operator:
*.
groovy:000> 'a , b, ccc ,d'.split(',')*.trim() ===> [a, b, ccc, d]
regular expression
\s*<opt>\s*
groovy:000> 'a , b, ccc ,d'.trim().split("\\s*,\\s*") ===> [a, b, ccc, d]
indices
& indexed()
def rows = ['foo', 'bar']
println rows.indices
println rows.indexed()
===> result
0..<2
[0:foo, 1:bar]
-
def userList = [ [name: 'user1', id:0, ip: '127.0.0.1'], [name: 'user2', id:1, ip: '127.0.0.2'], [name: 'user3', id:2, ip: '127.0.0.3'] ] def rows = ['foo', 'bar'] println rows.indices.collect { index -> // Using indices userList.find { it.id == index } } println rows.indexed().collect { index, item -> // Using indexed() userList.find { it.id == index } } ===> result [[name:user1, id:0, ip:127.0.0.1], [name:user2, id:1, ip:127.0.0.2]] [[name:user1, id:0, ip:127.0.0.1], [name:user2, id:1, ip:127.0.0.2]]
elegant way to merge Map<String, List<String>> structure by using groovy
original Map structure | wanted result |
|
|
original map structure:
Map<String, List<String>> case_pool = [ dev : [ funcA : ['devA'] , funcB : ['devB'] , funcC : ['devC'] ], 'dev/funcA' : [ funcA : ['performanceA'] ], 'dev/funcA/feature' : [ funcA : ['performanceA', 'feature'] ], staging : [ funcB : ['stgB'] , funcC : ['stgC'] ] ]
method 1st: by using loop
String branch = 'dev/funcA/feature-1.0' def result = [:].withDefault { [] as Set } case_pool.keySet().each { if ( branch.contains(it) ) { case_pool.get(it).each { k, v -> result[k].addAll(v) } } } println 'result: ' + result
method 2nd: by using closure
String branch = 'dev/funcA/feature-1.0' def result = [:].withDefault { [] as Set } case_pool.findAll{ k, v -> branch.contains(k) } .collectMany{ k, v -> v.collect{ c, l -> result[c].addAll(l) } } println 'result: ' + result
method 3rd: by using closure elegantly
def result = case_pool.inject([:].withDefault { [] as Set }) { result, key, value -> if (branch.contains(key)) { value.each { k, v -> result[k] += v } }; result } println 'result: ' + result
fuzzy search and merge Map<String, Map<String, Map<String, String>>>
/**
* "fuzzy" search and merge the {@code Map<String, Map<String, String>>} according to keywords.
* To replace the hardcode 'keyword' search {@code case_pool.get(stg).get(keyword).values()}. example:
* <pre><code>
* keyword = 'dev/funcA/feature1'
* fuzzyFindAll( case_pool, keyword )
* => Result: [funcA:[devA, performanceA, feature], funcB:[devB], funcC:[devC]]
* </pre></code>
*
* @param map the map structure for {@code Map<String, Map<String, String>>}
* @param keyword use branch as keyword normally
**/
def fuzzyFindAll( Map map, String keyword ) {
Map result = [:]
map.findAll{ k, v -> keyword.toLowerCase().contains(k.toLowerCase()) }.collect { k, v ->
v.each { key, value ->
result[key] = [ result.getOrDefault(key,[]) + value ].flatten().unique()
}
}
return result
}
groupBy
groupBy List<List<String>>
to Map<String, List>
requirements:
[ ["GX 470","Model"], ["Lexus","Make"], ["Jeep","Make"], ["Red","Color"], ["blue","Color"] ]
⇣⇣
["Model":["GX 470"],"Make":["Lexus","Jeep"],"Color":["Red", "blue"]]
solution
def list = [ ["GX-470","Model"], ["Lexus","Make"], ["Jeep","Make"], ["Red","Color"], ["blue","Color"] ] list.groupBy{ it[1] }.collectEntries{ k, v -> [(k): v.collect{it.get(0)}] }
list.inject([:].withDefault{[]}) { map, elem ->
map[elem[1]] << elem[0]
map
}
groupBy List<Map<String,List<String>>>
[!NOTE|label:references:]
List<Map<String,List<String>>> lstData = [
[ "Year":["FY19"] , "Period":["Oct"] , "Account":["A1000" , "A1001"] ] ,
[ "Year":["FY19"] , "Period":["Oct"] , "Account":["A1001" , "A1002"] ] ,
[ "Year":["FY19"] , "Period":["Nov"] , "Account":["A1000" , "A1001" , "A1002"] ] ,
[ "Year":["FY19"] , "Period":["Dec"] , "Account":["A1000" , "A1002"] ] ,
[ "Year":["FY20"] , "Period":["Jan"] , "Account":["A1000" , "A1003"] ]
]
lstData.groupBy { it.Year + it.Period }.collect { k, v ->
v.tail().inject(v.head()) { r, c -> r.Account = (r.Account + c.Account).unique(); r }
}.groupBy { it.Account }.collect { k, v ->
v.tail().inject(v.head()) { r, c ->
r.Year = (r.Year + c.Year).unique()
r.Period = (r.Period + c.Period).unique()
r
}
}
- result
[ [ "Year": [ "FY19" ], "Period": [ "Oct", "Nov" ], "Account": [ "A1000", "A1001", "A1002" ] ], [ "Year": [ "FY19" ], "Period": [ "Dec" ], "Account": [ "A1000", "A1002" ] ], [ "Year": [ "FY20" ], "Period": [ "Jan" ], "Account": [ "A1000", "A1003" ] ] ]
groupBy Map<String, Map<String, Object>>
[!NOTE|label:references:]
Map<String, Map<String, Object>> lineEdits = [
flag:[
[ id:10001 , mnemonic:'TRA' , action:'review' ] ,
[ id:10002 , mnemonic:'REB' , action:'deny' ] ,
[ id:10003 , mnemonic:'UNB' , action:'deny' ] ,
[ id:20001 , mnemonic:'REB' , action:'deny' ] ,
[ id:20002 , mnemonic:'ICD' , action:'review' ] ,
[ id:30001 , mnemonic:'REB' , action:'deny' ] ,
[ id:40001 , mnemonic:'ICD' , action:'review' ] ,
[ id:40002 , mnemonic:'MPR' , action:'review' ] ,
[ id:50001 , mnemonic:'CPT' , action:'deny' ] ,
[ id:60001 , mnemonic:'DTU' , action:'deny' ] ,
[ id:70001 , mnemonic:'ICD' , action:'review' ] ,
[ id:70002 , mnemonic:'MPR' , action:'review' ]
]
]
def editsMap = lineEdits.flag
.groupBy { it.id } // Group by id
.collectEntries { k, v ->
[ k, v[ 0 ] ] // Just grab the first one (flatten)
}
- result
[ "10001": [ "id": 10001, "mnemonic": "TRA", "action": "review" ] , "10002": [ "id": 10002, "mnemonic": "REB", "action": "deny" ] , "10003": [ "id": 10003, "mnemonic": "UNB", "action": "deny" ] , "20001": [ "id": 20001, "mnemonic": "REB", "action": "deny" ] , "20002": [ "id": 20002, "mnemonic": "ICD", "action": "review" ] , "30001": [ "id": 30001, "mnemonic": "REB", "action": "deny" ] , "40001": [ "id": 40001, "mnemonic": "ICD", "action": "review" ] , "40002": [ "id": 40002, "mnemonic": "MPR", "action": "review" ] , "50001": [ "id": 50001, "mnemonic": "CPT", "action": "deny" ] , "60001": [ "id": 60001, "mnemonic": "DTU", "action": "deny" ] , "70001": [ "id": 70001, "mnemonic": "ICD", "action": "review" ] , "70002": [ "id": 70002, "mnemonic": "MPR", "action": "review" ] ]
get object id (python -c 'id('abc')
)
java.lang.System.identityHashCode( obj )
example
String s = 'abc' String x = s println java.lang.System.identityHashCode(s) println java.lang.System.identityHashCode(x) x = s + 'aa' println java.lang.System.identityHashCode(x) ==> 51571311 51571311 733591550
example for
identityHashCode() and hashCode()
String a = new String("hhh") String b = new String("hhh") assert System.identityHashCode(a) != System.identityHashCode(b) assert a.hashCode() == b.hashCode()
loop if not empty
[]?.each{ println it } ?: println( 'empty' )
[:]?.each{ k, v -> println "${k} :: ${v}" } ?: println( 'empty' )
- details
assert [:]?.each{ k, v -> println "${k} :: ${v}" } == true | | [:] false
getField()
groovy:000 > 'aaa'.getClass().getFields()
===> [public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER]
generate the random String
[!NOTE] check also in * imarslo : random
String alphabet = (('a'..'z') + ('A'..'Z') + ('0'..'9')).join()
println new Random().with { (1..8).collect { alphabet[ nextInt( alphabet.length() ) ] }.join() }
- or
Closure generator = { String alphabet, int n -> new Random().with { (1..n).collect { alphabet[ nextInt( alphabet.length() ) ] }.join() } } String charset = (('A'..'Z')+('0'..'9')+('a'..'z')).join() randomValue = generator( charset, 15 )
dynamic method names
def codecs = classes.findAll { it.name.endsWith('Codec') }
codecs.each { codec ->
Object.metaClass."encodeAs${codec.name-'Codec'}" = { codec.newInstance().encode(delegate) }
Object.metaClass."decodeFrom${codec.name-'Codec'}" = { codec.newInstance().decode(delegate) }
}
def html = '<html><body>hello</body></html>'
assert '<html><body>hello</body></html>' == html.encodeAsHTML()
instanceof
[!NOTE]
assert '' instanceof String
Class clz = ''.getClass()
assert '' in clz
assert 0 in clz == false
assert clz.isCase( '' )
assert clz.isCase( [] ) == false
assert clz.isAssignableFrom( ''.getClass() )
assert clz.isAssignableFrom( [:].getClass() ) == false
assert clz.isInstance( '' )
assert clz.isInstance( [] ) == false
run groovy from docker
$ docker run \
--rm \
-e hola=caracola \
-it \
groovy:latest groovy -e "System.getenv().each{ println it }"
- mount volume
$ docker run \ --rm \ -v "$PWD":/home/marslo/scripts \ -w /home/marslo/scripts \ groovy:latest \ groovy DockerBasico.groovy -a
DockerBasico.groovy
if ( options.a ) { println "------------------------------------------------------------------" System.getenv().each{ println it } println "------------------------------------------------------------------" }
with Json
$ docker run \ --rm \ -v "$PWD":/home/marslo/scripts \ -w /home/marslo/scripts \ groovy:latest groovy DockerBasico.groovy -d
DockerBasico.groovy
> how to download the image via json
if( options.d ){ def json = new groovy.json.JsonSlurper().parse( new URL("https://dog.ceo/api/breed/hound/images/random") ) if( json.status=='success' ){ new File('perrito.jpg').bytes = new URL(json.message).bytes } }
MetaClass
[!NOTE] references:
class Stuff {
def invokeMe() { "foo" }
}
Stuff.metaClass.invokeMethod = { String name, args ->
def metaMethod = Stuff.metaClass.getMetaMethod(name, args)
def result
if(metaMethod) result = metaMethod.invoke(delegate,args)
else {
result = "bar"
}
result
}
def stf = new Stuff()
assert "foo" == stf.invokeMe()
assert "bar" == stf.doStuff()
get supported methods
String s = 'aa'
println s.metaClass.methods.name
result
[equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait, charAt, codePointAt, codePointBefore, codePointCount, compareTo, compareToIgnoreCase, concat, contains, contentEquals, contentEquals, copyValueOf, copyValueOf, endsWith, equals, equalsIgnoreCase, format, format, getBytes, getBytes, getBytes, getBytes, getChars, hashCode, indexOf, indexOf, indexOf, indexOf, intern, isEmpty, join, join, lastIndexOf, lastIndexOf, lastIndexOf, lastIndexOf, length, matches, offsetByCodePoints, regionMatches, regionMatches, replace, replace, replaceAll, replaceFirst, split, split, startsWith, startsWith, subSequence, substring, substring, toCharArray, toLowerCase, toLowerCase, toString, toUpperCase, toUpperCase, trim, valueOf, valueOf, valueOf, valueOf, valueOf, valueOf, valueOf, valueOf, valueOf]
-
println <var>.metaClass.methods*.name.sort().unique()
A Bit of metaClass DSL
String.metaClass {
or << { String s -> delegate.plus(' or ').plus(s) }
or << { List l -> delegate.findAll("(${l.join('|')})") }
and { String s -> delegate.plus(' and ').plus(s) }
'static' {
groovy { 'Yeah man!' }
}
}
assert 'Groovy or Java?' == ("Groovy" | "Java?")
assert ['o', 'o', 'y'] == ("Groovy" | ['o', 'y'])
assert 'Groovy and Java!' == ("Groovy" & "Java!")
assert 'Yeah man!' == String.groovy()
-
List.metaClass.eachUntilGreaterThanFive = { closure -> for ( value in delegate ) { if ( value > 5 ) break closure(value) } } [1, 2, 3, 4, 5, 6, 7].eachUntilGreaterThanFive { println it }
get class name
Sting s = 'string'
println s.metaClass.getTheClass() // Class
println s.getClass() // Class
println s.class.name // String
- output
class java.lang.String class java.lang.String java.lang.String
dynamically call methods
references:
def doPrint( String platform, String string ) {
this."do${platform.toLowerCase().capitalize()}Print"( string )
}
def doLinuxPrint( String string ) {
println "from Linux: ${string}"
}
def doWindowsPrint( String string ) {
println "from Windows: ${string}"
}
def doDockerPrint( String string ) {
println "from Docker: ${string}"
}
doPrint( 'LINUX', 'awesome marslo!' )
doPrint( 'dOCKER', 'awesome marslo!' )
- result
from Linux: awesome marslo! from Docker: awesome marslo!
others
groovy cli (args) with options
reference:
def cli = new CliBuilder(usage: 'groovy DockerBasico.groovy]')
cli.with {
h(longOpt: 'help', 'Usage Information \n', required: false)
a(longOpt: 'Hello','Al seleccionar "a" te saludara ', required: false)
d(longOpt: 'Dogs', 'Genera imagenes de perros', required:false)
}
def options = cli.parse(args)
if ( !options || options.h ) {
cli.usage
return
}
//tag::hello[]
if ( options.a ) {
println "------------------------------------------------------------------"
println "Hello"
System.getenv().each{ println it }
println "------------------------------------------------------------------"
}
//end::hello[]
//tag::dogs[]
if ( options.d ){
def json = new groovy.json.JsonSlurper().parse( new URL("https://dog.ceo/api/breed/hound/images/random") )
if( json.status=='success' ){
new File('perrito.jpg').bytes = new URL(json.message).bytes
}
}
//end::dogs[]
Get variable value for its name
import groovy.text.SimpleTemplateEngine
def binding = [ VAL1:'foo', VAL2:'bar' ]
def template = 'hello ${VAL1}, please have a ${VAL2}' // single quotes
println new SimpleTemplateEngine().createTemplate( template ).make( binding ).toString()
groovy.lang.Binding
-
reference:
baz = [ 'a':'b' ] foo = "abc" bar = "def" println this.binding.hasVariable('baz') this.binding.variables.each{ println "${it.key} : ${it.value}" }
- result
true args : [] baz : [a:b] foo : abc bar : def
- result
-
String beans = 'aabbcc-beans-ddeeff' Binding b = new Binding(); b.setVariable("beans", beans); b.variables.each{ println "${it.key} : ${it.value}" }
-
m = [ 'a' : '1', 'b' : '2' ] binding.setVariable("a", m) this.binding.variables.each{ println "${it.key} : ${it.value}" }
- result
args : [] m : [a:1, b:2] a : [a:1, b:2]
- result
load groovy file
sample.groovy:
#!/usr/bin/env groovy import groovy.transform.Field @Field final Map<String, Map<String, String>> SAMPLE = [ k1 : [ 'k11' : 'v11' ] , k2 : [ 'k21' : 'v21', 'k22' : 'v22' ] ]
references:
GroovyShell()
new GroovyShell().parse(new File('/path/to/file'))
Object sample = new GroovyShell().parse(new File('/path/to/sample.groovy')) println """ sample.getClass() : ${sample.getClass()} sample.SAMPLE.k1 : ${sample.SAMPLE.k1} """
- result
sample.getClass() : class sample sample.SAMPLE.k1 : [k11:v11]
- result
-
Object sample = new GroovyShell().parse(new File('/path/to/sample.groovy')) sample.with{ println SAMPLE println SAMPLE.k1 }
- result
[k1:[k11:v11], k2:[k21:v21, k22:v22]] [k11:v11]
- result
GroovyClassLoader()
new GroovyClassLoader().parseClass("/path/to/sample.groovy" as File)
Class clazz = new GroovyClassLoader().parseClass("/path/to/sample.groovy" as File) println """ clazz.getClass() : ${clazz.getClass()} clazz.newInstance().SAMPLE : ${clazz.newInstance().SAMPLE} """
- result
clazz.getClass() : class java.lang.Class clazz.newInstance().SAMPLE : [k1:[k11:v11], k2:[k21:v21, k22:v22]]
- result
this.class.classLoader.parseClass(new File("/path/to/sample.groovy"))
Class myClazz = this.class.classLoader.parseClass(new File("/Users/marslo/Desktop/sample.groovy")) println """ myClazz.getClass() : ${myClazz.getClass()} myClazz.newInstance().SAMPLE : ${myClazz.newInstance().SAMPLE} """
- result
myClazz.getClass() : class java.lang.Class myClazz.newInstance().SAMPLE : [k1:[k11:v11], k2:[k21:v21, k22:v22]]
- result
new GroovyClassLoader(getClass().getClassLoader()).parseClass(new File("/path/to/sample.groovy"))
Class gClass = new GroovyClassLoader(getClass().getClassLoader()).parseClass(new File("/path/to/sample.groovy")); println """ gClass.getClass() : ${gClass.getClass()} gClass.newInstance().SAMPLE : ${gClass.newInstance().SAMPLE} """
- result
gClass.getClass() : class java.lang.Class gClass.newInstance().SAMPLE : [k1:[k11:v11], k2:[k21:v21, k22:v22]]
- result
metaClass
Object sample = new GroovyShell().parse(new File('/path/to/sample.groovy'))
println sample.metaClass.hasProperty(sample, 'SAMPLE').type
println sample.metaClass.hasProperty(sample, 'SAMPLE').name
- result
interface java.util.Map SAMPLE
or
Class clazz = new GroovyClassLoader().parseClass("/path/to/sample.groovy" as File)
println clazz.metaClass.hasProperty(clazz, 'SAMPLE').dump()
- result
<org.codehaus.groovy.reflection.CachedField@6b915a64 field=final java.util.Map sample.SAMPLE madeAccessible=true name=SAMPLE type=interface java.util.Map>
more
def importScript(def scriptFile) {
def script = new GroovyShell().parse(new File(scriptFile))
script.metaClass.methods.each {
if (it.declaringClass.getTheClass() == script.class && ! it.name.contains('$') && it.name != 'main' && it.name != 'run') {
this.metaClass."$it.name" = script.&"$it.name"
}
}
}
importScript('File1.groovy')
method()