Groovy – Learn Another Language – Dan Vega



Groovy – Learn Another Language – Dan Vega

2 0


cfo-groovy

cfObjective 2014 - Intro to Groovy

On Github cfaddict / cfo-groovy

Groovy

Learn Another Language

Dan Vega / Joshua Caito http://bit.ly/cfogroovy

We are linking to the github repo. Open this open and explain to the audience where everything is.

Dan Vega

Senior Developer at FirstComp What keeps me busy
  • CrossFit / Running / Swimming
  • Cleveland Sports Fan
  • Groovy / Grails / Angular
Contact Information
  • blog: www: http://www.danvega.org
  • email: danvega@gmail.com
  • twitter: @cfaddict
  • github: http://github.com/cfaddict/

Joshua Caito

  • Working as an IT professional for 11 years
  • Working with ColdFusion since MX 7
  • Doctor Who loving, 日本語 speaking, whiskey drinking Buddhist
  • CodeCaito.blogspot.com
  • Twitter: @J_Caito

Presentation Overview

What is Groovy? Installation Data Types (Simple & Complex) Groovy Truth Logical Branching, Loops, & Operators Closures Meta-Programming Grails (Overview) Testing (Spock Overview) IDE Support (Overview) Resources Q&A Lets talk about why we here today. Why are we talking about Groovy.
  • Open Source / Alternative language for the JVM
  • Object Oriented, dynamic with functional flavor
  • Current Version 2.3 / Java 8 Support
  • Inspired by languages like
    • Python
    • Ruby
    • Smalltalk
  • This wasn't a case of developing a language and then latter porting it over to run on the JVM. From the very beggining Groovy was designed to run on the JVM.
  • Because of that there is seemles interop with Java (create and call classes in java from groovy and vice versa)
  • Powerful Dynamic Language
  • Easy to Learn
  • Groovy as a Java superset
  • Familiar Syntax for Java Developers
  • Powerful dynamic language that is really easy to learn
  • Groovy as a Java superset
  • Who makes Groovy?
  • Guillaume Laforge
healthy activity on the mailing lists stack overflow
target right here in MN netflix who as actually contributed software back to the groovy/grails community.

What does a Java Class Look Like

What does a Groovy Class Look Like

  • The point here is that java syntax for the most part is valid groovy syntax. The compiler for groovy compiles the code down to java byte code. There are a few exceptions where this isn't the case but there are ver few.
  • Again most valid java syntax is valid groovy syntax but if all you're going to do is rename the file then keep writing java we want to show you some the things Groovy can do to help you be more productive
  • most java code is valid groovy code
  • any java developer is a groovy developer

From Java to Groovy Demo

  • POJO Plain old Java Object. This is a simple example and there is a lot of noise going on here.
  • Person_start.groovy
  • Comments / Imports
  • Access Modifiers / Semi colons / return statements / parentheses
  • Properties / getters & setters / constructors
  • Mark a field private and you won't get the generated getters/setters (final will make it read only)

Installation

http://groovy.codehaus.org/downloadGVM

Groovy Console

Command Line Tools

http://groovy.codehaus.org/api Cover GVM only enough to say there is a tool out there and provide a link at the end.
  • Demo features of GroovyConsole
  • Options
  • Run Some Code
  • AST

Data Types

Groovy is a dynamic language

What does that mean?

  • We aren't restricted to strict type definitions or compiler checks
  • We can keep the same fluid typing we enjoy from ColdFusion
    def x = 11
    x = [ foo : 'bar' ]
  • Over all, less things to worry about[Run time validation still matters of course]

The DEF Keyword

def serves two main purposes

  • Generic Object instantiation[Well, sort of. We'll cover that in a moment...]
  • Scoping your variable

Pull up the console here and go through some examples of how Groovy is doing it's best to cast objects correctly at runtime and that for this matter 'DEF' isn't all that necessary. Also go into an example of scoping. def is like var keyword in JavaScript and ColdFusion
  • Byte
  • Short
  • Integer
  • Long
  • Float
  • Double
  • Character
  • Boolean
  • String
Talk about the difference between primative types and their object counterparts. When in doubt, it's best to use the object.

Groovy Strings

Groovy Strings (g-strings) are really powerful

Think ## but cooler, because it's Groovy

Whole lot of code examples here. Be sure to include 'lazy loading' examples G strings - yes they are reall called that You use intorpolation by putting a dollar in front of the g-string (hahahah) will you show regular expressions here? it would be a good time to at least make people they are here. what about templates? you could show string getAt() overloaded operator def s = "this is a string" s[1] s[1..3] s[-1..-3]

Complex Data Types

  • Dates
  • Ranges
  • Lists
  • Maps
  • Working with Collections
Groovy has native language support for collections, lists, maps and arrays.

Working with dates in Java

The Java date and time API's can be rather confusing when you first try to figure out how to use it. Talk about Java and how awful the date api was and then the new Java 8 Date Spec

Working with Dates in Groovy

def today = new Date() 
// Sat Apr 12 09:22:10 EDT 2014	
// java.util.Date

def day = new Date('05/19/2014')
//Mon May 19 00:00:00 EDT 2014
def today = new Date()
println today.format('MM/dd/yyyy')
// 04-12-2014
// java.lang.String

def today = new Date()
today.format('MM-dd-yyyy hh:mm a')
// 04-12-2014 09:31 AM
def today = new Date()
def yesterday = today - 1
def tomorrow = today + 1

// Sat Apr 12 09:33:01 EDT 2014
// Fri Apr 11 09:33:01 EDT 2014
// Sun Apr 13 09:33:01 EDT 2014

Working with Dates

Groovy ways to iterate through 2 dates

Date start = new Date()
Date end = new Date() + 7

start.upto(end) { d ->
    println d
}

end.downto(start) { d ->
    println d
}

(start..end).each { d ->
    println d
}

Time Category

import groovy.time.TimeCategory

def now = new Date()
println now // Sat Apr 12 09:38:11 EDT 2014

use( TimeCategory ) {
    println 10.minute.from.now // Sat Apr 12 09:48:11 EDT 2014 
    println 10.hours.ago // Fri Apr 11 23:38:11 EDT 2014
    println 10.weeks.from.now // Sat Jun 21 00:00:00 EDT 2014
    println 3.days.ago // Wed Apr 09 00:00:00 EDT 2014
    println 1.year.from.now // Sun Apr 12 00:00:00 EDT 2015
}
Apply a number of methods to allow convenient Date/Time manipulation

Working with dates in Groovy

Ranges

  • Ranges allow you to create a list of sequential values.
  • These can be used as Lists since Range extends java.util.List.
def range = 1..10
println range
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

def reverseRange = 10..1
println reverseRange
// [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

println range.class.name
// groovy.lang.IntRange
def range = 1..10

println range.size() // 10
println range.get(2) // 3
println range.contains(5) // true
println range.from // 1
println range.to // 10
println range instanceof java.util.List // true

Ranges - Not just for numbers

def range = 'a'..'p'
println range

// [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p]
enum Days {
    MONDAY,TUESDAY,WEDNESDAY,THURSDAY,
    FRIDAY,SATURDAY,SUNDAY
}

def workWeek = Days.MONDAY..Days.FRIDAY
def weekend = Days.SATURDAY..Days.SUNDAY
def week = Days.MONDAY..Days.SUNDAY

println workWeek
println weekend
println week

// [MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY]
// [SATURDAY, SUNDAY]
// [MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]
An enumeration is a collection of items that is a complete, ordered listing of all of the items in that collection.

Lists

A list is an ordered collection of objects (java.util.ArrayList)
def list = []
println list.class.name
//java.util.ArrayList

def list = [1,2,3,4,5]
println list
// [1, 2, 3, 4, 5]

def list = [1,"two",3,"four",new Date(),["Mon","Tue","Wed"]]
println list
// [1, two, 3, four, Sat Apr 12 13:26:16 EDT 2014, [Mon, Tue, Wed]]
Resizable-array implementation of the List interface. Implements all optional list operations, and permits all elements, including null.

List Manipulation

def list = []

list.add(1)
list.putAt(1,2) //equivalent method to [] when value being changed
list[2] = 3
list.push(4)
list << 5

assert list == [1,2,3,4,5]
def list = [1,2,3,4,5]

assert list[1] == 2 // indexing starts at 0
assert list.getAt(1) == 2 //equivalent method to []
assert list.get(1) == 2 //alternative method
assert list[-1] == 5 //use negative indices to count from the end
def list = [1,2,3,4,5]

assert list.remove(2)
assert list == [1,2,4,5]
list.pop()
assert list == [1,2,4]

list.clear()
assert list == []
In groovy, the bitwise operators can be overridden with the leftShift (<<) and rightShift (>>) methods defined on the class. it's idiomatic groovy to use the leftShift method for append actions on strings, buffers, streams, arrays, etc and thats what you're seeing here.

Maps

A map is a mapping from unique unordered keys to values
def map = [:]

// map.foo will always look for property foo so class will never work here
println map.class.name 

// java.util.LinkedHashMap
println map.getClass().name
def map = [first:'Dan',last:'Vega',email:'danvega@gmail.com']

println map
// [first:Dan, last:Vega, email:danvega@gmail.com]
assert [1:'a', 2:'b', 1:'c' ] == [1:'c', 2:'b'] //keys unique
Hash table and linked list implementation of the Map interface, with predictable iteration order. This implementation differs from HashMap in that it maintains a doubly-linked list running through all of its entries. This linked list defines the iteration ordering, which is normally the order in which keys were inserted into the map (insertion-order).

Maps

Maps can be made up of complex data

class Person {
    String first
    String last
}

def p = new Person(first:"Dan",last:"Vega")

def map = [
    key:"value",
    numbers: [1,2,3,4,5],
    person: p,
    now: new Date()
]

println map
[key:value, numbers:[1, 2, 3, 4, 5], 
person:Person@60aed478, now:Sat Apr 12 15:40:19 EDT 2014]

Map Keys

Map keys are strings by default: [a:1] is equivalent to ["a":1]
def map = [first:"Dan",last:"Vega"]
def keys = map.keySet()

println keys[0].class.name //java.lang.String
println keys[1].class.name //java.lang.String

If you really want a variable to become the key, you have to wrap it between parentheses: [(a):1]

def a = 1
def map = [first:"Dan",last:"Vega",(a):new Date()]
def keys = map.keySet()

println keys[0].class.name //java.lang.String
println keys[1].class.name //java.lang.String
println keys[2].class.name //java.lang.Integer

Maps

It is easy to set/get data in a map
def map = [first:"Dan",last:"Vega",email:'danvega@gmail.com']

map.first = "Daniel"
assert map.first == "Daniel"
map["first"] = "Dan"
assert map.first == "Dan"

assert map["first"] == "Dan"
assert map.get('first') == "Dan"
assert map.get('fullName','Dan Vega') == "Dan Vega"

We can check the contents of a map with various methods

def map = [first:"Dan",last:"Vega",email:'danvega@gmail.com']

assert [:].isEmpty()
assert !map.isEmpty()
assert map.containsKey('email')
assert map.containsValue('danvega@gmail.com')

Collections DEMO

Groovy Truth

Groovy provides us with standard boolean operators for determining 'truthiness'

def a = true
def b = true
def c = false
assert a
assert a && b
assert a || c
assert !c

But it also tries to coerce non-boolean objects into boolean examples

Empty collections are coerced to false.

def numbers = [1,2,3]
assert numbers //true, as numbers is not empty
numbers = []
assert !numbers //true, as numbers is now an empty collection

Iterators and Enumerations with no further elements are coerced to false.

assert ![].iterator() // false because the Iterator is empty
assert [0].iterator() // true because the Iterator has a next element
def v = new Vector()
assert !v.elements()  // false because the Enumeration is empty
v.add(new Object())
assert v.elements()   // true because the Enumeration has more elements

Non-empty maps are coerced to true.

assert ['one':1]
assert ![:]

Matching regex patterns are coerced to true.

assert ('Hello World' =~ /World/) //true as matcher has at least one match

Non-empty Strings, GStrings and CharSequences are coerced to true.

// Strings
assert 'This is true'
assert !''
//GStrings
def s = ''
assert !("$s")
s = 'x'
assert ("$s")

Non-zero numbers are coerced to true.

assert !0 //yeah, 0s are false, like in Perl
assert 1  //this is also true for all other number types

Non-null object references are coerced to true.

assert new Object()
assert !null

null does not implicitly coerce to anything, it can only be used as a state test against other values

assert null == false //Will fail
assert null == true //Also fails

assert !null == true //These test will pass as we're testing against state
assert !!null == false
.

Logical Branching, Loops, & Operators

Logical Branching

if( groovyIsAwesome )
	println( 'WOOT!' )
else
	youMustBeLying()

Nothing new or exciting here...

Lead into the next slide with a talk about how we're all used to if/else statements, etc...

The Switch Statement

The switch statement in Groovy does allow us to do more than we're used to with ColdFusion

def x = 'This is interesting'

switch( x ) {
    
    case ~/(?i)\bthis.*/:
        println 'first'

    case String:
        println 'second'

    case 'This is interesting':
        println 'third'
        break

}
Go over the verbosity of the switch statement and run the live example

Looping

Groovy supports syntax that seems more natural for looping

0.upto(4) { println( 'Hello World!' ) }
4.times { println( 'Hi World!' ) }

it also supports some syntax we're not used to seeing

for( x in 0..1 ) {println 'hi'}

as well as some things that should feel right at home

def x = [ 1:'dog', 2:'cat', 3:'bird' ]
for( i in x ) { println i.value }

Operators

The elvis operator

y = x ?: zis the equivelant ofy = x ? x : z

that seems really neat (I know! Right?) but there are quite a few fun operators Groovy brings to the table

  • Spread Operator - *.
  • Safe Navigation Operator - ?.
  • Regular Expression Operators - =~ / ==~
  • Spaceship Operator - <=>
Go through code examples here

Overloading Operators

Groovy comes with a _ton_ of operators predefined you can also overload

http://groovy.codehaus.org/Operator+Overloading
def x = 'Hello World!'
def y = x - 'World!'
println y
Live example adding a plus method to custom classes http://groovy.codehaus.org/Operator+Overloading

Closures

Closures in Groovy totally remove verbosity in code and help create lightweight reusable pieces of code. Closures are a really powerful and important part of the Groovy programming langauge. They may be nice to haves in other languages but to really take advantage of Groovy you need to understand this stuff. We have already looked at examples of closures (collections) In this section we are going to look at what they are, how to create them and how use them to elegantly implement some design patterns.

The Traditional Way

def myNumbers = [1,2,3,4,5,6,7,8,9,10]

def totalNumbers(numbers){
    def total = 0;

    for(number in numbers){
        total += number
    }

    total
}

// 55
println totalNumbers(myNumbers)
Start with a scenario, you're working on an application and your boss comes to you with a request. We need a function that can total any numbers that are passed to it.

Total Even Numbers

def myNumbers = [1,2,3,4,5,6,7,8,9,10]

def totalEvenNumbers(numbers){
    def total = 0;
    for(number in numbers){
        if(number % 2 == 0) total += number
    }
    total
}

// 30
println totalEvenNumbers(myNumbers)

Total Odd Numbers

def myNumbers = [1,2,3,4,5,6,7,8,9,10]

def totalOddNumbers(numbers){
    def total = 0;
    for(number in numbers){
        if(number % 2 != 0) total += number
    }
    total
}

// 30
println totalOddNumbers(myNumbers)

The Groovy Way

def myNumbers = [1,2,3,4,5,6,7,8,9,10]

def totalNumbers(numbers, selector){
    def total = 0;
    for(number in numbers){
        if(selector(number)){
            total += number
        }
    }
    total
}

println totalNumbers(myNumbers, { true } ) // 55
println totalNumbers(myNumbers, { it % 2 == 0 } ) // 30
println totalNumbers(myNumbers, { it % 2 != 0 } ) // 25
println totalNumbers(myNumbers) { true } // 55
println totalNumbers(myNumbers) { it % 2 == 0 } // 30
println totalNumbers(myNumbers) { it % 2 != 0 } // 25

Closure Basics

  • A block of code
  • May be passed as arguments
  • May accept parameters
  • May return a value
// the times method accepts a closure as an argument
3.times( {println "Hello Closures!"} )
// If the last argument is a closure you can omit the parentheses
3.times {println "Hello Closures!"}
def myClosure = {
    println "Hello Closures!"
}

// we could call it directly 
myClosure()

// or pass it around as a method argument
3.times(myClosure)
A closure is a block of code that is a first class object that can be passed around.

Closure arguments

3.times {
    // if i dont declare an argument list
    // the closure accepts 1 parameter and its called it
    println it
}

// 0
// 1
// 2
3.times { number ->
    println number
}
3.times { int number ->
    println number
}
printFullName = { firstName,lastName ->
    println "${firstName} ${lastName}"
}

printFullName("Dan","Vega")
it is not a reservd word or keyword

Closures

Hopefully this code starts to make sense now

def list = ["one","two","three","four","five"]

// loop over a list
list.each {
    println it
}

def map = [first:"Dan",last:"Vega",company:"FirstComp"]

// loop over a map
map.each { key, value ->
    println "${key}: ${value}"
}

Curried Closure

Closures with prebound parameters are called curried closures. When we curry a closure, we're asking the parameters to be prebound.

def addNumbers = { x, y -> x + y }
def addToTen = addNumbers.curry(10)
assert 14 == addToTen(4)
addNumbers.rcurry(10)
addNumbers.ncurry(index,obj)

Closure Scope

  • this: refers to the instance of the enclosing class where a Closure is defined
  • owner: the enclosing object (this or a surrounding Closure)
  • delegate: by default the same as owner, but changeable
class Foo {

   def closure = {
       println "${this.class.name},${owner.class.name},${delegate.class.name}"
       def innerClosure = {   
           //delegate = owner.delegate 
           println "${this.class.name},${owner.class.name},${delegate.class.name}"
       }
       innerClosure()
   }
   
}

def foo = new Foo().closure()

Closure Delegation

Groovy Closures support method delegation, and provide capabilities for method dispatching-much like JavaScript's support for prototypal inheritance.

class ClosureDemo {
    def foo() {
        def c = {
            write 'hello from foo.c'
        }
        c()
    }
}

def demo = new ClosureDemo()
demo.foo()
when groovy executes a closure it will try to resolve stuff first within the closure, then in the owner scope, and finally in the delegate. this ordering is only the default can be changed by setting the closures resolve strategy the ability to delegate is what makes DSL's possible and extremly powerful inside groovy

Closure Demos

8-10 min of demo remember return statement are optional. this is not just true of closures but methods as well. talk about delegates closure coercion curry example take care of properly opening / closing resource (new File())

Meta-Programming

Meta-Programming is one of the coolest features of Groovy!

So what is Meta-Programming?

Meta-Programming is the writing of computer programs that write or manipulate other programs (or themselves).

Groovy impliments Meta-Programming at runtime with Meta Object Protocol and the ExpandoMetaClass

Every java.lang.Class is supplied with a special "metaClass" property that will give you a reference to an ExpandoMetaClass instance.
Discuss the MOP and how Groovy resolves method calls

The Expando class

http://groovy.codehaus.org/api/groovy/util/Expando.html

Straight from the source, here's the list of all the stuff you can do with the ExpandoMetaClass

  • Borrowing Methods — Borrowing methods from other classes
  • Constructors — Adding or overriding constructors
  • Domain-Specific Language
  • Dynamic Method Names — Dynamically creating method names
  • GroovyObject Methods — Overriding invokeMethod, getProperty and setProperty
  • Interfaces — Adding methods on interfaces
  • Methods — Adding or overriding instance methods
  • Overriding static invokeMethod — Overriding invokeMethod for static methods
  • Properties — Adding or overriding properties
  • Runtime Discovery — Overriding invokeMethod for static methods
  • Static Methods — Adding or overriding static methods
Be sure to talk about how we're going to focus on a few of these today

Dynamically adding properties

class Developer { 
    String firstName, lastName
    def makeExcuse(){ println "I'm compiling!" }
}

josh = new Developer( firstName : 'Joshua', lastName : 'Caito' )
josh.metaClass.isTeamLead = true
gettingARaise = josh.isTeamLead ?: false 
println "Josh is getting a raise? ${gettingARaise}"

Adding methods dynamically

class Developer { 
    String firstName, lastName
    def makeExcuse(){ println "I'm compiling!" }
}

josh = new Developer( firstName : 'Joshua', lastName : 'Caito' )

Developer.metaClass.work = { Integer hours ->
    println """I promise I'll work ${hours} hours today
    or my name isn't ${firstName} ${lastName}!"""
}

dan = new Developer( firstName : 'Dan', lastName : 'Vega' )

try{ josh.work(3) } catch( e ) { josh.makeExcuse() }
dan.work(8)

Borrowing Methods

class Manager { 
    String firstName = 'Big'
    String lastName = 'Cheese'
}

boss = new Manager()

try{ boss.work(3) } catch( e ) {
    println "I've delegated that, I swear!"
}

boss.metaClass.work = josh.&makeExcuse
boss.work()

Adding Missing Methods

Using the ExpandoMetaClass, we can also invoke the methodMissing() method

This can be VERY useful

Thinking this is the first of a few code examples for this: class QA { String FirstName String LastName List expertise = [ 'Bugs', 'Issues', 'Errors' ] QA() { def mClass = new ExpandoMetaClass( QA, false, true ) //Add object, do not register, allow changes after init mClass.initialize() this.metaClass = mClass } def methodMissing(String methodName, arguments) { if( methodName.startsWith( 'locate' ) || methodName.startsWith( 'gripeAbout' ) ) { def listVar = methodName.startsWith( 'locate' ) ? methodName[6..-1] : methodName[10..-1] this.metaClass."$methodName" = {-> listVar + ' √' } listVar + ' √' } else { throw new MissingMethodException(methodName, this.class, arguments) } } } megan = new QA( firstName : 'Megan', lastName : 'Redacted' ) assert 'Bugs √' == megan.locateBugs() assert 'Issues √' == megan.gripeAboutIssues() assert 'Errors √' == megan.locateErrors() Found example code at: http://mrhaki.blogspot.com/2009/11/groovy-goodness-create-dynamic-methods.html and will be sure to credit Going to _really_ go through some examples here throughout and make sure people ask questions as they have them.... wondering if the closures conversation should go first just because of how much they are used here.... Also going to briefly cover DSLs and the whens and whys you'd want to use meta-programming I.E. don't just start mucking with every damn object as it's hard to trace when / how meta methods got registered.
The Groovy Landscape Grails/Gradle/Spock check the wiki for links to all of these resources
  • Grails is an Open Source, full stack, web application framework for the JVM.
  • It takes advantage of the Groovy programming language and convention over configuration
  • Rapid Application Development
  • Current version 2.3.8
  • Inspired by Ruby on Rails, Django & others
What does full stack mean? build tool / ORM / dependency injection / runtime container / testing framework / plugin system / etc...

The Grails Stack

It wasn't the case that Grails went out and built their own ORM/DI/Testing uses the best of breeds/proven technologies that are out there which is really important maybe mention GORM / the layer on top of hibernate you could use casandra or monogo db if you wanted talk about DI / Spring and how you really don't need to do any configuring at all

Getting Started

Getting Started (download) run command line tools IDEs also support (GroovyGrailsToolSuite/Intellij/) grails create-app maybe put danvega on github and link to that? might be easier to see folder structure there

Grails Plugins

  • Build tool with built in dependency management
  • Conventions through plugins
  • Full access to tasks and dependency tree
  • Easy to write your own tasks
    • Either in the build file
    • or view Groovy/Java classes
  • Default build tool for Android
  • http://www.gradle.org

Unit Testing & Testing With Spock

http://docs.spockframework.org/ This will be a quick code demo providing time

IDE Support

IntelliJGroovy/Grails Tool Suite (Eclipse)

Resources

https://github.com/cfaddict/cfo-groovy/wiki/Resoures

THE END / Q&A

BY Josh Caito / Dan Vega

If you liked our presentation (or even if you didn't), please be sure to leave feedback!