Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.

Groovy e Domain Specific Languages

Dopo una piccola introduzione al linguaggio Groovy, dove verranno illustrate brevemente alcune peculiarità, si passerà ad esaminare le caratteristiche che lo rendono adatto per la generazione di DSL.
Verrà quindi presentato come caso pratico la costruzione di una DSL e sarà mostrato come è possibile embeddarla in un progetto Java.

  • Identifiez-vous pour voir les commentaires

  • Soyez le premier à aimer ceci

Groovy e Domain Specific Languages

  1. 1. GROOVY E DSL BY TIZIANO LATTISI
  2. 2. INDICE • cos’è Groovy? • caratteristiche interessanti (a mio giudizio), in ordine arbitrariamente sparso • cos’è un DSL? • caratteristiche che rendono Groovy adatto a costruire un DSL • un esempio semplice (lo facciamo al volo) • un esempio meno semplice (non lo facciamo al volo) nota: in parallelo vedremo esempi
  3. 3. COS’È GROOVY (PARTE 1)? • linguaggio per la JVM alternativo a Java • ispirato a: Ruby, Python, Smalltalk • consente compilazione dinamica, ma può anche generare bytecode • tipizzazione forte dinamica • closure
  4. 4. COMMAND-LINE GROOVY HELLO GROOVY • $ groovy -e “println ‘Hello Groovy’”! • $ echo “println ‘Hello Groovy’” > hello.groovy
 $ groovy hello.groovy! • $ groovy -Dmsg=Groovy -e “println ‘Hello ‘ + System.getProperty(‘msg’)”
  5. 5. COMMAND-LINE GROOVY SWITCH -N -P -I • $ printf “1n2” > data.txt
 $ groovy -n -e “println line.toLong()*2” data.txt
 2
 4! • $ groovy -i.bak —n -p -e “line.toLong()*2” data.txt
 $ cat data.txt
 2
 4
 $ cat data.txt.bak
 1
 2

  6. 6. COMMAND-LINE GROOVY SWITCH -L • $ groovy -l 1234 -e “if(line==‘DATE’){println new Date()}”
 Groovy is listening on port 1234
 
 $ telnet localhost 1234
 Connect to localhost.
 Escape character is ‘^]’.
 DATE
 Mon Mar 17 21:38:49 CET 2014! • $ groovy -l 80 SimpleWebServer.groovy
 
 Esempio nei sorgenti Groovy: serve i file di una cartella come webserver

  7. 7. COS’È GROOVY (PARTE 2)? • è possibile usare direttamente l’API Java • accetta (salvo alcune eccezioni) anche sintassi Java (es. {1,2,3,4} non è array, ma [1,2,3,4] è un ArrayList) • import automatico (di convenienza) di alcune classi Java (es. java.io, java.lang, java.net, java.util…) • println -> System.out.println • parentesi opzionali nella chiamata a metodi • notazione breve per getter e setter (o.field -> o.getField()) • ; opzionale (salvo alcune eccezioni) • return opzionale (viene restituita l’ultima valutazione) • this usata in contesti statici punta alla classe
  8. 8. COS’È GROOVY (PARTE 3)? • GString interpolation: “Hello ${name}” • Lazily interpolation (eval in conversione a String): “Nr. ${-> i}” • == -> equals, equals -> is: non più “a != null && a.equals()” !! • in: è un operatore basato su contains(): 3 in [1,2,3,4] • sintassi nativa per alcune strutture dati: [1,2,3] list, [TN:’Trento’, BZ:’Bolzano] map, 1..10 range • contesti booleani: if( myString!=null && myString.length>0 ){} -> if(myString){} • safe-dereferencing: email?.destinatario?.indirizzo • costrutto and-or (Elvis operator):
 def result = name != null ? name : “Unknow”
  9. 9. FOR E FOR EACH • for (int i=0; i<n; i++) { … }! • for (i in 0..n-1) { … }! • for (i in 0..<n) { … }! • n.times { … }
 • (1..5).each { println “nr. $it” }! • 1..5 instanceof List! • { println “nr. $it” }(3)
 nr. 3
  10. 10. GROOVY BEANS class Book {
 String title
 String description
 }
 
 def b1 = new Book()
 b1.setTitle(“Anna Karenina”)
 b1.description = “A very long book…”! println b2.getDescription()
 println b2.title
 
 def b2 = new Book(title:”Anna Karenina”)
 println b2.title
  11. 11. ALTRO SUI GROOVY BEANS • Annotation based AST transformation (groovy.transform.*):! • @Immutable (read only bean)! • @ToString(includeNames=true, excludes=‘description,year’)! • @EqualsAndHashCode! • @Canonical (@ToString + @EqualsAndHashCode)! • @TupleConstructor -> new Book(“Anna Karenina”, “Very long book…”)! • @AutoClone(style=AutoCloneStyle.COPY_CONSTRUCTOR)
 
 def book1 = new Book(title:”Anna Karenina”)
 def book2 = book1.clone()
 assert book1.title == book2.title! • AutoCloneStyle.SERIALIZABLE se implementa Serializable

  12. 12. ALTRE COSE BELLE • methodMissing e propertyMissing per gestire accessi a proprietà o metodi mancanti • supporto nativo per markup XML, Json (Slurper e Builder) • conversioni bean in xml e json • ExpandoMetaClass • built-in memoize
  13. 13. DSL
 DOMAIN SPECIFIC LANGUAGE • Linguaggio di programmazione dedicato ad uno specifico dominio (contrapposto a “general-purpose”) • statistica (R e S) • programmazione matriciale (Mata) • Logo • SQL • …
  14. 14. DEFINIRE UN DSL IN GROOVY Combinazione di tre punti chiave: • fluent API • embedded shell • “specificità” del linguaggio
  15. 15. FLUENT API È un implementazione di un API “method chaining”, ovvero che permette chiamate di metodi “a catena”. Es. JavaFX Scene scene = SceneBuilder.create().width(516).height(387)
 ! .root(
 ! ! GroupBuilder.create().children(
 ! ! ! ImageViewBuilder.create().image(new Image(“..”)),
 ! ! ! [omissam]
 ! ! ).build()).build();
  16. 16. EMBEDING GROOVY IN JAVA // Semplice esecuzione di codice Groovy! GroovyShell shell = new GroovyShell();
 String groovyCode = “println ‘Hello ’ + ‘Groovy’”;
 String out = shell.evaluate(groovyCode); // Esecuzione codice Groovy con variabile embeddata! Book myBook = new Book();
 myBook.setTitle(“Anna Karenina”);! Binding binding = new Binding();
 binding.setVariable(“book”, myBook);
 String groovyCode = “println ‘Reading ‘ + book.title”;
 GroovyShell shell = new GroovyShell(binding);
 String out = shell.evaluate(groovyCode);
  17. 17. SPECIFICITÀ DI GROOVY • le chiamate di metodi possono omettere le parentesi • scriptBaseClass: la classe script base che rappresenta il contesto di esecuzione dello script • ImportCustomizer: importazione diretta nello script di classi e package (anche *) • SecureASTCustomizer: gestione della sicurezza (es. liste bianche/nere) • ASTTransformationCustomizer: per aggiungere automaticamente annotazioni di trasformazione ai metodi
  18. 18. ESEMPIO SEMPLICE Voglio creare un DSL in grado di eseguire: compute 4 plus 3 plus 2 minus 1 print total! • Una classe che implementa i metodi di linguaggio (compute, plus, minus, etc) come API fluent • Una classe astratta come base dello script groovy (si occuperà di proxare i metodi sullo script) • Un enum per le costanti (es. total) • GroovyShell con: • binding della classe linguaggio • classe base astratta (vedi sopra) • importazione custom delle costanti (vedi sopra) Vediamo in pratica come procedere! (sorry, no slides here…)
  19. 19. LA CLASSE DI LINGUAGGIO class Language {
 Integer tot;
 def compute(Integer a){
 tot=a
 this
 }
 def plus(Integer a){
 tot += a
 this
 }
 def minus(Integer a){
 tot -= a
 this
 }
 def print(Consts c){
 tot
 }
 }
  20. 20. LA SCRIPTBASE E LA COSTANTE abstract class AbstractScriptBaseClass extends Script{
 def compute(Integer a){
 this.lang.compute(a)
 }
 def plus(Integer a){
 this.lang.plus(a)
 }
 def minus(Integer a){
 this.lang.minus(a)
 }
 def print(String t){
 this.lang.print(t)
 }
 } public enum Consts {
 total
 }
  21. 21. TESTIAMO L’API void testAPI() {
 
 Language lang = new Language()
 String total = "total"
 
 // test API con sintassi tradizionale
 Integer tot1 = lang.compute(4).plus(3).plus(2).minus(1).print(total)
 
 // test API omettendo le parentesi
 Integer tot2 = lang.compute 4 plus 3 plus 2 minus 1 print total
 
 assert tot1 == 8
 assert tot2 == 8
 
 }
  22. 22. TESTIAMO IL DSL void testShell() {
 
 // il codice scritto nel DSL
 def code = "compute 4 plus 3 plus 2 minus 1 print total"
 
 Language lang = new Language()
 Binding binding = new Binding();
 binding.setVariable("lang", lang)
 
 CompilerConfiguration conf = new CompilerConfiguration()
 conf.scriptBaseClass = AbstractScriptBaseClass.class.name
 
 ImportCustomizer imports = new ImportCustomizer()
 imports.addStaticStars(Consts.name)
 conf.addCompilationCustomizers(imports)
 
 GroovyShell shell = new GroovyShell(binding, conf)
 Integer tot = (Integer) shell.evaluate(code)
 
 assert tot == 8
 }
  23. 23. ESEMPIO MENO SEMPLICE Un DSL per definire e risolvere problemi di geometria piana euclidea
 (https://github.com/tizianolattisi/peg) create triangle name "ABC"
 extend "AC" to "D" with measure:"BC"
 extend "BC" to "E" with measure:"AC"
 create segment name "ED"
 extend "DE" to "H"
 extend "AB" to "H"
 apply "10.8" on "ad", "bc" //angoli opposti
 apply "10.3" on "CED", "ABC"
 apply "10.6" on "ABC", "cba", "CED", "edc"
 create segment name "BD"
 apply "10.10" on "BCD", "BC", "CD"
  24. 24. –Tiziano Lattisi “Grazie a tutti!”.

×