Conception d'Applications
Interactives :
Applications Web et JEE
Séance #5
Groovy & Grails
Introduction à Groovy
Origine
James Strachan to Bob McWhirter in 2003:
Wouldn’t it be “groovy” if we could have native
syntax for lists, maps and regexs in Java
like in most scripting languages?
Wouldn’t it be “groovy” if we could have
duck typing in Java?
Wouldn’t it be “groovy” if we had
closures and properties in Java?
Groovy
Langage de POO destiné à la plate-forme Java
● Inspiré de Python, Ruby et Smalltalk
● Syntaxe très proche de Java
● Compilé
○ soit à la volée dynamiquement
○ soit classiquement vers bytecode
Groovy
Langage de POO destiné à la plate-forme Java
● Typages statique et dynamique
● Support natif pour listes, maps, et
expressions régulières
● Fermetures ou clôtures (closures)
● Surcharge des opérateurs
http://groovy.codehaus.org/
Intégration avec Java
○ Groovy génère du bytecode Java pour la JVM
■ Same strings, same regex S
■ Same APIs — JDK, collections, 3rd party, etc.
■ Same security model, same threading model
■ Same OO concepts
○ Compilation croisée
■ Compilateur groovyc pour Java et Groovy
■ Interopérabilité et mixité parfaite
Un programme en Java
public class HelloWorld {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String greet() {
return quot;Hello quot;+ name;
}
public static void main(String[] args) {
HelloWorld helloWorld = new HelloWorld();
helloWorld.setName(quot;Groovyquot;);
System.out.println( helloWorld.greet() );
}
}
Un programme en Groovy
public class HelloWorld {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String greet() {
return quot;Hello quot;+ name;
}
public static void main(String[] args) {
HelloWorld helloWorld = new HelloWorld();
helloWorld.setName(quot;Groovyquot;);
System.out.println( helloWorld.greet() );
}
}
Le même programme bien
récrit en Groovy
class HelloWorld {
String name
String greet() {
"Hello $name"
}
}
def helloWorld = new HelloWorld(name: "Groovy")
println helloWorld.greet()
● Même aspect qu'une déclaration Java
○ Le modificateur par défaut est publique
Déclaration de classes
class HelloWorld {
String name
String greet() {
"Hello $name"
}
}
● Possibilité d'utiliser du typage statique
comme dans Java
● Possibilité d'utiliser le typage dynamique en
remplaçant le type par le mot clé def
● Les paramètres formelles d'une méthode ou
closure n'ont pas besoin de def
Typage optionnel
def helloWorld = new HelloWorld(name: "Groovy")
● Dans les appels aux méthodes avec des paramètres on
peut omettre les parenthèses
Appel aux méthodes
def a = "Toto"
print(a)
print a
method(a, b)
method a, b
move(from:"ici", to:"là bas")
move from:"ici", to:"là bas"
list.each( { println it } )
list.each(){ println it }
list.each { println it }
● Script : du code Groovy non enfermé dans
une déclaration de classe
○ Pas besoin d'une méthode main
Scripts
class HelloWorld {
String name
String greet() {
"Hello $name"
}
}
def helloWorld = new HelloWorld(name: "Groovy")
println helloWorld.greet()
● Les propriétés d'une classe sont déclarées
comme attributs de la classe
○ Des getters et setters sont générés lors de la
compilation/interprétation
Propriétés
class Beer {
String name
String brewery
String country
double alcohol
}
Opérateurs
● Exemples
Chaînes de caractères
'literal String'
'''literal
multiline String'''
def lang = 'Groovy'
"GString for $lang"
"$lang has ${lang.size()} chars"
"""multiline GString with
late eval at ${-> new Date()}"""
text = "Hello World!"
text[0] // returns "H"
text[0..4] // returns "Hello"
text[0..<4] // returns "Hell"
text[-1] // returns "!" (last char)
text[-6..-1] // "World!"(last 6 to last char)
● Exemples
Gammes de valeurs
assert (0..10).contains(5)
assert (0.0..10.0).containsWithinBounds(3.5)
for (item in 0..10) { println item }
for (item in 10..0) { println item }
(0..<10).each { println it }
● Listes et maps sont des éléments de
première classe dans Groovy
○ Syntaxe adaptée, simplification
Listes et maps
// Une liste vide
def a=[]
//Ajoutons des élements
a.add("toto")
a.add("titi")
//Listons les contenus
print a
//Résultat : [toto, titi]
Manipulation des listes
[1,2,3,4] == (1..4)
[1,2,3] + [1] == [1,2,3,1]
[1,2,3] << 1 == [1,2,3,1]
[1,2,3,1] - [1] == [2,3]
[1,2,3] * 2 == [1,2,3,1,2,3]
[1,[2,3]].flatten() == [1,2,3]
[1,2,3].reverse() == [3,2,1]
[1,2,3].disjoint([4,5,6]) == true
[1,2,3].intersect([4,3,1]) == [3,1]
[1,2,3].collect{ it+3 } == [4,5,6]
[1,2,3,1].unique().size() == 3
[1,2,3,1].count(1) == 2
[1,2,3,4].min() == 1
[1,2,3,4].max() == 4
[1,2,3,4].sum() == 10
[4,2,1,3].sort() == [1, 2, 3, 4]
[4,2,1,3].findAll{it%2 == 0} == [4,2]
[['a', 'b'], [1, 2]].transpose() == [['a', 1], ['b', 2]]
Manipulation des listes
def anims = ['cat','kangaroo','koala']
anims[2] == 'koala'
anims[0..1,2] == ['cat','kangaroo','koala']
def kanims = anims[1..2]
anims.findAll{it =~ /k.*/} == kanims
anims.find{ it =~ /k.*/} == kanims[0]
anims.grep(~/k.*/) == kanims
anims.join(' ')
anims.remove(1)
anims.each { println it }
Des indexes négatives indiquent la fin de la liste
def list = [0,1,2]
assert list[-1] == 2
assert list[-1..0] == list.reverse()
assert list == [list.head()] + list.tail()
Maps
def map = [a:0, b:1]
def empty = [:]
Syntaxe semblable à celle des listes
Pour récupérer une valeur on peut mettre la clé entre
crochets ou comme une propriété de la map
assert map['a'] == 0
assert map.b == 1
map['a'] = 'x'
map.b = 'y'
assert map == [a:'x', b:'y']
Manipulation des maps
def map = [a:0, b:1]
def empty = [:]
Syntaxe semblable à celle des listes
Pour récupérer une valeur on peut :
● mettre la clé entre crochets
● mettre la clé comme une propriété de la map
● utiliser la méthode get
assert map['a'] == 0
assert map.b == 1
map['a'] = 'x'
map.b = 'y'
assert map == [a:'x', b:'y']
assert map.c == null
assert map.get('c', 2) == 2
assert map.c == 2
Manipulation des maps
map.each { entry ->
println entry.key
println entry.value
}
map.each { key, value -> println "$key $value" }
for (entry in map) {
println "$entry.key $entry.value"
}
assert map.every { it.value.size() == 1 }
assert map.any { it.key % 4 == 0 }
Des méthodes d'itération permettent de parcourir la map en
s'appliquant à chaque couple clé/valeur
● Des fonctions qui capturent des références à
l'environnement dans lequel ils s'exécutent
○ Des objets de première classe en Groovy
Closures (fermetures)
a = [1,2,3]
a.each({ x -> println x * x })
a.each { x -> println x * x }
a.each { println it * it }
def squareIt = { println it * it }
a.each(squareIt)
a.each squareIt
● Paramètres dans une closure
Closures (fermetures)
Comment apprendre
Groovy ?
Je ne vais pas passer une heure à vos passer
des slides
● Méthode peu efficace
Tentons quelque chose de nouveau
● Approche pratique
Essayons les Groovy Koans !
Groovy Koans ? Kesaco ?
Koans
Une nouvelle façon d'apprendre un langage
● Des petits cas pratiques
○ Sous la forme de suites de tests unitaires
● Chaque cas orienté pour un concept
○ Et un ensemble de tests qui ne passent pas
● Objectif : réparer les tests pour qu'ils
passent
○ Et apprendre le langage en passant
Méthode d'apprentissage différente et éfficace !
Groovy Koans :
Learn Groovy with the Koans
http://groovykoans.org/
Scala Koans
1. Telecharger le .zip sur http://groovykoans.org/
2. Extraire tout et exécuter ./gradlew removeSolutions
3. Exécuter chaque koan :
> ./gradlew koanXX
où XX est le numéro du koan sur 2 charactères
4. Ouvrir le fichier source du koan, l'éditer et voir si ça
passe
C'est l'heure des Groovy Koans !

Enib cours c.a.i. web - séance #5 - groovy

  • 1.
    Conception d'Applications Interactives : ApplicationsWeb et JEE Séance #5 Groovy & Grails
  • 2.
  • 3.
    Origine James Strachan toBob McWhirter in 2003: Wouldn’t it be “groovy” if we could have native syntax for lists, maps and regexs in Java like in most scripting languages? Wouldn’t it be “groovy” if we could have duck typing in Java? Wouldn’t it be “groovy” if we had closures and properties in Java?
  • 4.
    Groovy Langage de POOdestiné à la plate-forme Java ● Inspiré de Python, Ruby et Smalltalk ● Syntaxe très proche de Java ● Compilé ○ soit à la volée dynamiquement ○ soit classiquement vers bytecode
  • 5.
    Groovy Langage de POOdestiné à la plate-forme Java ● Typages statique et dynamique ● Support natif pour listes, maps, et expressions régulières ● Fermetures ou clôtures (closures) ● Surcharge des opérateurs http://groovy.codehaus.org/
  • 6.
    Intégration avec Java ○Groovy génère du bytecode Java pour la JVM ■ Same strings, same regex S ■ Same APIs — JDK, collections, 3rd party, etc. ■ Same security model, same threading model ■ Same OO concepts ○ Compilation croisée ■ Compilateur groovyc pour Java et Groovy ■ Interopérabilité et mixité parfaite
  • 7.
    Un programme enJava public class HelloWorld { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } public String greet() { return quot;Hello quot;+ name; } public static void main(String[] args) { HelloWorld helloWorld = new HelloWorld(); helloWorld.setName(quot;Groovyquot;); System.out.println( helloWorld.greet() ); } }
  • 8.
    Un programme enGroovy public class HelloWorld { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } public String greet() { return quot;Hello quot;+ name; } public static void main(String[] args) { HelloWorld helloWorld = new HelloWorld(); helloWorld.setName(quot;Groovyquot;); System.out.println( helloWorld.greet() ); } }
  • 9.
    Le même programmebien récrit en Groovy class HelloWorld { String name String greet() { "Hello $name" } } def helloWorld = new HelloWorld(name: "Groovy") println helloWorld.greet()
  • 10.
    ● Même aspectqu'une déclaration Java ○ Le modificateur par défaut est publique Déclaration de classes class HelloWorld { String name String greet() { "Hello $name" } }
  • 11.
    ● Possibilité d'utiliserdu typage statique comme dans Java ● Possibilité d'utiliser le typage dynamique en remplaçant le type par le mot clé def ● Les paramètres formelles d'une méthode ou closure n'ont pas besoin de def Typage optionnel def helloWorld = new HelloWorld(name: "Groovy")
  • 12.
    ● Dans lesappels aux méthodes avec des paramètres on peut omettre les parenthèses Appel aux méthodes def a = "Toto" print(a) print a method(a, b) method a, b move(from:"ici", to:"là bas") move from:"ici", to:"là bas" list.each( { println it } ) list.each(){ println it } list.each { println it }
  • 13.
    ● Script :du code Groovy non enfermé dans une déclaration de classe ○ Pas besoin d'une méthode main Scripts class HelloWorld { String name String greet() { "Hello $name" } } def helloWorld = new HelloWorld(name: "Groovy") println helloWorld.greet()
  • 14.
    ● Les propriétésd'une classe sont déclarées comme attributs de la classe ○ Des getters et setters sont générés lors de la compilation/interprétation Propriétés class Beer { String name String brewery String country double alcohol }
  • 15.
  • 16.
    ● Exemples Chaînes decaractères 'literal String' '''literal multiline String''' def lang = 'Groovy' "GString for $lang" "$lang has ${lang.size()} chars" """multiline GString with late eval at ${-> new Date()}""" text = "Hello World!" text[0] // returns "H" text[0..4] // returns "Hello" text[0..<4] // returns "Hell" text[-1] // returns "!" (last char) text[-6..-1] // "World!"(last 6 to last char)
  • 17.
    ● Exemples Gammes devaleurs assert (0..10).contains(5) assert (0.0..10.0).containsWithinBounds(3.5) for (item in 0..10) { println item } for (item in 10..0) { println item } (0..<10).each { println it }
  • 18.
    ● Listes etmaps sont des éléments de première classe dans Groovy ○ Syntaxe adaptée, simplification Listes et maps // Une liste vide def a=[] //Ajoutons des élements a.add("toto") a.add("titi") //Listons les contenus print a //Résultat : [toto, titi]
  • 19.
    Manipulation des listes [1,2,3,4]== (1..4) [1,2,3] + [1] == [1,2,3,1] [1,2,3] << 1 == [1,2,3,1] [1,2,3,1] - [1] == [2,3] [1,2,3] * 2 == [1,2,3,1,2,3] [1,[2,3]].flatten() == [1,2,3] [1,2,3].reverse() == [3,2,1] [1,2,3].disjoint([4,5,6]) == true [1,2,3].intersect([4,3,1]) == [3,1] [1,2,3].collect{ it+3 } == [4,5,6] [1,2,3,1].unique().size() == 3 [1,2,3,1].count(1) == 2 [1,2,3,4].min() == 1 [1,2,3,4].max() == 4 [1,2,3,4].sum() == 10 [4,2,1,3].sort() == [1, 2, 3, 4] [4,2,1,3].findAll{it%2 == 0} == [4,2] [['a', 'b'], [1, 2]].transpose() == [['a', 1], ['b', 2]]
  • 20.
    Manipulation des listes defanims = ['cat','kangaroo','koala'] anims[2] == 'koala' anims[0..1,2] == ['cat','kangaroo','koala'] def kanims = anims[1..2] anims.findAll{it =~ /k.*/} == kanims anims.find{ it =~ /k.*/} == kanims[0] anims.grep(~/k.*/) == kanims anims.join(' ') anims.remove(1) anims.each { println it } Des indexes négatives indiquent la fin de la liste def list = [0,1,2] assert list[-1] == 2 assert list[-1..0] == list.reverse() assert list == [list.head()] + list.tail()
  • 21.
    Maps def map =[a:0, b:1] def empty = [:] Syntaxe semblable à celle des listes Pour récupérer une valeur on peut mettre la clé entre crochets ou comme une propriété de la map assert map['a'] == 0 assert map.b == 1 map['a'] = 'x' map.b = 'y' assert map == [a:'x', b:'y']
  • 22.
    Manipulation des maps defmap = [a:0, b:1] def empty = [:] Syntaxe semblable à celle des listes Pour récupérer une valeur on peut : ● mettre la clé entre crochets ● mettre la clé comme une propriété de la map ● utiliser la méthode get assert map['a'] == 0 assert map.b == 1 map['a'] = 'x' map.b = 'y' assert map == [a:'x', b:'y'] assert map.c == null assert map.get('c', 2) == 2 assert map.c == 2
  • 23.
    Manipulation des maps map.each{ entry -> println entry.key println entry.value } map.each { key, value -> println "$key $value" } for (entry in map) { println "$entry.key $entry.value" } assert map.every { it.value.size() == 1 } assert map.any { it.key % 4 == 0 } Des méthodes d'itération permettent de parcourir la map en s'appliquant à chaque couple clé/valeur
  • 24.
    ● Des fonctionsqui capturent des références à l'environnement dans lequel ils s'exécutent ○ Des objets de première classe en Groovy Closures (fermetures) a = [1,2,3] a.each({ x -> println x * x }) a.each { x -> println x * x } a.each { println it * it } def squareIt = { println it * it } a.each(squareIt) a.each squareIt
  • 25.
    ● Paramètres dansune closure Closures (fermetures)
  • 26.
    Comment apprendre Groovy ? Jene vais pas passer une heure à vos passer des slides ● Méthode peu efficace Tentons quelque chose de nouveau ● Approche pratique Essayons les Groovy Koans ! Groovy Koans ? Kesaco ?
  • 27.
    Koans Une nouvelle façond'apprendre un langage ● Des petits cas pratiques ○ Sous la forme de suites de tests unitaires ● Chaque cas orienté pour un concept ○ Et un ensemble de tests qui ne passent pas ● Objectif : réparer les tests pour qu'ils passent ○ Et apprendre le langage en passant Méthode d'apprentissage différente et éfficace !
  • 28.
    Groovy Koans : LearnGroovy with the Koans http://groovykoans.org/
  • 29.
    Scala Koans 1. Telechargerle .zip sur http://groovykoans.org/ 2. Extraire tout et exécuter ./gradlew removeSolutions 3. Exécuter chaque koan : > ./gradlew koanXX où XX est le numéro du koan sur 2 charactères 4. Ouvrir le fichier source du koan, l'éditer et voir si ça passe
  • 30.
    C'est l'heure desGroovy Koans !