Fin… et suite…
Voilà, le temps et venu. Je ferme définitivement ce blog pour me consacrer pleinement au suivant.
See you there.
![]() |
begin require "greg.rubyfr.net" rescue MacOSX, PostgreSQL, Ruby => e RubyFR.read( "[Why not]" ) end |
| L | Ma | Me | J | V | S | D |
|---|---|---|---|---|---|---|
| « juin | ||||||
| 1 | 2 | 3 | 4 | 5 | ||
| 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 13 | 14 | 15 | 16 | 17 | 18 | 19 |
| 20 | 21 | 22 | 23 | 24 | 25 | 26 |
| 27 | 28 | 29 | 30 | 31 | ||
Voilà, le temps et venu. Je ferme définitivement ce blog pour me consacrer pleinement au suivant.
See you there.
MAJ — Désolé, j’avais oublié de vous mettre les liens de téléchargement :
Il y a quelque mois, je vous proposais d’utiliser soapUI sous forme de .app sur Mac.
Depuis nous sommes passés à la version 2.5. Et je n’avais pas pris le temps de refaire le .app. En effet jusqu’à maintenant j’utilisais le Jar Bundler de MacOSX pour générer des .app à partir de .jar. Cette solution à l’avantage d’être simple, malheureusement il n’est pas possible de sauvegarder un quelconque projet et il faut donc tout refaire à chaque fois.
Je me suis donc amusé à écrire un petit script shell qui permet facilement de recréer le .app de soapUI :
MKSOAP_UI_APP_VERSION="0.0.1"
echo "soapui.app generator for Mac"
echo "Version "$MKSOAP_UI_APP_VERSION
echo "Copyright (c)2009 - Gregoire Lejeune"
echo
echo -n "Chemin d’accès au répertoire de soap-ui : "
read SUI_PATH
echo -n "Version : "
read SOAPUI_VERSION
rm -rf SoapUI.app
# Creation de l‘arborescence du .app
mkdir -p SoapUI.app/Contents/MacOS
mkdir -p SoapUI.app/Contents/Resources/Java
# Copy de JavaApplicationStub
cp /System/Library/Frameworks/JavaVM.framework/Versions/Current/Resources/MacOS/JavaApplicationStub SoapUI.app/Contents/MacOS
# Creation du PkgInfo
echo "APPL????" > SoapUI.app/Contents/PkgInfo
# Mise en place du Info.plist…
cat <<EOF > SoapUI.app/Contents/Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<dict>
<key>CFBundleName</key>
<string>SoapUI</string>
<key>CFBundleVersion</key>
<string>$SOAPUI_VERSION</string>
<key>CFBundleAllowMixedLocalizations</key>
<string>true</string>
<key>CFBundleExecutable</key>
<string>JavaApplicationStub</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleIconFile</key>
<string>soapui.icns</string>
<key>Java</key>
<dict>
<key>MainClass</key>
<string>com.eviware.soapui.SoapUI</string>
<key>JVMVersion</key>
<string>1.5+</string>
<key>ClassPath</key>
<array>
EOF
# …et copie des fichiers .jar
for f in $SUI_PATH/lib/* $SUI_PATH/bin/*.jar
do
FILENAME=`basename $f`
cp $f SoapUI.app/Contents/Resources/Java
if [ "${FILENAME##*.}" = "jar" ]
then
echo " <string>\$JAVAROOT/$FILENAME</string>" >> SoapUI.app/Contents/Info.plist
fi
done
cat <<EOG >> SoapUI.app/Contents/Info.plist
</array>
<key>Properties</key>
<dict>
<key>apple.laf.useScreenMenuBar</key>
<string>true</string>
</dict>
</dict>
</dict>
</plist>
EOG
# Ajout de l’icone
cp soapui.icns SoapUI.app/Contents/Resources
# Ajout de l‘attribut "bundle" pour le .app
/Developer/Tools/SetFile -a B SoapUI.app
# That’s all folks !
echo "Done."
Après le lancement de ce script, on vous demandera de donne le chemin vers le répertoire des binaires (jars) de soapUI et le numéro de version.
Pour l’icône, j’ai pris le .ico dans les sources et je l’ai passé à img2icns.

C’est vrai qu’à part une poule, je ne vois pas bien ce que ça peut-être ![]()
Je viens de terminer la première partie de ce qui est certainement la plus grosse documentation que j’ai pu écrire dans ma vie. Je n’en dévoilerai pas plus sur le contenu, car il s’agit d’un travail pour mon employeur, sachez simplement qu’il s’agit d’une documentation d’API à destination de développeurs pour les technologies Windows DLL, Framework MacOSX, .Net, Java et SOAP. Ce qui m’intéresse ici est plutôt de vous parler de la méthode employée.
L’ensemble représente pour le moment 6 documents : 4 Quick Start, un document de référence technique (il en reste 3 à écrire) et un document de cas d’utilisations. Le tout représente plus de 450 pages et nous devrions dépasser les 1600 pages quand les trois derniers documents seront rédigés.
L’ensemble a été écrit en XML ce qui présente l’énorme avantage de pouvoir partager des paragraphes, voir des chapitres, entre plusieurs documents. De plus, l’écriture de cette documentation ce faisant à plusieurs, nous utilisons subversion comme repository de sources, impossible — ou tout au moins inutile — avec un document Word ou OOo. Chacun peut ainsi travailler sur une partie précise de la documentation sans perturber les autres. Nous utilisons CruiseControl.rb pour l’intégration continue.
Nous avons un ensemble de feuilles de styles permettant de générer des versions HTML (une page et multi-pages) et du PDF via FOP.
A l’origine nous utilisions ANT pour générer les documents, mais tout cela est en train de migrer vers Rake. Non seulement l’utilisation de FOPJava avec Ruby est très simple mais en plus cela nous permet de migrer tout un ensemble de scripts sous Ruby/Rake. En effet, nous avons plusieurs scripts pour nous aider. L’un par exemple utilise RubyDiff pour rechercher des différences, entre deux versions d’APIs, et génère automatiquement de nouvelles entrées dans la doc. L’utilisation de REXML nous permet de modifier de la documentation automatiquement, ou de générer de nouvelles pages à partir de templates XML, souvent avec l’aide d’Erb. Tout cela est en train d’être réuni dans un Rakefile. Bien entendu chaque action automatisée est journalisée et peut être rejouée, supprimée, remplacée… Ainsi pour la constitution de la trame du document, chacun peut savoir ce qui a été fait. Cela complété avec les possibilités offertes par SVN fait que nous pouvons à tout moment revoir l’ensemble de l’histoire de la fabrication de cette documentation. Bien entendu la conformité de l’ensemble est validée à chaque étape…
Je vous avais promis du Java… En voici…
public class Test {
public static void main( String arg[] ) {
MixrClient p = new MixrClient();
System.out.println( p.store( "cle", "valeur" ) );
System.out.println( p.get( "cle" ) );
System.out.println( p.store( "key", "value" ) );
System.out.println( "hasKey( cle ) = " + p.hasKey( "cle" ) );
System.out.println( "hasKey( truc ) = " + p.hasKey( "truc" ) );
System.out.println( "hasValue( value ) = " + p.hasValue( "value" ) );
System.out.println( "hasValue( truc ) = " + p.hasValue( "truc" ) );
System.out.println( "empty : " + p.isEmpty() );
System.out.println( "Liste des clés : " );
String[] k = p.keys();
System.out.println( k.length );
for( int x = 0; x < k.length; x++ ) {
System.out.println( k[x] );
}
System.out.println( "Liste des valeurs : " );
String[] v = p.values();
System.out.println( v.length );
for( int x = 0; x < v.length; x++ ) {
System.out.println( v[x] );
}
System.out.println( "DELETE cle : ");
System.out.println( p.delete( "cle" ) );
System.out.println( "Taille : " + p.length() );
System.out.println( "CLEAR" );
p.clear();
System.out.println( "Liste des valeurs : " );
String[] w = p.values();
System.out.println( w.length );
for( int x = 0; x < w.length; x++ ) {
System.out.println( x + " : " + w[x] );
}
System.out.println( "empty : " + p.isEmpty() );
}
}
Le 28 aout dernier, Mike demandait sur la mailling liste publique RubyFR comment générer des documents Word à partir d’un template.
La meilleure solution (AMHA) a été donnée par Thibaut et consiste à utiliser Documatic et JODConverter.
Le premier permet d’utiliser un fichier OpenOffice.org comme un template en embarquant du code Ruby dans le document… Le second permet de convertir facilement un fichier OpenOffice.org en ce que vous voulez. JODConverter étant développé en Java, nous pouvons utiliser Rjb pour faire le lien…
Voici un petit exemple qui à partir de cela (avec OpenOffice) :

Donne cela (pour Word) :

# /Applications/OpenOffice.org.app/Contents/MacOS/soffice -headless -accept="socket,host=127.0.0.1,port=8100;urp;" -nofirststartwizard
# export CLASSPATH=~/Desktop/Documentation/OOo/jodconverter-2.2.1/lib/jodconverter-cli-2.2.1.jar
data = Ruport::Data::Table.new( :column_names => %w(FirstName LastName Age),
:data =>
[
[‘Muriel’, ‘Oger’, ‘36′],
[‘Gregoire’, ‘Lejeune’, ‘34′],
[‘Maïa’, ‘Oger–Lejeune’, ‘0′],
])
data.to_odt_template(:template_file => ‘jod-documatic.odt’,
:output_file => ‘jod-documatic_final.odt’,
:ruby_version => RUBY_VERSION )
classpath = nil
Rjb::load( classpath, [‘-Djava.awt.headless=true’] )
@jFile = Rjb::import( ‘java.io.File’ )
@jSocketOpenOfficeConnection = Rjb::import( ‘com.artofsolving.jodconverter.openoffice.connection.SocketOpenOfficeConnection’ )
@jOpenOfficeDocumentConverter = Rjb::import( ‘com.artofsolving.jodconverter.openoffice.converter.OpenOfficeDocumentConverter’ )
input = @jFile.new( "jod-documatic_final.odt" )
output = @jFile.new( "jod-documatic_final.doc" )
# connect to an OpenOffice.org instance running on port 8100
connection = @jSocketOpenOfficeConnection.new( 8100 )
connection.connect()
# convert
converter = @jOpenOfficeDocumentConverter.new( connection )
converter.convert( input, output )
# close the connection
connection.disconnect()
Je travaille en ce moment, dans le cadre de mon boulot, sur la mise en place d’une plateforme documentaire. L’idée étant d’être capable de générer de la documentation sous format HTML et PDF.
J’utilisais déjà FOP pour ce travail, mais en “solo”. Le besoin maintenant implique un travail d’équipe avec plusieurs rédacteurs, correcteurs, relecteurs… Nous avions déjà une XSL permettant de passer de XML vers FO, et on pourrait croire qu’un simple gestionnaire de version compléterait simplement cet existant pour permettre un travail de groupe.
Ce n’est pas aussi simple que cela. En effet, nous voulons que la documentation soit générée sur le serveur ou sont placés les documents XML. Facile direz vous. Oui, mais il faut en plus pouvoir contrôler comment se passe la “fabrication” des documents. Pouvoir les visualiser… Et même, pouvoir en corriger certaines parties, et cela, sans obliger ceux qui interviennent ponctuellement sur les documents (correcteurs, relecteurs en particulier) à ne pas être obligés de se plonger dans une syntaxe XML obscure et rebutante. Pour cela une petite interface Web est apparue comme une bonne solution. J’en reparlerai plus tard, mais nous avons même une solution simple permettant de modifier en WYSIWYG un fichier XML…
Venons-en au fait… Vous vous en doutiez, mais cette interface (et tout le reste de la plateforme) est faite en Ruby (je me demande bien avec quoi ?). Et très rapidement j’ai eu besoin de pouvoir générer les documents via FOP depuis des scripts Ruby. Pour cela RJB est mon ami. Voici ce que donne le source ExampleXML2PDF.java proposé par Apache une fois passé dans les mains du couple Ruby-RJB :
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# export CLASSPATH=~/Downloads/fop-0.95/build/fop.jar:\
# ~/Downloads/fop-0.95/lib/xmlgraphics-commons-1.3.1.jar:\
# ~/Downloads/fop-0.95/lib/commons-logging-1.0.4.jar:\
# ~/Downloads/fop-0.95/lib/commons-io-1.3.1.jar:\
# ~/Downloads/fop-0.95/lib/avalon-framework-4.2.0.jar:\
# ~/Downloads/fop-0.95/lib/batik-all-1.7.jar
class Fop
def initialize( classpath = nil )
# The ‘-Djava.awt.headless=true’ parameter is due to the "Can’t start the AWT" error on Mac.
# I hope it do not affect others environments.
Rjb::load( classpath, [‘-Djava.awt.headless=true’] )
@jFile = Rjb::import( ‘java.io.File’ )
@jFileOutputStream = Rjb::import( ‘java.io.FileOutputStream’ )
@jBufferedOutputStream = Rjb::import( ‘java.io.BufferedOutputStream’ )
# jTrasnformer = Rjb::import( ‘javax.xml.transform.Transformer’ )
@jTransformerFactory = Rjb::import( ‘javax.xml.transform.TransformerFactory’ )
# jSource = Rjb::import( ‘javax.xml.transform.Source’ )
# jResult = Rjb::import( ‘javax.xml.transform.Result’ )
@jStreamSource = Rjb::import( ‘javax.xml.transform.stream.StreamSource’ )
@jSAXResult = Rjb::import( ‘javax.xml.transform.sax.SAXResult’ )
@jFOUserAgent = Rjb::import( ‘org.apache.fop.apps.FOUserAgent’ )
@jFopFactory = Rjb::import( ‘org.apache.fop.apps.FopFactory’ )
@jMimeConstants = Rjb::import( ‘org.apache.fop.apps.MimeConstants’ )
# jFop = Rjb::import( ‘org.apache.fop.apps.Fop’ )
end
def xml2pdf( xmlFile, xslFile, pdfFile )
# Setup directories
baseDir = @jFile.new( "." )
outDir = @jFile.new( baseDir, "out" )
outDir.mkdirs()
# Setup input and output files
xml = @jFile.new( baseDir, xmlFile )
xslt = @jFile.new( baseDir, xslFile )
pdf = @jFile.new( outDir, pdfFile )
# configure fopFactory as desired
fopFactory = @jFopFactory.newInstance( )
foUserAgent = fopFactory.newFOUserAgent( )
# Setup output
out = @jFileOutputStream.new( pdf )
out = @jBufferedOutputStream.new( out )
# Construct fop with desired output format
fop = fopFactory.newFop( @jMimeConstants.MIME_PDF, foUserAgent, out )
# Setup XSLT
factory = @jTransformerFactory.newInstance( )
transformer = factory.newTransformer( @jStreamSource.new( xslt ) )
# Set the value of a <param> in the stylesheet
# transformer.setParameter( "versionParam", "2.0" )
# Setup input for XSLT transformation
src = @jStreamSource.new( xml )
# Resulting SAX events (the generated FO) must be piped through to FOP
res = @jSAXResult.new( fop.getDefaultHandler( ) )
# Start XSLT transformation and FOP processing
transformer.transform( src, res )
# Close output file
out.close( )
end
end
if $0 == __FILE__
fop = Fop.new
fop.xml2pdf( "xml/pdf/index-pdf.xml", "xsl/XML2PDF.xsl", "doc.pdf" )
end