<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8003298816604397919</id><updated>2012-01-27T14:23:36.677+01:00</updated><category term='C++'/><category term='Bash scripting'/><category term='TDD'/><category term='Tests'/><category term='Software Engineering'/><category term='SQL'/><category term='Test Driven Development'/><category term='Informatica'/><category term='GNU/Linux'/><category term='OOP'/><category term='Qt'/><category term='Design'/><category term='Programmazione'/><category term='Object Oriented Programming'/><category term='Oracle'/><category term='Extreme Programming'/><category term='Testing'/><title type='text'>GuLinux's $HOME</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://rockman81.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://rockman81.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Marco Gulino</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-5TKjBFH5Ob4/AAAAAAAAAAI/AAAAAAAACNU/m2QmMz40phI/s512-c/photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>13</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8003298816604397919.post-2583503713993844749</id><published>2012-01-17T08:58:00.001+01:00</published><updated>2012-01-18T11:55:08.264+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Informatica'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><category scheme='http://www.blogger.com/atom/ns#' term='Design'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><category scheme='http://www.blogger.com/atom/ns#' term='Test Driven Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Extreme Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Object Oriented Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Tests'/><category scheme='http://www.blogger.com/atom/ns#' term='Programmazione'/><category scheme='http://www.blogger.com/atom/ns#' term='Qt'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><title type='text'>Test Driven Development, C++ e Qt: refactoring, ottimizzazioni, d-pointer</title><content type='html'>Nel &lt;inserire link=""&gt; precedente post abbiamo dato una messa a punto ai file del progetto. Potrebbe essere il caso di fare qualcosina anche per il codice sorgente...&lt;/inserire&gt;&lt;br&gt;&lt;inserire link=""&gt;In questa puntata vedremo alcuni passi di refactoring che ci aiuteranno ad implementare funzionalità future, e renderanno il codice più robusto. Vedremo ad esempio come applicare il meccanismo di &lt;i&gt;Signal &lt;/i&gt;e &lt;i&gt;Slot&lt;/i&gt; di Qt, particolarmente indicato per la programmazione &amp;quot;ad eventi&amp;quot;, e in cosa consiste il pattern &lt;i&gt;d-pointer&lt;/i&gt; che in alcuni ambienti (ad esempio nella programmazione per KDE) è divenuto uno standard praticamente obbligatorio&lt;/inserire&gt;&lt;br&gt;&lt;a href="http://rockman81.blogspot.com/2012/01/test-driven-development-c-e-qt_17.html#more"&gt;Continua a leggere...»&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8003298816604397919-2583503713993844749?l=rockman81.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rockman81.blogspot.com/feeds/2583503713993844749/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8003298816604397919&amp;postID=2583503713993844749' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/2583503713993844749'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/2583503713993844749'/><link rel='alternate' type='text/html' href='http://rockman81.blogspot.com/2012/01/test-driven-development-c-e-qt_17.html' title='Test Driven Development, C++ e Qt: refactoring, ottimizzazioni, d-pointer'/><author><name>Marco Gulino</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-5TKjBFH5Ob4/AAAAAAAAAAI/AAAAAAAACNU/m2QmMz40phI/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8003298816604397919.post-5074855692082425515</id><published>2012-01-08T21:09:00.000+01:00</published><updated>2012-01-08T21:10:21.496+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test Driven Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Informatica'/><category scheme='http://www.blogger.com/atom/ns#' term='Object Oriented Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Extreme Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Tests'/><category scheme='http://www.blogger.com/atom/ns#' term='Programmazione'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='Qt'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><category scheme='http://www.blogger.com/atom/ns#' term='Design'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Test Driven Development, C++ e Qt: ottimizzazioni layout progetti</title><content type='html'>Nella puntata precedente abbiamo creato un primo "vero" test di dominio perfettamente funzionante; il ciclo del TDD prevede a questo punto di effettuare un po' di refactoring, se necessario, prima di iniziare la nuova funzionalità.&lt;br /&gt;In questo capitolo ci occuperemo non tanto di refactoring relativi al design (qualcosa si può fare, ma avendo scritto pochissimo codice è davvero poca roba), quanto piuttosto di trasformare quello che adesso è codice "sperimentale" in qualcosa di più professionale, usando layout di progetto, ottimizzazioni e convenzioni che sono da favorire in progetti pronti per la produzione.&lt;br /&gt;Ma che problemi ha il nostro progettino?&lt;br /&gt;In realtà un bel po', cominciamo dalle cose più evidenti: la prima è che i progetti sono collegati tra loro piuttosto malamente.&lt;br /&gt;Sappiamo che il progetto &lt;i&gt;DownloadManager&amp;nbsp;&lt;/i&gt;deve usare &lt;i&gt;DownloadManagerCore&lt;/i&gt;, ma al momento non c'è nessun riferimento ad esso. Sappiamo anche che il progetto &lt;i&gt;UnitTests&lt;/i&gt;&amp;nbsp;deve fare, e in realtà fa già, la stessa cosa. Ma per farlo abbiamo dovuto aggiungere la riga:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="color: purple;"&gt;    LIBS&lt;/span&gt;&lt;span style="color: silver;"&gt; &lt;/span&gt;+=&lt;span style="color: silver;"&gt; &lt;/span&gt;-L../DownloadManagerCore-build-desktop/&lt;span style="color: silver;"&gt; &lt;/span&gt;-lDownloadManagerCore&lt;/pre&gt;&lt;br /&gt;e di certo non vorremo tenerla così: quando infatti dovremo compilare in modalità release sarebbe necessario modificare manualmente il file di progetto (tanto nel progetto &lt;i&gt;UnitTests&amp;nbsp;&lt;/i&gt;quanto in &lt;i&gt;DownloadManager&lt;/i&gt;), e non è sicuramente il massimo!&lt;br /&gt;Ma anche nel codice sorgente c'è qualcosina che non va: in&amp;nbsp;downloadmanagercoretest.cpp vediamo la riga&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span style="color: navy;"&gt;#include&lt;/span&gt;&lt;span style="color: silver;"&gt; &lt;/span&gt;&lt;span style="color: green;"&gt;"../DownloadManagerCore/downloadmanagercore.h"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;che dovremmo ripetere per ogni futuro test case. Non va bene!&lt;br /&gt;&lt;br /&gt;Per fortuna &lt;i&gt;qmake&lt;/i&gt;&amp;nbsp;ci viene in aiuto con alcune funzioni interessanti.&lt;br /&gt;Aggiungendo al file di progetto la riga&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="color: purple;"&gt;    INCLUDEPATH&lt;/span&gt;&lt;span style="color: silver;"&gt; &lt;/span&gt;+=&lt;span style="color: silver;"&gt; &lt;/span&gt;../DownloadManagerCore&lt;/pre&gt;&lt;br /&gt;rendiamo disponibli tutti gli header di &lt;i&gt;DownloadManagerCore&lt;/i&gt; al progetto &lt;i&gt;UnitTests&lt;/i&gt;, trasformando quindi la riga precedente in&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;    &lt;span style="color: navy;"&gt;#include&lt;/span&gt;&lt;span style="color: silver;"&gt; &lt;/span&gt;&lt;span style="color: green;"&gt;"downloadmanagercore.h"&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;Applichiamo questa modifica anche al progetto &lt;i&gt;DownloadManager&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;Per distinguere invece tra &lt;i&gt;debug&lt;/i&gt;&amp;nbsp;e &lt;i&gt;release&lt;/i&gt;, usando anche un path migliore per la direttiva &lt;b&gt;LIBS&lt;/b&gt;&amp;nbsp;dobbiamo invece usare una funzionalità un po' più avanzata di qmake.&lt;br /&gt;L'idea alla base è di compilare &lt;i&gt;DownloadManagerCore&lt;/i&gt;, installarlo in una directory comune (con suffisso -debug o -release a seconda di come l'abbiamo compilata) e far puntare gli altri progetti a quella directory.&lt;br /&gt;Per far questo dobbiamo aggiungere questa sezione a &lt;b&gt;tutti&lt;/b&gt;&amp;nbsp;i file di progetto (quindi &lt;i&gt;DownloadManagerCore&lt;/i&gt;, &lt;i&gt;DownloadManager&lt;/i&gt;&amp;nbsp;e &lt;i&gt;UnitTests&lt;/i&gt;):&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;win32&lt;span style="color: silver;"&gt; &lt;/span&gt;{&lt;/pre&gt;&lt;pre&gt;&lt;span style="color: silver;"&gt;    &lt;/span&gt;build_pass:&lt;span style="color: purple;"&gt;CONFIG&lt;/span&gt;(debug,&lt;span style="color: silver;"&gt; &lt;/span&gt;debug|release)&lt;span style="color: silver;"&gt;   &lt;/span&gt;{&lt;span style="color: silver;"&gt; &lt;/span&gt;COMPILE_MODE='debug'&lt;span style="color: silver;"&gt;   &lt;/span&gt;}&lt;/pre&gt;&lt;pre&gt;&lt;span style="color: silver;"&gt;    &lt;/span&gt;else:build_pass&lt;span style="color: silver;"&gt;                           &lt;/span&gt;{&lt;span style="color: silver;"&gt; &lt;/span&gt;COMPILE_MODE='release'&lt;span style="color: silver;"&gt; &lt;/span&gt;}&lt;/pre&gt;&lt;pre&gt;}&lt;span style="color: silver;"&gt; &lt;/span&gt;else&lt;span style="color: silver;"&gt; &lt;/span&gt;{&lt;/pre&gt;&lt;pre&gt;&lt;span style="color: silver;"&gt;    &lt;/span&gt;&lt;span style="color: purple;"&gt;CONFIG&lt;/span&gt;(debug,&lt;span style="color: silver;"&gt; &lt;/span&gt;debug|release)&lt;span style="color: silver;"&gt;   &lt;/span&gt;{&lt;span style="color: silver;"&gt; &lt;/span&gt;COMPILE_MODE='debug'&lt;span style="color: silver;"&gt; &lt;/span&gt;}&lt;/pre&gt;&lt;pre&gt;&lt;span style="color: silver;"&gt;    &lt;/span&gt;else&lt;span style="color: silver;"&gt;                           &lt;/span&gt;{&lt;span style="color: silver;"&gt; &lt;/span&gt;COMPILE_MODE='release'&lt;span style="color: silver;"&gt; &lt;/span&gt;}&lt;/pre&gt;&lt;pre&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Brevemente, viene assegnata una variabile COMPILE_MODE con un valore dipendente da come si compila il progetto corrente.&lt;br /&gt;&lt;i&gt;win32&lt;/i&gt;&amp;nbsp;viene gestito a parte perchè ho notato che COMPILE_MODE rimane vuota con la sintassi specificata nel ramo &lt;i&gt;else&lt;/i&gt;.&lt;br /&gt;Probabilmente dipende dal tipo di compilatore in uso, la sezione nel ramo &lt;i&gt;win32&lt;/i&gt;&amp;nbsp;è stata testata su visual c++ 2010, probabilmente usando invece mingw non è ncessaria.&lt;br /&gt;In ogni caso, provate a vedere se COMPILE_MODE viene popolata o meno usando l'istruzione&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="color: olive;"&gt;message&lt;/span&gt;("Using&lt;span style="color: silver;"&gt; &lt;/span&gt;compile&lt;span style="color: silver;"&gt; &lt;/span&gt;mode:&lt;span style="color: silver;"&gt; &lt;/span&gt;$$COMPILE_MODE")&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Adesso che abbiamo definito la variabile, proviamo ad usarla.&lt;br /&gt;Nel progetto &lt;i&gt;DownloadManagerCore&lt;/i&gt;&amp;nbsp;aggiungiamo il path per l'installazione.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;target.path='../static-libraries.bin/$$COMPILE_MODE'&lt;/pre&gt;&lt;pre&gt;&lt;span style="color: purple;"&gt;INSTALLS&lt;/span&gt;&lt;span style="color: silver;"&gt; &lt;/span&gt;+=&lt;span style="color: silver;"&gt; &lt;/span&gt;target&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Questo farà in modo che eseguendo &lt;i&gt;make install&lt;/i&gt;&amp;nbsp;la libreria verrà copiata nella directory static-libraries.bin/debug (o release).&lt;br /&gt;È consigliabile anche modificare i profili del progetto in qt creator: in "projects-&amp;gt;build settings", tra i build steps, aggiungiamo al passo &lt;i&gt;make&lt;/i&gt;&amp;nbsp;l'argomento &lt;i&gt;install&lt;/i&gt;. Questo per tutti i profili di &lt;i&gt;DownloadManagerCore&lt;/i&gt;.&lt;br /&gt;In questo modo, ad ogni build, la libreria statica verrà installata automaticamente.&lt;br /&gt;Ora nei progetti &lt;i&gt;DownloadManager&lt;/i&gt;&amp;nbsp;e &lt;i&gt;UnitTests&lt;/i&gt;&amp;nbsp;andiamo ad usare questa nuova funzionalità. Molto semplicemente, la riga "&lt;i&gt;LIBS+= .....&lt;/i&gt;" vista in precedenza, diventerà:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="color: purple;"&gt;LIBS&lt;/span&gt;&lt;span style="color: silver;"&gt; &lt;/span&gt;+=&lt;span style="color: silver;"&gt; &lt;/span&gt;-L../static-libraries.bin/$$COMPILE_MODE&lt;span style="color: silver;"&gt; &lt;/span&gt;-lDownloadManagerCore&lt;/pre&gt;&lt;br /&gt;aggiungendola a &lt;i&gt;DownloadManager&lt;/i&gt;&amp;nbsp;dove non esisteva ancora.&lt;br /&gt;Il modo migliore per verificare il risultato di quello che abbiamo fatto è cancellare tutte le directory di build, ricompilare da capo il progetto &lt;i&gt;UnitTests&lt;/i&gt;&amp;nbsp;(e naturalmente la sua dipendenza, &lt;i&gt;DownloadManagerCore&lt;/i&gt;) e verificare che i test passino ancora.&lt;br /&gt;&lt;br /&gt;Un' ultima ottimizzazione: risulta spesso utile in molti progetti avere una directory dove inserire script per automatizzare i task più frequenti, che spesso richiederebbero una serie di operazioni manuali non proprio comode. Creiamo quindi una directory "&lt;i&gt;scripts&lt;/i&gt;". Che script possiamo scrivere per inaugurarla?&lt;br /&gt;Beh, un primo task noioso e facilmente automatizzabile è la compilazione ed esecuzione automatica dei test: vogliamo uno script che sia in grado di compilare anzitutto il progetto &lt;i&gt;DownloadManagerCore&lt;/i&gt;, installarlo nella directory&amp;nbsp;static-libraries.bin, quindi compilare ed eseguire automaticamente i tests.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #e0eaee; color: black; font-family: 'Courier New'; font-size: 10pt;"&gt;&lt;span style="color: #838183; font-style: italic;"&gt;#!/bin/bash&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0057ae;"&gt;set&lt;/span&gt; &lt;span style="color: black;"&gt;-&lt;/span&gt;e&lt;br /&gt;&lt;br /&gt;PROJECTS&lt;span style="color: black;"&gt;=&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"UnitTests"&lt;/span&gt;&lt;br /&gt;COLORIZE_CMD&lt;span style="color: black;"&gt;=&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"ccze -A"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;MAIN_PROJECT&lt;span style="color: black;"&gt;=&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"DownloadManagerCore"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;BASE_DIRECTORY&lt;span style="color: black;"&gt;=&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"$PWD/$( dirname $0)/.."&lt;/span&gt;&lt;br /&gt;COMPILE_BUILD_PREFIX&lt;span style="color: black;"&gt;=&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"$BASE_DIRECTORY/.build-"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;test&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"x$TERM"&lt;/span&gt; &lt;span style="color: black;"&gt;!=&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"xxterm"&lt;/span&gt; || &lt;span style="color: #0057ae;"&gt;test&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"x$( which $( echo $COLORIZE_CMD | cut -d "&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;" -f 1 ) )"&lt;/span&gt; &lt;span style="color: black;"&gt;==&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"x"&lt;/span&gt;&lt;span style="color: black;"&gt;;&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;then&lt;/span&gt; &lt;span style="color: #838183; font-style: italic;"&gt;#TODO add other terminals supported by ccze here&lt;/span&gt;&lt;br /&gt;        COLORIZE_CMD&lt;span style="color: black;"&gt;=&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"cat"&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;fi&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;test&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"x$1"&lt;/span&gt; &lt;span style="color: black;"&gt;==&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"x--help"&lt;/span&gt;&lt;span style="color: black;"&gt;;&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;then&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0057ae;"&gt;echo&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"Usage: $0 [Test-Project-Name [test-method-name]]"&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0057ae;"&gt;echo&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"It runs every project configured in the PROJECTS variable, or can select from parameters"&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0057ae;"&gt;echo&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"The variable MODE can be used to choose between debug and release compilation"&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0057ae;"&gt;echo&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"Currently supported test projects: $PROJECTS"&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0057ae;"&gt;exit&lt;/span&gt; &lt;span style="color: #b07e00;"&gt;0&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;fi&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;test&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"x$1"&lt;/span&gt; &lt;span style="color: black;"&gt;!=&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"x"&lt;/span&gt;&lt;span style="color: black;"&gt;;&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;then&lt;/span&gt;&lt;br /&gt;        PROJECTS&lt;span style="color: black;"&gt;=&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"$1"&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: black;"&gt;[ -&lt;/span&gt;f &lt;span style="color: #010181;"&gt;$PROJECTS&lt;/span&gt; &lt;span style="color: black;"&gt;] &amp;amp;&amp;amp;&lt;/span&gt; PROJECTS&lt;span style="color: black;"&gt;=&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"$( basename "&lt;/span&gt;$&lt;span style="color: black;"&gt;(&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;dirname&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"$PROJECTS"&lt;/span&gt;&lt;span style="color: black;"&gt;)&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;" )"&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0057ae;"&gt;echo&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"**** Project: $PROJECTS"&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0057ae;"&gt;shift&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;fi&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;BUILD_MODE&lt;span style="color: black;"&gt;=&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"${MODE-debug}"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;function&lt;/span&gt; buildProject&lt;span style="color: black;"&gt;() {&lt;/span&gt;&lt;br /&gt;        project&lt;span style="color: black;"&gt;=&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"$1"&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0057ae;"&gt;shift&lt;/span&gt;&lt;br /&gt;        make_args&lt;span style="color: black;"&gt;=&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"$1"&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0057ae;"&gt;shift&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #838183; font-style: italic;"&gt;#rm -rf "$project.build"&lt;/span&gt;&lt;br /&gt;        mkdir &lt;span style="color: black;"&gt;-&lt;/span&gt;p &lt;span style="color: #bf0303;"&gt;"${COMPILE_BUILD_PREFIX}$project"&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0057ae;"&gt;cd&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"${COMPILE_BUILD_PREFIX}$project"&lt;/span&gt;&lt;br /&gt;        qmake &lt;span style="color: #bf0303;"&gt;"CONFIG+=$BUILD_MODE silent"&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"DEFINES += QT_NO_DEBUG_OUTPUT"&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"$@"&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"../$project"&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: black; font-weight: bold;"&gt;make&lt;/span&gt; &lt;span style="color: #010181;"&gt;$make_args&lt;/span&gt; &lt;span style="color: black;"&gt;&amp;gt; /&lt;/span&gt;dev&lt;span style="color: black;"&gt;/&lt;/span&gt;null&lt;br /&gt;        &lt;span style="color: #0057ae;"&gt;cd&lt;/span&gt; ..&lt;br /&gt;&lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;function&lt;/span&gt; runTests&lt;span style="color: black;"&gt;() {&lt;/span&gt;&lt;br /&gt;        suitename&lt;span style="color: black;"&gt;=&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"$1"&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0057ae;"&gt;shift&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0057ae;"&gt;echo&lt;/span&gt; &lt;span style="color: black;"&gt;-&lt;/span&gt;e &lt;span style="color: #bf0303;"&gt;"Running suite $suitename&lt;/span&gt;&lt;span style="color: magenta;"&gt;\n&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0057ae;"&gt;cd&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"${COMPILE_BUILD_PREFIX}$suitename"&lt;/span&gt;&lt;br /&gt;        binary&lt;span style="color: black;"&gt;=&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"./$suitename"&lt;/span&gt; &lt;br /&gt;        &lt;span style="color: #010181;"&gt;$binary&lt;/span&gt; $@ | &lt;span style="color: black; font-weight: bold;"&gt;while&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;read&lt;/span&gt; line&lt;span style="color: black;"&gt;;&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;do&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;echo&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"$line"&lt;/span&gt; | &lt;span style="color: #010181;"&gt;$COLORIZE_CMD&lt;/span&gt; &lt;span style="color: black;"&gt;;&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;done&lt;/span&gt;&lt;br /&gt;        ERRORS&lt;span style="color: black;"&gt;=&lt;/span&gt;&lt;span style="color: #010181;"&gt;${PIPESTATUS[0]}&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0057ae;"&gt;cd&lt;/span&gt; ..&lt;br /&gt;        &lt;span style="color: black; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;test&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"x$ERRORS"&lt;/span&gt; &lt;span style="color: black;"&gt;==&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"x0"&lt;/span&gt;&lt;span style="color: black;"&gt;;&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;then&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: #0057ae;"&gt;echo&lt;/span&gt; &lt;span style="color: black;"&gt;-&lt;/span&gt;e &lt;span style="color: #bf0303;"&gt;"&lt;/span&gt;&lt;span style="color: magenta;"&gt;\n&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;Suite $suitename completed without errors&lt;/span&gt;&lt;span style="color: magenta;"&gt;\n&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: black; font-weight: bold;"&gt;else&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: #0057ae;"&gt;echo&lt;/span&gt; &lt;span style="color: black;"&gt;-&lt;/span&gt;e &lt;span style="color: #bf0303;"&gt;"Suite $suitename finished with errors!&lt;/span&gt;&lt;span style="color: magenta;"&gt;\n&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: #0057ae;"&gt;exit&lt;/span&gt; &lt;span style="color: #010181;"&gt;$ERRORS&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: black; font-weight: bold;"&gt;fi&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;buildProject &lt;span style="color: #010181;"&gt;$MAIN_PROJECT&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"all install"&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;for&lt;/span&gt; project &lt;span style="color: black; font-weight: bold;"&gt;in&lt;/span&gt; &lt;span style="color: #010181;"&gt;$PROJECTS&lt;/span&gt;&lt;span style="color: black;"&gt;;&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;do&lt;/span&gt;&lt;br /&gt;        buildProject &lt;span style="color: #010181;"&gt;$project&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"clean all"&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"LIBS+=-L../${COMPILE_BUILD_PREFIX}$MAIN_PROJECT"&lt;/span&gt; &lt;br /&gt;        runTests &lt;span style="color: #010181;"&gt;$project&lt;/span&gt; $@&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;done&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Come al solito, i sorgenti per questa puntata sono disponibili &lt;a href="https://github.com/rockman81/DemoProjects/tree/1accdc4a19c9da74efbe7e5bc7561d99bae2320e/DownloadManager" target="_blank"&gt;sul mio account github&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Nella prossima puntata ci occuperemo invece di refactoring e ottimizzazioni del codice vero e proprio.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8003298816604397919-5074855692082425515?l=rockman81.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rockman81.blogspot.com/feeds/5074855692082425515/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8003298816604397919&amp;postID=5074855692082425515' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/5074855692082425515'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/5074855692082425515'/><link rel='alternate' type='text/html' href='http://rockman81.blogspot.com/2012/01/test-driven-development-c-e-qt.html' title='Test Driven Development, C++ e Qt: ottimizzazioni layout progetti'/><author><name>Marco Gulino</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-5TKjBFH5Ob4/AAAAAAAAAAI/AAAAAAAACNU/m2QmMz40phI/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8003298816604397919.post-8428928307071722039</id><published>2012-01-06T15:50:00.000+01:00</published><updated>2012-01-09T18:40:45.158+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test Driven Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Informatica'/><category scheme='http://www.blogger.com/atom/ns#' term='Object Oriented Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Extreme Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Tests'/><category scheme='http://www.blogger.com/atom/ns#' term='Programmazione'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='Qt'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><category scheme='http://www.blogger.com/atom/ns#' term='Design'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Test Driven Development, C++ e Qt: primi passi (e test)</title><content type='html'>Dopo aver creato la struttura del progetto nella &lt;a href="http://rockman81.blogspot.com/2011/12/test-driven-development-c-e-qt-setup-e.html" target="_blank"&gt;prima parte&lt;/a&gt;, cominciamo adesso ad implementare l'applicazione.&lt;br /&gt;Guardiamo l'&lt;a href="http://doc.qt.nokia.com/latest/network-downloadmanager-main-cpp.html" target="_blank"&gt;esempio di Qt&lt;/a&gt; da cui stiamo prendendo spunto: il main prende in ingresso la lista di downloads (usando QCoreApplication, che li converte automaticamente in una comoda QStringList), e, &lt;i&gt;se la lista è vuota stampa le informazioni di utilizzo, uscendo.&lt;/i&gt;&lt;br /&gt;Potremmo andare avanti ad analizzare le successive funzionalità, certo l'applicazione non si limita a far questo, ma il tdd ci impone di creare un primo test (che inizialmente fallisce), ed implementare la funzionalità facendo passare il test prima di procedere troppo oltre. In una applicazione così semplice, è meglio semplificare anche l'approccio evitando di pensar troppo al futuro.&lt;br /&gt;L'esempio mette il messaggio di errore nel main. Così facendo però non potremmo testarlo. D'altro canto è proprio il main che costruisce la lista di argomenti. Un buon compromesso quindi è di creare un metodo &lt;i&gt;download(const QStringList &amp;amp;arguments)*&lt;/i&gt;&amp;nbsp;nella classe&amp;nbsp;&lt;span class="Apple-style-span" style="color: purple; font-family: monospace; white-space: pre;"&gt;DownloadManagerCore &lt;/span&gt;che come risultato stampi le informazioni di utilizzo, usando gli argomenti creati da QCoreApplication.&lt;br /&gt;Può inoltre aiutare molto far estendere &lt;i&gt;QObject&lt;/i&gt;&amp;nbsp;alla classe &lt;i&gt;DownloadManagerCore&lt;/i&gt;; in questo modo si ottimizza la memoria (c++ non ha garbage collector, però ogni classe che estende QObject verrà automaticamente distrutta quando viene distrutta la classe parent) e si migliora l'iterazione con le classi che &amp;nbsp;verranno usate, le quali saranno infatti a loro volta derivate da &lt;i&gt;QObject&lt;/i&gt;.&lt;br /&gt;Nel main.cpp invocheremo QCoreApplication per estrarre gli argomenti, e invocheremo &lt;i&gt;DownloadManagerCore::download(arguments)&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;Proviamo quindi a scrivere il primo test. In particolare asseriremo che il metodo download stamperà su standard output (o meglio, su un output stream testabile), se la lista degli argomenti è vuota, la seguente stringa:&lt;br /&gt;&lt;blockquote class="tr_bq"&gt;&lt;span class="Apple-style-span" style="background-color: white; color: blue; font-size: 12px; line-height: 14px;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Usage: downloadmanager url1 [url2... urlN]&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;blockquote class="tr_bq"&gt;&lt;span class="Apple-style-span" style="background-color: white; font-size: 12px; line-height: 14px;"&gt;&lt;span class="st0" style="color: blue; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Downloads the URLs passed in the command-line to the local directory.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="background-color: white; color: blue; font-size: 12px; line-height: 14px;"&gt;If the target file already exists, a .0, .1, .2, etc. is appended to d&lt;/span&gt;&lt;span class="Apple-style-span" style="background-color: white; font-size: 12px; line-height: 14px;"&gt;&lt;span class="st0" style="color: blue; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;i&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="background-color: white; color: blue; font-size: 12px; line-height: 14px;"&gt;fferentiate.&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;br /&gt;Creiamo quindi il test case&amp;nbsp;itShouldPrintHelpMessageWithNoArguments.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #e0eaee; color: black; font-family: 'Courier New'; font-size: 10pt;"&gt;&lt;span style="color: #0057ae;"&gt;&lt;span style="color: #0057ae;"&gt;void&lt;/span&gt; DownloadManagerCoreTest&lt;span style="color: black;"&gt;::&lt;/span&gt;&lt;span style="color: #010181;"&gt;itShouldPrintHelpMessageWithNoArguments&lt;/span&gt;&lt;span style="color: black;"&gt;()&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black;"&gt;{&lt;/span&gt;&lt;br /&gt;    QString output&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;    QTextStream &lt;span style="color: #010181;"&gt;outputStream&lt;/span&gt;&lt;span style="color: black;"&gt;(&amp;amp;&lt;/span&gt;output&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;    DownloadManagerCore &lt;span style="color: black;"&gt;*&lt;/span&gt;lib &lt;span style="color: black;"&gt;=&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;new&lt;/span&gt; &lt;span style="color: #010181;"&gt;DownloadManagerCore&lt;/span&gt;&lt;span style="color: black;"&gt;(&amp;amp;&lt;/span&gt;outputStream, this&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;    lib&lt;span style="color: black;"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color: #010181;"&gt;start&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #010181;"&gt;QStringList&lt;/span&gt;&lt;span style="color: black;"&gt;());&lt;/span&gt;&lt;br /&gt;    QString &lt;span style="color: #010181;"&gt;expected&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"Usage: downloadmanager url1 [url2... urlN]&lt;/span&gt;&lt;span style="color: magenta;"&gt;\n&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"&lt;/span&gt;&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;    expected&lt;span style="color: black;"&gt;.&lt;/span&gt;&lt;span style="color: #010181;"&gt;append&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"Downloads the URLs passed in the command-line to the local directory."&lt;/span&gt;&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;    expected&lt;span style="color: black;"&gt;.&lt;/span&gt;&lt;span style="color: #010181;"&gt;append&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;" If the target file already exists, a .0, .1, .2, etc. is appended to differentiate.\n"&lt;/span&gt;&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #010181;"&gt;QCOMPARE&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;output&lt;span style="color: black;"&gt;,&lt;/span&gt; expected&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;Al di là della funzionalità, di per se banale, notiamo un po' di cose importanti su come il test stia definendo in maniera molto precisa il design della classe:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Abbiamo bisogno di testare l'output. È quindi da evitare che la classe stampi direttamente l'output su schermo. Definiamo invece un costruttore che prende in ingresso un puntatore a&amp;nbsp;&lt;span style="background-color: #e0eaee; color: #0057ae; font-family: 'Courier New'; font-size: 10pt;"&gt;QTextStream&lt;/span&gt;&amp;nbsp;e facciamo delle asserzioni su quello. Lo stream di test, in particolare, sarà uno stream che scrive su una stringa anzichè su stdout.&lt;/li&gt;&lt;li&gt;Abbiamo anche bisogno di una entry point che riceva in ingresso gli argomenti. Definiamo quindi il metodo "start" nella classe DownloadManagerCore, il cui header diventerà quindi questo:&lt;/li&gt;&lt;/ul&gt;&lt;pre style="background-color: #e0eaee; color: black; font-family: 'Courier New'; font-size: 10pt;"&gt;&lt;span style="color: #008200;"&gt;#ifndef DOWNLOADMANAGERCORE_H&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008200;"&gt;#define DOWNLOADMANAGERCORE_H&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008200;"&gt;#include &amp;lt;QObject&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;class&lt;/span&gt; QTextStream&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;class&lt;/span&gt; DownloadManagerCore &lt;span style="color: black;"&gt;:&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;public&lt;/span&gt; QObject &lt;span style="color: black;"&gt;{&lt;/span&gt;&lt;br /&gt;    Q_OBJECT&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;public&lt;/span&gt;&lt;span style="color: black;"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #010181;"&gt;DownloadManagerCore&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;QTextStream &lt;span style="color: black;"&gt;*&lt;/span&gt;output&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0057ae;"&gt;void&lt;/span&gt; &lt;span style="color: #010181;"&gt;start&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #0057ae;"&gt;const&lt;/span&gt; QStringList &lt;span style="color: black;"&gt;&amp;amp;&lt;/span&gt;arguments&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;private&lt;/span&gt;&lt;span style="color: black;"&gt;:&lt;/span&gt;&lt;br /&gt;    QTextStream &lt;span style="color: black;"&gt;*&lt;/span&gt;output&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black;"&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #008200;"&gt;#endif&lt;/span&gt; &lt;span style="color: #838183; font-style: italic;"&gt;// DOWNLOADMANAGERCORE_H&lt;/span&gt;&lt;span style="color: #008200;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Ho anche fatto estendere QObject a QDownloadManagerCore, in questo modo si potrà usare il meccanismo di auto-delete di Qt: se le classi del nostro progetto estendono QObject, e si assegna loro una classe "parent", le classi saranno automaticamente cancellate quando sarà cancellata la loro classe parent, senza nessun bisogno di cancellarle manualmente. In questo modo è possibile ridurre al minimo i rischi di memory leak, potendo assegnare alle classi uno scope ben preciso. &lt;a href="http://developer.qt.nokia.com/doc/qt-4.8/QObject.html#details" target="_blank"&gt;Maggiori dettagli qui&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Naturalmente il nostro test non può ancora passare: abbiamo definito l'interfaccia della nostra classe, ma non l'implementazione.&lt;br /&gt;Per avere un primo test verde basta usare lo stream per stampare in output l'help message, senza preoccuparci degli argomenti, dato che per il momento nessun test ne verifica l'utilizzo.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #e0eaee; color: black; font-family: 'Courier New'; font-size: 10pt;"&gt;&lt;span style="color: #008200;"&gt;#include&lt;/span&gt; &lt;span style="color: #818100;"&gt;"downloadmanagercore.h"&lt;/span&gt;&lt;span style="color: #008200;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008200;"&gt;#include &amp;lt;QTextStream&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;DownloadManagerCore&lt;span style="color: black;"&gt;::&lt;/span&gt;&lt;span style="color: #010181;"&gt;DownloadManagerCore&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;QTextStream &lt;span style="color: black;"&gt;*&lt;/span&gt;output&lt;span style="color: black;"&gt;,&lt;/span&gt; QObject &lt;span style="color: black;"&gt;*&lt;/span&gt;parent&lt;span style="color: black;"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: black;"&gt;:&lt;/span&gt; &lt;span style="color: #010181;"&gt;QObject&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;parent&lt;span style="color: black;"&gt;),&lt;/span&gt; &lt;span style="color: #010181;"&gt;output&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;output&lt;span style="color: black;"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0057ae;"&gt;void&lt;/span&gt; DownloadManagerCore&lt;span style="color: black;"&gt;::&lt;/span&gt;&lt;span style="color: #010181;"&gt;start&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #0057ae;"&gt;const&lt;/span&gt; QStringList &lt;span style="color: black;"&gt;&amp;amp;&lt;/span&gt;arguments&lt;span style="color: black;"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black;"&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: black;"&gt;*&lt;/span&gt;output &lt;span style="color: black;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"Usage: downloadmanager url1 [url2... urlN]"&lt;/span&gt; &lt;span style="color: black;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: black;"&gt;*&lt;/span&gt;output &lt;span style="color: black;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"Downloads the URLs passed in the command-line to the local directory."&lt;/span&gt;&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: black;"&gt;*&lt;/span&gt;output &lt;span style="color: black;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;" If the target file already exists, a .0, .1, .2, etc. is appended to differentiate."&lt;/span&gt; &lt;span style="color: black;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;E finalmente, barra verde!&lt;br /&gt;&lt;br /&gt;&lt;div class="cczediv"&gt;&lt;span class="ccze_default"&gt;*********&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_good"&gt;Start&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;testing&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;of&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_bad"&gt;DownloadManagerCoreTest&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;*********&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="ccze_default"&gt;Config&lt;/span&gt;&lt;span class="ccze_default"&gt;:&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;Using&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;QTest&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;library&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_version"&gt;4.7.4&lt;/span&gt;&lt;span class="ccze_default"&gt;,&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;Qt&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_version"&gt;4.7.4&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="ccze_default"&gt;PASS&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;:&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_bad"&gt;DownloadManagerCoreTest::initTestCase(&lt;/span&gt;&lt;span class="ccze_default"&gt;)&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="ccze_default"&gt;PASS&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;:&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_bad"&gt;DownloadManagerCoreTest::itShouldLinkToStaticLibrary(&lt;/span&gt;&lt;span class="ccze_default"&gt;)&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="ccze_default"&gt;PASS&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;:&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_bad"&gt;DownloadManagerCoreTest::itShouldPrintHelpMessageWithNoArguments(&lt;/span&gt;&lt;span class="ccze_default"&gt;)&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="ccze_default"&gt;PASS&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;:&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_bad"&gt;DownloadManagerCoreTest::cleanupTestCase(&lt;/span&gt;&lt;span class="ccze_default"&gt;)&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="ccze_default"&gt;Totals&lt;/span&gt;&lt;span class="ccze_default"&gt;:&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_numbers"&gt;4&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;passed&lt;/span&gt;&lt;span class="ccze_default"&gt;,&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_numbers"&gt;0&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_error"&gt;failed&lt;/span&gt;&lt;span class="ccze_default"&gt;,&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_numbers"&gt;0&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_bad"&gt;skipped&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="ccze_default"&gt;*********&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_good"&gt;Finished&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;testing&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;of&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_bad"&gt;DownloadManagerCoreTest&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="ccze_default"&gt;*********&lt;/span&gt;&lt;span class="ccze_default"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;La prossima volta vedremo di ottimizzare il nostro codice prima di aggiungere nuove funzionalità: refactoring, ma anche migliorie del layout del progetto e ottimizzazioni varie.&lt;br /&gt;&lt;a href="https://github.com/rockman81/DemoProjects/tree/0d25df0a7dfbcc15568027f480ce2f09c88b5713" target="_blank"&gt;Qui il codice sorgente&lt;/a&gt; per questa puntata.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote class="tr_bq"&gt;&lt;i&gt;* la sintassi "const QString &amp;amp;arg" o "const QStringList &amp;amp;arg"&amp;nbsp;è del tutto equivalente a specificare "QString arg". In genere però è molto meglio specificare il "const" e la "&amp;amp;", per ottimizzare le chiamate. In questo modo infatti i parametri saranno immutabili e passati esplicitamente per riferimento, anzichè ricopiate nel metodo, (occupando quindi più memoria e tempo cpu). Sono piccoli accorgimenti da memorizzare ed usare con costanza, che possono però migliorare di molto le prestazioni del proprio codice.&lt;/i&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8003298816604397919-8428928307071722039?l=rockman81.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rockman81.blogspot.com/feeds/8428928307071722039/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8003298816604397919&amp;postID=8428928307071722039' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/8428928307071722039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/8428928307071722039'/><link rel='alternate' type='text/html' href='http://rockman81.blogspot.com/2011/12/test-driven-development-c-e-qt-primi.html' title='Test Driven Development, C++ e Qt: primi passi (e test)'/><author><name>Marco Gulino</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-5TKjBFH5Ob4/AAAAAAAAAAI/AAAAAAAACNU/m2QmMz40phI/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8003298816604397919.post-3084336960330547981</id><published>2011-12-11T20:17:00.001+01:00</published><updated>2012-01-06T17:57:41.289+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test Driven Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Informatica'/><category scheme='http://www.blogger.com/atom/ns#' term='Extreme Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Tests'/><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Programmazione'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='Qt'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Test Driven Development, C++ e Qt: setup e layout progetto</title><content type='html'>I metodi agili cominciano a prendere piede anche in italia, e con essi quello che è probabilmente il loro più conosciuto cavallo di battaglia: il TDD, ossia &lt;a href="http://it.wikipedia.org/wiki/Test_Driven_Development" target="_blank"&gt;Test Driven Development&lt;/a&gt;. Uno dei linguaggi in cui il TDD viene più spesso è applicato è java: non solo perchè è uno dei più diffusi, ma probabilmente perchè offre allo sviluppatore degli strumenti veramente potenti: da JUnit, scritto proprio da &lt;a href="http://it.wikipedia.org/wiki/Kent_Beck" target="_blank"&gt;Kent Beck&lt;/a&gt;, ad Eclipse, che oltre ad integrare un perfetto supporto a JUnit offre anche dei potentissimi strumenti per il refactoring, che è parte integrante di questa tecnica.&lt;br /&gt;Ma per quanto riguarda altri linguaggi, come il vetusto ma sempre attuale C++? Come si può conciliare la "dinamicità" di un processo come il TDD alla macchinosità di un linguaggio che prevede costante sincronizzazione header-implementazione, build system non sempre amichevoli e pochissimi tool di refactoring?&lt;br /&gt;In questa guida cercherò di offrire uno dei possibili approcci. Dovendo scegliere un IDE e un toolkit ho optato per &lt;a href="http://qt.nokia.com/" target="_blank"&gt;Qt di Nokia&lt;/a&gt; (originariamente di Trolltech) e il suo IDE Qt Creator.&lt;br /&gt;Ovviamente ognuno avrà le sue preferenze, il mondo del C++ è fin troppo ricco. Per quanto mi riguarda, da utente e sviluppatore &lt;a href="http://www.kde.org/" target="_blank"&gt;KDE&lt;/a&gt;, conosco Qt da molti anni, lo trovo piuttosto semplice e intuitivo, e altrettanto può dirsi di Qt Creator, sicuramente non un IDE potente e pieno di strumenti come Eclipse, ma che ha dalla sua una notevole leggerezza, nonchè l'essere studiato proprio per Qt.&lt;br /&gt;Qt offre un ambiente molto omogeneo, includendo anche un modulo per i test unitari. Sicuramente ci sono framework di testi anche migliori, ma per continuare sulla via della semplicità ho preferito usare &lt;a href="http://doc.qt.nokia.com/4.7/qtestlib-manual.html" target="_blank"&gt;QTest&lt;/a&gt;. Ha anche il non indifferente vantaggio di essere orientato al cross platform, il che vuol dire che un'applicazione o libreria creata con Qt girerà sui principali sistemi operativi (Windows, Mac, Linux) senza modificare (o quasi) il codice, ma solo ricompilando per i sistemi desiderati.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Disclaimer: non oso definirmi nè un esperto di C++ nè tantomeno di Qt. Ho imparato entrambi amatorialmente, e sono un po' arrugginito dai molti anni lavorativi in cui ho utilizzato quasi esclusivamente Java.&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;Come progetto di esempio prenderò spunto dal &lt;a href="http://doc.qt.nokia.com/4.7/network-downloadmanager.html" target="_blank"&gt;Download Manager&lt;/a&gt; presente nella documentazione di Qt. Si tratta di un eseguibile da riga di comando, senza GUI, anche molto semplice da realizzare.&lt;br /&gt;&lt;br /&gt;Andiamo a creare il layout del nostro progetto.&lt;br /&gt;Da QtCreator sceglieremo l'opzione "New Project", scegliendo tra i vari template disponibili "Qt C++ Project &amp;lt;&amp;lt; Qt Console Application". Lo chiameremo "&lt;b&gt;DownloadManager&lt;/b&gt;", e lo creeremo nella directory "$HOME/qt".&lt;br /&gt;Il progetto verrà a trovarsi quindi in "DownloadManager", avrà un main pressochè vuoto.&lt;br /&gt;&lt;br /&gt;Adesso cominciamo a creare le prime classi? &lt;b&gt;Sbagliato&lt;/b&gt;. In realtà il progetto "&lt;i&gt;DownloadManager&lt;/i&gt;" è praticamente già finito. Tutto il nostro codice andrà invece in una &lt;b&gt;libreria statica&lt;/b&gt;: questo perchè dovrà essere accessibile anche dai test. Una libreria statica è molto diversa da una dinamica: essa non verrà infatti "esportata" come una dipendenza, ma viene inglobata dall'eseguibile, avendo però il vantaggio di poter condividere le proprie classi anche con i test che creeremo.&lt;br /&gt;Quindi, nuovo progetto, con tipo "Other Project &amp;lt;&amp;lt; C++ Library". Scegliamo nel wizard "Statically Linked Library", assegnamo come nome "&lt;b&gt;DownloadManagerCore&lt;/b&gt;" e lo creiamo sempre nella posizione "$HOME/qt". Nella pagina successiva scegliamo di aggiungere i moduli "QtCore" e "QtNetwork". Il wizard creerà anche una classe principale (che potremo usare come un main) DownloadManagerCore.&lt;br /&gt;&lt;br /&gt;Adesso è ora di creare il progetto (o come vedremo, i progetti) per i test, cominciando dagli unit: sempre dal menù nuovo progetto, scegliamo nuovamente "Other Project &amp;lt;&amp;lt; Qt Console Application", con nome "&lt;b&gt;UnitTests&lt;/b&gt;" e solita posizione, "$HOME/qt". Nel file UnitTests.pro creato dal wizard cambiamo la riga&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="color: purple;"&gt;   QT&lt;/span&gt;&lt;span style="color: silver;"&gt;       &lt;/span&gt;+=&lt;span style="color: silver;"&gt; &lt;/span&gt;core&lt;/pre&gt;in&lt;br /&gt;&lt;pre&gt;&lt;span style="color: purple;"&gt;   QT&lt;/span&gt;&lt;span style="color: silver;"&gt;       &lt;/span&gt;+=&lt;span style="color: silver;"&gt; &lt;/span&gt;core testlib&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;br /&gt;Col tasto destro sul progetto selezioniamo "Add New...", quindi scegliamo "C++ Class".&lt;br /&gt;Diamo nome alla classe: "&lt;b&gt;DownloadManagerCoreTest&lt;/b&gt;", base class "QObject".&lt;br /&gt;Modifichiamo lo header creando un primo test come private slot:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #e0eaee; color: black; font-family: 'Courier New'; font-size: 10pt;"&gt;&lt;span style="color: #008200;"&gt;#ifndef DOWNLOADMANAGERCORETEST_H&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008200;"&gt;#define DOWNLOADMANAGERCORETEST_H&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #008200;"&gt;#include &amp;lt;QObject&amp;gt;&lt;qobject&gt;&lt;/qobject&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;class&lt;/span&gt; DownloadManagerCoreTest &lt;span style="color: black;"&gt;:&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;public&lt;/span&gt; QObject&lt;br /&gt;&lt;span style="color: black;"&gt;{&lt;/span&gt;&lt;br /&gt;    Q_OBJECT&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;public&lt;/span&gt;&lt;span style="color: black;"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: black; font-weight: bold;"&gt;explicit&lt;/span&gt; &lt;span style="color: #010181;"&gt;DownloadManagerCoreTest&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;QObject &lt;span style="color: black;"&gt;*&lt;/span&gt;parent &lt;span style="color: black;"&gt;=&lt;/span&gt; &lt;span style="color: #b07e00;"&gt;0&lt;/span&gt;&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;private&lt;/span&gt; slots&lt;span style="color: black;"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0057ae;"&gt;void&lt;/span&gt; &lt;span style="color: #010181;"&gt;itShouldLinkToStaticLibrary&lt;/span&gt;&lt;span style="color: black;"&gt;();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: black;"&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #008200;"&gt;#endif&lt;/span&gt; &lt;span style="color: #838183; font-style: italic;"&gt;// DOWNLOADMANAGERCORETEST_H&lt;/span&gt;&lt;span style="color: #008200;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;e anche la sua implementazione:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #e0eaee; color: black; font-family: 'Courier New'; font-size: 10pt;"&gt;&lt;span style="color: #008200;"&gt;#include &amp;lt;QTest&amp;gt;&lt;qtest&gt;&lt;/qtest&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #008200;"&gt;#include&lt;/span&gt; &lt;span style="color: #818100;"&gt;"downloadmanagercoretest.h"&lt;/span&gt;&lt;span style="color: #008200;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008200;"&gt;#include&lt;/span&gt; &lt;span style="color: #818100;"&gt;"../DownloadManagerCore/downloadmanagercore.h"&lt;/span&gt;&lt;span style="color: #008200;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;DownloadManagerCoreTest&lt;span style="color: black;"&gt;::&lt;/span&gt;&lt;span style="color: #010181;"&gt;DownloadManagerCoreTest&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;QObject &lt;span style="color: black;"&gt;*&lt;/span&gt;parent&lt;span style="color: black;"&gt;) :&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #010181;"&gt;QObject&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;parent&lt;span style="color: black;"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0057ae;"&gt;void&lt;/span&gt; DownloadManagerCoreTest&lt;span style="color: black;"&gt;::&lt;/span&gt;&lt;span style="color: #010181;"&gt;itShouldLinkToStaticLibrary&lt;/span&gt;&lt;span style="color: black;"&gt;() {&lt;/span&gt;&lt;br /&gt;    DownloadManagerCore &lt;span style="color: black;"&gt;*&lt;/span&gt;lib &lt;span style="color: black;"&gt;=&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;new&lt;/span&gt; &lt;span style="color: #010181;"&gt;DownloadManagerCore&lt;/span&gt;&lt;span style="color: black;"&gt;();&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #010181;"&gt;QVERIFY2&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;lib &lt;span style="color: black;"&gt;!=&lt;/span&gt; NULL&lt;span style="color: black;"&gt;,&lt;/span&gt; &lt;span style="color: #bf0303;"&gt;"Library should not be null"&lt;/span&gt;&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;QVERIFY è una semplice asserzione che verifica il valore booleano passato come parametro.&lt;br /&gt;QVERIFY2 aggiunge la possibilità di specificare un messaggio.&lt;br /&gt;Questi sono un po' i "mattoncini base" per le asserzioni; ne esistono altre, ed è anche possibile implementarne di personalizzate.&lt;br /&gt;Modificare anche il &lt;i&gt;main.cpp&lt;/i&gt; come segue:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #e0eaee; color: black; font-family: 'Courier New'; font-size: 10pt;"&gt;&lt;span style="color: #008200;"&gt;#include &amp;lt;QtCore/QString&amp;gt;&lt;qtcore qstring=""&gt;&lt;/qtcore&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008200;"&gt;#include &amp;lt;QtTest/QTest&amp;gt;&lt;qttest qttest=""&gt;&lt;/qttest&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008200;"&gt;#include &amp;lt;QList&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #008200;"&gt;#include&lt;/span&gt; &lt;span style="color: #818100;"&gt;"downloadmanagercoretest.h"&lt;/span&gt;&lt;span style="color: #008200;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;class&lt;/span&gt; UnitTests &lt;span style="color: black;"&gt;:&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;public&lt;/span&gt; QObject&lt;br /&gt;&lt;span style="color: black;"&gt;{&lt;/span&gt;&lt;br /&gt;    Q_OBJECT&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;private&lt;/span&gt;&lt;span style="color: black;"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; argc&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0057ae;"&gt;char&lt;/span&gt; &lt;span style="color: black;"&gt;**&lt;/span&gt;argv&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;public&lt;/span&gt;&lt;span style="color: black;"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #010181;"&gt;UnitTests&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; argc&lt;span style="color: black;"&gt;,&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;char&lt;/span&gt; &lt;span style="color: black;"&gt;*&lt;/span&gt;argv&lt;span style="color: black;"&gt;[]);&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; &lt;span style="color: #010181;"&gt;runAll&lt;/span&gt;&lt;span style="color: black;"&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;private&lt;/span&gt;&lt;span style="color: black;"&gt;:&lt;/span&gt;&lt;br /&gt;    QList&lt;span style="color: black;"&gt;&amp;lt;&lt;/span&gt;QObject&lt;span style="color: black;"&gt;*&amp;gt;&lt;/span&gt; tests&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black;"&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;UnitTests&lt;span style="color: black;"&gt;::&lt;/span&gt;&lt;span style="color: #010181;"&gt;UnitTests&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; argc&lt;span style="color: black;"&gt;,&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;char&lt;/span&gt; &lt;span style="color: black;"&gt;*&lt;/span&gt;argv&lt;span style="color: black;"&gt;[])&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: black;"&gt;:&lt;/span&gt; &lt;span style="color: #010181;"&gt;argc&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;argc&lt;span style="color: black;"&gt;),&lt;/span&gt; &lt;span style="color: #010181;"&gt;argv&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;argv&lt;span style="color: black;"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black;"&gt;{&lt;/span&gt;&lt;br /&gt;    tests &lt;span style="color: black;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;new&lt;/span&gt; &lt;span style="color: #010181;"&gt;DownloadManagerCoreTest&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: black; font-weight: bold;"&gt;this&lt;/span&gt;&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; UnitTests&lt;span style="color: black;"&gt;::&lt;/span&gt;&lt;span style="color: #010181;"&gt;runAll&lt;/span&gt;&lt;span style="color: black;"&gt;() {&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; testResults&lt;span style="color: black;"&gt;=&lt;/span&gt;&lt;span style="color: #b07e00;"&gt;0&lt;/span&gt;&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #010181;"&gt;foreach&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;QObject &lt;span style="color: black;"&gt;*&lt;/span&gt;currentTest&lt;span style="color: black;"&gt;,&lt;/span&gt; tests&lt;span style="color: black;"&gt;) {&lt;/span&gt;&lt;br /&gt;        testResults &lt;span style="color: black;"&gt;+=&lt;/span&gt; QTest&lt;span style="color: black;"&gt;::&lt;/span&gt;&lt;span style="color: #010181;"&gt;qExec&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;currentTest&lt;span style="color: black;"&gt;,&lt;/span&gt; argc&lt;span style="color: black;"&gt;,&lt;/span&gt; argv&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: black; font-weight: bold;"&gt;return&lt;/span&gt; testResults&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; &lt;span style="color: #010181;"&gt;main&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; argc&lt;span style="color: black;"&gt;,&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;char&lt;/span&gt; &lt;span style="color: black;"&gt;*&lt;/span&gt;argv&lt;span style="color: black;"&gt;[])&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black;"&gt;{&lt;/span&gt;&lt;br /&gt;    UnitTests &lt;span style="color: #010181;"&gt;testSuite&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;argc&lt;span style="color: black;"&gt;,&lt;/span&gt; argv&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: black; font-weight: bold;"&gt;return&lt;/span&gt; testSuite&lt;span style="color: black;"&gt;.&lt;/span&gt;&lt;span style="color: #010181;"&gt;runAll&lt;/span&gt;&lt;span style="color: black;"&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #008200;"&gt;#include&lt;/span&gt; &lt;span style="color: #818100;"&gt;"main.moc"&lt;/span&gt;&lt;span style="color: #008200;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Aggiungere nuovi test alla suite è semplice, basta creare dei metodi (void) come "private slots" nelle classi di test.&lt;br /&gt;Se vorremo aggiungere nuove classi di test alla test suite, basterà invece creare nuove classi del tutto simili a DownloadManagerCoreTest: molto semplicemente devono estendere QObject e tutti i metodi dichiarati "&lt;i&gt;private slot&lt;/i&gt;" verranno automaticamente&amp;nbsp;usati come test case.&lt;br /&gt;Si deve poi includere lo header corretto nel main.cpp ed aggiungere una riga uguale all'esistente nel costruttore di UnitTests per aggiungere la classe di test alla suite.&lt;br /&gt;Infine, le altre suite di&amp;nbsp;test, come gli integration test e gli acceptance test, possono essere creati esattamente nello stesso modo del progetto UnitTests.&lt;br /&gt;&lt;br /&gt;Ma che succede se proviamo ad eseguire il nostro primo test unitario?&lt;br /&gt;Non compila nulla.. o per meglio dire, il link fallisce: questo perchè il nostro progetto di test non "vede" ancora il progetto contenente la classe "DownloadManagerCore". Come Fare?&lt;br /&gt;Beh, basta aprire nuovamente il file "UnitTests.pro" ed aggiungere alla fine del file la riga&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="color: purple;"&gt;   LIBS&lt;/span&gt;&lt;span style="color: silver;"&gt; &lt;/span&gt;+=&lt;span style="color: silver;"&gt; &lt;/span&gt;-L../DownloadManagerCore-build-desktop/&lt;span style="color: silver;"&gt; &lt;/span&gt;-lDownloadManagerCore&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Visto che anche l'applicazione "DownloadManager" richiederà la libreria può essere utile aggiungere questa riga anche nel suo file .pro.&lt;br /&gt;Può anche essere utile andare nel tab "Projects" di Qt Creator, e nei progetti "DownloadManager" e "UnitTests" selezionare come dipendenza (tab Dependencies) il progetto "DownloadManagerCore".&lt;br /&gt;&lt;br /&gt;Adesso basta compilare il tutto per avere la suite di test funzionante:&lt;br /&gt;&lt;div style="background-color: #a2dba6;"&gt;&lt;blockquote class="tr_bq"&gt;&lt;blockquote class="tr_bq"&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;********* Start testing of DownloadManagerCoreTest *********&lt;/span&gt;&lt;/blockquote&gt;&lt;blockquote class="tr_bq"&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;Config: Using QTest library 4.7.4, Qt 4.7.4&lt;/span&gt;&lt;/blockquote&gt;&lt;blockquote class="tr_bq"&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;PASS &amp;nbsp; : DownloadManagerCoreTest::initTestCase()&lt;/span&gt;&amp;nbsp;&lt;/blockquote&gt;&lt;/blockquote&gt;&lt;blockquote class="tr_bq"&gt;&lt;blockquote class="tr_bq"&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;PASS &amp;nbsp; : DownloadManagerCoreTest::itShouldLinkToStaticLibrary()&lt;/span&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;&lt;blockquote class="tr_bq"&gt;&lt;blockquote class="tr_bq"&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;PASS &amp;nbsp; : DownloadManagerCoreTest::cleanupTestCase()&lt;/span&gt;&lt;/blockquote&gt;&lt;blockquote class="tr_bq"&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;Totals: 3 passed, 0 failed, 0 skipped&lt;/span&gt;&lt;/blockquote&gt;&lt;blockquote class="tr_bq"&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;********* Finished testing of DownloadManagerCoreTest *********&lt;/span&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;&lt;/div&gt;Alla prossima puntata!&lt;br /&gt;&lt;br /&gt;p.s.: i sorgenti per questa versione del progetto potete trovarmi &lt;a href="https://github.com/rockman81/DemoProjects/tree/6adffa826c2830fc1300c345a06efd2bc78c1f55/DownloadManager" target="_blank"&gt;sul mio account github&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8003298816604397919-3084336960330547981?l=rockman81.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rockman81.blogspot.com/feeds/3084336960330547981/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8003298816604397919&amp;postID=3084336960330547981' title='1 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/3084336960330547981'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/3084336960330547981'/><link rel='alternate' type='text/html' href='http://rockman81.blogspot.com/2011/12/test-driven-development-c-e-qt-setup-e.html' title='Test Driven Development, C++ e Qt: setup e layout progetto'/><author><name>Marco Gulino</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-5TKjBFH5Ob4/AAAAAAAAAAI/AAAAAAAACNU/m2QmMz40phI/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8003298816604397919.post-6494577003705619143</id><published>2011-11-26T00:05:00.000+01:00</published><updated>2011-11-26T19:46:12.256+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Informatica'/><category scheme='http://www.blogger.com/atom/ns#' term='Object Oriented Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Programmazione'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><category scheme='http://www.blogger.com/atom/ns#' term='Design'/><title type='text'>Leggibilità: meglio fuori che dentro</title><content type='html'>Un argomento di cui recentemente si discute non poco nel nostro team è l'argomento leggibilità.&lt;br /&gt;Premesso che la leggibilità è sempre un soggetto altamente personale, ciò che per me può essere perfettamente leggibile può non esserlo per altri, la mia opinione è che, dovendo scegliere, è sempre meglio preferire la leggibilità &lt;b&gt;esterna&lt;/b&gt;&amp;nbsp;di una classe, piuttosto che quella interna.&lt;br /&gt;&lt;blockquote class="tr_bq"&gt;&lt;img src="http://a2.sphotos.ak.fbcdn.net/hphotos-ak-snc3/28863_112811985422463_110930122277316_81477_7563705_n.jpg" /&gt;&lt;br /&gt;"Meglio fuori che dentro, dico sempre io"&lt;/blockquote&gt;Difatti, in teoria (specie se si vuole rispettare&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Open/closed_principle" target="_blank"&gt;OCP&lt;/a&gt;), una classe dovrebbe essere modificata il meno possibile, e se scriviamo del buon design ben orientato agli oggetti è probabile che la classe stessa non sarà modificata mai, ma verranno solo aggiunte nuove implementazioni di interfacce a fronte di nuove funzionalità.&lt;br /&gt;La leggibilità interna ha quindi un valore abbastanza relativo, basta cioè che sia sufficientemente leggibile da rispettare principi come avere metodi corti e ben definiti, pochi (meglio niente) cicli for e if statement innestati in cascata (ma piuttosto estratti in metodi), &amp;nbsp;nessuna ambiguità su ingressi e uscite, meglio ancora se con un forte controllo sui tipi (per quanto in java i generics siano molto verbosi, preferisco usarli sempre e comunque quando servono, perchè offrono forti garanzie sulla correttezza dei tipi in uso).&lt;br /&gt;&lt;br /&gt;Un esempio concreto: la classe sottostante effettivamente ha una leggibilità interna sufficiente, ma non esaltante.&lt;br /&gt;Le classi inner e l'uso pesante di reflection (purtroppo inevitabile, dato lo scopo di questa classe) sicuramente confondono molto, e anche la gestione delle eccezioni ci mette il suo zampino.&lt;br /&gt;E' anche vero però che la classe principale ha un costruttore privato, e l'unico modo di istanziarla è usando l'unico metodo pubblico disponibile: il metodo "search(enumClass)". Da lì, navigando il codice seguendo lo stack delle chiamate, è possibile seguire il flusso senza perdersi troppo, dato che le biforcazioni non sono molte.&lt;br /&gt;Inoltre i metodi (così come le inner class) sono abbastanza compatti e focalizzati.&lt;br /&gt;Si riesce a capire cosa fa questa classe? (in basso la risposta...)&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #e0eaee; color: black; font-family: 'Courier New'; font-size: 10pt;"&gt;&lt;span style="color: black; font-weight: bold;"&gt;package&lt;/span&gt; com&lt;span style="color: black;"&gt;.&lt;/span&gt;gmail&lt;span style="color: black;"&gt;.&lt;/span&gt;gulino&lt;span style="color: black;"&gt;.&lt;/span&gt;marco&lt;span style="color: black;"&gt;.&lt;/span&gt;utils&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;import static&lt;/span&gt; com&lt;span style="color: black;"&gt;.&lt;/span&gt;google&lt;span style="color: black;"&gt;.&lt;/span&gt;common&lt;span style="color: black;"&gt;.&lt;/span&gt;collect&lt;span style="color: black;"&gt;.&lt;/span&gt;Iterables&lt;span style="color: black;"&gt;.&lt;/span&gt;find&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;import static&lt;/span&gt; com&lt;span style="color: black;"&gt;.&lt;/span&gt;google&lt;span style="color: black;"&gt;.&lt;/span&gt;common&lt;span style="color: black;"&gt;.&lt;/span&gt;collect&lt;span style="color: black;"&gt;.&lt;/span&gt;Lists&lt;span style="color: black;"&gt;.&lt;/span&gt;newArrayList&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;import&lt;/span&gt; java&lt;span style="color: black;"&gt;.&lt;/span&gt;lang&lt;span style="color: black;"&gt;.&lt;/span&gt;reflect&lt;span style="color: black;"&gt;.&lt;/span&gt;Field&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;import&lt;/span&gt; java&lt;span style="color: black;"&gt;.&lt;/span&gt;lang&lt;span style="color: black;"&gt;.&lt;/span&gt;reflect&lt;span style="color: black;"&gt;.&lt;/span&gt;Method&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;import&lt;/span&gt; java&lt;span style="color: black;"&gt;.&lt;/span&gt;util&lt;span style="color: black;"&gt;.&lt;/span&gt;List&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;import&lt;/span&gt; com&lt;span style="color: black;"&gt;.&lt;/span&gt;google&lt;span style="color: black;"&gt;.&lt;/span&gt;common&lt;span style="color: black;"&gt;.&lt;/span&gt;base&lt;span style="color: black;"&gt;.&lt;/span&gt;Predicate&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;@SuppressWarnings&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"unchecked"&lt;/span&gt;&lt;span style="color: black;"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;public class&lt;/span&gt; SmartEnums&lt;span style="color: black;"&gt;&amp;lt;&lt;/span&gt;EnumType &lt;span style="color: black; font-weight: bold;"&gt;extends&lt;/span&gt; Enum&lt;span style="color: black;"&gt;&amp;lt;&lt;/span&gt;EnumType&lt;span style="color: black;"&gt;&amp;gt;&amp;gt; {&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: black; font-weight: bold;"&gt;public static&lt;/span&gt; &lt;span style="color: black;"&gt;&amp;lt;&lt;/span&gt;EnumType &lt;span style="color: black; font-weight: bold;"&gt;extends&lt;/span&gt; Enum&lt;span style="color: black;"&gt;&amp;lt;&lt;/span&gt;EnumType&lt;span style="color: black;"&gt;&amp;gt;&amp;gt;&lt;/span&gt; SmartEnums&lt;span style="color: black;"&gt;&amp;lt;&lt;/span&gt;EnumType&lt;span style="color: black;"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #010181;"&gt;search&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;Class&lt;span style="color: black;"&gt;&amp;lt;&lt;/span&gt;EnumType&lt;span style="color: black;"&gt;&amp;gt;&lt;/span&gt; enumClass&lt;span style="color: black;"&gt;) {&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: black; font-weight: bold;"&gt;return new&lt;/span&gt; SmartEnums&lt;span style="color: black;"&gt;&amp;lt;&lt;/span&gt;EnumType&lt;span style="color: black;"&gt;&amp;gt;(&lt;/span&gt;enumClass&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: black; font-weight: bold;"&gt;private&lt;/span&gt; List&lt;span style="color: black;"&gt;&amp;lt;&lt;/span&gt;EnumType&lt;span style="color: black;"&gt;&amp;gt;&lt;/span&gt; allValues&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: black; font-weight: bold;"&gt;private&lt;/span&gt; &lt;span style="color: #010181;"&gt;SmartEnums&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;Class&lt;span style="color: black;"&gt;&amp;lt;&lt;/span&gt;EnumType&lt;span style="color: black;"&gt;&amp;gt;&lt;/span&gt; enumClass&lt;span style="color: black;"&gt;) {&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: black; font-weight: bold;"&gt;try&lt;/span&gt; &lt;span style="color: black;"&gt;{&lt;/span&gt;&lt;br /&gt;                        Method valuesMethod &lt;span style="color: black;"&gt;=&lt;/span&gt; enumClass&lt;span style="color: black;"&gt;.&lt;/span&gt;&lt;span style="color: #010181;"&gt;getMethod&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"values"&lt;/span&gt;&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;                        &lt;span style="color: black; font-weight: bold;"&gt;this&lt;/span&gt;&lt;span style="color: black;"&gt;.&lt;/span&gt;allValues &lt;span style="color: black;"&gt;=&lt;/span&gt; &lt;span style="color: #010181;"&gt;newArrayList&lt;/span&gt;&lt;span style="color: black;"&gt;((&lt;/span&gt;EnumType&lt;span style="color: black;"&gt;[])&lt;/span&gt; valuesMethod&lt;span style="color: black;"&gt;.&lt;/span&gt;&lt;span style="color: #010181;"&gt;invoke&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;enumClass&lt;span style="color: black;"&gt;));&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: black;"&gt;}&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;catch&lt;/span&gt; &lt;span style="color: black;"&gt;(&lt;/span&gt;Exception e&lt;span style="color: black;"&gt;) {&lt;/span&gt;&lt;br /&gt;                        &lt;span style="color: black; font-weight: bold;"&gt;throw new&lt;/span&gt; &lt;span style="color: #010181;"&gt;RuntimeException&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"Are you trying to apply SmartEnums to a non enum class?"&lt;/span&gt;&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: black; font-weight: bold;"&gt;public&lt;/span&gt; MemberSearch &lt;span style="color: #010181;"&gt;byField&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: black; font-weight: bold;"&gt;final&lt;/span&gt; String fieldName&lt;span style="color: black;"&gt;) {&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: black; font-weight: bold;"&gt;return new&lt;/span&gt; &lt;span style="color: #010181;"&gt;MemberSearch&lt;/span&gt;&lt;span style="color: black;"&gt;() {&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                        &lt;span style="color: black; font-weight: bold;"&gt;@Override&lt;/span&gt;&lt;br /&gt;                        &lt;span style="color: black; font-weight: bold;"&gt;protected&lt;/span&gt; Object &lt;span style="color: #010181;"&gt;findValueOn&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;EnumType enumType&lt;span style="color: black;"&gt;)&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;throws&lt;/span&gt; Exception &lt;span style="color: black;"&gt;{&lt;/span&gt;&lt;br /&gt;                                Field field &lt;span style="color: black;"&gt;=&lt;/span&gt; enumType&lt;span style="color: black;"&gt;.&lt;/span&gt;&lt;span style="color: #010181;"&gt;getClass&lt;/span&gt;&lt;span style="color: black;"&gt;().&lt;/span&gt;&lt;span style="color: #010181;"&gt;getDeclaredField&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;fieldName&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;                                field&lt;span style="color: black;"&gt;.&lt;/span&gt;&lt;span style="color: #010181;"&gt;setAccessible&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;true&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;                                &lt;span style="color: black; font-weight: bold;"&gt;return&lt;/span&gt; field&lt;span style="color: black;"&gt;.&lt;/span&gt;&lt;span style="color: #010181;"&gt;get&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;enumType&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;                        &lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: black;"&gt;};&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: black; font-weight: bold;"&gt;public&lt;/span&gt; MemberSearch &lt;span style="color: #010181;"&gt;byMethod&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: black; font-weight: bold;"&gt;final&lt;/span&gt; String methodName&lt;span style="color: black;"&gt;) {&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: black; font-weight: bold;"&gt;return new&lt;/span&gt; &lt;span style="color: #010181;"&gt;MemberSearch&lt;/span&gt;&lt;span style="color: black;"&gt;() {&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                        &lt;span style="color: black; font-weight: bold;"&gt;protected&lt;/span&gt; Object &lt;span style="color: #010181;"&gt;findValueOn&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;EnumType enumType&lt;span style="color: black;"&gt;)&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;throws&lt;/span&gt; Exception &lt;span style="color: black;"&gt;{&lt;/span&gt;&lt;br /&gt;                                Method method &lt;span style="color: black;"&gt;=&lt;/span&gt; enumType&lt;span style="color: black;"&gt;.&lt;/span&gt;&lt;span style="color: #010181;"&gt;getClass&lt;/span&gt;&lt;span style="color: black;"&gt;().&lt;/span&gt;&lt;span style="color: #010181;"&gt;getDeclaredMethod&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;methodName&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;                                method&lt;span style="color: black;"&gt;.&lt;/span&gt;&lt;span style="color: #010181;"&gt;setAccessible&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;true&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;                                &lt;span style="color: black; font-weight: bold;"&gt;return&lt;/span&gt; method&lt;span style="color: black;"&gt;.&lt;/span&gt;&lt;span style="color: #010181;"&gt;invoke&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;enumType&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;                        &lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span style="color: black;"&gt;};&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: black; font-weight: bold;"&gt;public abstract class&lt;/span&gt; MemberSearch &lt;span style="color: black;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span style="color: black; font-weight: bold;"&gt;public&lt;/span&gt; EnumType &lt;span style="color: #010181;"&gt;havingValue&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;Object value&lt;span style="color: black;"&gt;) {&lt;/span&gt;&lt;br /&gt;                        &lt;span style="color: black; font-weight: bold;"&gt;try&lt;/span&gt; &lt;span style="color: black;"&gt;{&lt;/span&gt;&lt;br /&gt;                                &lt;span style="color: black; font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: #010181;"&gt;find&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;allValues&lt;span style="color: black;"&gt;,&lt;/span&gt; &lt;span style="color: #010181;"&gt;valueFinderPredicate&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;value&lt;span style="color: black;"&gt;));&lt;/span&gt;&lt;br /&gt;                        &lt;span style="color: black;"&gt;}&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;catch&lt;/span&gt; &lt;span style="color: black;"&gt;(&lt;/span&gt;Exception e&lt;span style="color: black;"&gt;) {&lt;/span&gt;&lt;br /&gt;                                &lt;span style="color: black; font-weight: bold;"&gt;throw new&lt;/span&gt; &lt;span style="color: #010181;"&gt;RuntimeException&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;e&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;                        &lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span style="color: black; font-weight: bold;"&gt;protected abstract&lt;/span&gt; Object &lt;span style="color: #010181;"&gt;findValueOn&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;EnumType enumType&lt;span style="color: black;"&gt;)&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;throws&lt;/span&gt; Exception&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span style="color: black; font-weight: bold;"&gt;protected&lt;/span&gt; Predicate&lt;span style="color: black;"&gt;&amp;lt;&lt;/span&gt;EnumType&lt;span style="color: black;"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #010181;"&gt;valueFinderPredicate&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: black; font-weight: bold;"&gt;final&lt;/span&gt; Object value&lt;span style="color: black;"&gt;) {&lt;/span&gt;&lt;br /&gt;                        &lt;span style="color: black; font-weight: bold;"&gt;return new&lt;/span&gt; Predicate&lt;span style="color: black;"&gt;&amp;lt;&lt;/span&gt;EnumType&lt;span style="color: black;"&gt;&amp;gt;() {&lt;/span&gt;&lt;br /&gt;                                &lt;span style="color: black; font-weight: bold;"&gt;@Override&lt;/span&gt;&lt;br /&gt;                                &lt;span style="color: black; font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;boolean&lt;/span&gt; &lt;span style="color: #010181;"&gt;apply&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;EnumType enumType&lt;span style="color: black;"&gt;) {&lt;/span&gt;&lt;br /&gt;                                        &lt;span style="color: black; font-weight: bold;"&gt;try&lt;/span&gt; &lt;span style="color: black;"&gt;{&lt;/span&gt;&lt;br /&gt;                                                &lt;span style="color: black; font-weight: bold;"&gt;return&lt;/span&gt; value&lt;span style="color: black;"&gt;.&lt;/span&gt;&lt;span style="color: #010181;"&gt;equals&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #010181;"&gt;findValueOn&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;enumType&lt;span style="color: black;"&gt;));&lt;/span&gt;&lt;br /&gt;                                        &lt;span style="color: black;"&gt;}&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;catch&lt;/span&gt; &lt;span style="color: black;"&gt;(&lt;/span&gt;Exception e&lt;span style="color: black;"&gt;) {&lt;/span&gt;&lt;br /&gt;                                                &lt;span style="color: black; font-weight: bold;"&gt;throw new&lt;/span&gt; &lt;span style="color: #010181;"&gt;RuntimeException&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;e&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;                                        &lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;                                &lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;                        &lt;span style="color: black;"&gt;};&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Certo, come ho già scritto prima la leggibilità interna non è esaltante...&lt;br /&gt;Ma vediamo come viene utilizzata &lt;b&gt;esternamente&lt;/b&gt;&amp;nbsp;questa classe, nella fattispecie il suo unit test::&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #e0eaee; color: black; font-family: 'Courier New'; font-size: 10pt;"&gt;&lt;span style="color: black; font-weight: bold;"&gt;package&lt;/span&gt; com&lt;span style="color: black;"&gt;.&lt;/span&gt;gmail&lt;span style="color: black;"&gt;.&lt;/span&gt;gulino&lt;span style="color: black;"&gt;.&lt;/span&gt;marco&lt;span style="color: black;"&gt;.&lt;/span&gt;utils&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;import static&lt;/span&gt; com&lt;span style="color: black;"&gt;.&lt;/span&gt;gmail&lt;span style="color: black;"&gt;.&lt;/span&gt;gulino&lt;span style="color: black;"&gt;.&lt;/span&gt;marco&lt;span style="color: black;"&gt;.&lt;/span&gt;utils&lt;span style="color: black;"&gt;.&lt;/span&gt;SmartEnums&lt;span style="color: black;"&gt;.&lt;/span&gt;search&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;import static&lt;/span&gt; org&lt;span style="color: black;"&gt;.&lt;/span&gt;hamcrest&lt;span style="color: black;"&gt;.&lt;/span&gt;CoreMatchers&lt;span style="color: black;"&gt;.&lt;/span&gt;equalTo&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;import static&lt;/span&gt; org&lt;span style="color: black;"&gt;.&lt;/span&gt;junit&lt;span style="color: black;"&gt;.&lt;/span&gt;Assert&lt;span style="color: black;"&gt;.&lt;/span&gt;assertThat&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;import&lt;/span&gt; org&lt;span style="color: black;"&gt;.&lt;/span&gt;junit&lt;span style="color: black;"&gt;.&lt;/span&gt;Test&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: black; font-weight: bold;"&gt;public class&lt;/span&gt; SmartEnumsTest &lt;span style="color: black;"&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: black; font-weight: bold;"&gt;@Test&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: black; font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;void&lt;/span&gt; &lt;span style="color: #010181;"&gt;itShouldRetrieveEnumByField&lt;/span&gt;&lt;span style="color: black;"&gt;()&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;throws&lt;/span&gt; Exception &lt;span style="color: black;"&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: #010181;"&gt;assertThat&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #010181;"&gt;search&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;AnExampleEnum&lt;span style="color: black;"&gt;.&lt;/span&gt;&lt;span style="color: black; font-weight: bold;"&gt;class&lt;/span&gt;&lt;span style="color: black;"&gt;).&lt;/span&gt;&lt;span style="color: #010181;"&gt;byField&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"enumFieldToSearchFor"&lt;/span&gt;&lt;span style="color: black;"&gt;).&lt;/span&gt;&lt;span style="color: #010181;"&gt;havingValue&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"first"&lt;/span&gt;&lt;span style="color: black;"&gt;),&lt;/span&gt; &lt;span style="color: #010181;"&gt;equalTo&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;AnExampleEnum&lt;span style="color: black;"&gt;.&lt;/span&gt;firstElement&lt;span style="color: black;"&gt;));&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: #010181;"&gt;assertThat&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #010181;"&gt;search&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;AnExampleEnum&lt;span style="color: black;"&gt;.&lt;/span&gt;&lt;span style="color: black; font-weight: bold;"&gt;class&lt;/span&gt;&lt;span style="color: black;"&gt;).&lt;/span&gt;&lt;span style="color: #010181;"&gt;byField&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"enumFieldToSearchFor"&lt;/span&gt;&lt;span style="color: black;"&gt;).&lt;/span&gt;&lt;span style="color: #010181;"&gt;havingValue&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"second"&lt;/span&gt;&lt;span style="color: black;"&gt;),&lt;/span&gt; &lt;span style="color: #010181;"&gt;equalTo&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;AnExampleEnum&lt;span style="color: black;"&gt;.&lt;/span&gt;secondElement&lt;span style="color: black;"&gt;));&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: black; font-weight: bold;"&gt;@Test&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: black; font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;void&lt;/span&gt; &lt;span style="color: #010181;"&gt;itShouldRetrieveEnumByMethods&lt;/span&gt;&lt;span style="color: black;"&gt;()&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;throws&lt;/span&gt; Exception &lt;span style="color: black;"&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: #010181;"&gt;assertThat&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #010181;"&gt;search&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;AnExampleEnum&lt;span style="color: black;"&gt;.&lt;/span&gt;&lt;span style="color: black; font-weight: bold;"&gt;class&lt;/span&gt;&lt;span style="color: black;"&gt;).&lt;/span&gt;&lt;span style="color: #010181;"&gt;byMethod&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"enumMethodToSearchFor"&lt;/span&gt;&lt;span style="color: black;"&gt;).&lt;/span&gt;&lt;span style="color: #010181;"&gt;havingValue&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"first"&lt;/span&gt;&lt;span style="color: black;"&gt;),&lt;/span&gt; &lt;span style="color: #010181;"&gt;equalTo&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;AnExampleEnum&lt;span style="color: black;"&gt;.&lt;/span&gt;firstElement&lt;span style="color: black;"&gt;));&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: #010181;"&gt;assertThat&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #010181;"&gt;search&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;AnExampleEnum&lt;span style="color: black;"&gt;.&lt;/span&gt;&lt;span style="color: black; font-weight: bold;"&gt;class&lt;/span&gt;&lt;span style="color: black;"&gt;).&lt;/span&gt;&lt;span style="color: #010181;"&gt;byMethod&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"enumMethodToSearchFor"&lt;/span&gt;&lt;span style="color: black;"&gt;).&lt;/span&gt;&lt;span style="color: #010181;"&gt;havingValue&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"second"&lt;/span&gt;&lt;span style="color: black;"&gt;),&lt;/span&gt; &lt;span style="color: #010181;"&gt;equalTo&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;AnExampleEnum&lt;span style="color: black;"&gt;.&lt;/span&gt;secondElement&lt;span style="color: black;"&gt;));&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: black; font-weight: bold;"&gt;public&lt;/span&gt; enum AnExampleEnum &lt;span style="color: black;"&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: #010181;"&gt;firstElement&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"first"&lt;/span&gt;&lt;span style="color: black;"&gt;),&lt;/span&gt; &lt;span style="color: #010181;"&gt;secondElement&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;&lt;span style="color: #bf0303;"&gt;"second"&lt;/span&gt;&lt;span style="color: black;"&gt;);&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: black; font-weight: bold;"&gt;private final&lt;/span&gt; String enumFieldToSearchFor&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span style="color: black; font-weight: bold;"&gt;private&lt;/span&gt; &lt;span style="color: #010181;"&gt;AnExampleEnum&lt;/span&gt;&lt;span style="color: black;"&gt;(&lt;/span&gt;String value&lt;span style="color: black;"&gt;) {&lt;/span&gt;&lt;br /&gt;                        &lt;span style="color: black; font-weight: bold;"&gt;this&lt;/span&gt;&lt;span style="color: black;"&gt;.&lt;/span&gt;enumFieldToSearchFor &lt;span style="color: black;"&gt;=&lt;/span&gt; value&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span style="color: black; font-weight: bold;"&gt;public&lt;/span&gt; String &lt;span style="color: #010181;"&gt;enumMethodToSearchFor&lt;/span&gt;&lt;span style="color: black;"&gt;() {&lt;/span&gt;&lt;br /&gt;                        &lt;span style="color: black; font-weight: bold;"&gt;return&lt;/span&gt; enumFieldToSearchFor&lt;span style="color: black;"&gt;;&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Le assert sono chiare: traducendo letteralmente dall'inglese, abbiamo, mettendo tra parentesi le parole sottointese:&lt;br /&gt;&lt;blockquote class="tr_bq"&gt;Asserisci (che la) ricerca (di) &lt;b&gt;AnExampleEnum&lt;/b&gt; per field "&lt;b&gt;enumFieldToSearchFor&lt;/b&gt;" avente valore "first" (sia) uguale a AnExampleEnum.firstElement&lt;/blockquote&gt;Le parole sottointese sono ben poche, è quindi evidente che fa la classe:&lt;br /&gt;&lt;blockquote class="tr_bq"&gt;&lt;b&gt;Ricerca &lt;/b&gt;una enum &lt;b&gt;per field&lt;/b&gt;&amp;nbsp;"nome del field" &lt;b&gt;avente valore &lt;/b&gt;"valore da ricercare".&lt;/blockquote&gt;o, nella seconda delle due interfacce disponibili:&lt;br /&gt;&lt;blockquote class="tr_bq"&gt;&lt;b&gt;Ricerca&amp;nbsp;&lt;/b&gt;una enum&amp;nbsp;&lt;b&gt;per metodo&lt;/b&gt;&amp;nbsp;"nome del metodo"&amp;nbsp;&lt;b&gt;avente valore&amp;nbsp;&lt;/b&gt;"valore da ricercare".&lt;/blockquote&gt;&lt;div&gt;Ora, il vantaggio evidente è che gli utilizzatori di questa classe non dovranno scervellarsi troppo nel capirla, in effetti non avranno proprio alcun bisogno di aprire l'implementazione e leggerla. Basta solo leggere il suo test (o un eventuale altro utilizzo) per capire cosa fa e come va invocata.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8003298816604397919-6494577003705619143?l=rockman81.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rockman81.blogspot.com/feeds/6494577003705619143/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8003298816604397919&amp;postID=6494577003705619143' title='2 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/6494577003705619143'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/6494577003705619143'/><link rel='alternate' type='text/html' href='http://rockman81.blogspot.com/2011/11/leggibilita-meglio-dentro-o-meglio.html' title='Leggibilità: meglio fuori che dentro'/><author><name>Marco Gulino</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-5TKjBFH5Ob4/AAAAAAAAAAI/AAAAAAAACNU/m2QmMz40phI/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8003298816604397919.post-7684137833960125579</id><published>2011-07-08T21:30:00.012+02:00</published><updated>2011-07-09T13:45:10.754+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Object Oriented Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Programmazione'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><category scheme='http://www.blogger.com/atom/ns#' term='Design'/><title type='text'>FizzBuzz Game</title><content type='html'>E dopo anni di silenzio, qualcosa da scrivere ogni tanto torna in mente...&lt;br /&gt;Questa settimana abbiamo iniziato un nuovo progetto con il nostro team in &lt;a href="http://xpeppers.com"&gt;XPeppers&lt;/a&gt;, l'azienda con cui collaboro da diversi anni.&lt;br /&gt;La prima settimana l'abbiamo dedicata allo studio, approfondendo vari design pattern e tecniche per la programmazione orientata agli oggetti.&lt;br /&gt;&lt;br /&gt;Un esercizio (ormai quasi un classico :P ) proposto dal nostro Coach, &lt;a href="http://matteo.vaccari.name/"&gt;Matteo Vaccari&lt;/a&gt;, è di implementare il gioco del FizzBuzz. Brevemente, un'applicazione che dato un numero restituisce lo stesso numero; per multipli di certi numeri però sostituisce la stampa del numero con quella di determinate parole preimpostate.&lt;br /&gt;Un esempio è che per multipli di due restituisce "Fizz", per multipli di tre "Buzz". Il numero "6" quindi restituirà la concatenazione, ovvero "FizzBuzz".&lt;br /&gt;&lt;br /&gt;Chiaramente un'implementazione molto semplice potrebbe essere quella di creare una serie di blocchi IF per gestire i casi particolari.&lt;br /&gt;Ovviamente non è scalabile, perchè all'aggiunta di nuove regole la serie di blocchi condizionali verrebbe a crescere in maniera sproporzionatamente complessa.&lt;br /&gt;La sfida era quindi di scrivere con un design il più orientato ad oggetti possibile un algoritmo tutto sommato non semplicissimo (ad esempio, l'output è condizionato dalle regole precedenti).&lt;br /&gt;Ecco &lt;a href="https://github.com/xpeppers/Studio-FizzBuzz"&gt;la mia soluzione&lt;/a&gt;.&lt;br /&gt;Il punto d'ingresso è &lt;a href="https://github.com/xpeppers/Studio-FizzBuzz/blob/master/src/com/xpeppers/gum/Game.java"&gt;game.java&lt;/a&gt;, che prende in costruzione tre oggetti: &lt;a href="https://github.com/xpeppers/Studio-FizzBuzz/blob/master/src/com/xpeppers/gum/RulesBuilder.java"&gt;RulesBuilder&lt;/a&gt;, una factory che crea le regole con le giuste dipendenze, &lt;a href="https://github.com/xpeppers/Studio-FizzBuzz/blob/master/src/com/xpeppers/gum/OutputBuilder.java"&gt;OutputBuilder&lt;/a&gt;, che si occupa di comporre i risultati delle regole (che sono a loro volta oggetti di tipo &lt;a href="https://github.com/xpeppers/Studio-FizzBuzz/blob/master/src/com/xpeppers/gum/OutputAdder.java"&gt;OutputAdder&lt;/a&gt; e non semplici stringhe) dando loro uno StringBuilder su cui scrivere del testo, e &lt;a href="https://github.com/xpeppers/Studio-FizzBuzz/blob/master/src/com/xpeppers/gum/OutputPrinter.java"&gt;OutputPrinter&lt;/a&gt;, un'interfaccia di rendering su cui OutputBuilder stamperà la stringa risultante.&lt;br /&gt;Le regole sono verificate dalla classe &lt;a href="https://github.com/xpeppers/Studio-FizzBuzz/blob/master/src/com/xpeppers/gum/DividerRule.java"&gt;DividerRule&lt;/a&gt;; in questo caso si tratta di una classe concreta e ben specializzata; aggiungendo nuovi tipi di regole si potrebbe estrarre un'interfaccia comune.&lt;br /&gt;Da notare che DividerRule ha la sola responsabilità di verificare l'applicarsi della condizione, ma non di scrivere o creare l'output; questa responsabilità è delegata alle singole implementazioni di OutputAdder.&lt;br /&gt;Ad esempio, la DividerRule che deve controllare la divisibilità per 3 collaborerà con un &lt;a href="https://github.com/xpeppers/Studio-FizzBuzz/blob/master/src/com/xpeppers/gum/AddWordToOutput.java"&gt;AddToWordOutput&lt;/a&gt; istanziato per scrivere "Buzz". Lo stampare il numero senza sostituzioni è delegato a un caso particolare di OutputAdder: la DividerRule corrispondente viene sempre verificata, dato che viene istanziata per dividere per 1, mentre l'OutputAdder &lt;a href="https://github.com/xpeppers/Studio-FizzBuzz/blob/master/src/com/xpeppers/gum/AddNumberIfOutputIsEmpty.java"&gt;AddNumberIfOutputIsEmpty&lt;/a&gt; controlla che lo StringBuilder sia vuoto (ossia che le regole precedenti non hanno avuto successo) e in tal caso aggiunge il numero.&lt;br /&gt;Altro caso particolare la divisibilità per 7: in questo caso &lt;a href="https://github.com/xpeppers/Studio-FizzBuzz/blob/master/src/com/xpeppers/gum/PatatracAdder.java"&gt;PatatracAdder&lt;/a&gt; cancella tutto l'output delle regole precedenti e sostituisce il tutto con "Patatrac".&lt;br /&gt;&lt;br /&gt;Il progetto così realizzato cerca di rispettare tutte le principali regole di buona programmazione: anzitutto &lt;a href="http://en.wikipedia.org/wiki/Single_responsibility_principle"&gt;SRP&lt;/a&gt;, dato che ogni classe è altamente specializzata ed ha una sola responsabilità; &lt;a href="http://en.wikipedia.org/wiki/Open/closed_principle"&gt;OCP&lt;/a&gt;, infatti per aggiungere nuove regole non serve modificare il codice esistente (a meno di stravolgimenti logici, ovviamente), ma è sufficiente implementare nuovi OutputAdder o eventualmente nuove Rules; &lt;a href="http://c2.com/cgi/wiki?TellDontAsk"&gt;Tell, don't ask&lt;/a&gt;, nessuna classe ha statement "return", quindi nessun oggetto chiede ad altri oggetti qualcosa, ma piuttosto comanda ai suoi collaboratori di eseguire qualcosa, ignorando i dettagli implementativi; infine l'&lt;a href="http://jfranzoi.wordpress.com/2008/09/20/disaccoppiamento-inversione-delle-dipendenze-e-architetture-esagonali/"&gt;architettura esagonale&lt;/a&gt;, ossia fare in modo che il dominio non abbia alcuna conoscenza del mondo esterno: difatti le classi di dominio non operano nessuna system.out, nè ritornano valori, piuttosto viene usata una generica interfaccia OutputPrinter, oltretutto non implementata se non nei &lt;a href="https://github.com/xpeppers/Studio-FizzBuzz/tree/master/test/com/xpeppers/gum"&gt;test&lt;/a&gt;, e che potrebbe essere sostituita  con una classe qualsiasi in grado di stampare su console, su web, su file.&lt;br /&gt;Ovviamente sono anche rispettati i classici pattern come rimozione duplicazione e semplicità logica (pochi IF o cicli).&lt;br /&gt;&lt;br /&gt;Sono graditi commenti :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8003298816604397919-7684137833960125579?l=rockman81.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rockman81.blogspot.com/feeds/7684137833960125579/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8003298816604397919&amp;postID=7684137833960125579' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/7684137833960125579'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/7684137833960125579'/><link rel='alternate' type='text/html' href='http://rockman81.blogspot.com/2011/07/fizzbuzz-game.html' title='FizzBuzz Game'/><author><name>Marco Gulino</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-5TKjBFH5Ob4/AAAAAAAAAAI/AAAAAAAACNU/m2QmMz40phI/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8003298816604397919.post-1896891083048528702</id><published>2009-12-03T12:51:00.002+01:00</published><updated>2012-01-09T00:20:20.423+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Informatica'/><category scheme='http://www.blogger.com/atom/ns#' term='Programmazione'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='Bash scripting'/><title type='text'>Merge Utilities (command line)</title><content type='html'>This script helps you merging different branches on a project.&lt;br /&gt;It offers some advantages:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;It ignores whitespaces, so you don't have to care (too much) about formatting&lt;/li&gt;&lt;br /&gt;&lt;li&gt;it uses a single reject file, so you don't have to find .rej files in all your project for "debug" applying patch&lt;/li&gt;&lt;br /&gt;&lt;li&gt;It doesn't use backup files, so you can avoid polluting the project with .orig files too (who needs backup files, when you can do svn revert?)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;It can accept both "r1234" and "1234" for revision number (useful for copy&amp;amp;paste from svn log)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Here's the code&lt;br /&gt;&lt;pre class="hl"&gt;&lt;span class="hl slc"&gt;#!/bin/bash&lt;/span&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;function&lt;/span&gt; helpMsg&lt;span class="hl sym"&gt;() {&lt;/span&gt;&lt;br /&gt; nextMsg&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;"$1"&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwb"&gt;echo&lt;/span&gt; &lt;span class="hl str"&gt;"Usage: $(basename $0) &amp;lt;command&amp;gt;"&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwb"&gt;echo&lt;/span&gt; &lt;span class="hl str"&gt;"Available commands: "&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwb"&gt;echo&lt;/span&gt; &lt;span class="hl str"&gt;"° diff - creates a diff file (using svn diff) to compare different branches"&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwb"&gt;echo&lt;/span&gt; &lt;span class="hl str"&gt;"° patch - applies the previously created diff file"&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwa"&gt;if&lt;/span&gt; &lt;span class="hl kwb"&gt;test&lt;/span&gt; &lt;span class="hl str"&gt;"x$nextMsg"&lt;/span&gt; &lt;span class="hl sym"&gt;!=&lt;/span&gt; &lt;span class="hl str"&gt;"x"&lt;/span&gt;&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl kwa"&gt;then&lt;/span&gt;&lt;br /&gt;  &lt;span class="hl kwb"&gt;echo&lt;/span&gt; &lt;span class="hl sym"&gt;-&lt;/span&gt;e &lt;span class="hl str"&gt;"&lt;/span&gt;&lt;span class="hl esc"&gt;\n&lt;/span&gt;&lt;span class="hl str"&gt;$nextMsg"&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwa"&gt;fi&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwb"&gt;echo&lt;/span&gt; &lt;span class="hl str"&gt;""&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwb"&gt;exit&lt;/span&gt; &lt;span class="hl num"&gt;1&lt;/span&gt;&lt;br /&gt;&lt;span class="hl sym"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;function&lt;/span&gt; doPatch&lt;span class="hl sym"&gt;() {&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwa"&gt;if&lt;/span&gt; &lt;span class="hl kwb"&gt;test&lt;/span&gt; &lt;span class="hl str"&gt;"x$1"&lt;/span&gt; &lt;span class="hl sym"&gt;==&lt;/span&gt; &lt;span class="hl str"&gt;"x"&lt;/span&gt; &lt;span class="hl sym"&gt;|| ! [ -&lt;/span&gt;r &lt;span class="hl str"&gt;"$1"&lt;/span&gt; &lt;span class="hl sym"&gt;];&lt;/span&gt; &lt;span class="hl kwa"&gt;then&lt;/span&gt;&lt;br /&gt;  helpMSG&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;"Arguments for patch: &amp;lt;diff file&amp;gt; [optional arguments for patch]"&lt;/span&gt;&lt;br /&gt;  helpMsg &lt;span class="hl str"&gt;"$helpMSG"&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwa"&gt;fi&lt;/span&gt;&lt;br /&gt; FILE&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;"$1"&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwb"&gt;shift&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwc"&gt;patch&lt;/span&gt; &lt;span class="hl sym"&gt;-&lt;/span&gt;p0 &lt;span class="hl sym"&gt;--&lt;/span&gt;no&lt;span class="hl sym"&gt;-&lt;/span&gt;backup&lt;span class="hl sym"&gt;-&lt;/span&gt;&lt;span class="hl kwa"&gt;if&lt;/span&gt;&lt;span class="hl sym"&gt;-&lt;/span&gt;mismatch &lt;span class="hl sym"&gt;-&lt;/span&gt;l &lt;span class="hl sym"&gt;-&lt;/span&gt;E &lt;span class="hl sym"&gt;--&lt;/span&gt;global&lt;span class="hl sym"&gt;-&lt;/span&gt;reject&lt;span class="hl sym"&gt;-&lt;/span&gt;&lt;span class="hl kwc"&gt;file&lt;/span&gt;&lt;span class="hl sym"&gt;=&lt;/span&gt;cambiamentiRifiutati.rej &lt;span class="hl sym"&gt;-&lt;/span&gt;i &lt;span class="hl str"&gt;"$FILE"&lt;/span&gt; $@&lt;br /&gt;&lt;span class="hl sym"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;function&lt;/span&gt; doDiff&lt;span class="hl sym"&gt;() {&lt;/span&gt;&lt;br /&gt;      REV1&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl kwb"&gt;$1&lt;/span&gt;&lt;br /&gt;      REV2&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl kwb"&gt;$2&lt;/span&gt;&lt;br /&gt;      FILE&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;"$3"&lt;/span&gt;&lt;br /&gt;      &lt;span class="hl kwa"&gt;if&lt;/span&gt; &lt;span class="hl kwb"&gt;test&lt;/span&gt; &lt;span class="hl str"&gt;"x$1"&lt;/span&gt; &lt;span class="hl sym"&gt;==&lt;/span&gt; &lt;span class="hl str"&gt;"x"&lt;/span&gt; &lt;span class="hl sym"&gt;||&lt;/span&gt; &lt;span class="hl kwb"&gt;test&lt;/span&gt; &lt;span class="hl str"&gt;"x$2"&lt;/span&gt; &lt;span class="hl sym"&gt;==&lt;/span&gt; &lt;span class="hl str"&gt;"x"&lt;/span&gt; &lt;span class="hl sym"&gt;||&lt;/span&gt; &lt;span class="hl kwb"&gt;test&lt;/span&gt; &lt;span class="hl str"&gt;"x$3"&lt;/span&gt; &lt;span class="hl sym"&gt;==&lt;/span&gt; &lt;span class="hl str"&gt;"x"&lt;/span&gt;&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl kwa"&gt;then&lt;/span&gt;&lt;br /&gt; helpMSG&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;"Arguments for diff: &amp;lt;first revision&amp;gt; &amp;lt;second revision&amp;gt; &amp;lt;diff file&amp;gt; [optional arguments for svn diff]&lt;/span&gt;&lt;br /&gt;&lt;span class="hl str"&gt;Revision number format can either be r1234 or 1234"&lt;/span&gt;&lt;br /&gt; helpMsg &lt;span class="hl str"&gt;"$helpMSG"&lt;/span&gt;&lt;br /&gt;      &lt;span class="hl kwa"&gt;fi&lt;/span&gt;&lt;br /&gt;      &lt;span class="hl kwb"&gt;shift&lt;/span&gt;&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl kwb"&gt;shift&lt;/span&gt;&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl kwb"&gt;shift&lt;/span&gt;&lt;br /&gt;      &lt;span class="hl slc"&gt;#Sostituzione "r1234" con "1234" in modo da facilitare il cut&amp;amp;paste da svn log&lt;/span&gt;&lt;br /&gt;      REV1&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;"$( echo $REV1 | sed "&lt;/span&gt;s&lt;span class="hl sym"&gt;/&lt;/span&gt;r&lt;span class="hl sym"&gt;//&lt;/span&gt;g&lt;span class="hl str"&gt;")"&lt;/span&gt;&lt;br /&gt;      REV2&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;"$( echo $REV2 | sed "&lt;/span&gt;s&lt;span class="hl sym"&gt;/&lt;/span&gt;r&lt;span class="hl sym"&gt;//&lt;/span&gt;g&lt;span class="hl str"&gt;")"&lt;/span&gt;&lt;br /&gt;      svn &lt;span class="hl kwc"&gt;diff&lt;/span&gt; &lt;span class="hl sym"&gt;-&lt;/span&gt;r &lt;span class="hl kwb"&gt;$REV1&lt;/span&gt;&lt;span class="hl sym"&gt;:&lt;/span&gt;&lt;span class="hl kwb"&gt;$REV2&lt;/span&gt; &lt;span class="hl sym"&gt;--&lt;/span&gt;&lt;span class="hl kwc"&gt;diff&lt;/span&gt;&lt;span class="hl sym"&gt;-&lt;/span&gt;cmd&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl kwc"&gt;diff&lt;/span&gt; &lt;span class="hl sym"&gt;-&lt;/span&gt;x &lt;span class="hl sym"&gt;-&lt;/span&gt;uw $@ &lt;span class="hl sym"&gt;&amp;gt;&lt;/span&gt; &lt;span class="hl str"&gt;"$FILE"&lt;/span&gt;&lt;br /&gt;&lt;span class="hl sym"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;CMD&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl kwb"&gt;$1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;if&lt;/span&gt; &lt;span class="hl kwb"&gt;test&lt;/span&gt; &lt;span class="hl str"&gt;"x$1"&lt;/span&gt; &lt;span class="hl sym"&gt;==&lt;/span&gt; &lt;span class="hl str"&gt;"x"&lt;/span&gt;&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl kwa"&gt;then&lt;/span&gt;&lt;br /&gt; helpMsg&lt;br /&gt;&lt;span class="hl kwa"&gt;fi&lt;/span&gt;&lt;br /&gt;&lt;span class="hl kwb"&gt;shift&lt;/span&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;case&lt;/span&gt; &lt;span class="hl kwb"&gt;$CMD&lt;/span&gt; &lt;span class="hl kwa"&gt;in&lt;/span&gt;&lt;br /&gt; &lt;span class="hl str"&gt;"diff"&lt;/span&gt;&lt;span class="hl sym"&gt;)&lt;/span&gt;&lt;br /&gt; doDiff $@&lt;br /&gt; &lt;span class="hl sym"&gt;;;&lt;/span&gt;&lt;br /&gt; &lt;span class="hl str"&gt;"patch"&lt;/span&gt;&lt;span class="hl sym"&gt;)&lt;/span&gt;&lt;br /&gt; doPatch $@&lt;br /&gt; &lt;span class="hl sym"&gt;;;&lt;/span&gt;&lt;br /&gt; &lt;span class="hl sym"&gt;*)&lt;/span&gt;&lt;br /&gt; helpMsg&lt;br /&gt; &lt;span class="hl sym"&gt;;;&lt;/span&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;esac&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8003298816604397919-1896891083048528702?l=rockman81.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rockman81.blogspot.com/feeds/1896891083048528702/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8003298816604397919&amp;postID=1896891083048528702' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/1896891083048528702'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/1896891083048528702'/><link rel='alternate' type='text/html' href='http://rockman81.blogspot.com/2009/12/merge-utilities-command-line.html' title='Merge Utilities (command line)'/><author><name>Marco Gulino</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-5TKjBFH5Ob4/AAAAAAAAAAI/AAAAAAAACNU/m2QmMz40phI/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8003298816604397919.post-437754557982836582</id><published>2008-08-21T11:32:00.004+02:00</published><updated>2008-08-21T16:32:48.372+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Informatica'/><category scheme='http://www.blogger.com/atom/ns#' term='Bash scripting'/><category scheme='http://www.blogger.com/atom/ns#' term='GNU/Linux'/><title type='text'>Estetica Bash</title><content type='html'>Da così...&lt;br /&gt;&lt;pre class="hl"&gt;&lt;span class="hl slc"&gt;#!/bin/bash&lt;/span&gt;&lt;br /&gt;found_in_application_xml&lt;span class="hl sym"&gt;=&lt;/span&gt;$&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwc"&gt;grep&lt;/span&gt; ProjectName &lt;span class="hl sym"&gt;/&lt;/span&gt;bea&lt;span class="hl sym"&gt;/&lt;/span&gt;one&lt;span class="hl sym"&gt;/&lt;/span&gt;&lt;span class="hl num"&gt;9&lt;/span&gt;&lt;span class="hl sym"&gt;/&lt;/span&gt;&lt;span class="hl num"&gt;923&lt;/span&gt;&lt;span class="hl sym"&gt;/&lt;/span&gt;apps&lt;span class="hl sym"&gt;/&lt;/span&gt;BEdomain&lt;span class="hl sym"&gt;/&lt;/span&gt;BHcluster&lt;span class="hl sym"&gt;/&lt;/span&gt;ear&lt;span class="hl sym"&gt;/&lt;/span&gt;h2o&lt;span class="hl sym"&gt;/&lt;/span&gt;BHapp&lt;span class="hl sym"&gt;/&lt;/span&gt;app&lt;span class="hl sym"&gt;/&lt;/span&gt;META&lt;span class="hl sym"&gt;-&lt;/span&gt;INF&lt;span class="hl sym"&gt;/&lt;/span&gt;application.xml&lt;span class="hl sym"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;if&lt;/span&gt; &lt;span class="hl sym"&gt;[ -&lt;/span&gt;n &lt;span class="hl str"&gt;&amp;quot;$found_in_application_xml&amp;quot;&lt;/span&gt; &lt;span class="hl sym"&gt;];&lt;/span&gt; &lt;span class="hl kwa"&gt;then&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwb"&gt;echo&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;/bea/one/9/923/apps/BEdomain/BHcluster/ear/h2o/BHapp/app/META-INF/application.xml: OK&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;else&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwb"&gt;echo&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;/bea/one/9/923/apps/BEdomain/BHcluster/ear/h2o/BHapp/app/META-INF/application.xml: ProjectName not found&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwc"&gt;sed&lt;/span&gt; &lt;span class="hl sym"&gt;-&lt;/span&gt;i &lt;span class="hl str"&gt;'s/&amp;lt;\/application&amp;gt;/&amp;lt;module&amp;gt;&amp;lt;ejb&amp;gt;ejb\/ProjectName\/ejb20_BH_ProjectName_81.jar&amp;lt;\/ejb&amp;gt;&amp;lt;\/module&amp;gt;&lt;/span&gt;&lt;span class="hl esc"&gt;\n&lt;/span&gt;&lt;span class="hl str"&gt;&amp;lt;\/application&amp;gt;/'&lt;/span&gt; &lt;span class="hl sym"&gt;/&lt;/span&gt;bea&lt;span class="hl sym"&gt;/&lt;/span&gt;one&lt;span class="hl sym"&gt;/&lt;/span&gt;&lt;span class="hl num"&gt;9&lt;/span&gt;&lt;span class="hl sym"&gt;/&lt;/span&gt;&lt;span class="hl num"&gt;923&lt;/span&gt;&lt;span class="hl sym"&gt;/&lt;/span&gt;apps&lt;span class="hl sym"&gt;/&lt;/span&gt;BEdomain&lt;span class="hl sym"&gt;/&lt;/span&gt;BHcluster&lt;span class="hl sym"&gt;/&lt;/span&gt;ear&lt;span class="hl sym"&gt;/&lt;/span&gt;h2o&lt;span class="hl sym"&gt;/&lt;/span&gt;BHapp&lt;span class="hl sym"&gt;/&lt;/span&gt;app&lt;span class="hl sym"&gt;/&lt;/span&gt;META&lt;span class="hl sym"&gt;-&lt;/span&gt;INF&lt;span class="hl sym"&gt;/&lt;/span&gt;application.xml&lt;br /&gt;&lt;span class="hl kwa"&gt;fi&lt;/span&gt;&lt;br /&gt;found_in_log4j&lt;span class="hl sym"&gt;=&lt;/span&gt;$&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwc"&gt;grep&lt;/span&gt; projectname &lt;span class="hl sym"&gt;/&lt;/span&gt;bea&lt;span class="hl sym"&gt;/&lt;/span&gt;one&lt;span class="hl sym"&gt;/&lt;/span&gt;&lt;span class="hl num"&gt;9&lt;/span&gt;&lt;span class="hl sym"&gt;/&lt;/span&gt;&lt;span class="hl num"&gt;923&lt;/span&gt;&lt;span class="hl sym"&gt;/&lt;/span&gt;system&lt;span class="hl sym"&gt;/&lt;/span&gt;BEdomain&lt;span class="hl sym"&gt;/&lt;/span&gt;BHcluster&lt;span class="hl sym"&gt;/&lt;/span&gt;log4j.properties&lt;span class="hl sym"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;if&lt;/span&gt; &lt;span class="hl sym"&gt;[ -&lt;/span&gt;n &lt;span class="hl str"&gt;&amp;quot;$found_in_log4j&amp;quot;&lt;/span&gt; &lt;span class="hl sym"&gt;];&lt;/span&gt; &lt;span class="hl kwa"&gt;then&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwb"&gt;echo&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;/bea/one/9/923/system/BEdomain/BHcluster/log4j.properties: OK&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;else&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwb"&gt;echo&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;/bea/one/9/923/system/BEdomain/BHcluster/log4j.properties: projectname not found&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwb"&gt;echo&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="hl str"&gt;log4j.appender.PROJECTNAME=org.apache.log4j.FileAppender&lt;/span&gt;&lt;br /&gt;&lt;span class="hl str"&gt;log4j.appender.PROJECTNAME.File=/log/projectname.log&lt;/span&gt;&lt;br /&gt;&lt;span class="hl str"&gt;log4j.appender.PROJECTNAME.layout=org.apache.log4j.PatternLayout&lt;/span&gt;&lt;br /&gt;&lt;span class="hl str"&gt;log4j.appender.PROJECTNAME.layout.ConversionPattern=[%t] [%d{DATE}] - %c -%p: %m%n&lt;/span&gt;&lt;br /&gt;&lt;span class="hl str"&gt;log4j.logger.it.sella.projectname=INFO, PROJECTNAME&amp;quot;&lt;/span&gt; &lt;span class="hl sym"&gt;&amp;gt;&amp;gt; /&lt;/span&gt;bea&lt;span class="hl sym"&gt;/&lt;/span&gt;one&lt;span class="hl sym"&gt;/&lt;/span&gt;&lt;span class="hl num"&gt;9&lt;/span&gt;&lt;span class="hl sym"&gt;/&lt;/span&gt;&lt;span class="hl num"&gt;923&lt;/span&gt;&lt;span class="hl sym"&gt;/&lt;/span&gt;system&lt;span class="hl sym"&gt;/&lt;/span&gt;BEdomain&lt;span class="hl sym"&gt;/&lt;/span&gt;BHcluster&lt;span class="hl sym"&gt;/&lt;/span&gt;log4j.properties&lt;br /&gt;&lt;span class="hl kwa"&gt;fi&lt;/span&gt;&lt;br /&gt;found_in_integrazione_sistemi_esterni_properties&lt;span class="hl sym"&gt;=&lt;/span&gt;$&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwc"&gt;grep&lt;/span&gt; ProjectName &lt;span class="hl sym"&gt;/&lt;/span&gt;bea&lt;span class="hl sym"&gt;/&lt;/span&gt;one&lt;span class="hl sym"&gt;/&lt;/span&gt;&lt;span class="hl num"&gt;9&lt;/span&gt;&lt;span class="hl sym"&gt;/&lt;/span&gt;&lt;span class="hl num"&gt;923&lt;/span&gt;&lt;span class="hl sym"&gt;/&lt;/span&gt;system&lt;span class="hl sym"&gt;/&lt;/span&gt;BEdomain&lt;span class="hl sym"&gt;/&lt;/span&gt;BHcluster&lt;span class="hl sym"&gt;/&lt;/span&gt;subSystem.properties&lt;span class="hl sym"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;if&lt;/span&gt; &lt;span class="hl sym"&gt;[ -&lt;/span&gt;n &lt;span class="hl str"&gt;&amp;quot;$found_in_integrazione_sistemi_esterni_properties&amp;quot;&lt;/span&gt; &lt;span class="hl sym"&gt;];&lt;/span&gt; &lt;span class="hl kwa"&gt;then&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwb"&gt;echo&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;/bea/one/9/923/system/BEdomain/BHcluster/subSystem.properties: OK&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;else&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwb"&gt;echo&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;/bea/one/9/923/system/BEdomain/BHcluster/subSystem.properties: ProjectName not found&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwb"&gt;echo&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="hl str"&gt;#&amp;lt;ProjectName&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="hl str"&gt;Service.SomeSystem.serviceType=ejb&lt;/span&gt;&lt;br /&gt;&lt;span class="hl str"&gt;Service.SomeSystem.xmlStrategy=./data/ProjectName/subsystem.xml&lt;/span&gt;&lt;br /&gt;&lt;span class="hl str"&gt;Service.TestSomeSystem.serviceType=ejb&lt;/span&gt;&lt;br /&gt;&lt;span class="hl str"&gt;Service.TestSomeSystem.xmlStrategy=./data/ProjectName/ise/ise_TestSomeSystem.xml&lt;/span&gt;&lt;br /&gt;&lt;span class="hl str"&gt;#&amp;lt;/ProjectName&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class="hl sym"&gt;&amp;gt;&amp;gt; /&lt;/span&gt;bea&lt;span class="hl sym"&gt;/&lt;/span&gt;one&lt;span class="hl sym"&gt;/&lt;/span&gt;&lt;span class="hl num"&gt;9&lt;/span&gt;&lt;span class="hl sym"&gt;/&lt;/span&gt;&lt;span class="hl num"&gt;923&lt;/span&gt;&lt;span class="hl sym"&gt;/&lt;/span&gt;system&lt;span class="hl sym"&gt;/&lt;/span&gt;BEdomain&lt;span class="hl sym"&gt;/&lt;/span&gt;BHcluster&lt;span class="hl sym"&gt;/&lt;/span&gt;subSystem.properties&lt;br /&gt;&lt;span class="hl kwa"&gt;fi&lt;/span&gt;&lt;br /&gt;found_in_do_post_contabilizzazione_properties&lt;span class="hl sym"&gt;=&lt;/span&gt;$&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwc"&gt;grep&lt;/span&gt; projectname &lt;span class="hl sym"&gt;/&lt;/span&gt;bea&lt;span class="hl sym"&gt;/&lt;/span&gt;one&lt;span class="hl sym"&gt;/&lt;/span&gt;&lt;span class="hl num"&gt;9&lt;/span&gt;&lt;span class="hl sym"&gt;/&lt;/span&gt;&lt;span class="hl num"&gt;923&lt;/span&gt;&lt;span class="hl sym"&gt;/&lt;/span&gt;system&lt;span class="hl sym"&gt;/&lt;/span&gt;BEdomain&lt;span class="hl sym"&gt;/&lt;/span&gt;BHcluster&lt;span class="hl sym"&gt;/&lt;/span&gt;OtherSubSystem.properties&lt;span class="hl sym"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;if&lt;/span&gt; &lt;span class="hl sym"&gt;[ -&lt;/span&gt;n &lt;span class="hl str"&gt;&amp;quot;$found_in_do_post_contabilizzazione_properties&amp;quot;&lt;/span&gt; &lt;span class="hl sym"&gt;];&lt;/span&gt; &lt;span class="hl kwa"&gt;then&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwb"&gt;echo&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;/bea/one/9/923/system/BEdomain/BHcluster/OtherSubSystem.properties: OK&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;else&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwb"&gt;echo&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;/bea/one/9/923/system/BEdomain/BHcluster/OtherSubSystem.properties: projectname not found&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;span class="hl kwb"&gt;echo&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="hl str"&gt;#&amp;lt;ProjectName&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="hl str"&gt;DEB03=it.home.projectname.lib.Class&lt;/span&gt;&lt;br /&gt;&lt;span class="hl str"&gt;DEB05=it.home.projectname.lib.Class&lt;/span&gt;&lt;br /&gt;&lt;span class="hl str"&gt;#&amp;lt;/ProjectName&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="hl str"&gt;&amp;quot;&lt;/span&gt; &lt;span class="hl sym"&gt;&amp;gt;&amp;gt; /&lt;/span&gt;bea&lt;span class="hl sym"&gt;/&lt;/span&gt;one&lt;span class="hl sym"&gt;/&lt;/span&gt;&lt;span class="hl num"&gt;9&lt;/span&gt;&lt;span class="hl sym"&gt;/&lt;/span&gt;&lt;span class="hl num"&gt;923&lt;/span&gt;&lt;span class="hl sym"&gt;/&lt;/span&gt;system&lt;span class="hl sym"&gt;/&lt;/span&gt;BEdomain&lt;span class="hl sym"&gt;/&lt;/span&gt;BHcluster&lt;span class="hl sym"&gt;/&lt;/span&gt;OtherSubSystem.properties&lt;br /&gt;&lt;span class="hl kwa"&gt;fi&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;a così:&lt;br /&gt;&lt;pre class="hl"&gt;&lt;span class="hl slc"&gt;#!/bin/bash&lt;/span&gt;&lt;br /&gt;PROJECTNAME&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;ProjectName&amp;quot;&lt;/span&gt;&lt;br /&gt;BEADIR&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;/bea/one/9/923&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;BH_JAR_NAME&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;ejb20_BH_${PROJECTNAME}_81.jar&amp;quot;&lt;/span&gt;&lt;br /&gt;MODULEPATH&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;ejb/$PROJECTNAME/&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;APPLICATION_XML&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;${BEADIR}/apps/BEdomain/BHcluster/ear/h2o/BHapp/app/META-INF/application.xml&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;LOG4JFILE&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;${BEADIR}/system/BEdomain/BHcluster/log4j.properties&amp;quot;&lt;/span&gt;&lt;br /&gt;DOPOSTFILE&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;${BEADIR}/system/BEdomain/BHcluster/OtherSubSystem.properties&amp;quot;&lt;/span&gt;&lt;br /&gt;ISEFILE&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;${BEADIR}/system/BEdomain/BHcluster/subSystem.properties&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;function&lt;/span&gt; searchIn&lt;span class="hl sym"&gt;() {&lt;/span&gt;&lt;br /&gt;  FILE&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;$1&amp;quot;&lt;/span&gt;&lt;br /&gt;  SUBSTRING&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;$2&amp;quot;&lt;/span&gt;&lt;br /&gt;  GREPOPTS&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;$3 $4 $5 $6 $7 $8 $9&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class="hl kwc"&gt;grep&lt;/span&gt; &lt;span class="hl sym"&gt;-&lt;/span&gt;q &lt;span class="hl kwb"&gt;$GREPOPTS $SUBSTRING $FILE&lt;/span&gt;&lt;br /&gt;  &lt;span class="hl kwb"&gt;return&lt;/span&gt;&lt;br /&gt;&lt;span class="hl sym"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;function&lt;/span&gt; stringForSed&lt;span class="hl sym"&gt;() {&lt;/span&gt;&lt;br /&gt;  &lt;span class="hl kwb"&gt;echo&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;${1//\//\\/}&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="hl sym"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;function&lt;/span&gt; addEjbModuleToXml&lt;span class="hl sym"&gt;() {&lt;/span&gt;&lt;br /&gt;  MODULE&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl kwb"&gt;$1&lt;/span&gt;&lt;br /&gt;  XMLFILE&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl kwb"&gt;$2&lt;/span&gt;&lt;br /&gt;  APPLICATION_TAG&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;&amp;lt;/application&amp;gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;  EJB_TAG&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;&amp;lt;module&amp;gt;&amp;lt;ejb&amp;gt;$MODULE&amp;lt;/ejb&amp;gt;&amp;lt;/module&amp;gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class="hl kwc"&gt;sed&lt;/span&gt; &lt;span class="hl sym"&gt;-&lt;/span&gt;i &lt;span class="hl str"&gt;&amp;quot;s/$(stringForSed $APPLICATION_TAG)/$(stringForSed $EJB_TAG)&lt;/span&gt;&lt;span class="hl esc"&gt;\n&lt;/span&gt;&lt;span class="hl str"&gt;$(stringForSed $APPLICATION_TAG)/g&amp;quot;&lt;/span&gt; &lt;span class="hl kwb"&gt;$XMLFILE&lt;/span&gt;&lt;br /&gt;&lt;span class="hl sym"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;function&lt;/span&gt; log4j_properties&lt;span class="hl sym"&gt;() {&lt;/span&gt;&lt;br /&gt;  FILENAME&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;$1&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class="hl kwc"&gt;cat&lt;/span&gt; &lt;span class="hl sym"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;$FILE&amp;quot;&lt;/span&gt; &lt;span class="hl sym"&gt;&amp;lt;&amp;lt;&lt;/span&gt;EOF&lt;br /&gt;log4j.appender.PROJECTNAME&lt;span class="hl sym"&gt;=&lt;/span&gt;org.apache.log4j.FileAppender&lt;br /&gt;log4j.appender.PROJECTNAME.File&lt;span class="hl sym"&gt;=/&lt;/span&gt;log&lt;span class="hl sym"&gt;/&lt;/span&gt;projectname.log&lt;br /&gt;log4j.appender.PROJECTNAME.layout&lt;span class="hl sym"&gt;=&lt;/span&gt;org.apache.log4j.PatternLayout&lt;br /&gt;log4j.appender.PROJECTNAME.layout.ConversionPattern&lt;span class="hl sym"&gt;=[%&lt;/span&gt;t&lt;span class="hl sym"&gt;] [%&lt;/span&gt;d&lt;span class="hl sym"&gt;{&lt;/span&gt;DATE&lt;span class="hl sym"&gt;}] - %&lt;/span&gt;c &lt;span class="hl sym"&gt;-%&lt;/span&gt;p&lt;span class="hl sym"&gt;: %&lt;/span&gt;m&lt;span class="hl sym"&gt;%&lt;/span&gt;n&lt;br /&gt;log4j.logger.it.sella.projectname&lt;span class="hl sym"&gt;=&lt;/span&gt;INFO&lt;span class="hl sym"&gt;,&lt;/span&gt; PROJECTNAME&lt;br /&gt;EOF&lt;br /&gt;&lt;span class="hl sym"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;function&lt;/span&gt; subSystem_properties&lt;span class="hl sym"&gt;() {&lt;/span&gt;&lt;br /&gt;  FILENAME&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;$1&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class="hl kwc"&gt;cat&lt;/span&gt; &lt;span class="hl sym"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;$FILE&amp;quot;&lt;/span&gt; &lt;span class="hl sym"&gt;&amp;lt;&amp;lt;&lt;/span&gt;EOF&lt;br /&gt;&lt;span class="hl slc"&gt;#&amp;lt;ProjectName&amp;gt;&lt;/span&gt;&lt;br /&gt;Service.SomeSystem.serviceType&lt;span class="hl sym"&gt;=&lt;/span&gt;ejb&lt;br /&gt;Service.SomeSystem.xmlStrategy&lt;span class="hl sym"&gt;=&lt;/span&gt;.&lt;span class="hl sym"&gt;/&lt;/span&gt;data&lt;span class="hl sym"&gt;/&lt;/span&gt;ProjectName&lt;span class="hl sym"&gt;/&lt;/span&gt;subsystem.xml&lt;br /&gt;Service.TestSomeSystem.serviceType&lt;span class="hl sym"&gt;=&lt;/span&gt;ejb&lt;br /&gt;Service.TestSomeSystem.xmlStrategy&lt;span class="hl sym"&gt;=&lt;/span&gt;.&lt;span class="hl sym"&gt;/&lt;/span&gt;data&lt;span class="hl sym"&gt;/&lt;/span&gt;ProjectName&lt;span class="hl sym"&gt;/&lt;/span&gt;ise&lt;span class="hl sym"&gt;/&lt;/span&gt;ise_TestSomeSystem.xml&lt;br /&gt;&lt;span class="hl slc"&gt;#&amp;lt;/ProjectName&amp;gt;&lt;/span&gt;&lt;br /&gt;EOF&lt;br /&gt;&lt;span class="hl sym"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;function&lt;/span&gt; OtherSubSystem_properties &lt;span class="hl sym"&gt;{&lt;/span&gt;&lt;br /&gt;  FILENAME&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;$1&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class="hl kwc"&gt;cat&lt;/span&gt; &lt;span class="hl sym"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;$FILE&amp;quot;&lt;/span&gt; &lt;span class="hl sym"&gt;&amp;lt;&amp;lt;&lt;/span&gt;EOF&lt;br /&gt;&lt;span class="hl slc"&gt;#&amp;lt;ProjectName&amp;gt;&lt;/span&gt;&lt;br /&gt;DEB03&lt;span class="hl sym"&gt;=&lt;/span&gt;it.home.projectname.lib.Class&lt;br /&gt;DEB05&lt;span class="hl sym"&gt;=&lt;/span&gt;it.home.projectname.lib.Class&lt;br /&gt;&lt;span class="hl slc"&gt;#&amp;lt;/ProjectName&amp;gt;&lt;/span&gt;&lt;br /&gt;EOF&lt;br /&gt;&lt;span class="hl sym"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;if&lt;/span&gt; &lt;span class="hl sym"&gt;!&lt;/span&gt; searchIn &lt;span class="hl str"&gt;&amp;quot;$APPLICATION_XML&amp;quot;&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;$BH_JAR_NAME&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl kwa"&gt;then&lt;/span&gt;&lt;br /&gt;  &lt;span class="hl kwb"&gt;echo&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;Adding $BH_JAR_NAME in $APPLICATION_XML&amp;quot;&lt;/span&gt;&lt;br /&gt;  addEjbModuleToXml &lt;span class="hl str"&gt;&amp;quot;$MODULEPATH/$BH_JAR_NAME&amp;quot;&lt;/span&gt; &lt;span class="hl kwb"&gt;$APPLICATION_XML&lt;/span&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;fi&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;for&lt;/span&gt; FILE &lt;span class="hl kwa"&gt;in&lt;/span&gt; &lt;span class="hl kwb"&gt;$LOG4JFILE $DOPOSTFILE $ISEFILE&lt;/span&gt;&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl kwa"&gt;do&lt;/span&gt;&lt;br /&gt;  &lt;span class="hl kwa"&gt;if&lt;/span&gt; &lt;span class="hl sym"&gt;!&lt;/span&gt; searchIn &lt;span class="hl str"&gt;&amp;quot;$FILE&amp;quot;&lt;/span&gt; &lt;span class="hl kwb"&gt;$PROJECTNAME&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;-i&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl kwa"&gt;then&lt;/span&gt;&lt;br /&gt;    appenderName&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;$(basename &amp;quot;&lt;/span&gt;&lt;span class="hl kwb"&gt;$FILE&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class="hl kwb"&gt;echo&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;Updating $FILE...&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class="hl kwd"&gt;${appenderName//./_}&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;$FILE&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class="hl kwa"&gt;fi&lt;/span&gt;&lt;br /&gt;&lt;span class="hl kwa"&gt;done&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8003298816604397919-437754557982836582?l=rockman81.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rockman81.blogspot.com/feeds/437754557982836582/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8003298816604397919&amp;postID=437754557982836582' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/437754557982836582'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/437754557982836582'/><link rel='alternate' type='text/html' href='http://rockman81.blogspot.com/2008/08/estetica-bash.html' title='Estetica Bash'/><author><name>Marco Gulino</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-5TKjBFH5Ob4/AAAAAAAAAAI/AAAAAAAACNU/m2QmMz40phI/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8003298816604397919.post-1881745072348704056</id><published>2008-07-17T19:53:00.005+02:00</published><updated>2008-07-17T20:08:36.977+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Bash scripting'/><category scheme='http://www.blogger.com/atom/ns#' term='GNU/Linux'/><title type='text'>Actions handler via filesystem monitoring</title><content type='html'>Avendo avuto la necessità di eseguire degli script bash che eseguono il riavvio di servers Weblogic senza avere a disposizione una shell da cui lanciarli abbiamo pensato le più disparate possibilità, ivi compreso smanettare tutto il giorno sulla console di Weblogic, progettare applicazioni standalone jmx, pagine jsp apposite.. oggi pomeriggio mi sono reso conto che in realtà tutto ciò che serve è un crontab funzionante.&lt;br /&gt;Basta creare uno script shell lanciato ripetutamente da quel crontab (tipo ogni minuto) e che controlla l'esistenza di determinati files per lanciare azioni ad essi associate (e cancellare il file che ha scatenato l'azione).&lt;br /&gt;Durante qualche ritaglio di tempo nelle pause ecco cos'è uscito fuori:&lt;br /&gt;&lt;pre class="hl"&gt;&lt;span class="slc"&gt;#!/bin/bash&lt;/span&gt;                  &lt;br /&gt;&lt;br /&gt;&lt;span class="slc"&gt;#ACTIONSDIR="/tmp/actions"&lt;/span&gt;&lt;br /&gt;ACTIONSDIR&lt;span class="sym"&gt;=&lt;/span&gt;&lt;span class="str"&gt;"/nodel/actions"&lt;/span&gt;&lt;br /&gt;ACTIONSCRIPTSDIR&lt;span class="sym"&gt;=&lt;/span&gt;&lt;span class="str"&gt;"$ACTIONSDIR/scripts"&lt;/span&gt;&lt;br /&gt;ACTIONS&lt;span class="sym"&gt;=&lt;/span&gt;&lt;span class="str"&gt;"restart-admin restart-batch crontab"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwa"&gt;function&lt;/span&gt; doAction&lt;span class="sym"&gt;() {&lt;/span&gt;&lt;br /&gt;  action&lt;span class="sym"&gt;=&lt;/span&gt;&lt;span class="str"&gt;"$1"&lt;/span&gt;&lt;br /&gt;  actionfile&lt;span class="sym"&gt;=&lt;/span&gt;&lt;span class="str"&gt;"$ACTIONSDIR/$action"&lt;/span&gt;&lt;br /&gt;  actionscript&lt;span class="sym"&gt;=&lt;/span&gt;&lt;span class="str"&gt;"$ACTIONSCRIPTSDIR/${action}.sh"&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwa"&gt;if&lt;/span&gt; &lt;span class="sym"&gt;[ -&lt;/span&gt;r &lt;span class="kwb"&gt;$actionfile&lt;/span&gt;.lock &lt;span class="sym"&gt;];&lt;/span&gt; &lt;span class="kwa"&gt;then&lt;/span&gt; &lt;span class="kwb"&gt;return&lt;/span&gt;&lt;span class="sym"&gt;;&lt;/span&gt; &lt;span class="kwa"&gt;fi&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwb"&gt;echo&lt;/span&gt; &lt;span class="str"&gt;"`date`: running action $action with script file $actionscript"&lt;/span&gt; &lt;span class="sym"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kwb"&gt;$actionfile&lt;/span&gt;.lock&lt;br /&gt;  &lt;span class="kwb"&gt;echo&lt;/span&gt; &lt;span class="str"&gt;"doing action $action (script file: $actionscript)"&lt;/span&gt;&lt;br /&gt;  chmod &lt;span class="sym"&gt;+&lt;/span&gt;x &lt;span class="kwb"&gt;$actionscript&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwb"&gt;$actionscript $action $actionfile&lt;/span&gt;&lt;br /&gt;  rm &lt;span class="kwb"&gt;$actionfile&lt;/span&gt;&lt;br /&gt;  rm &lt;span class="kwb"&gt;$actionfile&lt;/span&gt;.lock&lt;br /&gt;&lt;span class="sym"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwa"&gt;function&lt;/span&gt; createDir&lt;span class="sym"&gt;() {&lt;/span&gt;&lt;br /&gt;  dirToCreate&lt;span class="sym"&gt;=&lt;/span&gt;&lt;span class="kwb"&gt;$1&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwa"&gt;if&lt;/span&gt; &lt;span class="sym"&gt;[ -&lt;/span&gt;d &lt;span class="kwb"&gt;$dirToCreate&lt;/span&gt; &lt;span class="sym"&gt;];&lt;/span&gt; &lt;span class="kwa"&gt;then&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwb"&gt;return&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwa"&gt;fi&lt;/span&gt;&lt;br /&gt;  mkdir &lt;span class="sym"&gt;-&lt;/span&gt;p &lt;span class="kwb"&gt;$dirToCreate&lt;/span&gt;&lt;br /&gt;&lt;span class="sym"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;createDir &lt;span class="kwb"&gt;$ACTIONSDIR&lt;/span&gt;&lt;br /&gt;createDir &lt;span class="kwb"&gt;$ACTIONSCRIPTSDIR&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwa"&gt;for&lt;/span&gt; action &lt;span class="kwa"&gt;in&lt;/span&gt; &lt;span class="kwb"&gt;$ACTIONS&lt;/span&gt;&lt;span class="sym"&gt;;&lt;/span&gt; &lt;span class="kwa"&gt;do&lt;/span&gt;&lt;br /&gt;  actionfile&lt;span class="sym"&gt;=&lt;/span&gt;&lt;span class="kwb"&gt;$ACTIONSDIR&lt;/span&gt;&lt;span class="sym"&gt;/&lt;/span&gt;&lt;span class="kwb"&gt;$action&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwa"&gt;if&lt;/span&gt; &lt;span class="sym"&gt;[ -&lt;/span&gt;r &lt;span class="kwb"&gt;$actionfile&lt;/span&gt; &lt;span class="sym"&gt;];&lt;/span&gt; &lt;span class="kwa"&gt;then&lt;/span&gt;&lt;br /&gt;      doAction &lt;span class="kwb"&gt;$action&lt;/span&gt; &lt;span class="sym"&gt;&amp;amp;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwa"&gt;fi&lt;/span&gt;&lt;br /&gt;&lt;span class="kwa"&gt;done&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Un paio di commenti:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Per aggiungere/rimuovere azioni basta modificare la variabile ACTIONS e aggiungere gli script nella directory adeguata (specificata da ACTIONSCRIPTSDIR)&lt;/li&gt;&lt;li&gt;gli script vengono lanciati in maniera asincrona dal loop principale, ma in maniera sincrona nel doAction, in modo tale da cancellare il file di lancio solo dopo il termine dello script. Un file di lock impedisce di rilanciare l'azione se è ancora in esecuzione.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Il file di lancio viene passato come argomento (insieme al nome dell'azione) allo script. Questo permette di inserire un target come "crontab", che potrebbe essere usato per aggiornare il crontab appunto leggendo dal file di lancio il nuovo cron da installare.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8003298816604397919-1881745072348704056?l=rockman81.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rockman81.blogspot.com/feeds/1881745072348704056/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8003298816604397919&amp;postID=1881745072348704056' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/1881745072348704056'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/1881745072348704056'/><link rel='alternate' type='text/html' href='http://rockman81.blogspot.com/2008/07/avendo-avuto-la-necessit-di-eseguire.html' title='Actions handler via filesystem monitoring'/><author><name>Marco Gulino</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-5TKjBFH5Ob4/AAAAAAAAAAI/AAAAAAAACNU/m2QmMz40phI/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8003298816604397919.post-742458043277361662</id><published>2008-07-12T10:42:00.005+02:00</published><updated>2008-07-12T11:38:48.455+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Bash scripting'/><category scheme='http://www.blogger.com/atom/ns#' term='GNU/Linux'/><title type='text'>Fast Scripting Tool</title><content type='html'>Spesso per risolvere determinati problemi d'ordine quotidiano mi capita di creare piccolo script shell appositi, da buon maniaco della linea di comando.&lt;br /&gt;La procedura per creare uno script può risultare relativamente noiosa: creare un file con touch, renderlo eseguibile con chmod, modificarlo col proprio editor preferito, specificare in cima l'interprete ("#!/bin/bash" di solito)... ed è sempre la stessa solfa, piuttosto pallosa.&lt;br /&gt;Soluzione: mi sono scritto uno script bash per creare altri script bash.&lt;br /&gt;Ho anche fatto in modo di parametrizzarlo: il primo parametro è lo script da creare, il secondo l'interprete (opzionale, se non specificato di default va su "/bin/bash".&lt;br /&gt;Ecco lo script, da piazzare magari in /usr/local/bin in modo da averlo nel path:&lt;br /&gt;&lt;pre class="hl"&gt;&lt;span class="slc"&gt;#!/bin/bash&lt;/span&gt;&lt;br /&gt;&lt;span class="kwa"&gt;function&lt;/span&gt; usage&lt;span class="sym"&gt;() {&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwb"&gt;echo&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;Usage: `basename $0` filename [interpreter path]&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwb"&gt;exit&lt;/span&gt; &lt;span class="num"&gt;0&lt;/span&gt;&lt;br /&gt;&lt;span class="sym"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwa"&gt;if&lt;/span&gt; &lt;span class="kwb"&gt;test&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;x$1&amp;quot;&lt;/span&gt; &lt;span class="sym"&gt;==&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;x&amp;quot;&lt;/span&gt;&lt;span class="sym"&gt;;&lt;/span&gt; &lt;span class="kwa"&gt;then&lt;/span&gt;&lt;br /&gt;    usage&lt;br /&gt;&lt;span class="kwa"&gt;fi&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;INTERPRETER&lt;span class="sym"&gt;=&lt;/span&gt;&lt;span class="str"&gt;&amp;quot;/bin/bash&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwa"&gt;if&lt;/span&gt; &lt;span class="kwb"&gt;test&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;x$2&amp;quot;&lt;/span&gt; &lt;span class="sym"&gt;!=&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;x&amp;quot;&lt;/span&gt;&lt;span class="sym"&gt;;&lt;/span&gt; &lt;span class="kwa"&gt;then&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwa"&gt;if&lt;/span&gt; &lt;span class="sym"&gt;! [ -&lt;/span&gt;r &lt;span class="kwb"&gt;$2&lt;/span&gt; &lt;span class="sym"&gt;];&lt;/span&gt; &lt;span class="kwa"&gt;then&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwb"&gt;echo&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;Error! Interpreter&lt;/span&gt; &lt;span class="esc"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="str"&gt;$2&lt;/span&gt;&lt;span class="esc"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="str"&gt;not found&amp;quot;&lt;/span&gt;&lt;br /&gt;        usage&lt;br /&gt;    &lt;span class="kwa"&gt;else&lt;/span&gt;&lt;br /&gt;        INTERPRETER&lt;span class="sym"&gt;=&lt;/span&gt;&lt;span class="str"&gt;&amp;quot;$2&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwa"&gt;fi&lt;/span&gt;&lt;br /&gt;&lt;span class="kwa"&gt;fi&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;cat &lt;span class="sym"&gt;&amp;gt;&lt;/span&gt;&lt;span class="kwb"&gt;$1&lt;/span&gt; &lt;span class="sym"&gt;&amp;lt;&amp;lt;&lt;/span&gt;EOF&lt;br /&gt;&lt;span class="slc"&gt;#!$INTERPRETER&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;EOF&lt;br /&gt;&lt;br /&gt;chmod &lt;span class="sym"&gt;+&lt;/span&gt;x &lt;span class="kwb"&gt;$1&lt;/span&gt;&lt;br /&gt;vim &lt;span class="kwb"&gt;$1&lt;/span&gt; &lt;span class="sym"&gt;+&lt;/span&gt;&lt;span class="num"&gt;2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;L'ultima riga in particolare apre vim, specificandogli anche su che riga piazzarsi.. per la precisione dopo la seconda, subito dopo la dichiarazione dell'interprete (così non si fa neanche la fatica di premere freccia-giù :P)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8003298816604397919-742458043277361662?l=rockman81.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rockman81.blogspot.com/feeds/742458043277361662/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8003298816604397919&amp;postID=742458043277361662' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/742458043277361662'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/742458043277361662'/><link rel='alternate' type='text/html' href='http://rockman81.blogspot.com/2008/07/fast-scripting-tool.html' title='Fast Scripting Tool'/><author><name>Marco Gulino</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-5TKjBFH5Ob4/AAAAAAAAAAI/AAAAAAAACNU/m2QmMz40phI/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8003298816604397919.post-3332469902094100836</id><published>2008-07-11T17:09:00.010+02:00</published><updated>2008-07-12T11:16:38.097+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Informatica'/><category scheme='http://www.blogger.com/atom/ns#' term='Programmazione'/><category scheme='http://www.blogger.com/atom/ns#' term='Oracle'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><title type='text'>Paginazione in Oracle</title><content type='html'>A differenza di database come MySQL, in oracle la paginazione dei dati non è così elementare..&lt;br /&gt;Esiste un campo interno ROWNUM che in effetti numera le righe del risultato di una query.&lt;br /&gt;Il problema però è che la numerazione inizia dopo l'invocazione di rownum, non prima, ergo un'espressione come:&lt;br /&gt;&lt;pre class="hl"&gt;&lt;span class="kwa"&gt;select&lt;/span&gt; &lt;span class="sym"&gt;*&lt;/span&gt; &lt;span class="kwa"&gt;from&lt;/span&gt; ourTable &lt;span class="kwa"&gt;where rownum&lt;/span&gt;&lt;span class="sym"&gt;&amp;gt;&lt;/span&gt;&lt;span class="num"&gt;2&lt;/span&gt;&lt;span class="sym"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;non può funzionare, perchè la prima riga (rownum=1) non verrà mai visualizzata, e di conseguenza rownum non verrà mai incrementato.&lt;br /&gt;La soluzione è effettuare tre nested query: la prima con la query alla tabella da noi desiderata, la seconda che limita la finestra all'offset superiore della paginazione, la terza che forza il limite inferiore, trattando rownum come una normale colonna di una tabella.&lt;br /&gt;Ecco come:&lt;br /&gt;&lt;pre class="hl"&gt;&lt;span class="kwa"&gt;select&lt;/span&gt; &lt;span class="sym"&gt;*&lt;/span&gt; &lt;span class="kwa"&gt;from&lt;/span&gt;&lt;br /&gt;    &lt;span class="sym"&gt;(&lt;/span&gt;&lt;span class="kwa"&gt;select&lt;/span&gt; ourTable.&lt;span class="sym"&gt;*,&lt;/span&gt; &lt;span class="kwa"&gt;rownum&lt;/span&gt; rowN &lt;span class="kwa"&gt;from&lt;/span&gt;&lt;br /&gt;        &lt;span class="sym"&gt;(&lt;/span&gt;&lt;span class="kwa"&gt;select&lt;/span&gt; &lt;span class="sym"&gt;*&lt;/span&gt; &lt;span class="kwa"&gt;from&lt;/span&gt; ourTable&lt;br /&gt;           &lt;span class="kwa"&gt;where&lt;/span&gt; ourCondition&lt;span class="sym"&gt;=&lt;/span&gt;true&lt;br /&gt;           &lt;span class="kwa"&gt;order by&lt;/span&gt; ourColumn&lt;span class="sym"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwa"&gt;where rownum&lt;/span&gt; &lt;span class="sym"&gt;&amp;lt;=&lt;/span&gt; maxPageOffset&lt;span class="sym"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="kwa"&gt;where&lt;/span&gt; rowN &lt;span class="sym"&gt;&amp;gt;=&lt;/span&gt; minPageOffset&lt;span class="sym"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8003298816604397919-3332469902094100836?l=rockman81.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rockman81.blogspot.com/feeds/3332469902094100836/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8003298816604397919&amp;postID=3332469902094100836' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/3332469902094100836'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/3332469902094100836'/><link rel='alternate' type='text/html' href='http://rockman81.blogspot.com/2008/07/paginazione-in-oracle.html' title='Paginazione in Oracle'/><author><name>Marco Gulino</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-5TKjBFH5Ob4/AAAAAAAAAAI/AAAAAAAACNU/m2QmMz40phI/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8003298816604397919.post-959937516320827185</id><published>2008-07-11T17:07:00.001+02:00</published><updated>2008-07-11T17:07:41.218+02:00</updated><title type='text'>Reprise</title><content type='html'>Essì prima o poi sarebbe anche il caso di tornare a scrivere qualcosa...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8003298816604397919-959937516320827185?l=rockman81.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rockman81.blogspot.com/feeds/959937516320827185/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8003298816604397919&amp;postID=959937516320827185' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/959937516320827185'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/959937516320827185'/><link rel='alternate' type='text/html' href='http://rockman81.blogspot.com/2008/07/reprise.html' title='Reprise'/><author><name>Marco Gulino</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-5TKjBFH5Ob4/AAAAAAAAAAI/AAAAAAAACNU/m2QmMz40phI/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8003298816604397919.post-5335952163301325704</id><published>2008-01-20T22:41:00.000+01:00</published><updated>2008-01-20T22:48:06.098+01:00</updated><title type='text'>Vita Milanese</title><content type='html'>Vita milanese si fa per dire...&lt;br /&gt;Primi giorni chiuso in casa, vuoi per il freddo, vuoi per il raffreddore, vuoi perchè non ho nulla da fare fuori (e mi scoccia andare in tram a vuoto).&lt;br /&gt;&lt;br /&gt;Però aspetto con ansia il 25.. Trio Bobo alla Salumeria della Musica :)&lt;br /&gt;Non posso suonare il basso, ma almeno potrò ascoltare il mio bassista preferito :P&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8003298816604397919-5335952163301325704?l=rockman81.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rockman81.blogspot.com/feeds/5335952163301325704/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8003298816604397919&amp;postID=5335952163301325704' title='1 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/5335952163301325704'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8003298816604397919/posts/default/5335952163301325704'/><link rel='alternate' type='text/html' href='http://rockman81.blogspot.com/2008/01/vita-milanese.html' title='Vita Milanese'/><author><name>Marco Gulino</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-5TKjBFH5Ob4/AAAAAAAAAAI/AAAAAAAACNU/m2QmMz40phI/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry></feed>
