slides631 paulking agile2007 groovy 2 631

Upload: fredy-hernandez

Post on 03-Apr-2018

217 views

Category:

Documents


0 download

TRANSCRIPT

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    1/70

    Submission631

    ASERT2007

    Agile 2007 - 1

    Groovy Tutorial

    Dr Paul King

    ASERT, Australia

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    2/70

    Agile 2007 - 2

    Submission631

    ASERT2007

    Topics

    Introduction

    Language Basics Closures

    Processing XML

    Accessing Databases Other Features

    Testing with Groovy

    Further Integration

    Grails

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    3/70

    Agile 2007 - 3

    Submission631

    ASERT2007

    What is Groovy?

    Groovy is like a super versionof J ava. It can leverage Java'senterprise capabilities but also

    has cool productivity features like closures,

    DSL support, builders and dynamic typing.

    A slow and steady start but now gaining in

    momentum; growing in maturity & mindshare

    Groovy

    Recipes

    PragmaticBookshelf

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    4/70

    Agile 2007 - 4

    Submission631

    ASERT2007

    What is Groovy? an agile and dynamic language for the Java Virtual Machine

    builds upon the strengths of Java but has additional powerfeatures inspired by languages like Python, Ruby & Smalltalk

    makes modern programming features available to Javadevelopers with almost-zero learning curve

    supports Domain Specific Languages and other compactsyntax so your code becomes easy to read and maintain

    makes writing shell and build scripts easy with its powerfulprocessing primitives, OO abilities and an Ant DSL

    increases developer productivity byreducing scaffolding code whendeveloping web, GUI, database orconsole applications

    simplifies testing by supporting unittesting and mocking out-of-the-box

    seamlessly integrates with all existingJava objects and libraries

    compiles straight to Java bytecode so youcan use it anywhere you can use Java

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    5/70

    Agile 2007 - 5

    Submi

    ssion631

    ASERT2007

    The Landscape of JVM Languages

    Java bytecode calls

    forstatic types

    Dynamic features call

    fordynamic types

    optional

    types

    The terms Java Virtual Machine and JVM mean a Virtual Machine for the Java platform.

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    6/70

    Agile 2007 - 6

    Submission631

    ASERT2007

    Usages of Scripting for Your Java Platform Project

    Super glue

    Combine building blocks Groovy glues

    infrastructure andbusiness logic together

    Melted core

    Keep domain modelsadaptable

    Groovy supports smartconfigs and DSLs

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    7/70Agile 2007 - 7

    Submission631

    ASERT2007

    Leverage Dynamic Language Features

    Meta-Object Protocolcan change structureand behaviour atruntime

    Intercepting methodcalls

    Compares to AOPor Mixin

    Tracing and debuggingMocks and stubs

    Enhance the Java

    Development Kit (JDK) with

    richer functionality (GDK)

    No moreincomplete library smell

    Behaviour becomes

    injectable, even

    non-intrusive! Avoid duplication

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    8/70Agile 2007 - 8

    Submission631

    ASERT2007

    Groovy StarterSystem.out.println("Hello, World!"); // optional semicolon,

    println 'Hello, World!' // System.out, brackets,// main() method

    def name = 'Guillaume' // dynamic typingprintln "$name, I'll get the car." // GString

    String longer = """${name}, the caris in the next row.""" // multi-line string

    // with static typing

    assert 0.5 == 1/2 // BigDecimal equals()

    defprintSize(obj) { // optional duck typingprint obj?.size() // safe dereferencing

    }

    def animals = ['ant', 'bee', 'cat'] // native list syntaxassert animals.every { pet -> // closure support

    pet < 'dog' // overloading}

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    9/70Agile 2007 - 9

    Submission631

    ASERT2007

    Java Platforms Dynamic Friend Flat learning curve

    Leverage any Java library (JDK)

    Syntax like Java (expressive++) Java object and runtime model

    Java architecture (threading, security,

    debugging)

    Compiles down to standard Java bytecode

    precompiled or with runtime compilation

    No impedance mismatch with parent language!

    Supports duck typing and static typing

    Only dynamic language to support Annotations

    Combined compiler for shared Java/Groovy object model

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    10/70

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    11/70Agile 2007 - 11

    Submission631

    ASERT2007

    Topics

    Introduction

    Language Basics

    Closures

    Processing XML

    Accessing Databases Other Features

    Testing with Groovy

    Further Integration

    Grails

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    12/70Agile 2007 - 12

    Submission631

    ASERT2007

    Strings

    Several forms Single quotes for

    simple strings

    Double quotes for

    GStrings which

    support variable

    expansion Slashy strings

    behave like GStrings

    but preserve

    backslashes (greatfor regex and

    directory names)

    Multi-line versions

    // normal strings

    deffirstname = 'Kate'defsurname= "Bush"assert firstname * 2 == 'KateKate'

    // GStringdeffullname = "$firstname $surname"assert fullname == 'Kate Bush'assert fullname - firstname == ' Bush'assert fullname.padLeft(10) ==

    ' Kate Bush'

    // indexing (including ranges)assert fullname[0..3] == firstnameassert fullname[-4..-1] == surnameassert fullname[5, 3..1] == 'Beta'

    S

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    13/70

    Strings

    Agile 2007 - 13

    Submission631

    ASERT2007

    // slashy string: (almost) no escapingdefpath = /C:\Windows\System32/

    defplain = '\n\r\t\b\\\f\$'assert plain.size() == 7defslashy = /\n\r\t\b\\\f\$/

    assert slashy.size() == 14

    // late binding trick with closuresfullname = "${ -> firstname} $surname"assert fullname == 'Kate Bush'firstname = 'George'

    surname = 'Clooney'assert fullname == 'George Bush'

    // Multi-line stringsdeftwister = '''\

    She sells, sea shellsBy the sea shore'''assert twister.split('\n').size() == 2

    defaddress = """$fullname

    123 First AveNew York""".trim()assert address.split('\n').size() == 3

    println """----------------------

    | $fullname |

    | 123 First Ave |

    | New York |

    ----------------------

    """

    S i

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    14/70

    Strings

    Agile 2007 - 14

    Submission631

    ASERT2007

    // more substringsstring = 'hippopotamus'assert string - 'hippo' - 'mus' + 'to' == 'potato'

    assert string.replace('ppopotam','bisc') == 'hibiscus'

    // processing charactersassert 'apple'.toList() == ['a', 'p', 'p', 'l', 'e']//also: 'apple' as String[], 'apple'.split(''), 'apple'.each{}string = "an apple a day"

    assert string.toList().unique().sort().join() == ' adelnpy'

    // reversing chars/wordsassert 'string'.reverse() == 'gnirts'

    string = 'Yoda said, "can you see this?"'

    revwords = string.split(' ').toList().reverse().join(' ')assert revwords == 'this?" see you "can said, Yoda'

    words = ['bob', 'alpha', 'rotator', 'omega', 'reviver']long_palindromes = words.findAll{ w -> w == w.reverse() && w.size() > 5 }assert long_palindromes == ['rotator', 'reviver]

    N b

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    15/70

    Numbers

    Agile 2007 - 15

    Submission631

    ASERT2007

    def x = 3def y = 4assert x + y == 7assert x.plus(y) == 7

    assert x instanceof Integer

    assert 0.5 == 1/2 // uses BigDecimal arithmetic as defaultdef a = 2 / 3 // 0.6666666666defb = a.setScale(3, BigDecimal.ROUND_HALF_UP)assertb.toString() == '0.667'

    assert 4 + 3 == 7 // 4.plus(3)assert 4 - 3 == 1 // 4.minus(3)assert 4 * 3 == 12 // 4.multiply(12)assert 4 % 3 == 1 // 4.mod(3)assert 4 ** 3 == 64 // 4.power(3)assert 4 / 3 == 1.3333333333 // 4.div(3)assert 4.intdiv(3) == 1 // normal integer division

    assert !(4 == 3) // !(4.equals(3))assert 4 != 3 // ! 4.equals(3)assert !(4< 3) // 4.compareTo(3) < 0assert !(4 0

    assert 4 >= 3 // 4.compareTo(3) >= 0assert 43 == 1 // 4.compareTo(3)

    D t

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    16/70

    Dates

    Agile 2007 - 16

    Submission631

    ASERT2007

    import static java.util.Calendar.getInstance as nowimport org.codehaus.groovy.runtime.TimeCategory

    import java.text.SimpleDateFormat

    println now().time

    def date = new Date() + 1println date

    use(TimeCategory) {

    println new Date() + 1.hour + 3.weeks - 2.days}

    input = "1998-06-03"df1 = new SimpleDateFormat("yyyy-MM-dd")date = df1.parse(input)

    df2 = new SimpleDateFormat("MMM/dd/yyyy")println 'Date was ' + df2.format(date)

    Thu Jun 28 10:10:34 EST 2007

    Fri Jun 29 10:10:35 EST 2007

    Tue Jul 17 11:10:35 EST 2007

    Date was Jun/03/1998

    Li t M R

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    17/70Agile 2007 - 17

    Submission631

    ASERT2007

    Lists, Maps, Ranges

    def empty = []def full = [1, 2, 'J1']

    assert full+full == full*2

    assert full[0] == 1assert full[0..1]==[1, 2]

    full[0..1] = [0, 1, 2, 3]

    assert full ==

    [0, 1, 2, 3, 'J1']

    def empty = [:]def full = [a: 1,b: 2]

    assert full['a'] == 1

    assert full.a == 1

    full.a = 2assert full == [a:2,b:2]

    def inclusive = 'a'..'z'

    inclusive.each {}

    def exclusive = 0..

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    18/70Agile 2007 - 18

    Submission631

    ASERT2007

    Listsassert [1,2,3,4] == (1..4)assert [1,2,3] + [1] == [1,2,3,1]

    assert [1,2,3]

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    19/70Agile 2007 - 19

    Submis

    sion631

    ASERT2007

    Mapsdefmap = [a:1, 'b':2]

    printlnmap // ["a":1, "b":2]printlnmap.a // 1

    printlnmap['a'] // 1printlnmap.keySet() // ["a", "b"]

    defmap4 = [:]// extend the map through assignment

    map4[1] = 'a'; map4[2] = 'b'

    map4[true] = 'p'; map4[false] = 'q'map4[null] = 'x'; map4['null'] = 'z'assertmap4 == [1:'a', 2:'b', (true):'p',

    (false):'q', (null):'x', 'null':'z' ]

    def sb = new StringBuffer()[1:'a', 2:'b', 3:'c'].each{ k, v-> sb "$k:$v" }.join(', ')

    assert s == '1:a, 2:b, 3:c'

    M

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    20/70Agile 2007 - 20

    Submis

    sion631

    ASERT2007

    Mapsassert [

    [name:'Clark', city:'London'], [name:'Sharma', city:'London'],[name:'Maradona', city:'LA'], [name:'Zhang', city:'HK'],

    [name:'Ali', city: 'HK'], [name:'Liu', city:'HK'],].groupBy{ it.city } == [

    London: [[name:'Clark', city:'London'], [name:'Sharma', city:'London'] ],LA: [[name:'Maradona', city:'LA'] ],HK: [[name:'Zhang', city:'HK'], [name:'Ali', city: 'HK'], [name:'Liu', city:'HK'] ],

    ]

    defphrase = 'The quick brown fox jumps over the lazy dog'assert (phrase.toList()*.toLowerCase() - ' ').findAll{ it in 'aeiou'.toList() }. // like WHEREgroupBy{ it }. // like GROUP BYfindAll{ it.value.size() >1 }. // like HAVING

    entrySet().sort{ it.key }.reverse(). // like ORDER BYcollect{ "$it.key:${it.value.size()}" }.join(', ') == 'u:2, o:4, e:3'

    // single-element list that can't be modifieddef singMap = Collections.singletonMap('a', 1)assert singMap == ['a': 1]

    Reg lar E pressions

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    21/70

    Agile 2007 - 21

    Submis

    sion631

    ASERT2007

    Regular Expressions

    Find operator

    Match operator Pattern operator

    Replace with

    calculated

    values

    if ("Hello World!" =~ /Hello/)

    if ("Hello World!" ==~ /Hello\b.*/)~/Hello\b.*/

    "1.23".replaceAll(/\d+/){ num->

    num.toInteger() + 1}

    -> 2.24

    "1.23".replaceAll(/\d/){ num->

    num.toInteger() + 1

    }

    -> 2.34

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    22/70

    Control Structures

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    23/70

    Agile 2007 - 23

    Submis

    sion631

    ASERT2007

    Control Structures

    switch (10) {case 0 : ; break

    case 0..9 :

    case [8,9,11] :

    case Float :

    case {it%3 == 0}: case ~/../ :

    default :

    }

    implementboolean isCase(candidate)

    if (1)if (object)

    if (list)

    for (itemin iterable) { }

    myMap.each { key, value ->

    println "$key : $value"

    }

    throw, catch, finallywhile, eachWithIndex,

    eachLine

    GroovyBeans and GPath

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    24/70

    Agile 2007 - 24

    Submis

    sion631

    ASERT2007

    GroovyBeans and GPath

    class Dir {

    String nameList dirs

    }

    def root =

    new Dir (name: '/', dirs: [

    new Dir (name: 'a'),

    new Dir (name: 'b')

    ])

    root.dirs[0].name == 'a'

    root.dirs.name == ['a','b']

    root.dirs.name*.size() ==

    [1, 1]

    Dir.methods.name

    .grep(~/(g|s)et/)

    ->[getName, setName, getDirs,setDirs, ]

    find, findAll, grep,

    every, any,

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    25/70

    Static Imports

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    26/70

    Static Imports

    Agile 2007 - 26

    Submis

    sion631

    ASERT2007

    import staticjava.awt.Color.LIGHT_GRAYimport static Boolean.FALSE as Fimport static Calendar.getInstance as now

    import static Integer.*

    println LIGHT_GRAY // => java.awt.Color[r=192,g=192,b=192]println !F // => trueprintln now().time // => Sun Apr 29 11:12:43 EST 2007

    println "Integers are between $MIN_VALUE and $MAX_VALUE"// => Integers are between -2147483648 and 2147483647

    deftoHexString(int val, boolean upperCase) {defhexval = upperCase ? toHexString(val).toUpperCase() : toHexString(val)return '0x' + hexval

    }println toHexString(15, true) // => 0xFprintln toHexString(15, false) // => 0xf

    import static Math.*println sin(123.456) * cos(456.789)

    // => 0.24733809349262376

    Works with Java 1.4

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    27/70

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    28/70

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    29/70

    Using Closures

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    30/70

    Agile 2007 - 30

    Submis

    sion631

    ASERT2007

    ...Using Closures

    defpairWise(list, Closure invoke) {

    if (list.size() < 2) return []def next = invoke(list[0],list[1])return [next] + pairWise(list[1..-1], invoke)

    }

    // using min, max, etc. From previous slideassertpairWise(1..5, add) == [3, 5, 7, 9]assertpairWise(1..5, mult) == [2, 6, 12, 20]assertpairWise(1..5, min) == [1, 2, 3, 4]assertpairWise(1..5, max) == [2, 3, 4, 5]

    assert 'cbaxabc' == ['a','b','c'].inject('x'){result, item -> item + result + item }

    Topics

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    31/70

    Agile 2007 - 31

    Submis

    sion631

    ASERT2007

    Topics

    Introduction

    Language Basics

    Closures

    Processing XML

    Accessing Databases Other Features

    Testing with Groovy

    Further Integration

    Grails

    XmlSlurper

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    32/70

    Agile 2007 - 32

    Submis

    sion631

    ASERT2007

    XmlSlurper

    Features One-line parsing

    GPath Syntax

    Efficient lazy evaluation

    static defCAR_RECORDS = '''

    AustraliaProduction Pickup Truck with speed of 271kph

    Isle of ManSmallest Street-Legal Car at 99cm wide and 59 kg in weight

    FranceMost Valuable Car at $15 million

    '''

    XmlSlurper

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    33/70

    Agile 2007 - 33

    Submis

    sion631

    ASERT2007

    XmlSlurperdefrecords = new XmlSlurper().parseText(XmlExamples.CAR_RECORDS)// 3 records in totalassert 3 == records.car.size()// 10 nested nodes

    assert 10 == records.depthFirst().collect{ it }.size()// test properties of the first recorddeffirstRecord = records.car[0]assert 'car' == firstRecord.name()assert 'Holden' == [email protected]()assert 'Australia' == firstRecord.country.text()// 2 cars have an 'e' in the make

    assert 2 == records.car.findAll{ [email protected]().contains('e') }.size()// 2 cars have an 'e' in the makeassert 2 == records.car.findAll{ it.@make =~ '.*e.*' }.size()// makes of cars that have an 's' followed by an 'a' in the countryassert ['Holden', 'Peel'] == records.car.findAll{ it.country =~ '.*s.*a.*' }[email protected]{ it.toStrin// types of recordsassert ['speed', 'size', 'price'] == records.depthFirst().grep{ it.@type != '' }.'@type'*.toString()

    assert ['speed', 'size', 'price'] == records.'**'.grep{ it.@type != '' }.'@type'*.toString()// check parent() operatordefcountryOne = records.car[1].countryassert 'Peel' == countryOne.parent()[email protected]()assert 'Peel' == countryOne.'..'[email protected]()// names of cars with records sorted by yeardefnames = records.car.list().sort{ [email protected]() }.'@name'*.toString()

    assert ['Royale', 'P50', 'HSV Maloo'] == names

    Topics

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    34/70

    Agile 2007 - 34

    Submis

    sion631

    ASERT2007

    Topics

    Introduction

    Language Basics

    Closures

    Processing XML

    Accessing Databases Other Features

    Testing with Groovy

    Further Integration Grails

    Working with Databases

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    35/70

    Agile 2007 - 35

    Submis

    sion631

    ASERT2007

    Working with Databases

    Using standard SQL statements

    Using DataSets

    import groovy.sql.Sql

    deffoo = 'cheese'defsql = Sql.newInstance("jdbc:mysql://localhost:3306/mydb", "user",

    "pswd", "com.mysql.jdbc.Driver")

    sql.eachRow("select * from FOOD where type=${foo}") {println "Gromit likes ${it.name}"

    }

    import groovy.sql.Sql

    defsql = Sql.newInstance("jdbc:mysql://localhost:3306/mydb", "user","pswd", "com.mysql.jdbc.Driver")

    deffood = sql.dataSet('FOOD')defcheese = food.findAll { it.type == 'cheese' }cheese.each { println "Eat ${it.name}" }

    DataSets and Lazy Evaluation

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    36/70

    DataSets and Lazy Evaluation

    Agile 2007 - 36

    Submis

    sion631

    ASERT2007

    athleteSet = db.dataSet('Athlete')youngsters = athleteSet.findAll{ it.datexOfBirth > '1970-1-1'}paula = youngsters.findAll{ it.firstname == 'Paula'}

    println paula.sql

    // => select * from Athlete where dataOfBirth > ? and firstname = ?

    println paula.parameters// => [1970-1-1, Paula]

    paula.each { println it.lastname } // database called here// => Radcliffe

    SQL Database to XML

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    37/70

    Agile 2007 - 37

    Submission631

    ASERT2007

    SQL Database to XML

    import groovy.sql.Sqlimport groovy.xml.MarkupBuilderdefschema = "PROD"defsql = Sql.newInstance("jdbc:oracle:thin:@hostname:1526:${schema}", "scott", "tiger",

    "oracle.jdbc.driver.OracleDriver")

    /* Request */defreq = """SELECT id, name, givenname, unit FROM ${schema}.peopleWHEREin_unit=1AND visible=0"""defout = new File('out.xml')defwriter = new FileWriter( out )defxml = new MarkupBuilder( writer )

    xml.agents {sql.eachRow( req as String ) {

    /* For each row output detail */row ->

    xml.agent(id:row.id) {name( row.name )givenname( row.givenname )unit( row.unit )}

    }}

    ABTI

    Jean

    Sales

    ...

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    38/70

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    39/70

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    40/70

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    41/70

    ExpandoMetaClass

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    42/70

    Agile 2007 - 42

    Submission631

    ASERT2007

    ExpandoMetaClass

    String.metaClass.swapCase = {->def sb = new StringBuffer()

    delegate.each {sb delegate.size() * 2 }

    LinkedList list = []

    list

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    43/70

    Agile 2007 - 43

    Submission631

    ASERT2007

    ExpandoMetaClass

    class Person {String name

    }

    classMortgageLender {defborrowMoney() {

    "buy house"}

    }

    def lender = newMortgageLender()

    Person.metaClass.buyHouse = lender.&borrowMoney

    defp = new Person()

    assert "buy house" == p.buyHouse()

    Constraint Programming

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    44/70

    Agile 2007 - 44

    Submission631

    ASERT2007

    Constraint Programming// require(url:'http://www.alice.unibo.it/tuProlog/', jar:'tuprolog.jar', version:'2.1')import alice.tuprolog.*

    /** Pretty Printing */defpprint(soln) {

    println soln.isSuccess() ?"$soln.query = $soln.solution" :'no solution found'

    }

    /** Prolog clauses */defgetTheory() {new Theory("""

    parent(pam, bob).parent(tom, bob).parent(tom, liz).parent(bob, ann).parent(bob, pat).parent(pat, jim).

    female(pam).male(tom).male(bob).female(liz).female(pat).female(ann).male(jim).

    mother(X,Y) :- parent(X,Y), female(X).father(X,Y) :- parent(X,Y), male(X).

    grandparent(X,Z) :- parent(X,Y),parent(Y,Z).grandmother(X,Y) :- grandparent(X,Y),female(X).grandfather(X,Y) :- grandparent(X,Y),male(X).

    sister(X,Y) :-/*different(X,Y), */parent(Z,X),parent(Z,Y),female(X).brother(X,Y) :-/*different(X,Y), */parent(Z,X),parent(Z,Y),male(X).

    ancestor(X,Y) :- parent(X,Y).ancestor(X,Z) :- parent(X,Y),ancestor(Y,Z).""")}

    defengine = new Prolog()engine.theory = theorypprint engine.solve('ancestor(tom,X).')while(engine.hasOpenAlternatives()) {

    pprint engine.solveNext()}

    ancestor(tom,X) = ancestor(tom,bob)

    ancestor(tom,X) = ancestor(tom,liz)

    ancestor(tom,X) = ancestor(tom,ann)

    ancestor(tom,X) = ancestor(tom,pat)

    ancestor(tom,X) = ancestor(tom,jim)

    no solution found

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    45/70

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    46/70

    Using XStream - Annotations

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    47/70

    Agile 2007 - 47

    Submission631

    ASERT2007

    Using XStream Annotationsimport com.thoughtworks.xstream.*import com.thoughtworks.xstream.annotations.*

    @XStreamAlias("person")class Associate {@XStreamAsAttribute@XStreamAlias('first-name')private String firstname

    @XStreamAlias('surname')private String lastname

    @XStreamOmitFieldprivate String position

    }

    msg = new Associate(firstname:'Sarah',lastname:'Connor',position:'Protector')

    Annotations.configureAliases(stream, Associate)

    println stream.toXML(msg)

    Connor

    Topics

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    48/70

    Agile 2007 - 48

    Submission631

    ASERT2007

    op cs

    Introduction

    Language Basics

    Closures

    Processing XML

    Accessing Databases

    Other Features

    Testing GroovyUnit Testing

    MocksAcceptance Testing

    Further Integration

    Grails

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    49/70

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    50/70

    Built-in Mocks for Groovy

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    51/70

    Agile 2007 - 51

    Submiss

    ion631

    ASERT2007

    y

    Handle statics, explicit constructors, etc.

    import groovy.mock.interceptor.MockFor

    defmocker = new MockFor(Collaborator.class) // create the Mock supportmocker.demand.one(1..2) { 1 } // demand the 'one' method one or two times, returning 1mocker.demand.two() { 2 } // demand the 'two' method exactly once, returning 2mocker.use { // start using the Mock

    defcaller = new Caller() // caller will call CollaboratorassertEquals 1, caller.collaborateOne() // will call Collaborator.oneassertEquals 1, caller.collaborateOne() // will call Collaborator.oneassertEquals 2, caller.collaborateTwo() // will call Collaborator.two

    } // implicit verify for strict expectation here

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    52/70

    JMock 2

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    53/70

    Agile 2007 - 53

    Submiss

    ion631

    ASERT2007

    import org.jmock.integration.junit4.JMockimport org.jmock.Mockeryimport org.junit.Testimport org.junit.Beforeimport org.junit.runner.RunWithimport org.junit.runner.JUnitCore

    @RunWith(JMock)class JMock2Test {

    Mockery context = new JUnit4GroovyMockery()defmockReverser, storer

    @Before void setUp() throws Exception {mockReverser = context.mock(Reverser.class)storer = new JavaStorer(mockReverser)

    }

    @Test void testStorage() {expectReverse(123.456, -123.456)expectReverse('hello', 'olleh')checkReverse(123.456, -123.456)checkReverse('hello', 'olleh')

    }

    defexpectReverse(input, output) {context.checking{

    one(mockReverser).reverse(input); will(returnValue(output))}

    }

    defcheckReverse(value, reverseValue) {storer.put(value)assert value == storer.get()assert reverseValue == storer.getReverse()

    }}

    JUnitCore.main('JMock2Test')

    Popper

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    54/70

    Agile 2007 - 54

    Submiss

    ion631

    ASERT2007

    pp

    @RunWith(Theories)class PopperBetweenTest extends GroovyTheoryContainer {

    private int test, total // for explanatory purposes only

    @Theory void multiplyIsInverseOfDivide(@Between(first = -4, last = 2) int amount,@Between(first = -2, last = 5) int m

    ) {total++

    assume m != 0assert new Dollar(amount).times(m).divideBy(m).amount == amounttest++

    }

    @After void dumpLog() {

    println "$test tests performed out of $total combinations"}}

    JUnitCore.main('PopperBetweenTest')

    JUnit version 4.3.1

    .49 tests performed out of 56 combinations

    Time: 0.234

    OK (1 test)

    Instinct

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    55/70

    Agile 2007 - 55

    Submiss

    ion631

    ASERT2007

    import com.googlecode.instinct.marker.annotate.BeforeSpecification as initiallyimport com.googlecode.instinct.marker.annotate.Specification as specimport static com.googlecode.instinct.runner.TextContextRunner.runContexts as check_specs_for

    class a_default_storer {

    defstorer@initially void create_new_storer() {

    storer = new Storer()}

    private check_persist_and_reverse(value, reverseValue) {storer.put(value)assert value == storer.get()assert reverseValue == storer.reverse

    }

    @spec defshould_reverse_numbers() {check_persist_and_reverse 123.456, -123.456

    }

    @spec defshould_reverse_strings() {check_persist_and_reverse 'hello', 'olleh'

    }

    @spec defshould_reverse_lists() {check_persist_and_reverse([1, 3, 5], [5, 3, 1])

    }}

    check_specs_for a_default_storer

    a_default_storer- should_reverse_lists

    - should_reverse_strings

    - should_reverse_numbers

    WebTest testing Web Sites

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    56/70

    Agile 2007 - 56

    Submiss

    ion631

    ASERT2007

    gdefant = new AntBuilder()

    defwebtest_home = System.properties.'webtest.home'

    ant.taskdef(resource:'webtest.taskdef'){classpath(){

    pathelement(location:"$webtest_home/lib")fileset(dir:"$webtest_home/lib", includes:"**/*.jar")

    }}

    defconfig_map = [:]['protocol','host','port','basepath','resultfile','resultpath', 'summary', 'saveresponse','defaultpropertytype'].each{

    config_map[it] = System.properties['webtest.'+it]}

    ant.testSpec(name:'groovy: Test Groovy Scripting at creation time'){

    config(config_map)steps(){invoke(url:'linkpage.html')for (i in 1..10){

    verifyText(description:"verify number ${i} is on pages", text:"${i}")}

    }

    }

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    57/70

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    58/70

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    59/70

    Integration With Existing Native Apps

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    60/70

    Agile 2007 - 60

    Submiss

    ion631

    ASERT2007

    g g pp Scriptom allows you to script any ActiveX

    or COM Windows component from within

    your Groovy scripts

    import org.codehaus.groovy.scriptom.ActiveXProxy

    def outlook = new ActiveXProxy("Outlook.Application")

    defmessage = outlook.CreateItem(0)

    def emails = "[email protected];[email protected]"

    def rec =message.Recipients.add(emails)

    rec.Type = 1

    message.Display(true)

    Integration With Existing Services

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    61/70

    Agile 2007 - 61

    Submiss

    ion631

    ASERT2007

    g g WS or XML/RPC allow seamless

    connection to existing services

    No need to generate stubs,

    Complex types are supported

    import groovy.net.soap.SoapClient

    proxy = new SoapClient("http://www.webservicex.net/CurrencyConvertor.asmx?WSDL" )

    rate =proxy.ConversionRate("USD", "EUR")

    println rate

    Integration with Spring...

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    62/70

    g p g

    Agile 2007 - 62

    Submiss

    ion631

    ASERT2007

    // traditional approach using a beans xml fileimport org.springframework.context.support.ClassPathXmlApplicationContext

    defctx = new ClassPathXmlApplicationContext('calcbeans.xml')defcalc = ctx.getBean('calcBean')println calc.doAdd(3, 4) // => 7

    // using BeanBuilderdefbb = new grails.spring.BeanBuilder()bb.beans {

    adder(AdderImpl)calcBean(CalcImpl2) { adder = adder }

    }defctx = bb.createApplicationContext()defcalc = ctx.getBean('calcBean')println calc.doAdd(3, 4) // => 7

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    63/70

    Groovy.Net...

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    64/70

    y

    Agile 2007 - 64

    Submiss

    ion631

    ASERT2007

    // To create dlls:// ikvmc -target:library groovy-all-1.1-SNAPSHOT.jar

    // Invoking groovy shell via GroovyDotNet.exeusing System;using System.Collections.Generic;

    namespace GroovyDotNet {classMainClass {

    public static voidMain(string[] args) {groovy.ui.InteractiveShell.main(args);

    }}

    }

    // you can invoke normal groovy[1, 2, 3].each {println it }

    // you can also invoke a .NET methodcli.System.Console.WriteLine('hello world {0}', 'from Groovy')

    ...Groovy.Net

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    65/70

    y

    Agile 2007 - 65

    Submiss

    ion631

    ASERT2007

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    66/70

    SOAP

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    67/70

    Agile 2007 - 67

    Submiss

    ion631

    ASERT2007

    class MathService {double add(double a, double b) {

    a + b

    }double square(double c) {c * c

    }}

    import groovy.net.soap.SoapServer

    defserver = new SoapServer('localhost', 6789)server.setNode('MathService')server.start()

    import groovy.net.soap.SoapClient

    defmath = new SoapClient('http://localhost:6789/MathServiceInterface?wsdl')assert math.add(1.0, 2.0) == 3.0assert math.square(3.0) == 9.0

    Mashups

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    68/70

    Agile 2007 - 68

    Submiss

    ion631

    ASERT2007

    Topics

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    69/70

    Agile 2007 - 69

    Submission631

    ASERT2007

    Introduction

    Language Basics

    Closures

    Processing XML

    Accessing Databases Other Features

    Testing with Groovy

    Further IntegrationGrails

  • 7/28/2019 Slides631 PaulKing Agile2007 Groovy 2 631

    70/70