35
GROOVY Zdenek Urban 20. ledna 2010

Groovy

Embed Size (px)

DESCRIPTION

Groovy and its place in Java world and scripting

Citation preview

Page 1: Groovy

GROOVYZdenek Urban20. ledna 2010

Page 2: Groovy

Groovykind

of love

 excellent, fashionable, or amazing

Page 3: Groovy

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

Page 4: Groovy

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

Page 5: Groovy

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)

Page 6: Groovy

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");}

}

Page 7: Groovy

Hello, world

Nadbytečné declarace obecných objektůZávorky, ukončení věty …

System.out.println("Hello, world");

Page 8: Groovy

Hello, world

println 'Hello, world'

Page 9: Groovy

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

Page 10: Groovy

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

Page 11: Groovy

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

Page 12: Groovy

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')

Page 13: Groovy

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)

Page 14: Groovy

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"!'

Page 15: Groovy

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]

Page 16: Groovy

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

Page 17: Groovy

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]) }}

Page 18: Groovy

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()

Page 19: Groovy

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“}

Page 20: Groovy

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]

Page 21: Groovy

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”)

Page 22: Groovy

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)}

Page 23: Groovy

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); }

Page 24: Groovy

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());

}}

Page 25: Groovy

Dynamic Groovy: multimethods

class Equalizer {boolean equals(Equalizer e) {...}boolean equals(Object o) {...}

}Object obj = new Equalizer()obj.equals(new Equalizer())

Page 26: Groovy

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()

}

Page 27: Groovy

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()

Page 28: 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>

Page 29: Groovy

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

Page 30: Groovy

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)

Page 31: Groovy

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)

Page 32: Groovy

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() }

Page 33: Groovy

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()}

Page 34: Groovy

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

Page 35: Groovy

Otázky, diskuze

Ain’t-cha got no rhymes for me? Doot’n doo-doo feelin’ groovy.