Upload
zen-urban
View
2.248
Download
3
Embed Size (px)
DESCRIPTION
Groovy and its place in Java world and scripting
Citation preview
GROOVYZdenek Urban20. ledna 2010
Groovykind
of love
excellent, fashionable, or amazing
Groovy
Historie
Scripting
Syntax
Přiklady
•Strings•Lists and Maps•Regex and Ranges•Operators•Closures•Groovy Beans•Operator overloading•DSL – Domain Specific Language•Metaprogramming•Builders
•Files•Database
HistorieGROOVYJAMES STRACHANGUILLAUME LAFORGE
JAVAJAMES GOSLING SUN MICROSYSTEMS
JSR 241 Process2004
Ver 1.0 2.l.2007
Oak 1991 Ver 1.0 1995 Java 2 11, 1998 WORA write once, run
anywhere
Open Source 11, 2007
Industry standardJCP Java Community ProcessJSR Java Specification RequestJava EE(enterprise edition), SE, ME
JCP 2.7 standard
Scripting dynamic langs (JVM)• 2001 Jan Peterson• Ruby on Rails• Going your way
JRuby
• 2001 Lausanne Martin Oderski
• Functional language• Java platform, different
paradigm• ! Statically typedScala
• 1997 Jim Huginin• Functional approach &
closures• Extra lang+paradigm• ! Form ! Form
Jython? Clojure (Lisp dialekt, codeAsData, 2007 Rick Hickey)
Hello, world
Legální java code, ale co vše je nadbytečné
class Foo {public static void main(String[] args) {
System.out.println("Hello, world");}
}
Hello, world
Nadbytečné declarace obecných objektůZávorky, ukončení věty …
System.out.println("Hello, world");
Hello, world
println 'Hello, world'
CLI Command Line Interface
def cli = new CliBuilder(usage: 'showdate.groovy -[chflms] [date] [prefix]')cli.with {// Create the list of options. h longOpt: 'help', 'Show usage information' c longOpt: 'format-custom', args: 1, argName: 'format', 'Format date with custom format defined by "format"' f longOpt: 'format-full', 'Use DateFormat#FULL format' l longOpt: 'format-long', 'Use DateFormat#LONG format' m longOpt: 'format-medium', 'Use DateFormat#MEDIUM format (default)' s longOpt: 'format-short', 'Use DateFormat#SHORT format'}cli.p(argName:'heslo', longOpt:'password', args:1, required:true, type:GString, 'fill up the hic')
def options = cli.parse(args)if (!options) returnif ( options.h) { cli.usage() // usage: showdate.groovy -[chflms] [date] [prefix] // -c,--format-custom <format> Format date with custom format defined by "format" // -f,--format-full Use DateFormat#FULL format // -h,--help Show usage information // -l,--format-long Use DateFormat#LONG format // -m,--format-medium Use DateFormat#MEDIUM format // -s,--format-short Use DateFormat#SHORT format return}
GOP Groovy Option Parser Alternativa
Proč Groovy?
Dynamický skriptovací jazyk plus … JSR 241: Java standard Two-way contract:
Groovy class je Java class: bytecode identita. Groovy and Java dědičnost tříd.
Integrace s Java: annotations, generics, enums, familiar syntax.
Groovy platforma je Java platforma: JSE library, debugging, ... Spring, Hibernate, web services, TestNG
Some Groovy language features
Dynamically typed Closures Everything is an object. No primitives. == means equals. Really. Native syntax for lists, maps, regex Operator overriding Compact, expressive, readable
Strings
greeting = 'Hello “my darling”'println "$greeting, world is ‘easy’“
println """Today's “date” is ‘${new Date().toGMTString()’}Multiline string, isn't it?"""
greeting = "Hello, world “;greeting[7] == 'w‘;greeting[2..4] == 'llo‘
"\\#{'}\${\"}/“ == '\\#{\'}${"}/‘ == /\#{'}${'$'}{"}\//
def capitalize(s) { s[0].toUpperCase() + s[1..-1].toLowerCase() }caps = "man OF stEEL".replaceAll(/\w+/) { w -> capitalize(w) }
println "cmd /c dir|grep cli".execute().text.split('\n')
Lists and maps
mylist = [1, 2, 3, 4, 5] // an ArrayListassert mylist[0] == 1mylist[2..3] = [] // deleted 3, 4[2,3,4].collect { it * 2 } == [4, 6, 8][1,2,3].find { it > 1 } == 2[1,2,3,[1,[2,3]]].flatten().unique() == [1, 2, 3]mylist.each { doSomethingWith(it) }
mymap = [a:1, b:2, c:3] // a HashMapmymap['a'] == mymap.a // == mymap.get("a")mymap['c'] = 5 // mymap.put("c", 5)
Ranges and regex
Ranges (1..10).each { it -> println it } switch (age) { case 15..30: … } for (i in 1..10) { … } 'Hello, world'[2..4] == 'llo'
Regexif ('rain' =~ /\b\w*ain\b/) println '"rain" does rhyme with "Spain"!'
Regex
str = 'groovy.codehaus.org and www.aboutgroovy.com ‘reNoWhiteSpace = /((?:(?![-_][\w-])+\.)+[A-Za-z][\w-]+)/reWhiteSpace = /(?x) ( (?: (?! [-_]) [\w-]+ \. )+ [A-Za-z] [\w-]+ ) /re = '''(?x) # to enable whitespace and comments ( # capture the hostname in $1 (?: # these parens for grouping only (?! [-_] ) # lookahead for neither underscore nor dash [\\w-] + # hostname component \\. # and the domain dot ) + # now repeat that whole thing a bunch of times [A-Za-z] # next must be a letter [\\w-] + # now trailing domain part ) # end of $1 capture '''
finder = str =~ reout = str(0..<finder.count).each{ adr = finder[it][0] out = out.replaceAll(adr, "$adr [${InetAddress.getByName(adr).hostAddress}]")
}println out// => groovy.codehaus.org [63.246.7.187] and www.aboutgroovy.com [63.246.7.76]
Closures
Metoda jako objekt Default argument “it” je volitelný.
def squareIt = { return it * it }assert squareIt(5) == 2510.times { println “I will not talk in class” }
Variables visibilityint x = 10Closure addToX = { addThis -> x += addThis }addToX(2)assert x == 12
ClosuresStrategy pattern
def multiplicationStrategies = [ { n, m -> n * m }, { n, m -> def result = 0; n.times{ result += m };
result }]
def sampleData = [ [3, 4, 12], [5, -5, -25]]
sampleData.each{ data -> multiplicationStrategies.each{ calc -> assert data[2] == calc(data[0], data[1]) }}
Operator overloading
Override operators by overriding methods: a + b a.plus(b) a[b] a.getAt(b) a << b a.leftShift(b) switch (a) { case b: ... } b.isCase(a) a == b a.equals(b) a < b a.compareTo(b)
< 0+ plus()
[ ] getAt() / putAt()
<< leftShift()
Smart switch
switch (x) {case 'James':
println "yes it is me"break
case 18..65:println "ok you are old"break
case ~/Gw?+e/:println "your name starts with G and ends in e!"break
case Date:println 'got a Date instance'break
case ['John', 'Ringo', 'Paul', 'George']:println "Got one of the Beatles"
breakdefault:
println "Don't know $x“}
Groovy convenience operators
=~ regex find brandMatch = (line =~ /\<b\>([a-zA-Z\s]*)\:\<br\>/) if(brandMatch) brandName = brandMatch[0][1]
==~regex match <=>spaceship, compareTo method of the Comparable interface
?: elvis ternary operatorJava: name = name != null ? name : "default"Groovy: name = name ?: "default"
?. safe dereference. No worry about nulls.street = user?.address?.street
* (spread) – “explode” the contents of a list or arraydef list = ['Groovy', 'Java‘];assert ['Groovy', 'Java', 'Scala'] == [*list, 'Scala']
*. spread dot. Invoke on all items, return list.List result = invoice.lineItems*.total()parent*.action //equivalent to: parent.collect{ child -> child?.action }assert ['cat', 'elephant']*.size() == [3, 8]
GroovyBeans and JavaBeans
// Groovyclass MyBean {
String item}
MyBean b = new MyBean(item:‘foo’)
String val = b.item
b.item = ‘bar’b[‘item’] = ‘bar’
// Javaclass MyBean {
private String item;public String getItem() {…}public void setItem(…) {…}
}
MyBean b = new MyBean();b.setItem(“foo”);
String val = b.getItem();
b.setItem(“bar”)
Why brevity matters: Quicksortfunction sort(array) // pseudocode from Wikipedia var list less, greater if length(array) ≤ 1 return array select a pivot value pivot from array for each x in array if x < pivot then append x to less if x > pivot then append x to greater return concatenate(sort(less), pivot, sort(greater))--------------------------------------------------------def sort(list) { // Groovy implementation if (list.size() <= 1) return list def pivot = list[0] def less = list.findAll {it < pivot} def same = list.findAll {it == pivot} def greater = list.findAll {it > pivot} sort(less) + same + sort(greater)}
Quicksort in Java public static void qsort(Comparable[] c,int start,int end){ if(end <= start) return; Comparable comp = c[start]; int i = start,j = end + 1; for(;;){ do i++; while(i<end && c[i].compareTo(comp)<0); do j--; while(j>start && c[j].compareTo(comp)>0); if(j <= i) break; Comparable tmp = c[i]; c[i] = c[j]; c[j] = tmp; } c[start] = c[j]; c[j] = comp; qsort(c,start,j-1); qsort(c,j+1,end); }
public static void qsort(Comparable[] c){ qsort(c,0,c.length-1); }
Object graph navigation: GPaths
class Invoice { List items; … }class Item { Product product; int total() {…} … }class Product { String name; … }List<Invoice> invoices = …;
// get all product names where item total > 7000List result = invoices.items.grep{it.total() > 7000}.product.name
// Java version:List result = new ArrayList();for (Iterator<Invoice> i = invoices.iterator(); i.hasNext(); ) { List items = i.next().getItems(); for (Iterator j = items.iterator(); j.hasNext(); ) {
Item item = (Item) j.next(); if (item.total() > 7000) result.add(item.getProduct().getName());
}}
Dynamic Groovy: multimethods
class Equalizer {boolean equals(Equalizer e) {...}boolean equals(Object o) {...}
}Object obj = new Equalizer()obj.equals(new Equalizer())
Dynamic Groovy: categories
// Dynamically add methods to any class
class PersistenceCategory {static void save(Object o) {
// save object}
}use (PersistenceCategory) {
// all objects now have save() methodnew MyBean().save()
}
Dynamic Groovy: meta programming
Change class/object behavior at runtime Meta-Object Protocol (MOP) You can intercept method calls and property accesses
invokeMethod(...) getProperty(...) setProperty(...) etc
String.metaClass.groovy << { Integer number -> delegate * number} << { String s -> delegate + s} << { -> delegate + ' Groovy rocks.'}
assert 'GroovyGroovy' == 'Groovy'.groovy(2)assert 'Hello world from Groovy' == 'Hello world'.groovy(' from Groovy')assert 'It is true. Groovy rocks.' == 'It is true.'.groovy()
MarkupBuilderbuilder = new groovy.xml.MarkupBuilder()builder.numbersAndSquares { description 'Numbers and squares' (3..6).each { number (value: it, square: it*it) }}
<numbersAndSquares> <description>Numbers and squares</description> <number value='3' square='9' /> <number value='4' square='16' /> <number value='5' square='25' /> <number value='6' square='36' /></numbersAndSquares>
SwingBuilderswing = new SwingBuilder()frame = swing.frame(title: 'Hello, world') { panel(layout: new BorderLayout()) { label(text: 'Hello, world', constraints: BorderLayout.CENTER) button(text: 'Exit', constraints: BorderLayout.SOUTH, actionPerformed: { System.exit(0) }) }}frame.pack()frame.show()
•SwingBuilder is a declarative hierarchal DSL for building Swing applications•Terse notation for JavaBeans architecture properties and events•Promotes native platform fidelity•Promotes good threading interaction•Promotes good MVC design•External Swing components are easily added
Domain-specific languages (DSL)
A DSL “is a mini-language aiming at representing constructs for a given domain”
Groovy features for DSLs: add new methods/properties to classes, override operators.
Integer.metaClass.getDaysFromNow = { -> Calendar today = Calendar.instance today.add(Calendar.DAY_OF_MONTH, delegate) today.time}
println(5.daysFromNow)
Grails ORM (GORM)
class Book {String titleString authorDate releaseDate
}
book = Book.get(id) // let's change the titlebook.title = 'War and Peace'book.save()
Book.listOrderByTitle()Book.findByReleaseDateBetween(startDate, endDate)
Files
def file1 = new File('groovy1.txt')file1 << 'See how easy it is to add text to a file.\n‚file1.withWriter('UTF-8') { writer -> writer.write('We can also use writers to add contents.‘)}
sw = new StringWriter()file1.filterLine(sw) { it =~ /Groovy/ }assert 'Working with files the Groovy way is easy.\r\n' ==
sw.toString()
files = []new File('.').eachFileMatch(~/^groovy.*\.txt$/) { files << it.name
}assert ['groovy1.txt', 'groovy2.txt', 'groovy3.txt'] == filesfiles.each { new File(it).delete() }
Database
def c = new ConfigSlurper().parse(new File('config.groovy').toURL())def sql = groovy.sql.Sql.newInstance(c.db.schema, c.db.user, c.db.pwd, c.db.driver)
sql.execute("CREATE TABLE tbl(oid integer,nam char(5))")def ds = sql.dataSet("tbl")new File(‘file.csv').splitEachLine(';') {ds.add(oid: it[0], name: it[1])}ds.each { println it}
sql.eachRow("""select oid, name from tbl”””) {println “${it.name}}
db{ config.groovy driver=denormalize("com.mysql.jdbc.Driver“) schema="jdbc:mysql://localhost/test" user="zen" pwd=“p" date = new Date() active = true}app{ //assert new Integer(20).equals(app.get("servers.setting2")); [1, 2, 3].each {this."setting${it}" = it * 10}}def normalize(s){return s.toUpperCase()}
Proč Groovy?
Java is Groovy, Groovy is Java Standardizace Společný jazyk Architektura – Pseudocode Testování Automatizace Instalační a konfigurační skripty Builders, DSL Java Domain Grails, Spring, Seam
Otázky, diskuze
Ain’t-cha got no rhymes for me? Doot’n doo-doo feelin’ groovy.